From 8b5979a7e8b9732aa2883d2384f853d87b594770 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Wed, 28 Jul 1993 12:00:00 +0000 Subject: [PATCH 01/97] Lua 1.0 --- Makefile | 29 + README | 22 + array.lua | 15 + fixed/iolib.c | 402 ++++++++++++ fixed/lex_yy.c | 923 ++++++++++++++++++++++++++ fixed/lua.c | 55 ++ floatingpoint.h | 1 + globals.lua | 5 + hash.c | 259 ++++++++ hash.h | 35 + inout.c | 188 ++++++ inout.h | 24 + iolib.c | 401 ++++++++++++ lex_yy.c | 923 ++++++++++++++++++++++++++ lua.c | 54 ++ lua.h | 54 ++ lualib.h | 15 + mathlib.c | 234 +++++++ opcode.c | 933 +++++++++++++++++++++++++++ opcode.h | 144 +++++ save.lua | 47 ++ sort.lua | 56 ++ strlib.c | 131 ++++ table.c | 351 ++++++++++ table.h | 39 ++ test.lua | 15 + type.lua | 35 + y_tab.c | 1639 +++++++++++++++++++++++++++++++++++++++++++++++ y_tab.h | 35 + 29 files changed, 7064 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 array.lua create mode 100644 fixed/iolib.c create mode 100644 fixed/lex_yy.c create mode 100644 fixed/lua.c create mode 100644 floatingpoint.h create mode 100644 globals.lua create mode 100644 hash.c create mode 100644 hash.h create mode 100644 inout.c create mode 100644 inout.h create mode 100644 iolib.c create mode 100644 lex_yy.c create mode 100644 lua.c create mode 100644 lua.h create mode 100644 lualib.h create mode 100644 mathlib.c create mode 100644 opcode.c create mode 100644 opcode.h create mode 100644 save.lua create mode 100644 sort.lua create mode 100644 strlib.c create mode 100644 table.c create mode 100644 table.h create mode 100644 test.lua create mode 100644 type.lua create mode 100644 y_tab.c create mode 100644 y_tab.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..8ed18bb5dd --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +OBJS= hash.o inout.o lex_yy.o opcode.o table.o y_tab.o lua.o iolib.o mathlib.o strlib.o + +CFLAGS= -O2 -I. + +T= lua + +all: $T + +$T: $(OBJS) + $(CC) -o $@ $(OBJS) -lm + +A=-------------------------------------------------------------------------- +test: $T + @echo "$A" + ./$T sort.lua main + @echo "$A" + ./$T globals.lua | sort | column + @echo "$A" + ./$T array.lua + @echo "$A" + ./$T save.lua + @echo "$A" + ./$T test.lua retorno_multiplo norma + +clean: + rm -f $T $(OBJS) core core.* + +diff: + diff . fixed | grep -v ^Only diff --git a/README b/README new file mode 100644 index 0000000000..29ad01d58f --- /dev/null +++ b/README @@ -0,0 +1,22 @@ +This is Lua 1.0. It was never publicly released. This code is a snapshot of +the status of Lua on 28 Jul 1993. It is distributed for historical curiosity +to celebrate 10 years of Lua and is hereby placed in the public domain. + +There is no documentation, except the test programs. The manual for Lua 1.1 +probably works for this version as well. + +The source files for the lexer and parser have been lost: all that is left is +the output of lex and yacc. A grammar can be found inside y_tab.c in yyreds. + +The code compiles and runs in RedHat 5.2 with gcc 2.7.2.3. It may not run in +newer systems, because it assumes that stdin and stdout are constants, though +ANSI C does not promise they are. If make fails, try using the fixed modules +provided in the "fixed" directory. To see the differences (which are really +quite minor), do "make diff". + +To see Lua 1.0 in action, do "make test". (The last test raises an error on +purpose.) + +Enjoy! + +-- The Lua team, lua@tecgraf.puc-rio.br diff --git a/array.lua b/array.lua new file mode 100644 index 0000000000..349fb81821 --- /dev/null +++ b/array.lua @@ -0,0 +1,15 @@ +$debug + +a = @() + +i=0 +while i<10 do + a[i] = i*i + i=i+1 +end + +r,v = next(a,nil) +while r ~= nil do + print ("array["..r.."] = "..v) + r,v = next(a,r) +end diff --git a/fixed/iolib.c b/fixed/iolib.c new file mode 100644 index 0000000000..dce91f9dbe --- /dev/null +++ b/fixed/iolib.c @@ -0,0 +1,402 @@ +/* +** iolib.c +** Input/output library to LUA +** +** Waldemar Celes Filho +** TeCGraf - PUC-Rio +** 19 May 93 +*/ + +#include +#include +#include +#include +#ifdef __GNUC__ +#include +#endif + +#include "lua.h" + +static FILE *in=NULL, *out=NULL; + +/* +** Open a file to read. +** LUA interface: +** status = readfrom (filename) +** where: +** status = 1 -> success +** status = 0 -> error +*/ +static void io_readfrom (void) +{ + lua_Object o = lua_getparam (1); + if (o == NULL) /* restore standart input */ + { + if (in != stdin) + { + fclose (in); + in = stdin; + } + lua_pushnumber (1); + } + else + { + if (!lua_isstring (o)) + { + lua_error ("incorrect argument to function 'readfrom`"); + lua_pushnumber (0); + } + else + { + FILE *fp = fopen (lua_getstring(o),"r"); + if (fp == NULL) + { + lua_pushnumber (0); + } + else + { + if (in != stdin) fclose (in); + in = fp; + lua_pushnumber (1); + } + } + } +} + + +/* +** Open a file to write. +** LUA interface: +** status = writeto (filename) +** where: +** status = 1 -> success +** status = 0 -> error +*/ +static void io_writeto (void) +{ + lua_Object o = lua_getparam (1); + if (o == NULL) /* restore standart output */ + { + if (out != stdout) + { + fclose (out); + out = stdout; + } + lua_pushnumber (1); + } + else + { + if (!lua_isstring (o)) + { + lua_error ("incorrect argument to function 'writeto`"); + lua_pushnumber (0); + } + else + { + FILE *fp = fopen (lua_getstring(o),"w"); + if (fp == NULL) + { + lua_pushnumber (0); + } + else + { + if (out != stdout) fclose (out); + out = fp; + lua_pushnumber (1); + } + } + } +} + + +/* +** Read a variable. On error put nil on stack. +** LUA interface: +** variable = read ([format]) +** +** O formato pode ter um dos seguintes especificadores: +** +** s ou S -> para string +** f ou F, g ou G, e ou E -> para reais +** i ou I -> para inteiros +** +** Estes especificadores podem vir seguidos de numero que representa +** o numero de campos a serem lidos. +*/ +static void io_read (void) +{ + lua_Object o = lua_getparam (1); + if (o == NULL) /* free format */ + { + int c; + char s[256]; + while (isspace(c=fgetc(in))) + ; + if (c == '\"') + { + if (fscanf (in, "%[^\"]\"", s) != 1) + { + lua_pushnil (); + return; + } + } + else if (c == '\'') + { + if (fscanf (in, "%[^\']\'", s) != 1) + { + lua_pushnil (); + return; + } + } + else + { + char *ptr; + double d; + ungetc (c, in); + if (fscanf (in, "%s", s) != 1) + { + lua_pushnil (); + return; + } + d = strtod (s, &ptr); + if (!(*ptr)) + { + lua_pushnumber (d); + return; + } + } + lua_pushstring (s); + return; + } + else /* formatted */ + { + char *e = lua_getstring(o); + char t; + int m=0; + while (isspace(*e)) e++; + t = *e++; + while (isdigit(*e)) + m = m*10 + (*e++ - '0'); + + if (m > 0) + { + char f[80]; + char s[256]; + sprintf (f, "%%%ds", m); + fscanf (in, f, s); + switch (tolower(t)) + { + case 'i': + { + long int l; + sscanf (s, "%ld", &l); + lua_pushnumber(l); + } + break; + case 'f': case 'g': case 'e': + { + float f; + sscanf (s, "%f", &f); + lua_pushnumber(f); + } + break; + default: + lua_pushstring(s); + break; + } + } + else + { + switch (tolower(t)) + { + case 'i': + { + long int l; + fscanf (in, "%ld", &l); + lua_pushnumber(l); + } + break; + case 'f': case 'g': case 'e': + { + float f; + fscanf (in, "%f", &f); + lua_pushnumber(f); + } + break; + default: + { + char s[256]; + fscanf (in, "%s", s); + lua_pushstring(s); + } + break; + } + } + } +} + + +/* +** Write a variable. On error put 0 on stack, otherwise put 1. +** LUA interface: +** status = write (variable [,format]) +** +** O formato pode ter um dos seguintes especificadores: +** +** s ou S -> para string +** f ou F, g ou G, e ou E -> para reais +** i ou I -> para inteiros +** +** Estes especificadores podem vir seguidos de: +** +** [?][m][.n] +** +** onde: +** ? -> indica justificacao +** < = esquerda +** | = centro +** > = direita (default) +** m -> numero maximo de campos (se exceder estoura) +** n -> indica precisao para +** reais -> numero de casas decimais +** inteiros -> numero minimo de digitos +** string -> nao se aplica +*/ +static char *buildformat (char *e, lua_Object o) +{ + static char buffer[512]; + static char f[80]; + char *string = &buffer[255]; + char t, j='r'; + int m=0, n=0, l; + while (isspace(*e)) e++; + t = *e++; + if (*e == '<' || *e == '|' || *e == '>') j = *e++; + while (isdigit(*e)) + m = m*10 + (*e++ - '0'); + e++; /* skip point */ + while (isdigit(*e)) + n = n*10 + (*e++ - '0'); + + sprintf(f,"%%"); + if (j == '<' || j == '|') sprintf(strchr(f,0),"-"); + if (m != 0) sprintf(strchr(f,0),"%d", m); + if (n != 0) sprintf(strchr(f,0),".%d", n); + sprintf(strchr(f,0), "%c", t); + switch (tolower(t)) + { + case 'i': t = 'i'; + sprintf (string, f, (long int)lua_getnumber(o)); + break; + case 'f': case 'g': case 'e': t = 'f'; + sprintf (string, f, (float)lua_getnumber(o)); + break; + case 's': t = 's'; + sprintf (string, f, lua_getstring(o)); + break; + default: return ""; + } + l = strlen(string); + if (m!=0 && l>m) + { + int i; + for (i=0; iyysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar) +# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;*yysptr++=yytchar;} +# define yymore() (yymorfg=1) +# define ECHO fprintf(yyout, "%s",yytext) +# define REJECT { nstr = yyreject(); goto yyfussy;} +int yyleng; extern char yytext[]; +int yymorfg; +extern char *yysptr, yysbuf[]; +int yytchar; +FILE *yyin = {NULL}, *yyout = {NULL}; +extern int yylineno; +struct yysvf { + struct yywork *yystoff; + struct yysvf *yyother; + int *yystops;}; +struct yysvf *yyestate; +extern struct yysvf yysvec[], *yybgin; +#include +#include + +#include "opcode.h" +#include "hash.h" +#include "inout.h" +#include "table.h" +#include "y_tab.h" + +#undef input +#undef unput + +static Input input; +static Unput unput; + +void lua_setinput (Input fn) +{ + input = fn; +} + +void lua_setunput (Unput fn) +{ + unput = fn; +} + +char *lua_lasttext (void) +{ + return yytext; +} + +# define YYNEWLINE 10 +yylex(){ +int nstr; extern int yyprevious; +while((nstr = yylook()) >= 0) +yyfussy: switch(nstr){ +case 0: +if(yywrap()) return(0); break; +case 1: + ; +break; +case 2: + {yylval.vInt = 1; return DEBUG;} +break; +case 3: + {yylval.vInt = 0; return DEBUG;} +break; +case 4: + lua_linenumber++; +break; +case 5: + ; +break; +case 6: + return LOCAL; +break; +case 7: + return IF; +break; +case 8: + return THEN; +break; +case 9: + return ELSE; +break; +case 10: + return ELSEIF; +break; +case 11: + return WHILE; +break; +case 12: + return DO; +break; +case 13: + return REPEAT; +break; +case 14: + return UNTIL; +break; +case 15: + { + yylval.vWord = lua_nfile-1; + return FUNCTION; + } +break; +case 16: + return END; +break; +case 17: + return RETURN; +break; +case 18: + return LOCAL; +break; +case 19: + return NIL; +break; +case 20: + return AND; +break; +case 21: + return OR; +break; +case 22: + return NOT; +break; +case 23: + return NE; +break; +case 24: + return LE; +break; +case 25: + return GE; +break; +case 26: + return CONC; +break; +case 27: + case 28: + { + yylval.vWord = lua_findenclosedconstant (yytext); + return STRING; + } +break; +case 29: +case 30: +case 31: +case 32: +{ + yylval.vFloat = atof(yytext); + return NUMBER; + } +break; +case 33: + { + yylval.vWord = lua_findsymbol (yytext); + return NAME; + } +break; +case 34: + return *yytext; +break; +case -1: +break; +default: +fprintf(yyout,"bad switch yylook %d",nstr); +} return(0); } +/* end of yylex */ +int yyvstop[] = { +0, + +1, +0, + +1, +0, + +34, +0, + +1, +34, +0, + +4, +0, + +34, +0, + +34, +0, + +34, +0, + +34, +0, + +29, +34, +0, + +34, +0, + +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +34, +0, + +34, +0, + +1, +0, + +27, +0, + +28, +0, + +5, +0, + +26, +0, + +30, +0, + +29, +0, + +29, +0, + +24, +0, + +25, +0, + +33, +0, + +33, +0, + +12, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +7, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +21, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +23, +0, + +29, +30, +0, + +31, +0, + +20, +33, +0, + +33, +0, + +16, +33, +0, + +33, +0, + +33, +0, + +19, +33, +0, + +22, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +32, +0, + +9, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +8, +33, +0, + +33, +0, + +33, +0, + +31, +32, +0, + +33, +0, + +33, +0, + +6, +18, +33, +0, + +33, +0, + +33, +0, + +14, +33, +0, + +11, +33, +0, + +10, +33, +0, + +33, +0, + +13, +33, +0, + +17, +33, +0, + +2, +0, + +33, +0, + +15, +33, +0, + +3, +0, +0}; +# define YYTYPE char +struct yywork { YYTYPE verify, advance; } yycrank[] = { +0,0, 0,0, 1,3, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 1,4, 1,5, +6,29, 4,28, 0,0, 0,0, +0,0, 0,0, 7,31, 0,0, +6,29, 6,29, 0,0, 0,0, +0,0, 0,0, 7,31, 7,31, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 1,6, +4,28, 0,0, 0,0, 0,0, +1,7, 0,0, 0,0, 0,0, +1,3, 6,30, 1,8, 1,9, +0,0, 1,10, 6,29, 7,31, +8,33, 0,0, 6,29, 0,0, +7,32, 0,0, 0,0, 6,29, +7,31, 1,11, 0,0, 1,12, +2,27, 7,31, 1,13, 11,39, +12,40, 1,13, 26,56, 0,0, +0,0, 2,8, 2,9, 0,0, +6,29, 0,0, 0,0, 6,29, +0,0, 0,0, 7,31, 0,0, +0,0, 7,31, 0,0, 0,0, +2,11, 0,0, 2,12, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 1,14, 0,0, +0,0, 1,15, 1,16, 1,17, +0,0, 22,52, 1,18, 18,47, +23,53, 1,19, 42,63, 1,20, +1,21, 25,55, 14,42, 1,22, +15,43, 1,23, 1,24, 16,44, +1,25, 16,45, 17,46, 19,48, +21,51, 2,14, 20,49, 1,26, +2,15, 2,16, 2,17, 24,54, +20,50, 2,18, 44,64, 45,65, +2,19, 46,66, 2,20, 2,21, +27,57, 48,67, 2,22, 49,68, +2,23, 2,24, 50,69, 2,25, +52,70, 53,72, 27,58, 54,73, +52,71, 9,34, 2,26, 9,35, +9,35, 9,35, 9,35, 9,35, +9,35, 9,35, 9,35, 9,35, +9,35, 10,36, 55,74, 10,37, +10,37, 10,37, 10,37, 10,37, +10,37, 10,37, 10,37, 10,37, +10,37, 57,75, 58,76, 64,80, +66,81, 67,82, 70,83, 71,84, +72,85, 73,86, 74,87, 10,38, +10,38, 38,61, 10,38, 38,61, +75,88, 76,89, 38,62, 38,62, +38,62, 38,62, 38,62, 38,62, +38,62, 38,62, 38,62, 38,62, +80,92, 81,93, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +82,94, 83,95, 84,96, 10,38, +10,38, 86,97, 10,38, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 87,98, 88,99, 60,79, +60,79, 13,41, 60,79, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 33,33, 89,100, 60,79, +60,79, 92,101, 60,79, 93,102, +95,103, 33,33, 33,0, 96,104, +99,105, 100,106, 102,107, 106,108, +107,109, 35,35, 35,35, 35,35, +35,35, 35,35, 35,35, 35,35, +35,35, 35,35, 35,35, 108,110, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 33,33, 0,0, +0,0, 35,59, 35,59, 33,33, +35,59, 0,0, 0,0, 33,33, +0,0, 0,0, 0,0, 0,0, +33,33, 0,0, 0,0, 0,0, +0,0, 36,60, 36,60, 36,60, +36,60, 36,60, 36,60, 36,60, +36,60, 36,60, 36,60, 0,0, +0,0, 33,33, 0,0, 0,0, +33,33, 35,59, 35,59, 0,0, +35,59, 36,38, 36,38, 59,77, +36,38, 59,77, 0,0, 0,0, +59,78, 59,78, 59,78, 59,78, +59,78, 59,78, 59,78, 59,78, +59,78, 59,78, 61,62, 61,62, +61,62, 61,62, 61,62, 61,62, +61,62, 61,62, 61,62, 61,62, +0,0, 0,0, 0,0, 0,0, +0,0, 36,38, 36,38, 0,0, +36,38, 77,78, 77,78, 77,78, +77,78, 77,78, 77,78, 77,78, +77,78, 77,78, 77,78, 79,90, +0,0, 79,90, 0,0, 0,0, +79,91, 79,91, 79,91, 79,91, +79,91, 79,91, 79,91, 79,91, +79,91, 79,91, 90,91, 90,91, +90,91, 90,91, 90,91, 90,91, +90,91, 90,91, 90,91, 90,91, +0,0}; +struct yysvf yysvec[] = { +0, 0, 0, +yycrank+-1, 0, yyvstop+1, +yycrank+-28, yysvec+1, yyvstop+3, +yycrank+0, 0, yyvstop+5, +yycrank+4, 0, yyvstop+7, +yycrank+0, 0, yyvstop+10, +yycrank+-11, 0, yyvstop+12, +yycrank+-17, 0, yyvstop+14, +yycrank+7, 0, yyvstop+16, +yycrank+107, 0, yyvstop+18, +yycrank+119, 0, yyvstop+20, +yycrank+6, 0, yyvstop+23, +yycrank+7, 0, yyvstop+25, +yycrank+158, 0, yyvstop+27, +yycrank+4, yysvec+13, yyvstop+30, +yycrank+5, yysvec+13, yyvstop+33, +yycrank+11, yysvec+13, yyvstop+36, +yycrank+5, yysvec+13, yyvstop+39, +yycrank+5, yysvec+13, yyvstop+42, +yycrank+12, yysvec+13, yyvstop+45, +yycrank+21, yysvec+13, yyvstop+48, +yycrank+10, yysvec+13, yyvstop+51, +yycrank+4, yysvec+13, yyvstop+54, +yycrank+4, yysvec+13, yyvstop+57, +yycrank+21, yysvec+13, yyvstop+60, +yycrank+9, yysvec+13, yyvstop+63, +yycrank+9, 0, yyvstop+66, +yycrank+40, 0, yyvstop+68, +yycrank+0, yysvec+4, yyvstop+70, +yycrank+0, yysvec+6, 0, +yycrank+0, 0, yyvstop+72, +yycrank+0, yysvec+7, 0, +yycrank+0, 0, yyvstop+74, +yycrank+-280, 0, yyvstop+76, +yycrank+0, 0, yyvstop+78, +yycrank+249, 0, yyvstop+80, +yycrank+285, 0, yyvstop+82, +yycrank+0, yysvec+10, yyvstop+84, +yycrank+146, 0, 0, +yycrank+0, 0, yyvstop+86, +yycrank+0, 0, yyvstop+88, +yycrank+0, yysvec+13, yyvstop+90, +yycrank+10, yysvec+13, yyvstop+92, +yycrank+0, yysvec+13, yyvstop+94, +yycrank+19, yysvec+13, yyvstop+97, +yycrank+35, yysvec+13, yyvstop+99, +yycrank+27, yysvec+13, yyvstop+101, +yycrank+0, yysvec+13, yyvstop+103, +yycrank+42, yysvec+13, yyvstop+106, +yycrank+35, yysvec+13, yyvstop+108, +yycrank+30, yysvec+13, yyvstop+110, +yycrank+0, yysvec+13, yyvstop+112, +yycrank+36, yysvec+13, yyvstop+115, +yycrank+48, yysvec+13, yyvstop+117, +yycrank+35, yysvec+13, yyvstop+119, +yycrank+61, yysvec+13, yyvstop+121, +yycrank+0, 0, yyvstop+123, +yycrank+76, 0, 0, +yycrank+67, 0, 0, +yycrank+312, 0, 0, +yycrank+183, yysvec+36, yyvstop+125, +yycrank+322, 0, 0, +yycrank+0, yysvec+61, yyvstop+128, +yycrank+0, yysvec+13, yyvstop+130, +yycrank+78, yysvec+13, yyvstop+133, +yycrank+0, yysvec+13, yyvstop+135, +yycrank+81, yysvec+13, yyvstop+138, +yycrank+84, yysvec+13, yyvstop+140, +yycrank+0, yysvec+13, yyvstop+142, +yycrank+0, yysvec+13, yyvstop+145, +yycrank+81, yysvec+13, yyvstop+148, +yycrank+66, yysvec+13, yyvstop+150, +yycrank+74, yysvec+13, yyvstop+152, +yycrank+80, yysvec+13, yyvstop+154, +yycrank+78, yysvec+13, yyvstop+156, +yycrank+94, 0, 0, +yycrank+93, 0, 0, +yycrank+341, 0, 0, +yycrank+0, yysvec+77, yyvstop+158, +yycrank+356, 0, 0, +yycrank+99, yysvec+13, yyvstop+160, +yycrank+89, yysvec+13, yyvstop+163, +yycrank+108, yysvec+13, yyvstop+165, +yycrank+120, yysvec+13, yyvstop+167, +yycrank+104, yysvec+13, yyvstop+169, +yycrank+0, yysvec+13, yyvstop+171, +yycrank+113, yysvec+13, yyvstop+174, +yycrank+148, yysvec+13, yyvstop+176, +yycrank+133, 0, 0, +yycrank+181, 0, 0, +yycrank+366, 0, 0, +yycrank+0, yysvec+90, yyvstop+178, +yycrank+183, yysvec+13, yyvstop+181, +yycrank+182, yysvec+13, yyvstop+183, +yycrank+0, yysvec+13, yyvstop+185, +yycrank+172, yysvec+13, yyvstop+189, +yycrank+181, yysvec+13, yyvstop+191, +yycrank+0, yysvec+13, yyvstop+193, +yycrank+0, yysvec+13, yyvstop+196, +yycrank+189, 0, 0, +yycrank+195, 0, 0, +yycrank+0, yysvec+13, yyvstop+199, +yycrank+183, yysvec+13, yyvstop+202, +yycrank+0, yysvec+13, yyvstop+204, +yycrank+0, yysvec+13, yyvstop+207, +yycrank+0, 0, yyvstop+210, +yycrank+178, 0, 0, +yycrank+186, yysvec+13, yyvstop+212, +yycrank+204, 0, 0, +yycrank+0, yysvec+13, yyvstop+214, +yycrank+0, 0, yyvstop+217, +0, 0, 0}; +struct yywork *yytop = yycrank+423; +struct yysvf *yybgin = yysvec+1; +char yymatch[] = { +00 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,011 ,012 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +011 ,01 ,'"' ,01 ,01 ,01 ,01 ,047 , +01 ,01 ,01 ,'+' ,01 ,'+' ,01 ,01 , +'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' , +'0' ,'0' ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,'A' ,'A' ,'A' ,'D' ,'D' ,'A' ,'D' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,01 ,01 ,01 ,01 ,'A' , +01 ,'A' ,'A' ,'A' ,'D' ,'D' ,'A' ,'D' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,01 ,01 ,01 ,01 ,01 , +0}; +char yyextra[] = { +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0}; +#ifndef lint +static char ncform_sccsid[] = "@(#)ncform 1.6 88/02/08 SMI"; /* from S5R2 1.2 */ +#endif + +int yylineno =1; +# define YYU(x) x +# define NLSTATE yyprevious=YYNEWLINE +char yytext[YYLMAX]; +struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp; +char yysbuf[YYLMAX]; +char *yysptr = yysbuf; +int *yyfnd; +extern struct yysvf *yyestate; +int yyprevious = YYNEWLINE; +yylook(){ + register struct yysvf *yystate, **lsp; + register struct yywork *yyt; + struct yysvf *yyz; + int yych, yyfirst; + struct yywork *yyr; +# ifdef LEXDEBUG + int debug; +# endif + char *yylastch; + /* start off machines */ +# ifdef LEXDEBUG + debug = 0; +# endif + yyfirst=1; + if (!yymorfg) + yylastch = yytext; + else { + yymorfg=0; + yylastch = yytext+yyleng; + } + for(;;){ + lsp = yylstate; + yyestate = yystate = yybgin; + if (yyprevious==YYNEWLINE) yystate++; + for (;;){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1); +# endif + yyt = yystate->yystoff; + if(yyt == yycrank && !yyfirst){ /* may not be any transitions */ + yyz = yystate->yyother; + if(yyz == 0)break; + if(yyz->yystoff == yycrank)break; + } + *yylastch++ = yych = input(); + yyfirst=0; + tryagain: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"char "); + allprint(yych); + putchar('\n'); + } +# endif + yyr = yyt; + if ( (int)yyt > (int)yycrank){ + yyt = yyr + yych; + if (yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } +# ifdef YYOPTIM + else if((int)yyt < (int)yycrank) { /* r < yycrank */ + yyt = yyr = yycrank+(yycrank-yyt); +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"compressed state\n"); +# endif + yyt = yyt + yych; + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + yyt = yyr + YYU(yymatch[yych]); +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"try fall back character "); + allprint(YYU(yymatch[yych])); + putchar('\n'); + } +# endif + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transition */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } + if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1); +# endif + goto tryagain; + } +# endif + else + {unput(*--yylastch);break;} + contin: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"state %d char ",yystate-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + ; + } +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + while (lsp-- > yylstate){ + *yylastch-- = 0; + if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){ + yyolsp = lsp; + if(yyextra[*yyfnd]){ /* must backup */ + while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){ + lsp--; + unput(*yylastch--); + } + } + yyprevious = YYU(*yylastch); + yylsp = lsp; + yyleng = yylastch-yytext+1; + yytext[yyleng] = 0; +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"\nmatch "); + sprint(yytext); + fprintf(yyout," action %d\n",*yyfnd); + } +# endif + return(*yyfnd++); + } + unput(*yylastch); + } + if (yytext[0] == 0 /* && feof(yyin) */) + { + yysptr=yysbuf; + return(0); + } + yyprevious = yytext[0] = input(); + if (yyprevious>0) + output(yyprevious); + yylastch=yytext; +# ifdef LEXDEBUG + if(debug)putchar('\n'); +# endif + } + } +yyback(p, m) + int *p; +{ +if (p==0) return(0); +while (*p) + { + if (*p++ == m) + return(1); + } +return(0); +} + /* the following are only used in the lex library */ +yyinput(){ + return(input()); + } +yyoutput(c) + int c; { + output(c); + } +yyunput(c) + int c; { + unput(c); + } diff --git a/fixed/lua.c b/fixed/lua.c new file mode 100644 index 0000000000..f2cfc0b633 --- /dev/null +++ b/fixed/lua.c @@ -0,0 +1,55 @@ +/* +** lua.c +** Linguagem para Usuarios de Aplicacao +** TeCGraf - PUC-Rio +** 28 Apr 93 +*/ + +#include + +#include "lua.h" +#include "lualib.h" + + +void test (void) +{ + lua_pushobject(lua_getparam(1)); + lua_call ("c", 1); +} + + +static void callfunc (void) +{ + lua_Object obj = lua_getparam (1); + if (lua_isstring(obj)) lua_call(lua_getstring(obj),0); +} + +static void execstr (void) +{ + lua_Object obj = lua_getparam (1); + if (lua_isstring(obj)) lua_dostring(lua_getstring(obj)); +} + +int main (int argc, char *argv[]) +{ + int i; + if (argc < 2) + { + puts ("usage: lua filename [functionnames]"); + return; + } + lua_register ("callfunc", callfunc); + lua_register ("execstr", execstr); + lua_register ("test", test); + iolib_open (); + strlib_open (); + mathlib_open (); + lua_dofile (argv[1]); + for (i=2; i +#include + +#include "opcode.h" +#include "hash.h" +#include "inout.h" +#include "table.h" +#include "lua.h" + +#define streq(s1,s2) (strcmp(s1,s2)==0) +#define strneq(s1,s2) (strcmp(s1,s2)!=0) + +#define new(s) ((s *)malloc(sizeof(s))) +#define newvector(n,s) ((s *)calloc(n,sizeof(s))) + +#define nhash(t) ((t)->nhash) +#define nodelist(t) ((t)->list) +#define list(t,i) ((t)->list[i]) +#define ref_tag(n) (tag(&(n)->ref)) +#define ref_nvalue(n) (nvalue(&(n)->ref)) +#define ref_svalue(n) (svalue(&(n)->ref)) + +static int head (Hash *t, Object *ref) /* hash function */ +{ + if (tag(ref) == T_NUMBER) return (((int)nvalue(ref))%nhash(t)); + else if (tag(ref) == T_STRING) + { + int h; + char *name = svalue(ref); + for (h=0; *name!=0; name++) /* interpret name as binary number */ + { + h <<= 8; + h += (unsigned char) *name; /* avoid sign extension */ + h %= nhash(t); /* make it a valid index */ + } + return h; + } + else + { + lua_reportbug ("unexpected type to index table"); + return -1; + } +} + +static Node *present(Hash *t, Object *ref, int h) +{ + Node *n=NULL, *p; + if (tag(ref) == T_NUMBER) + { + for (p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next) + if (ref_tag(n) == T_NUMBER && nvalue(ref) == ref_nvalue(n)) break; + } + else if (tag(ref) == T_STRING) + { + for (p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next) + if (ref_tag(n) == T_STRING && streq(svalue(ref),ref_svalue(n))) break; + } + if (n==NULL) /* name not present */ + return NULL; +#if 0 + if (p!=NULL) /* name present but not first */ + { + p->next=n->next; /* move-to-front self-organization */ + n->next=list(t,h); + list(t,h)=n; + } +#endif + return n; +} + +static void freelist (Node *n) +{ + while (n) + { + Node *next = n->next; + free (n); + n = next; + } +} + +/* +** Create a new hash. Return the hash pointer or NULL on error. +*/ +Hash *lua_hashcreate (unsigned int nhash) +{ + Hash *t = new (Hash); + if (t == NULL) + { + lua_error ("not enough memory"); + return NULL; + } + nhash(t) = nhash; + markarray(t) = 0; + nodelist(t) = newvector (nhash, Node*); + if (nodelist(t) == NULL) + { + lua_error ("not enough memory"); + return NULL; + } + return t; +} + +/* +** Delete a hash +*/ +void lua_hashdelete (Hash *h) +{ + int i; + for (i=0; iref = *ref; + tag(&n->val) = T_NIL; + n->next = list(t,h); /* link node to head of list */ + list(t,h) = n; + } + return (&n->val); +} + +/* +** Mark a hash and check its elements +*/ +void lua_hashmark (Hash *h) +{ + int i; + + markarray(h) = 1; + + for (i=0; inext) + { + lua_markobject (&n->ref); + lua_markobject (&n->val); + } + } +} + + +/* +** Internal function to manipulate arrays. +** Given an array object and a reference value, return the next element +** in the hash. +** This function pushs the element value and its reference to the stack. +*/ +#include "lua.h" +static void firstnode (Hash *a, int h) +{ + if (h < nhash(a)) + { + int i; + for (i=h; ival) != T_NIL) + { + lua_pushobject (&list(a,i)->ref); + lua_pushobject (&list(a,i)->val); + return; + } + } + } + lua_pushnil(); + lua_pushnil(); +} +void lua_next (void) +{ + Hash *a; + Object *o = lua_getparam (1); + Object *r = lua_getparam (2); + if (o == NULL || r == NULL) + { lua_error ("too few arguments to function `next'"); return; } + if (lua_getparam (3) != NULL) + { lua_error ("too many arguments to function `next'"); return; } + if (tag(o) != T_ARRAY) + { lua_error ("first argument of function `next' is not a table"); return; } + a = avalue(o); + if (tag(r) == T_NIL) + { + firstnode (a, 0); + return; + } + else + { + int h = head (a, r); + if (h >= 0) + { + Node *n = list(a,h); + while (n) + { + if (memcmp(&n->ref,r,sizeof(Object)) == 0) + { + if (n->next == NULL) + { + firstnode (a, h+1); + return; + } + else if (tag(&n->next->val) != T_NIL) + { + lua_pushobject (&n->next->ref); + lua_pushobject (&n->next->val); + return; + } + else + { + Node *next = n->next->next; + while (next != NULL && tag(&next->val) == T_NIL) next = next->next; + if (next == NULL) + { + firstnode (a, h+1); + return; + } + else + { + lua_pushobject (&next->ref); + lua_pushobject (&next->val); + } + return; + } + } + n = n->next; + } + if (n == NULL) + lua_error ("error in function 'next': reference not found"); + } + } +} diff --git a/hash.h b/hash.h new file mode 100644 index 0000000000..28c50317b6 --- /dev/null +++ b/hash.h @@ -0,0 +1,35 @@ +/* +** hash.h +** hash manager for lua +** Luiz Henrique de Figueiredo - 17 Aug 90 +** Modified by Waldemar Celes Filho +** 26 Apr 93 +*/ + +#ifndef hash_h +#define hash_h + +typedef struct node +{ + Object ref; + Object val; + struct node *next; +} Node; + +typedef struct Hash +{ + char mark; + unsigned int nhash; + Node **list; +} Hash; + +#define markarray(t) ((t)->mark) + +Hash *lua_hashcreate (unsigned int nhash); +void lua_hashdelete (Hash *h); +Object *lua_hashdefine (Hash *t, Object *ref); +void lua_hashmark (Hash *h); + +void lua_next (void); + +#endif diff --git a/inout.c b/inout.c new file mode 100644 index 0000000000..3ba32ba7e7 --- /dev/null +++ b/inout.c @@ -0,0 +1,188 @@ +/* +** inout.c +** Provide function to realise the input/output function and debugger +** facilities. +** +** Waldemar Celes Filho +** TeCGraf - PUC-Rio +** 11 May 93 +*/ + +#include +#include + +#include "opcode.h" +#include "hash.h" +#include "inout.h" +#include "table.h" + +/* Exported variables */ +int lua_linenumber; +int lua_debug; +int lua_debugline; + +/* Internal variables */ +#ifndef MAXFUNCSTACK +#define MAXFUNCSTACK 32 +#endif +static struct { int file; int function; } funcstack[MAXFUNCSTACK]; +static int nfuncstack=0; + +static FILE *fp; +static char *st; +static void (*usererror) (char *s); + +/* +** Function to set user function to handle errors. +*/ +void lua_errorfunction (void (*fn) (char *s)) +{ + usererror = fn; +} + +/* +** Function to get the next character from the input file +*/ +static int fileinput (void) +{ + int c = fgetc (fp); + return (c == EOF ? 0 : c); +} + +/* +** Function to unget the next character from to input file +*/ +static void fileunput (int c) +{ + ungetc (c, fp); +} + +/* +** Function to get the next character from the input string +*/ +static int stringinput (void) +{ + st++; + return (*(st-1)); +} + +/* +** Function to unget the next character from to input string +*/ +static void stringunput (int c) +{ + st--; +} + +/* +** Function to open a file to be input unit. +** Return 0 on success or 1 on error. +*/ +int lua_openfile (char *fn) +{ + lua_linenumber = 1; + lua_setinput (fileinput); + lua_setunput (fileunput); + fp = fopen (fn, "r"); + if (fp == NULL) return 1; + if (lua_addfile (fn)) return 1; + return 0; +} + +/* +** Function to close an opened file +*/ +void lua_closefile (void) +{ + if (fp != NULL) + { + fclose (fp); + fp = NULL; + } +} + +/* +** Function to open a string to be input unit +*/ +int lua_openstring (char *s) +{ + lua_linenumber = 1; + lua_setinput (stringinput); + lua_setunput (stringunput); + st = s; + { + char sn[64]; + sprintf (sn, "String: %10.10s...", s); + if (lua_addfile (sn)) return 1; + } + return 0; +} + +/* +** Call user function to handle error messages, if registred. Or report error +** using standard function (fprintf). +*/ +void lua_error (char *s) +{ + if (usererror != NULL) usererror (s); + else fprintf (stderr, "lua: %s\n", s); +} + +/* +** Called to execute SETFUNCTION opcode, this function pushs a function into +** function stack. Return 0 on success or 1 on error. +*/ +int lua_pushfunction (int file, int function) +{ + if (nfuncstack >= MAXFUNCSTACK-1) + { + lua_error ("function stack overflow"); + return 1; + } + funcstack[nfuncstack].file = file; + funcstack[nfuncstack].function = function; + nfuncstack++; + return 0; +} + +/* +** Called to execute RESET opcode, this function pops a function from +** function stack. +*/ +void lua_popfunction (void) +{ + nfuncstack--; +} + +/* +** Report bug building a message and sending it to lua_error function. +*/ +void lua_reportbug (char *s) +{ + char msg[1024]; + strcpy (msg, s); + if (lua_debugline != 0) + { + int i; + if (nfuncstack > 0) + { + sprintf (strchr(msg,0), + "\n\tin statement begining at line %d in function \"%s\" of file \"%s\"", + lua_debugline, s_name(funcstack[nfuncstack-1].function), + lua_file[funcstack[nfuncstack-1].file]); + sprintf (strchr(msg,0), "\n\tactive stack\n"); + for (i=nfuncstack-1; i>=0; i--) + sprintf (strchr(msg,0), "\t-> function \"%s\" of file \"%s\"\n", + s_name(funcstack[i].function), + lua_file[funcstack[i].file]); + } + else + { + sprintf (strchr(msg,0), + "\n\tin statement begining at line %d of file \"%s\"", + lua_debugline, lua_filename()); + } + } + lua_error (msg); +} + diff --git a/inout.h b/inout.h new file mode 100644 index 0000000000..5a72261c70 --- /dev/null +++ b/inout.h @@ -0,0 +1,24 @@ +/* +** inout.h +** +** Waldemar Celes Filho +** TeCGraf - PUC-Rio +** 11 May 93 +*/ + + +#ifndef inout_h +#define inout_h + +extern int lua_linenumber; +extern int lua_debug; +extern int lua_debugline; + +int lua_openfile (char *fn); +void lua_closefile (void); +int lua_openstring (char *s); +int lua_pushfunction (int file, int function); +void lua_popfunction (void); +void lua_reportbug (char *s); + +#endif diff --git a/iolib.c b/iolib.c new file mode 100644 index 0000000000..174dd5018e --- /dev/null +++ b/iolib.c @@ -0,0 +1,401 @@ +/* +** iolib.c +** Input/output library to LUA +** +** Waldemar Celes Filho +** TeCGraf - PUC-Rio +** 19 May 93 +*/ + +#include +#include +#include +#include +#ifdef __GNUC__ +#include +#endif + +#include "lua.h" + +static FILE *in=stdin, *out=stdout; + +/* +** Open a file to read. +** LUA interface: +** status = readfrom (filename) +** where: +** status = 1 -> success +** status = 0 -> error +*/ +static void io_readfrom (void) +{ + lua_Object o = lua_getparam (1); + if (o == NULL) /* restore standart input */ + { + if (in != stdin) + { + fclose (in); + in = stdin; + } + lua_pushnumber (1); + } + else + { + if (!lua_isstring (o)) + { + lua_error ("incorrect argument to function 'readfrom`"); + lua_pushnumber (0); + } + else + { + FILE *fp = fopen (lua_getstring(o),"r"); + if (fp == NULL) + { + lua_pushnumber (0); + } + else + { + if (in != stdin) fclose (in); + in = fp; + lua_pushnumber (1); + } + } + } +} + + +/* +** Open a file to write. +** LUA interface: +** status = writeto (filename) +** where: +** status = 1 -> success +** status = 0 -> error +*/ +static void io_writeto (void) +{ + lua_Object o = lua_getparam (1); + if (o == NULL) /* restore standart output */ + { + if (out != stdout) + { + fclose (out); + out = stdout; + } + lua_pushnumber (1); + } + else + { + if (!lua_isstring (o)) + { + lua_error ("incorrect argument to function 'writeto`"); + lua_pushnumber (0); + } + else + { + FILE *fp = fopen (lua_getstring(o),"w"); + if (fp == NULL) + { + lua_pushnumber (0); + } + else + { + if (out != stdout) fclose (out); + out = fp; + lua_pushnumber (1); + } + } + } +} + + +/* +** Read a variable. On error put nil on stack. +** LUA interface: +** variable = read ([format]) +** +** O formato pode ter um dos seguintes especificadores: +** +** s ou S -> para string +** f ou F, g ou G, e ou E -> para reais +** i ou I -> para inteiros +** +** Estes especificadores podem vir seguidos de numero que representa +** o numero de campos a serem lidos. +*/ +static void io_read (void) +{ + lua_Object o = lua_getparam (1); + if (o == NULL) /* free format */ + { + int c; + char s[256]; + while (isspace(c=fgetc(in))) + ; + if (c == '\"') + { + if (fscanf (in, "%[^\"]\"", s) != 1) + { + lua_pushnil (); + return; + } + } + else if (c == '\'') + { + if (fscanf (in, "%[^\']\'", s) != 1) + { + lua_pushnil (); + return; + } + } + else + { + char *ptr; + double d; + ungetc (c, in); + if (fscanf (in, "%s", s) != 1) + { + lua_pushnil (); + return; + } + d = strtod (s, &ptr); + if (!(*ptr)) + { + lua_pushnumber (d); + return; + } + } + lua_pushstring (s); + return; + } + else /* formatted */ + { + char *e = lua_getstring(o); + char t; + int m=0; + while (isspace(*e)) e++; + t = *e++; + while (isdigit(*e)) + m = m*10 + (*e++ - '0'); + + if (m > 0) + { + char f[80]; + char s[256]; + sprintf (f, "%%%ds", m); + fscanf (in, f, s); + switch (tolower(t)) + { + case 'i': + { + long int l; + sscanf (s, "%ld", &l); + lua_pushnumber(l); + } + break; + case 'f': case 'g': case 'e': + { + float f; + sscanf (s, "%f", &f); + lua_pushnumber(f); + } + break; + default: + lua_pushstring(s); + break; + } + } + else + { + switch (tolower(t)) + { + case 'i': + { + long int l; + fscanf (in, "%ld", &l); + lua_pushnumber(l); + } + break; + case 'f': case 'g': case 'e': + { + float f; + fscanf (in, "%f", &f); + lua_pushnumber(f); + } + break; + default: + { + char s[256]; + fscanf (in, "%s", s); + lua_pushstring(s); + } + break; + } + } + } +} + + +/* +** Write a variable. On error put 0 on stack, otherwise put 1. +** LUA interface: +** status = write (variable [,format]) +** +** O formato pode ter um dos seguintes especificadores: +** +** s ou S -> para string +** f ou F, g ou G, e ou E -> para reais +** i ou I -> para inteiros +** +** Estes especificadores podem vir seguidos de: +** +** [?][m][.n] +** +** onde: +** ? -> indica justificacao +** < = esquerda +** | = centro +** > = direita (default) +** m -> numero maximo de campos (se exceder estoura) +** n -> indica precisao para +** reais -> numero de casas decimais +** inteiros -> numero minimo de digitos +** string -> nao se aplica +*/ +static char *buildformat (char *e, lua_Object o) +{ + static char buffer[512]; + static char f[80]; + char *string = &buffer[255]; + char t, j='r'; + int m=0, n=0, l; + while (isspace(*e)) e++; + t = *e++; + if (*e == '<' || *e == '|' || *e == '>') j = *e++; + while (isdigit(*e)) + m = m*10 + (*e++ - '0'); + e++; /* skip point */ + while (isdigit(*e)) + n = n*10 + (*e++ - '0'); + + sprintf(f,"%%"); + if (j == '<' || j == '|') sprintf(strchr(f,0),"-"); + if (m != 0) sprintf(strchr(f,0),"%d", m); + if (n != 0) sprintf(strchr(f,0),".%d", n); + sprintf(strchr(f,0), "%c", t); + switch (tolower(t)) + { + case 'i': t = 'i'; + sprintf (string, f, (long int)lua_getnumber(o)); + break; + case 'f': case 'g': case 'e': t = 'f'; + sprintf (string, f, (float)lua_getnumber(o)); + break; + case 's': t = 's'; + sprintf (string, f, lua_getstring(o)); + break; + default: return ""; + } + l = strlen(string); + if (m!=0 && l>m) + { + int i; + for (i=0; iyysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar) +# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;*yysptr++=yytchar;} +# define yymore() (yymorfg=1) +# define ECHO fprintf(yyout, "%s",yytext) +# define REJECT { nstr = yyreject(); goto yyfussy;} +int yyleng; extern char yytext[]; +int yymorfg; +extern char *yysptr, yysbuf[]; +int yytchar; +FILE *yyin = {stdin}, *yyout = {stdout}; +extern int yylineno; +struct yysvf { + struct yywork *yystoff; + struct yysvf *yyother; + int *yystops;}; +struct yysvf *yyestate; +extern struct yysvf yysvec[], *yybgin; +#include +#include + +#include "opcode.h" +#include "hash.h" +#include "inout.h" +#include "table.h" +#include "y_tab.h" + +#undef input +#undef unput + +static Input input; +static Unput unput; + +void lua_setinput (Input fn) +{ + input = fn; +} + +void lua_setunput (Unput fn) +{ + unput = fn; +} + +char *lua_lasttext (void) +{ + return yytext; +} + +# define YYNEWLINE 10 +yylex(){ +int nstr; extern int yyprevious; +while((nstr = yylook()) >= 0) +yyfussy: switch(nstr){ +case 0: +if(yywrap()) return(0); break; +case 1: + ; +break; +case 2: + {yylval.vInt = 1; return DEBUG;} +break; +case 3: + {yylval.vInt = 0; return DEBUG;} +break; +case 4: + lua_linenumber++; +break; +case 5: + ; +break; +case 6: + return LOCAL; +break; +case 7: + return IF; +break; +case 8: + return THEN; +break; +case 9: + return ELSE; +break; +case 10: + return ELSEIF; +break; +case 11: + return WHILE; +break; +case 12: + return DO; +break; +case 13: + return REPEAT; +break; +case 14: + return UNTIL; +break; +case 15: + { + yylval.vWord = lua_nfile-1; + return FUNCTION; + } +break; +case 16: + return END; +break; +case 17: + return RETURN; +break; +case 18: + return LOCAL; +break; +case 19: + return NIL; +break; +case 20: + return AND; +break; +case 21: + return OR; +break; +case 22: + return NOT; +break; +case 23: + return NE; +break; +case 24: + return LE; +break; +case 25: + return GE; +break; +case 26: + return CONC; +break; +case 27: + case 28: + { + yylval.vWord = lua_findenclosedconstant (yytext); + return STRING; + } +break; +case 29: +case 30: +case 31: +case 32: +{ + yylval.vFloat = atof(yytext); + return NUMBER; + } +break; +case 33: + { + yylval.vWord = lua_findsymbol (yytext); + return NAME; + } +break; +case 34: + return *yytext; +break; +case -1: +break; +default: +fprintf(yyout,"bad switch yylook %d",nstr); +} return(0); } +/* end of yylex */ +int yyvstop[] = { +0, + +1, +0, + +1, +0, + +34, +0, + +1, +34, +0, + +4, +0, + +34, +0, + +34, +0, + +34, +0, + +34, +0, + +29, +34, +0, + +34, +0, + +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +33, +34, +0, + +34, +0, + +34, +0, + +1, +0, + +27, +0, + +28, +0, + +5, +0, + +26, +0, + +30, +0, + +29, +0, + +29, +0, + +24, +0, + +25, +0, + +33, +0, + +33, +0, + +12, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +7, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +21, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +23, +0, + +29, +30, +0, + +31, +0, + +20, +33, +0, + +33, +0, + +16, +33, +0, + +33, +0, + +33, +0, + +19, +33, +0, + +22, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +32, +0, + +9, +33, +0, + +33, +0, + +33, +0, + +33, +0, + +33, +0, + +8, +33, +0, + +33, +0, + +33, +0, + +31, +32, +0, + +33, +0, + +33, +0, + +6, +18, +33, +0, + +33, +0, + +33, +0, + +14, +33, +0, + +11, +33, +0, + +10, +33, +0, + +33, +0, + +13, +33, +0, + +17, +33, +0, + +2, +0, + +33, +0, + +15, +33, +0, + +3, +0, +0}; +# define YYTYPE char +struct yywork { YYTYPE verify, advance; } yycrank[] = { +0,0, 0,0, 1,3, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 1,4, 1,5, +6,29, 4,28, 0,0, 0,0, +0,0, 0,0, 7,31, 0,0, +6,29, 6,29, 0,0, 0,0, +0,0, 0,0, 7,31, 7,31, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 0,0, 1,6, +4,28, 0,0, 0,0, 0,0, +1,7, 0,0, 0,0, 0,0, +1,3, 6,30, 1,8, 1,9, +0,0, 1,10, 6,29, 7,31, +8,33, 0,0, 6,29, 0,0, +7,32, 0,0, 0,0, 6,29, +7,31, 1,11, 0,0, 1,12, +2,27, 7,31, 1,13, 11,39, +12,40, 1,13, 26,56, 0,0, +0,0, 2,8, 2,9, 0,0, +6,29, 0,0, 0,0, 6,29, +0,0, 0,0, 7,31, 0,0, +0,0, 7,31, 0,0, 0,0, +2,11, 0,0, 2,12, 0,0, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 1,14, 0,0, +0,0, 1,15, 1,16, 1,17, +0,0, 22,52, 1,18, 18,47, +23,53, 1,19, 42,63, 1,20, +1,21, 25,55, 14,42, 1,22, +15,43, 1,23, 1,24, 16,44, +1,25, 16,45, 17,46, 19,48, +21,51, 2,14, 20,49, 1,26, +2,15, 2,16, 2,17, 24,54, +20,50, 2,18, 44,64, 45,65, +2,19, 46,66, 2,20, 2,21, +27,57, 48,67, 2,22, 49,68, +2,23, 2,24, 50,69, 2,25, +52,70, 53,72, 27,58, 54,73, +52,71, 9,34, 2,26, 9,35, +9,35, 9,35, 9,35, 9,35, +9,35, 9,35, 9,35, 9,35, +9,35, 10,36, 55,74, 10,37, +10,37, 10,37, 10,37, 10,37, +10,37, 10,37, 10,37, 10,37, +10,37, 57,75, 58,76, 64,80, +66,81, 67,82, 70,83, 71,84, +72,85, 73,86, 74,87, 10,38, +10,38, 38,61, 10,38, 38,61, +75,88, 76,89, 38,62, 38,62, +38,62, 38,62, 38,62, 38,62, +38,62, 38,62, 38,62, 38,62, +80,92, 81,93, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +82,94, 83,95, 84,96, 10,38, +10,38, 86,97, 10,38, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 87,98, 88,99, 60,79, +60,79, 13,41, 60,79, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 13,41, 13,41, 13,41, +13,41, 33,33, 89,100, 60,79, +60,79, 92,101, 60,79, 93,102, +95,103, 33,33, 33,0, 96,104, +99,105, 100,106, 102,107, 106,108, +107,109, 35,35, 35,35, 35,35, +35,35, 35,35, 35,35, 35,35, +35,35, 35,35, 35,35, 108,110, +0,0, 0,0, 0,0, 0,0, +0,0, 0,0, 33,33, 0,0, +0,0, 35,59, 35,59, 33,33, +35,59, 0,0, 0,0, 33,33, +0,0, 0,0, 0,0, 0,0, +33,33, 0,0, 0,0, 0,0, +0,0, 36,60, 36,60, 36,60, +36,60, 36,60, 36,60, 36,60, +36,60, 36,60, 36,60, 0,0, +0,0, 33,33, 0,0, 0,0, +33,33, 35,59, 35,59, 0,0, +35,59, 36,38, 36,38, 59,77, +36,38, 59,77, 0,0, 0,0, +59,78, 59,78, 59,78, 59,78, +59,78, 59,78, 59,78, 59,78, +59,78, 59,78, 61,62, 61,62, +61,62, 61,62, 61,62, 61,62, +61,62, 61,62, 61,62, 61,62, +0,0, 0,0, 0,0, 0,0, +0,0, 36,38, 36,38, 0,0, +36,38, 77,78, 77,78, 77,78, +77,78, 77,78, 77,78, 77,78, +77,78, 77,78, 77,78, 79,90, +0,0, 79,90, 0,0, 0,0, +79,91, 79,91, 79,91, 79,91, +79,91, 79,91, 79,91, 79,91, +79,91, 79,91, 90,91, 90,91, +90,91, 90,91, 90,91, 90,91, +90,91, 90,91, 90,91, 90,91, +0,0}; +struct yysvf yysvec[] = { +0, 0, 0, +yycrank+-1, 0, yyvstop+1, +yycrank+-28, yysvec+1, yyvstop+3, +yycrank+0, 0, yyvstop+5, +yycrank+4, 0, yyvstop+7, +yycrank+0, 0, yyvstop+10, +yycrank+-11, 0, yyvstop+12, +yycrank+-17, 0, yyvstop+14, +yycrank+7, 0, yyvstop+16, +yycrank+107, 0, yyvstop+18, +yycrank+119, 0, yyvstop+20, +yycrank+6, 0, yyvstop+23, +yycrank+7, 0, yyvstop+25, +yycrank+158, 0, yyvstop+27, +yycrank+4, yysvec+13, yyvstop+30, +yycrank+5, yysvec+13, yyvstop+33, +yycrank+11, yysvec+13, yyvstop+36, +yycrank+5, yysvec+13, yyvstop+39, +yycrank+5, yysvec+13, yyvstop+42, +yycrank+12, yysvec+13, yyvstop+45, +yycrank+21, yysvec+13, yyvstop+48, +yycrank+10, yysvec+13, yyvstop+51, +yycrank+4, yysvec+13, yyvstop+54, +yycrank+4, yysvec+13, yyvstop+57, +yycrank+21, yysvec+13, yyvstop+60, +yycrank+9, yysvec+13, yyvstop+63, +yycrank+9, 0, yyvstop+66, +yycrank+40, 0, yyvstop+68, +yycrank+0, yysvec+4, yyvstop+70, +yycrank+0, yysvec+6, 0, +yycrank+0, 0, yyvstop+72, +yycrank+0, yysvec+7, 0, +yycrank+0, 0, yyvstop+74, +yycrank+-280, 0, yyvstop+76, +yycrank+0, 0, yyvstop+78, +yycrank+249, 0, yyvstop+80, +yycrank+285, 0, yyvstop+82, +yycrank+0, yysvec+10, yyvstop+84, +yycrank+146, 0, 0, +yycrank+0, 0, yyvstop+86, +yycrank+0, 0, yyvstop+88, +yycrank+0, yysvec+13, yyvstop+90, +yycrank+10, yysvec+13, yyvstop+92, +yycrank+0, yysvec+13, yyvstop+94, +yycrank+19, yysvec+13, yyvstop+97, +yycrank+35, yysvec+13, yyvstop+99, +yycrank+27, yysvec+13, yyvstop+101, +yycrank+0, yysvec+13, yyvstop+103, +yycrank+42, yysvec+13, yyvstop+106, +yycrank+35, yysvec+13, yyvstop+108, +yycrank+30, yysvec+13, yyvstop+110, +yycrank+0, yysvec+13, yyvstop+112, +yycrank+36, yysvec+13, yyvstop+115, +yycrank+48, yysvec+13, yyvstop+117, +yycrank+35, yysvec+13, yyvstop+119, +yycrank+61, yysvec+13, yyvstop+121, +yycrank+0, 0, yyvstop+123, +yycrank+76, 0, 0, +yycrank+67, 0, 0, +yycrank+312, 0, 0, +yycrank+183, yysvec+36, yyvstop+125, +yycrank+322, 0, 0, +yycrank+0, yysvec+61, yyvstop+128, +yycrank+0, yysvec+13, yyvstop+130, +yycrank+78, yysvec+13, yyvstop+133, +yycrank+0, yysvec+13, yyvstop+135, +yycrank+81, yysvec+13, yyvstop+138, +yycrank+84, yysvec+13, yyvstop+140, +yycrank+0, yysvec+13, yyvstop+142, +yycrank+0, yysvec+13, yyvstop+145, +yycrank+81, yysvec+13, yyvstop+148, +yycrank+66, yysvec+13, yyvstop+150, +yycrank+74, yysvec+13, yyvstop+152, +yycrank+80, yysvec+13, yyvstop+154, +yycrank+78, yysvec+13, yyvstop+156, +yycrank+94, 0, 0, +yycrank+93, 0, 0, +yycrank+341, 0, 0, +yycrank+0, yysvec+77, yyvstop+158, +yycrank+356, 0, 0, +yycrank+99, yysvec+13, yyvstop+160, +yycrank+89, yysvec+13, yyvstop+163, +yycrank+108, yysvec+13, yyvstop+165, +yycrank+120, yysvec+13, yyvstop+167, +yycrank+104, yysvec+13, yyvstop+169, +yycrank+0, yysvec+13, yyvstop+171, +yycrank+113, yysvec+13, yyvstop+174, +yycrank+148, yysvec+13, yyvstop+176, +yycrank+133, 0, 0, +yycrank+181, 0, 0, +yycrank+366, 0, 0, +yycrank+0, yysvec+90, yyvstop+178, +yycrank+183, yysvec+13, yyvstop+181, +yycrank+182, yysvec+13, yyvstop+183, +yycrank+0, yysvec+13, yyvstop+185, +yycrank+172, yysvec+13, yyvstop+189, +yycrank+181, yysvec+13, yyvstop+191, +yycrank+0, yysvec+13, yyvstop+193, +yycrank+0, yysvec+13, yyvstop+196, +yycrank+189, 0, 0, +yycrank+195, 0, 0, +yycrank+0, yysvec+13, yyvstop+199, +yycrank+183, yysvec+13, yyvstop+202, +yycrank+0, yysvec+13, yyvstop+204, +yycrank+0, yysvec+13, yyvstop+207, +yycrank+0, 0, yyvstop+210, +yycrank+178, 0, 0, +yycrank+186, yysvec+13, yyvstop+212, +yycrank+204, 0, 0, +yycrank+0, yysvec+13, yyvstop+214, +yycrank+0, 0, yyvstop+217, +0, 0, 0}; +struct yywork *yytop = yycrank+423; +struct yysvf *yybgin = yysvec+1; +char yymatch[] = { +00 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,011 ,012 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 , +011 ,01 ,'"' ,01 ,01 ,01 ,01 ,047 , +01 ,01 ,01 ,'+' ,01 ,'+' ,01 ,01 , +'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' , +'0' ,'0' ,01 ,01 ,01 ,01 ,01 ,01 , +01 ,'A' ,'A' ,'A' ,'D' ,'D' ,'A' ,'D' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,01 ,01 ,01 ,01 ,'A' , +01 ,'A' ,'A' ,'A' ,'D' ,'D' ,'A' ,'D' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' , +'A' ,'A' ,'A' ,01 ,01 ,01 ,01 ,01 , +0}; +char yyextra[] = { +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, +0}; +#ifndef lint +static char ncform_sccsid[] = "@(#)ncform 1.6 88/02/08 SMI"; /* from S5R2 1.2 */ +#endif + +int yylineno =1; +# define YYU(x) x +# define NLSTATE yyprevious=YYNEWLINE +char yytext[YYLMAX]; +struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp; +char yysbuf[YYLMAX]; +char *yysptr = yysbuf; +int *yyfnd; +extern struct yysvf *yyestate; +int yyprevious = YYNEWLINE; +yylook(){ + register struct yysvf *yystate, **lsp; + register struct yywork *yyt; + struct yysvf *yyz; + int yych, yyfirst; + struct yywork *yyr; +# ifdef LEXDEBUG + int debug; +# endif + char *yylastch; + /* start off machines */ +# ifdef LEXDEBUG + debug = 0; +# endif + yyfirst=1; + if (!yymorfg) + yylastch = yytext; + else { + yymorfg=0; + yylastch = yytext+yyleng; + } + for(;;){ + lsp = yylstate; + yyestate = yystate = yybgin; + if (yyprevious==YYNEWLINE) yystate++; + for (;;){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1); +# endif + yyt = yystate->yystoff; + if(yyt == yycrank && !yyfirst){ /* may not be any transitions */ + yyz = yystate->yyother; + if(yyz == 0)break; + if(yyz->yystoff == yycrank)break; + } + *yylastch++ = yych = input(); + yyfirst=0; + tryagain: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"char "); + allprint(yych); + putchar('\n'); + } +# endif + yyr = yyt; + if ( (int)yyt > (int)yycrank){ + yyt = yyr + yych; + if (yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } +# ifdef YYOPTIM + else if((int)yyt < (int)yycrank) { /* r < yycrank */ + yyt = yyr = yycrank+(yycrank-yyt); +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"compressed state\n"); +# endif + yyt = yyt + yych; + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transitions */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + yyt = yyr + YYU(yymatch[yych]); +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"try fall back character "); + allprint(YYU(yymatch[yych])); + putchar('\n'); + } +# endif + if(yyt <= yytop && yyt->verify+yysvec == yystate){ + if(yyt->advance+yysvec == YYLERR) /* error transition */ + {unput(*--yylastch);break;} + *lsp++ = yystate = yyt->advance+yysvec; + goto contin; + } + } + if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){ +# ifdef LEXDEBUG + if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1); +# endif + goto tryagain; + } +# endif + else + {unput(*--yylastch);break;} + contin: +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"state %d char ",yystate-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + ; + } +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1); + allprint(yych); + putchar('\n'); + } +# endif + while (lsp-- > yylstate){ + *yylastch-- = 0; + if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){ + yyolsp = lsp; + if(yyextra[*yyfnd]){ /* must backup */ + while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){ + lsp--; + unput(*yylastch--); + } + } + yyprevious = YYU(*yylastch); + yylsp = lsp; + yyleng = yylastch-yytext+1; + yytext[yyleng] = 0; +# ifdef LEXDEBUG + if(debug){ + fprintf(yyout,"\nmatch "); + sprint(yytext); + fprintf(yyout," action %d\n",*yyfnd); + } +# endif + return(*yyfnd++); + } + unput(*yylastch); + } + if (yytext[0] == 0 /* && feof(yyin) */) + { + yysptr=yysbuf; + return(0); + } + yyprevious = yytext[0] = input(); + if (yyprevious>0) + output(yyprevious); + yylastch=yytext; +# ifdef LEXDEBUG + if(debug)putchar('\n'); +# endif + } + } +yyback(p, m) + int *p; +{ +if (p==0) return(0); +while (*p) + { + if (*p++ == m) + return(1); + } +return(0); +} + /* the following are only used in the lex library */ +yyinput(){ + return(input()); + } +yyoutput(c) + int c; { + output(c); + } +yyunput(c) + int c; { + unput(c); + } diff --git a/lua.c b/lua.c new file mode 100644 index 0000000000..be01b70f02 --- /dev/null +++ b/lua.c @@ -0,0 +1,54 @@ +/* +** lua.c +** Linguagem para Usuarios de Aplicacao +** TeCGraf - PUC-Rio +** 28 Apr 93 +*/ + +#include + +#include "lua.h" +#include "lualib.h" + + +void test (void) +{ + lua_pushobject(lua_getparam(1)); + lua_call ("c", 1); +} + + +static void callfunc (void) +{ + lua_Object obj = lua_getparam (1); + if (lua_isstring(obj)) lua_call(lua_getstring(obj),0); +} + +static void execstr (void) +{ + lua_Object obj = lua_getparam (1); + if (lua_isstring(obj)) lua_dostring(lua_getstring(obj)); +} + +void main (int argc, char *argv[]) +{ + int i; + if (argc < 2) + { + puts ("usage: lua filename [functionnames]"); + return; + } + lua_register ("callfunc", callfunc); + lua_register ("execstr", execstr); + lua_register ("test", test); + iolib_open (); + strlib_open (); + mathlib_open (); + lua_dofile (argv[1]); + for (i=2; i /* NULL */ +#include + +#include "lua.h" + +static void math_abs (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `abs'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `abs'"); return; } + d = lua_getnumber(o); + if (d < 0) d = -d; + lua_pushnumber (d); +} + + +static void math_sin (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `sin'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `sin'"); return; } + d = lua_getnumber(o); + lua_pushnumber (sin(d)); +} + + + +static void math_cos (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `cos'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `cos'"); return; } + d = lua_getnumber(o); + lua_pushnumber (cos(d)); +} + + + +static void math_tan (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `tan'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `tan'"); return; } + d = lua_getnumber(o); + lua_pushnumber (tan(d)); +} + + +static void math_asin (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `asin'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `asin'"); return; } + d = lua_getnumber(o); + lua_pushnumber (asin(d)); +} + + +static void math_acos (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `acos'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `acos'"); return; } + d = lua_getnumber(o); + lua_pushnumber (acos(d)); +} + + + +static void math_atan (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `atan'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `atan'"); return; } + d = lua_getnumber(o); + lua_pushnumber (atan(d)); +} + + +static void math_ceil (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `ceil'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `ceil'"); return; } + d = lua_getnumber(o); + lua_pushnumber (ceil(d)); +} + + +static void math_floor (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `floor'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `floor'"); return; } + d = lua_getnumber(o); + lua_pushnumber (floor(d)); +} + +static void math_mod (void) +{ + int d1, d2; + lua_Object o1 = lua_getparam (1); + lua_Object o2 = lua_getparam (2); + if (!lua_isnumber(o1) || !lua_isnumber(o2)) + { lua_error ("incorrect arguments to function `mod'"); return; } + d1 = (int) lua_getnumber(o1); + d2 = (int) lua_getnumber(o2); + lua_pushnumber (d1%d2); +} + + +static void math_sqrt (void) +{ + double d; + lua_Object o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `sqrt'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `sqrt'"); return; } + d = lua_getnumber(o); + lua_pushnumber (sqrt(d)); +} + +static void math_pow (void) +{ + double d1, d2; + lua_Object o1 = lua_getparam (1); + lua_Object o2 = lua_getparam (2); + if (!lua_isnumber(o1) || !lua_isnumber(o2)) + { lua_error ("incorrect arguments to function `pow'"); return; } + d1 = lua_getnumber(o1); + d2 = lua_getnumber(o2); + lua_pushnumber (pow(d1,d2)); +} + +static void math_min (void) +{ + int i=1; + double d, dmin; + lua_Object o; + if ((o = lua_getparam(i++)) == NULL) + { lua_error ("too few arguments to function `min'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `min'"); return; } + dmin = lua_getnumber (o); + while ((o = lua_getparam(i++)) != NULL) + { + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `min'"); return; } + d = lua_getnumber (o); + if (d < dmin) dmin = d; + } + lua_pushnumber (dmin); +} + + +static void math_max (void) +{ + int i=1; + double d, dmax; + lua_Object o; + if ((o = lua_getparam(i++)) == NULL) + { lua_error ("too few arguments to function `max'"); return; } + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `max'"); return; } + dmax = lua_getnumber (o); + while ((o = lua_getparam(i++)) != NULL) + { + if (!lua_isnumber(o)) + { lua_error ("incorrect arguments to function `max'"); return; } + d = lua_getnumber (o); + if (d > dmax) dmax = d; + } + lua_pushnumber (dmax); +} + + + +/* +** Open math library +*/ +void mathlib_open (void) +{ + lua_register ("abs", math_abs); + lua_register ("sin", math_sin); + lua_register ("cos", math_cos); + lua_register ("tan", math_tan); + lua_register ("asin", math_asin); + lua_register ("acos", math_acos); + lua_register ("atan", math_atan); + lua_register ("ceil", math_ceil); + lua_register ("floor", math_floor); + lua_register ("mod", math_mod); + lua_register ("sqrt", math_sqrt); + lua_register ("pow", math_pow); + lua_register ("min", math_min); + lua_register ("max", math_max); +} diff --git a/opcode.c b/opcode.c new file mode 100644 index 0000000000..97975ba1b8 --- /dev/null +++ b/opcode.c @@ -0,0 +1,933 @@ +/* +** opcode.c +** TecCGraf - PUC-Rio +** 26 Apr 93 +*/ + +#include +#include +#include +#ifdef __GNUC__ +#include +#endif + +#include "opcode.h" +#include "hash.h" +#include "inout.h" +#include "table.h" +#include "lua.h" + +#define tonumber(o) ((tag(o) != T_NUMBER) && (lua_tonumber(o) != 0)) +#define tostring(o) ((tag(o) != T_STRING) && (lua_tostring(o) != 0)) + +#ifndef MAXSTACK +#define MAXSTACK 256 +#endif +static Object stack[MAXSTACK] = {{T_MARK, {NULL}}}; +static Object *top=stack+1, *base=stack+1; + + +/* +** Concatenate two given string, creating a mark space at the beginning. +** Return the new string pointer. +*/ +static char *lua_strconc (char *l, char *r) +{ + char *s = calloc (strlen(l)+strlen(r)+2, sizeof(char)); + if (s == NULL) + { + lua_error ("not enough memory"); + return NULL; + } + *s++ = 0; /* create mark space */ + return strcat(strcpy(s,l),r); +} + +/* +** Duplicate a string, creating a mark space at the beginning. +** Return the new string pointer. +*/ +char *lua_strdup (char *l) +{ + char *s = calloc (strlen(l)+2, sizeof(char)); + if (s == NULL) + { + lua_error ("not enough memory"); + return NULL; + } + *s++ = 0; /* create mark space */ + return strcpy(s,l); +} + +/* +** Convert, if possible, to a number tag. +** Return 0 in success or not 0 on error. +*/ +static int lua_tonumber (Object *obj) +{ + char *ptr; + if (tag(obj) != T_STRING) + { + lua_reportbug ("unexpected type at conversion to number"); + return 1; + } + nvalue(obj) = strtod(svalue(obj), &ptr); + if (*ptr) + { + lua_reportbug ("string to number convertion failed"); + return 2; + } + tag(obj) = T_NUMBER; + return 0; +} + +/* +** Test if is possible to convert an object to a number one. +** If possible, return the converted object, otherwise return nil object. +*/ +static Object *lua_convtonumber (Object *obj) +{ + static Object cvt; + + if (tag(obj) == T_NUMBER) + { + cvt = *obj; + return &cvt; + } + + tag(&cvt) = T_NIL; + if (tag(obj) == T_STRING) + { + char *ptr; + nvalue(&cvt) = strtod(svalue(obj), &ptr); + if (*ptr == 0) + tag(&cvt) = T_NUMBER; + } + return &cvt; +} + + + +/* +** Convert, if possible, to a string tag +** Return 0 in success or not 0 on error. +*/ +static int lua_tostring (Object *obj) +{ + static char s[256]; + if (tag(obj) != T_NUMBER) + { + lua_reportbug ("unexpected type at conversion to string"); + return 1; + } + if ((int) nvalue(obj) == nvalue(obj)) + sprintf (s, "%d", (int) nvalue(obj)); + else + sprintf (s, "%g", nvalue(obj)); + svalue(obj) = lua_createstring(lua_strdup(s)); + if (svalue(obj) == NULL) + return 1; + tag(obj) = T_STRING; + return 0; +} + + +/* +** Execute the given opcode. Return 0 in success or 1 on error. +*/ +int lua_execute (Byte *pc) +{ + while (1) + { + switch ((OpCode)*pc++) + { + case NOP: break; + + case PUSHNIL: tag(top++) = T_NIL; break; + + case PUSH0: tag(top) = T_NUMBER; nvalue(top++) = 0; break; + case PUSH1: tag(top) = T_NUMBER; nvalue(top++) = 1; break; + case PUSH2: tag(top) = T_NUMBER; nvalue(top++) = 2; break; + + case PUSHBYTE: tag(top) = T_NUMBER; nvalue(top++) = *pc++; break; + + case PUSHWORD: + tag(top) = T_NUMBER; nvalue(top++) = *((Word *)(pc)); pc += sizeof(Word); + break; + + case PUSHFLOAT: + tag(top) = T_NUMBER; nvalue(top++) = *((float *)(pc)); pc += sizeof(float); + break; + case PUSHSTRING: + { + int w = *((Word *)(pc)); + pc += sizeof(Word); + tag(top) = T_STRING; svalue(top++) = lua_constant[w]; + } + break; + + case PUSHLOCAL0: *top++ = *(base + 0); break; + case PUSHLOCAL1: *top++ = *(base + 1); break; + case PUSHLOCAL2: *top++ = *(base + 2); break; + case PUSHLOCAL3: *top++ = *(base + 3); break; + case PUSHLOCAL4: *top++ = *(base + 4); break; + case PUSHLOCAL5: *top++ = *(base + 5); break; + case PUSHLOCAL6: *top++ = *(base + 6); break; + case PUSHLOCAL7: *top++ = *(base + 7); break; + case PUSHLOCAL8: *top++ = *(base + 8); break; + case PUSHLOCAL9: *top++ = *(base + 9); break; + + case PUSHLOCAL: *top++ = *(base + (*pc++)); break; + + case PUSHGLOBAL: + *top++ = s_object(*((Word *)(pc))); pc += sizeof(Word); + break; + + case PUSHINDEXED: + --top; + if (tag(top-1) != T_ARRAY) + { + lua_reportbug ("indexed expression not a table"); + return 1; + } + { + Object *h = lua_hashdefine (avalue(top-1), top); + if (h == NULL) return 1; + *(top-1) = *h; + } + break; + + case PUSHMARK: tag(top++) = T_MARK; break; + + case PUSHOBJECT: *top = *(top-3); top++; break; + + case STORELOCAL0: *(base + 0) = *(--top); break; + case STORELOCAL1: *(base + 1) = *(--top); break; + case STORELOCAL2: *(base + 2) = *(--top); break; + case STORELOCAL3: *(base + 3) = *(--top); break; + case STORELOCAL4: *(base + 4) = *(--top); break; + case STORELOCAL5: *(base + 5) = *(--top); break; + case STORELOCAL6: *(base + 6) = *(--top); break; + case STORELOCAL7: *(base + 7) = *(--top); break; + case STORELOCAL8: *(base + 8) = *(--top); break; + case STORELOCAL9: *(base + 9) = *(--top); break; + + case STORELOCAL: *(base + (*pc++)) = *(--top); break; + + case STOREGLOBAL: + s_object(*((Word *)(pc))) = *(--top); pc += sizeof(Word); + break; + + case STOREINDEXED0: + if (tag(top-3) != T_ARRAY) + { + lua_reportbug ("indexed expression not a table"); + return 1; + } + { + Object *h = lua_hashdefine (avalue(top-3), top-2); + if (h == NULL) return 1; + *h = *(top-1); + } + top -= 3; + break; + + case STOREINDEXED: + { + int n = *pc++; + if (tag(top-3-n) != T_ARRAY) + { + lua_reportbug ("indexed expression not a table"); + return 1; + } + { + Object *h = lua_hashdefine (avalue(top-3-n), top-2-n); + if (h == NULL) return 1; + *h = *(top-1); + } + --top; + } + break; + + case STOREFIELD: + if (tag(top-3) != T_ARRAY) + { + lua_error ("internal error - table expected"); + return 1; + } + *(lua_hashdefine (avalue(top-3), top-2)) = *(top-1); + top -= 2; + break; + + case ADJUST: + { + Object *newtop = base + *(pc++); + if (top != newtop) + { + while (top < newtop) tag(top++) = T_NIL; + top = newtop; + } + } + break; + + case CREATEARRAY: + if (tag(top-1) == T_NIL) + nvalue(top-1) = 101; + else + { + if (tonumber(top-1)) return 1; + if (nvalue(top-1) <= 0) nvalue(top-1) = 101; + } + avalue(top-1) = lua_createarray(lua_hashcreate(nvalue(top-1))); + if (avalue(top-1) == NULL) + return 1; + tag(top-1) = T_ARRAY; + break; + + case EQOP: + { + Object *l = top-2; + Object *r = top-1; + --top; + if (tag(l) != tag(r)) + tag(top-1) = T_NIL; + else + { + switch (tag(l)) + { + case T_NIL: tag(top-1) = T_NUMBER; break; + case T_NUMBER: tag(top-1) = (nvalue(l) == nvalue(r)) ? T_NUMBER : T_NIL; break; + case T_ARRAY: tag(top-1) = (avalue(l) == avalue(r)) ? T_NUMBER : T_NIL; break; + case T_FUNCTION: tag(top-1) = (bvalue(l) == bvalue(r)) ? T_NUMBER : T_NIL; break; + case T_CFUNCTION: tag(top-1) = (fvalue(l) == fvalue(r)) ? T_NUMBER : T_NIL; break; + case T_USERDATA: tag(top-1) = (uvalue(l) == uvalue(r)) ? T_NUMBER : T_NIL; break; + case T_STRING: tag(top-1) = (strcmp (svalue(l), svalue(r)) == 0) ? T_NUMBER : T_NIL; break; + case T_MARK: return 1; + } + } + nvalue(top-1) = 1; + } + break; + + case LTOP: + { + Object *l = top-2; + Object *r = top-1; + --top; + if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) + tag(top-1) = (nvalue(l) < nvalue(r)) ? T_NUMBER : T_NIL; + else + { + if (tostring(l) || tostring(r)) + return 1; + tag(top-1) = (strcmp (svalue(l), svalue(r)) < 0) ? T_NUMBER : T_NIL; + } + nvalue(top-1) = 1; + } + break; + + case LEOP: + { + Object *l = top-2; + Object *r = top-1; + --top; + if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) + tag(top-1) = (nvalue(l) <= nvalue(r)) ? T_NUMBER : T_NIL; + else + { + if (tostring(l) || tostring(r)) + return 1; + tag(top-1) = (strcmp (svalue(l), svalue(r)) <= 0) ? T_NUMBER : T_NIL; + } + nvalue(top-1) = 1; + } + break; + + case ADDOP: + { + Object *l = top-2; + Object *r = top-1; + if (tonumber(r) || tonumber(l)) + return 1; + nvalue(l) += nvalue(r); + --top; + } + break; + + case SUBOP: + { + Object *l = top-2; + Object *r = top-1; + if (tonumber(r) || tonumber(l)) + return 1; + nvalue(l) -= nvalue(r); + --top; + } + break; + + case MULTOP: + { + Object *l = top-2; + Object *r = top-1; + if (tonumber(r) || tonumber(l)) + return 1; + nvalue(l) *= nvalue(r); + --top; + } + break; + + case DIVOP: + { + Object *l = top-2; + Object *r = top-1; + if (tonumber(r) || tonumber(l)) + return 1; + nvalue(l) /= nvalue(r); + --top; + } + break; + + case CONCOP: + { + Object *l = top-2; + Object *r = top-1; + if (tostring(r) || tostring(l)) + return 1; + svalue(l) = lua_createstring (lua_strconc(svalue(l),svalue(r))); + if (svalue(l) == NULL) + return 1; + --top; + } + break; + + case MINUSOP: + if (tonumber(top-1)) + return 1; + nvalue(top-1) = - nvalue(top-1); + break; + + case NOTOP: + tag(top-1) = tag(top-1) == T_NIL ? T_NUMBER : T_NIL; + break; + + case ONTJMP: + { + int n = *((Word *)(pc)); + pc += sizeof(Word); + if (tag(top-1) != T_NIL) pc += n; + } + break; + + case ONFJMP: + { + int n = *((Word *)(pc)); + pc += sizeof(Word); + if (tag(top-1) == T_NIL) pc += n; + } + break; + + case JMP: pc += *((Word *)(pc)) + sizeof(Word); break; + + case UPJMP: pc -= *((Word *)(pc)) - sizeof(Word); break; + + case IFFJMP: + { + int n = *((Word *)(pc)); + pc += sizeof(Word); + top--; + if (tag(top) == T_NIL) pc += n; + } + break; + + case IFFUPJMP: + { + int n = *((Word *)(pc)); + pc += sizeof(Word); + top--; + if (tag(top) == T_NIL) pc -= n; + } + break; + + case POP: --top; break; + + case CALLFUNC: + { + Byte *newpc; + Object *b = top-1; + while (tag(b) != T_MARK) b--; + if (tag(b-1) == T_FUNCTION) + { + lua_debugline = 0; /* always reset debug flag */ + newpc = bvalue(b-1); + bvalue(b-1) = pc; /* store return code */ + nvalue(b) = (base-stack); /* store base value */ + base = b+1; + pc = newpc; + if (MAXSTACK-(base-stack) < STACKGAP) + { + lua_error ("stack overflow"); + return 1; + } + } + else if (tag(b-1) == T_CFUNCTION) + { + int nparam; + lua_debugline = 0; /* always reset debug flag */ + nvalue(b) = (base-stack); /* store base value */ + base = b+1; + nparam = top-base; /* number of parameters */ + (fvalue(b-1))(); /* call C function */ + + /* shift returned values */ + { + int i; + int nretval = top - base - nparam; + top = base - 2; + base = stack + (int) nvalue(base-1); + for (i=0; i= stack; o--) + lua_markobject (o); +} + +/* +** Open file, generate opcode and execute global statement. Return 0 on +** success or 1 on error. +*/ +int lua_dofile (char *filename) +{ + if (lua_openfile (filename)) return 1; + if (lua_parse ()) { lua_closefile (); return 1; } + lua_closefile (); + return 0; +} + +/* +** Generate opcode stored on string and execute global statement. Return 0 on +** success or 1 on error. +*/ +int lua_dostring (char *string) +{ + if (lua_openstring (string)) return 1; + if (lua_parse ()) return 1; + return 0; +} + +/* +** Execute the given function. Return 0 on success or 1 on error. +*/ +int lua_call (char *functionname, int nparam) +{ + static Byte startcode[] = {CALLFUNC, HALT}; + int i; + Object func = s_object(lua_findsymbol(functionname)); + if (tag(&func) != T_FUNCTION) return 1; + for (i=1; i<=nparam; i++) + *(top-i+2) = *(top-i); + top += 2; + tag(top-nparam-1) = T_MARK; + *(top-nparam-2) = func; + return (lua_execute (startcode)); +} + +/* +** Get a parameter, returning the object handle or NULL on error. +** 'number' must be 1 to get the first parameter. +*/ +Object *lua_getparam (int number) +{ + if (number <= 0 || number > top-base) return NULL; + return (base+number-1); +} + +/* +** Given an object handle, return its number value. On error, return 0.0. +*/ +real lua_getnumber (Object *object) +{ + if (tonumber (object)) return 0.0; + else return (nvalue(object)); +} + +/* +** Given an object handle, return its string pointer. On error, return NULL. +*/ +char *lua_getstring (Object *object) +{ + if (tostring (object)) return NULL; + else return (svalue(object)); +} + +/* +** Given an object handle, return a copy of its string. On error, return NULL. +*/ +char *lua_copystring (Object *object) +{ + if (tostring (object)) return NULL; + else return (strdup(svalue(object))); +} + +/* +** Given an object handle, return its cfuntion pointer. On error, return NULL. +*/ +lua_CFunction lua_getcfunction (Object *object) +{ + if (tag(object) != T_CFUNCTION) return NULL; + else return (fvalue(object)); +} + +/* +** Given an object handle, return its user data. On error, return NULL. +*/ +void *lua_getuserdata (Object *object) +{ + if (tag(object) != T_USERDATA) return NULL; + else return (uvalue(object)); +} + +/* +** Given an object handle and a field name, return its field object. +** On error, return NULL. +*/ +Object *lua_getfield (Object *object, char *field) +{ + if (tag(object) != T_ARRAY) + return NULL; + else + { + Object ref; + tag(&ref) = T_STRING; + svalue(&ref) = lua_createstring(lua_strdup(field)); + return (lua_hashdefine(avalue(object), &ref)); + } +} + +/* +** Given an object handle and an index, return its indexed object. +** On error, return NULL. +*/ +Object *lua_getindexed (Object *object, float index) +{ + if (tag(object) != T_ARRAY) + return NULL; + else + { + Object ref; + tag(&ref) = T_NUMBER; + nvalue(&ref) = index; + return (lua_hashdefine(avalue(object), &ref)); + } +} + +/* +** Get a global object. Return the object handle or NULL on error. +*/ +Object *lua_getglobal (char *name) +{ + int n = lua_findsymbol(name); + if (n < 0) return NULL; + return &s_object(n); +} + +/* +** Pop and return an object +*/ +Object *lua_pop (void) +{ + if (top <= base) return NULL; + top--; + return top; +} + +/* +** Push a nil object +*/ +int lua_pushnil (void) +{ + if ((top-stack) >= MAXSTACK-1) + { + lua_error ("stack overflow"); + return 1; + } + tag(top) = T_NIL; + return 0; +} + +/* +** Push an object (tag=number) to stack. Return 0 on success or 1 on error. +*/ +int lua_pushnumber (real n) +{ + if ((top-stack) >= MAXSTACK-1) + { + lua_error ("stack overflow"); + return 1; + } + tag(top) = T_NUMBER; nvalue(top++) = n; + return 0; +} + +/* +** Push an object (tag=string) to stack. Return 0 on success or 1 on error. +*/ +int lua_pushstring (char *s) +{ + if ((top-stack) >= MAXSTACK-1) + { + lua_error ("stack overflow"); + return 1; + } + tag(top) = T_STRING; + svalue(top++) = lua_createstring(lua_strdup(s)); + return 0; +} + +/* +** Push an object (tag=cfunction) to stack. Return 0 on success or 1 on error. +*/ +int lua_pushcfunction (lua_CFunction fn) +{ + if ((top-stack) >= MAXSTACK-1) + { + lua_error ("stack overflow"); + return 1; + } + tag(top) = T_CFUNCTION; fvalue(top++) = fn; + return 0; +} + +/* +** Push an object (tag=userdata) to stack. Return 0 on success or 1 on error. +*/ +int lua_pushuserdata (void *u) +{ + if ((top-stack) >= MAXSTACK-1) + { + lua_error ("stack overflow"); + return 1; + } + tag(top) = T_USERDATA; uvalue(top++) = u; + return 0; +} + +/* +** Push an object to stack. +*/ +int lua_pushobject (Object *o) +{ + if ((top-stack) >= MAXSTACK-1) + { + lua_error ("stack overflow"); + return 1; + } + *top++ = *o; + return 0; +} + +/* +** Store top of the stack at a global variable array field. +** Return 1 on error, 0 on success. +*/ +int lua_storeglobal (char *name) +{ + int n = lua_findsymbol (name); + if (n < 0) return 1; + if (tag(top-1) == T_MARK) return 1; + s_object(n) = *(--top); + return 0; +} + +/* +** Store top of the stack at an array field. Return 1 on error, 0 on success. +*/ +int lua_storefield (lua_Object object, char *field) +{ + if (tag(object) != T_ARRAY) + return 1; + else + { + Object ref, *h; + tag(&ref) = T_STRING; + svalue(&ref) = lua_createstring(lua_strdup(field)); + h = lua_hashdefine(avalue(object), &ref); + if (h == NULL) return 1; + if (tag(top-1) == T_MARK) return 1; + *h = *(--top); + } + return 0; +} + + +/* +** Store top of the stack at an array index. Return 1 on error, 0 on success. +*/ +int lua_storeindexed (lua_Object object, float index) +{ + if (tag(object) != T_ARRAY) + return 1; + else + { + Object ref, *h; + tag(&ref) = T_NUMBER; + nvalue(&ref) = index; + h = lua_hashdefine(avalue(object), &ref); + if (h == NULL) return 1; + if (tag(top-1) == T_MARK) return 1; + *h = *(--top); + } + return 0; +} + + +/* +** Given an object handle, return if it is nil. +*/ +int lua_isnil (Object *object) +{ + return (object != NULL && tag(object) == T_NIL); +} + +/* +** Given an object handle, return if it is a number one. +*/ +int lua_isnumber (Object *object) +{ + return (object != NULL && tag(object) == T_NUMBER); +} + +/* +** Given an object handle, return if it is a string one. +*/ +int lua_isstring (Object *object) +{ + return (object != NULL && tag(object) == T_STRING); +} + +/* +** Given an object handle, return if it is an array one. +*/ +int lua_istable (Object *object) +{ + return (object != NULL && tag(object) == T_ARRAY); +} + +/* +** Given an object handle, return if it is a cfunction one. +*/ +int lua_iscfunction (Object *object) +{ + return (object != NULL && tag(object) == T_CFUNCTION); +} + +/* +** Given an object handle, return if it is an user data one. +*/ +int lua_isuserdata (Object *object) +{ + return (object != NULL && tag(object) == T_USERDATA); +} + +/* +** Internal function: return an object type. +*/ +void lua_type (void) +{ + Object *o = lua_getparam(1); + lua_pushstring (lua_constant[tag(o)]); +} + +/* +** Internal function: convert an object to a number +*/ +void lua_obj2number (void) +{ + Object *o = lua_getparam(1); + lua_pushobject (lua_convtonumber(o)); +} + +/* +** Internal function: print object values +*/ +void lua_print (void) +{ + int i=1; + void *obj; + while ((obj=lua_getparam (i++)) != NULL) + { + if (lua_isnumber(obj)) printf("%g\n",lua_getnumber (obj)); + else if (lua_isstring(obj)) printf("%s\n",lua_getstring (obj)); + else if (lua_iscfunction(obj)) printf("cfunction: %p\n",lua_getcfunction (obj)); + else if (lua_isuserdata(obj)) printf("userdata: %p\n",lua_getuserdata (obj)); + else if (lua_istable(obj)) printf("table: %p\n",obj); + else if (lua_isnil(obj)) printf("nil\n"); + else printf("invalid value to print\n"); + } +} + diff --git a/opcode.h b/opcode.h new file mode 100644 index 0000000000..b32969d5f4 --- /dev/null +++ b/opcode.h @@ -0,0 +1,144 @@ +/* +** opcode.h +** TeCGraf - PUC-Rio +** 16 Apr 92 +*/ + +#ifndef opcode_h +#define opcode_h + +#ifndef STACKGAP +#define STACKGAP 128 +#endif + +#ifndef real +#define real float +#endif + +typedef unsigned char Byte; + +typedef unsigned short Word; + +typedef enum +{ + NOP, + PUSHNIL, + PUSH0, PUSH1, PUSH2, + PUSHBYTE, + PUSHWORD, + PUSHFLOAT, + PUSHSTRING, + PUSHLOCAL0, PUSHLOCAL1, PUSHLOCAL2, PUSHLOCAL3, PUSHLOCAL4, + PUSHLOCAL5, PUSHLOCAL6, PUSHLOCAL7, PUSHLOCAL8, PUSHLOCAL9, + PUSHLOCAL, + PUSHGLOBAL, + PUSHINDEXED, + PUSHMARK, + PUSHOBJECT, + STORELOCAL0, STORELOCAL1, STORELOCAL2, STORELOCAL3, STORELOCAL4, + STORELOCAL5, STORELOCAL6, STORELOCAL7, STORELOCAL8, STORELOCAL9, + STORELOCAL, + STOREGLOBAL, + STOREINDEXED0, + STOREINDEXED, + STOREFIELD, + ADJUST, + CREATEARRAY, + EQOP, + LTOP, + LEOP, + ADDOP, + SUBOP, + MULTOP, + DIVOP, + CONCOP, + MINUSOP, + NOTOP, + ONTJMP, + ONFJMP, + JMP, + UPJMP, + IFFJMP, + IFFUPJMP, + POP, + CALLFUNC, + RETCODE, + HALT, + SETFUNCTION, + SETLINE, + RESET +} OpCode; + +typedef enum +{ + T_MARK, + T_NIL, + T_NUMBER, + T_STRING, + T_ARRAY, + T_FUNCTION, + T_CFUNCTION, + T_USERDATA +} Type; + +typedef void (*Cfunction) (void); +typedef int (*Input) (void); +typedef void (*Unput) (int ); + +typedef union +{ + Cfunction f; + real n; + char *s; + Byte *b; + struct Hash *a; + void *u; +} Value; + +typedef struct Object +{ + Type tag; + Value value; +} Object; + +typedef struct +{ + char *name; + Object object; +} Symbol; + +/* Macros to access structure members */ +#define tag(o) ((o)->tag) +#define nvalue(o) ((o)->value.n) +#define svalue(o) ((o)->value.s) +#define bvalue(o) ((o)->value.b) +#define avalue(o) ((o)->value.a) +#define fvalue(o) ((o)->value.f) +#define uvalue(o) ((o)->value.u) + +/* Macros to access symbol table */ +#define s_name(i) (lua_table[i].name) +#define s_object(i) (lua_table[i].object) +#define s_tag(i) (tag(&s_object(i))) +#define s_nvalue(i) (nvalue(&s_object(i))) +#define s_svalue(i) (svalue(&s_object(i))) +#define s_bvalue(i) (bvalue(&s_object(i))) +#define s_avalue(i) (avalue(&s_object(i))) +#define s_fvalue(i) (fvalue(&s_object(i))) +#define s_uvalue(i) (uvalue(&s_object(i))) + + +/* Exported functions */ +int lua_execute (Byte *pc); +void lua_markstack (void); +char *lua_strdup (char *l); + +void lua_setinput (Input fn); /* from "lua.lex" module */ +void lua_setunput (Unput fn); /* from "lua.lex" module */ +char *lua_lasttext (void); /* from "lua.lex" module */ +int lua_parse (void); /* from "lua.stx" module */ +void lua_type (void); +void lua_obj2number (void); +void lua_print (void); + +#endif diff --git a/save.lua b/save.lua new file mode 100644 index 0000000000..1a4ba04d8c --- /dev/null +++ b/save.lua @@ -0,0 +1,47 @@ +$debug + + +function savevar (n,v) + if v = nil then return end; + if type(v) = "number" then print(n.."="..v) return end + if type(v) = "string" then print(n.."='"..v.."'") return end + if type(v) = "table" then + if v.__visited__ ~= nil then + print(n .. "=" .. v.__visited__); + else + print(n.."=@()") + v.__visited__ = n; + local r,f; + r,f = next(v,nil); + while r ~= nil do + if r ~= "__visited__" then + if type(r) = 'string' then + savevar(n.."['"..r.."']",f) + else + savevar(n.."["..r.."]",f) + end + end + r,f = next(v,r) + end + end + end +end + +function save () +local n,v + n,v = nextvar(nil) + while n ~= nil do + savevar(n,v); + n,v = nextvar(n) + end +end + +a = 3 +x = @{a = 4, b = "name", l=@[4,5,67]} + +b = @{t=5} +x.next = b + + +save() + diff --git a/sort.lua b/sort.lua new file mode 100644 index 0000000000..f749c12248 --- /dev/null +++ b/sort.lua @@ -0,0 +1,56 @@ +$debug + +function quicksort(r,s) + if s<=r then return end -- caso basico da recursao + local v=x[r] + local i=r + local j=s+1 + i=i+1; while x[i]v do j=j-1 end + x[i],x[j]=x[j],x[i] + while j>i do -- separacao + i=i+1; while x[i]v do j=j-1 end + x[i],x[j]=x[j],x[i] + end + x[i],x[j]=x[j],x[i] -- undo last swap + x[j],x[r]=x[r],x[j] + quicksort(r,j-1) -- recursao + quicksort(j+1,s) +end + +function sort(a,n) -- selection sort + local i=1 + while i<=n do + local m=i + local j=i+1 + while j<=n do + if a[j] +#include +#include + + +#include "lua.h" + +/* +** Return the position of the first caracter of a substring into a string +** LUA interface: +** n = strfind (string, substring) +*/ +static void str_find (void) +{ + int n; + char *s1, *s2; + lua_Object o1 = lua_getparam (1); + lua_Object o2 = lua_getparam (2); + if (!lua_isstring(o1) || !lua_isstring(o2)) + { lua_error ("incorrect arguments to function `strfind'"); return; } + s1 = lua_getstring(o1); + s2 = lua_getstring(o2); + n = strstr(s1,s2) - s1 + 1; + lua_pushnumber (n); +} + +/* +** Return the string length +** LUA interface: +** n = strlen (string) +*/ +static void str_len (void) +{ + lua_Object o = lua_getparam (1); + if (!lua_isstring(o)) + { lua_error ("incorrect arguments to function `strlen'"); return; } + lua_pushnumber(strlen(lua_getstring(o))); +} + + +/* +** Return the substring of a string, from start to end +** LUA interface: +** substring = strsub (string, start, end) +*/ +static void str_sub (void) +{ + int start, end; + char *s; + lua_Object o1 = lua_getparam (1); + lua_Object o2 = lua_getparam (2); + lua_Object o3 = lua_getparam (3); + if (!lua_isstring(o1) || !lua_isnumber(o2) || !lua_isnumber(o3)) + { lua_error ("incorrect arguments to function `strsub'"); return; } + s = strdup (lua_getstring(o1)); + start = lua_getnumber (o2); + end = lua_getnumber (o3); + if (end < start || start < 1 || end > strlen(s)) + lua_pushstring (""); + else + { + s[end] = 0; + lua_pushstring (&s[start-1]); + } + free (s); +} + +/* +** Convert a string to lower case. +** LUA interface: +** lowercase = strlower (string) +*/ +static void str_lower (void) +{ + char *s, *c; + lua_Object o = lua_getparam (1); + if (!lua_isstring(o)) + { lua_error ("incorrect arguments to function `strlower'"); return; } + c = s = strdup(lua_getstring(o)); + while (*c != 0) + { + *c = tolower(*c); + c++; + } + lua_pushstring(s); + free(s); +} + + +/* +** Convert a string to upper case. +** LUA interface: +** uppercase = strupper (string) +*/ +static void str_upper (void) +{ + char *s, *c; + lua_Object o = lua_getparam (1); + if (!lua_isstring(o)) + { lua_error ("incorrect arguments to function `strlower'"); return; } + c = s = strdup(lua_getstring(o)); + while (*c != 0) + { + *c = toupper(*c); + c++; + } + lua_pushstring(s); + free(s); +} + + +/* +** Open string library +*/ +void strlib_open (void) +{ + lua_register ("strfind", str_find); + lua_register ("strlen", str_len); + lua_register ("strsub", str_sub); + lua_register ("strlower", str_lower); + lua_register ("strupper", str_upper); +} diff --git a/table.c b/table.c new file mode 100644 index 0000000000..3bae7ebd54 --- /dev/null +++ b/table.c @@ -0,0 +1,351 @@ +/* +** table.c +** Module to control static tables +** TeCGraf - PUC-Rio +** 11 May 93 +*/ + +#include +#include + +#include "opcode.h" +#include "hash.h" +#include "inout.h" +#include "table.h" +#include "lua.h" + +#define streq(s1,s2) (strcmp(s1,s2)==0) + +#ifndef MAXSYMBOL +#define MAXSYMBOL 512 +#endif +static Symbol tablebuffer[MAXSYMBOL] = { + {"type",{T_CFUNCTION,{lua_type}}}, + {"tonumber",{T_CFUNCTION,{lua_obj2number}}}, + {"next",{T_CFUNCTION,{lua_next}}}, + {"nextvar",{T_CFUNCTION,{lua_nextvar}}}, + {"print",{T_CFUNCTION,{lua_print}}} + }; +Symbol *lua_table=tablebuffer; +Word lua_ntable=5; + +#ifndef MAXCONSTANT +#define MAXCONSTANT 256 +#endif +static char *constantbuffer[MAXCONSTANT] = {"mark","nil","number", + "string","table", + "function","cfunction" + }; +char **lua_constant = constantbuffer; +Word lua_nconstant=T_CFUNCTION+1; + +#ifndef MAXSTRING +#define MAXSTRING 512 +#endif +static char *stringbuffer[MAXSTRING]; +char **lua_string = stringbuffer; +Word lua_nstring=0; + +#ifndef MAXARRAY +#define MAXARRAY 512 +#endif +static Hash *arraybuffer[MAXARRAY]; +Hash **lua_array = arraybuffer; +Word lua_narray=0; + +#define MAXFILE 20 +char *lua_file[MAXFILE]; +int lua_nfile; + + +/* +** Given a name, search it at symbol table and return its index. If not +** found, allocate at end of table, checking oveflow and return its index. +** On error, return -1. +*/ +int lua_findsymbol (char *s) +{ + int i; + for (i=0; i= MAXSYMBOL-1) + { + lua_error ("symbol table overflow"); + return -1; + } + s_name(lua_ntable) = strdup(s); + if (s_name(lua_ntable) == NULL) + { + lua_error ("not enough memory"); + return -1; + } + s_tag(lua_ntable++) = T_NIL; + + return (lua_ntable-1); +} + +/* +** Given a constant string, eliminate its delimeters (" or '), search it at +** constant table and return its index. If not found, allocate at end of +** the table, checking oveflow and return its index. +** +** For each allocation, the function allocate a extra char to be used to +** mark used string (it's necessary to deal with constant and string +** uniformily). The function store at the table the second position allocated, +** that represents the beginning of the real string. On error, return -1. +** +*/ +int lua_findenclosedconstant (char *s) +{ + int i, j, l=strlen(s); + char *c = calloc (l, sizeof(char)); /* make a copy */ + + c++; /* create mark space */ + + /* introduce scape characters */ + for (i=1,j=0; i= MAXCONSTANT-1) + { + lua_error ("lua: constant string table overflow"); + return -1; + } + lua_constant[lua_nconstant++] = c; + return (lua_nconstant-1); +} + +/* +** Given a constant string, search it at constant table and return its index. +** If not found, allocate at end of the table, checking oveflow and return +** its index. +** +** For each allocation, the function allocate a extra char to be used to +** mark used string (it's necessary to deal with constant and string +** uniformily). The function store at the table the second position allocated, +** that represents the beginning of the real string. On error, return -1. +** +*/ +int lua_findconstant (char *s) +{ + int i; + for (i=0; i= MAXCONSTANT-1) + { + lua_error ("lua: constant string table overflow"); + return -1; + } + { + char *c = calloc(strlen(s)+2,sizeof(char)); + c++; /* create mark space */ + lua_constant[lua_nconstant++] = strcpy(c,s); + } + return (lua_nconstant-1); +} + + +/* +** Mark an object if it is a string or a unmarked array. +*/ +void lua_markobject (Object *o) +{ + if (tag(o) == T_STRING) + lua_markstring (svalue(o)) = 1; + else if (tag(o) == T_ARRAY && markarray(avalue(o)) == 0) + lua_hashmark (avalue(o)); +} + +/* +** Mark all strings and arrays used by any object stored at symbol table. +*/ +static void lua_marktable (void) +{ + int i; + for (i=0; i= MAXSTRING-1) + { + lua_pack (); + if (lua_nstring >= MAXSTRING-1) + { + lua_error ("string table overflow"); + return NULL; + } + } + lua_string[lua_nstring++] = s; + return s; +} + +/* +** Allocate a new array, already created, at array table. The function puts +** it at the end of the table, checking overflow, and returns its own pointer, +** or NULL on error. +*/ +void *lua_createarray (void *a) +{ + if (a == NULL) return NULL; + + if (lua_narray >= MAXARRAY-1) + { + lua_pack (); + if (lua_narray >= MAXARRAY-1) + { + lua_error ("indexed table overflow"); + return NULL; + } + } + lua_array[lua_narray++] = a; + return a; +} + + +/* +** Add a file name at file table, checking overflow. This function also set +** the external variable "lua_filename" with the function filename set. +** Return 0 on success or 1 on error. +*/ +int lua_addfile (char *fn) +{ + if (lua_nfile >= MAXFILE-1) + { + lua_error ("too many files"); + return 1; + } + if ((lua_file[lua_nfile++] = strdup (fn)) == NULL) + { + lua_error ("not enough memory"); + return 1; + } + return 0; +} + +/* +** Return the last file name set. +*/ +char *lua_filename (void) +{ + return lua_file[lua_nfile-1]; +} + +/* +** Internal function: return next global variable +*/ +void lua_nextvar (void) +{ + int index; + Object *o = lua_getparam (1); + if (o == NULL) + { lua_error ("too few arguments to function `nextvar'"); return; } + if (lua_getparam (2) != NULL) + { lua_error ("too many arguments to function `nextvar'"); return; } + if (tag(o) == T_NIL) + { + index = 0; + } + else if (tag(o) != T_STRING) + { + lua_error ("incorrect argument to function `nextvar'"); + return; + } + else + { + for (index=0; index +#include +#include + +#include "opcode.h" +#include "hash.h" +#include "inout.h" +#include "table.h" +#include "lua.h" + +#ifndef ALIGNMENT +#define ALIGNMENT (sizeof(void *)) +#endif + +#ifndef MAXCODE +#define MAXCODE 1024 +#endif +static long buffer[MAXCODE]; +static Byte *code = (Byte *)buffer; +static long mainbuffer[MAXCODE]; +static Byte *maincode = (Byte *)mainbuffer; +static Byte *basepc; +static Byte *pc; + +#define MAXVAR 32 +static long varbuffer[MAXVAR]; +static Byte nvarbuffer=0; /* number of variables at a list */ + +static Word localvar[STACKGAP]; +static Byte nlocalvar=0; /* number of local variables */ +static int ntemp; /* number of temporary var into stack */ +static int err; /* flag to indicate error */ + +/* Internal functions */ +#define align(n) align_n(sizeof(n)) + +static void code_byte (Byte c) +{ + if (pc-basepc>MAXCODE-1) + { + lua_error ("code buffer overflow"); + err = 1; + } + *pc++ = c; +} + +static void code_word (Word n) +{ + if (pc-basepc>MAXCODE-sizeof(Word)) + { + lua_error ("code buffer overflow"); + err = 1; + } + *((Word *)pc) = n; + pc += sizeof(Word); +} + +static void code_float (float n) +{ + if (pc-basepc>MAXCODE-sizeof(float)) + { + lua_error ("code buffer overflow"); + err = 1; + } + *((float *)pc) = n; + pc += sizeof(float); +} + +static void incr_ntemp (void) +{ + if (ntemp+nlocalvar+MAXVAR+1 < STACKGAP) + ntemp++; + else + { + lua_error ("stack overflow"); + err = 1; + } +} + +static void incr_nlocalvar (void) +{ + if (ntemp+nlocalvar+MAXVAR+1 < STACKGAP) + nlocalvar++; + else + { + lua_error ("too many local variables or expression too complicate"); + err = 1; + } +} + +static void incr_nvarbuffer (void) +{ + if (nvarbuffer < MAXVAR-1) + nvarbuffer++; + else + { + lua_error ("variable buffer overflow"); + err = 1; + } +} + +static void align_n (unsigned size) +{ + if (size > ALIGNMENT) size = ALIGNMENT; + while (((pc+1-code)%size) != 0) /* +1 to include BYTECODE */ + code_byte (NOP); +} + +static void code_number (float f) +{ int i = f; + if (f == i) /* f has an integer value */ + { + if (i <= 2) code_byte(PUSH0 + i); + else if (i <= 255) + { + code_byte(PUSHBYTE); + code_byte(i); + } + else + { + align(Word); + code_byte(PUSHWORD); + code_word(i); + } + } + else + { + align(float); + code_byte(PUSHFLOAT); + code_float(f); + } + incr_ntemp(); +} + + +# line 140 "lua.stx" +typedef union +{ + int vInt; + long vLong; + float vFloat; + Word vWord; + Byte *pByte; +} YYSTYPE; +# define NIL 257 +# define IF 258 +# define THEN 259 +# define ELSE 260 +# define ELSEIF 261 +# define WHILE 262 +# define DO 263 +# define REPEAT 264 +# define UNTIL 265 +# define END 266 +# define RETURN 267 +# define LOCAL 268 +# define NUMBER 269 +# define FUNCTION 270 +# define NAME 271 +# define STRING 272 +# define DEBUG 273 +# define NOT 274 +# define AND 275 +# define OR 276 +# define NE 277 +# define LE 278 +# define GE 279 +# define CONC 280 +# define UNARY 281 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 +extern int yychar; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +YYSTYPE yylval, yyval; +# define YYERRCODE 256 + +# line 530 "lua.stx" + + +/* +** Search a local name and if find return its index. If do not find return -1 +*/ +static int lua_localname (Word n) +{ + int i; + for (i=nlocalvar-1; i >= 0; i--) + if (n == localvar[i]) return i; /* local var */ + return -1; /* global var */ +} + +/* +** Push a variable given a number. If number is positive, push global variable +** indexed by (number -1). If negative, push local indexed by ABS(number)-1. +** Otherwise, if zero, push indexed variable (record). +*/ +static void lua_pushvar (long number) +{ + if (number > 0) /* global var */ + { + align(Word); + code_byte(PUSHGLOBAL); + code_word(number-1); + incr_ntemp(); + } + else if (number < 0) /* local var */ + { + number = (-number) - 1; + if (number < 10) code_byte(PUSHLOCAL0 + number); + else + { + code_byte(PUSHLOCAL); + code_byte(number); + } + incr_ntemp(); + } + else + { + code_byte(PUSHINDEXED); + ntemp--; + } +} + +static void lua_codeadjust (int n) +{ + code_byte(ADJUST); + code_byte(n + nlocalvar); +} + +static void lua_codestore (int i) +{ + if (varbuffer[i] > 0) /* global var */ + { + align(Word); + code_byte(STOREGLOBAL); + code_word(varbuffer[i]-1); + } + else if (varbuffer[i] < 0) /* local var */ + { + int number = (-varbuffer[i]) - 1; + if (number < 10) code_byte(STORELOCAL0 + number); + else + { + code_byte(STORELOCAL); + code_byte(number); + } + } + else /* indexed var */ + { + int j; + int upper=0; /* number of indexed variables upper */ + int param; /* number of itens until indexed expression */ + for (j=i+1; j ", 62, + "<", 60, + "LE", 278, + "GE", 279, + "CONC", 280, + "+", 43, + "-", 45, + "*", 42, + "/", 47, + "%", 37, + "UNARY", 281, + "-unknown-", -1 /* ends search */ +}; + +char * yyreds[] = +{ + "-no such reduction-", + "functionlist : /* empty */", + "functionlist : functionlist", + "functionlist : functionlist stat sc", + "functionlist : functionlist function", + "functionlist : functionlist setdebug", + "function : FUNCTION NAME", + "function : FUNCTION NAME '(' parlist ')'", + "function : FUNCTION NAME '(' parlist ')' block END", + "statlist : /* empty */", + "statlist : statlist stat sc", + "stat : /* empty */", + "stat : stat1", + "sc : /* empty */", + "sc : ';'", + "stat1 : IF expr1 THEN PrepJump block PrepJump elsepart END", + "stat1 : WHILE", + "stat1 : WHILE expr1 DO PrepJump block PrepJump END", + "stat1 : REPEAT", + "stat1 : REPEAT block UNTIL expr1 PrepJump", + "stat1 : varlist1 '=' exprlist1", + "stat1 : functioncall", + "stat1 : LOCAL declist", + "elsepart : /* empty */", + "elsepart : ELSE block", + "elsepart : ELSEIF expr1 THEN PrepJump block PrepJump elsepart", + "block : /* empty */", + "block : statlist", + "block : statlist ret", + "ret : /* empty */", + "ret : /* empty */", + "ret : RETURN exprlist sc", + "PrepJump : /* empty */", + "expr1 : expr", + "expr : '(' expr ')'", + "expr : expr1 '=' expr1", + "expr : expr1 '<' expr1", + "expr : expr1 '>' expr1", + "expr : expr1 NE expr1", + "expr : expr1 LE expr1", + "expr : expr1 GE expr1", + "expr : expr1 '+' expr1", + "expr : expr1 '-' expr1", + "expr : expr1 '*' expr1", + "expr : expr1 '/' expr1", + "expr : expr1 CONC expr1", + "expr : '+' expr1", + "expr : '-' expr1", + "expr : '@'", + "expr : '@' objectname fieldlist", + "expr : '@' '(' dimension ')'", + "expr : var", + "expr : NUMBER", + "expr : STRING", + "expr : NIL", + "expr : functioncall", + "expr : NOT expr1", + "expr : expr1 AND PrepJump", + "expr : expr1 AND PrepJump expr1", + "expr : expr1 OR PrepJump", + "expr : expr1 OR PrepJump expr1", + "dimension : /* empty */", + "dimension : expr1", + "functioncall : functionvalue", + "functioncall : functionvalue '(' exprlist ')'", + "functionvalue : var", + "exprlist : /* empty */", + "exprlist : exprlist1", + "exprlist1 : expr", + "exprlist1 : exprlist1 ','", + "exprlist1 : exprlist1 ',' expr", + "parlist : /* empty */", + "parlist : parlist1", + "parlist1 : NAME", + "parlist1 : parlist1 ',' NAME", + "objectname : /* empty */", + "objectname : NAME", + "fieldlist : '{' ffieldlist '}'", + "fieldlist : '[' lfieldlist ']'", + "ffieldlist : /* empty */", + "ffieldlist : ffieldlist1", + "ffieldlist1 : ffield", + "ffieldlist1 : ffieldlist1 ',' ffield", + "ffield : NAME", + "ffield : NAME '=' expr1", + "lfieldlist : /* empty */", + "lfieldlist : lfieldlist1", + "lfieldlist1 : /* empty */", + "lfieldlist1 : lfield", + "lfieldlist1 : lfieldlist1 ','", + "lfieldlist1 : lfieldlist1 ',' lfield", + "lfield : expr1", + "varlist1 : var", + "varlist1 : varlist1 ',' var", + "var : NAME", + "var : var", + "var : var '[' expr1 ']'", + "var : var", + "var : var '.' NAME", + "declist : NAME init", + "declist : declist ',' NAME init", + "init : /* empty */", + "init : '='", + "init : '=' expr1", + "setdebug : DEBUG", +}; +#endif /* YYDEBUG */ +#line 1 "/usr/lib/yaccpar" +/* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */ + +/* +** Skeleton parser driver for yacc output +*/ + +/* +** yacc user known macros and defines +*/ +#define YYERROR goto yyerrlab +#define YYACCEPT { free(yys); free(yyv); return(0); } +#define YYABORT { free(yys); free(yyv); return(1); } +#define YYBACKUP( newtoken, newvalue )\ +{\ + if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\ + {\ + yyerror( "syntax error - cannot backup" );\ + goto yyerrlab;\ + }\ + yychar = newtoken;\ + yystate = *yyps;\ + yylval = newvalue;\ + goto yynewstate;\ +} +#define YYRECOVERING() (!!yyerrflag) +#ifndef YYDEBUG +# define YYDEBUG 1 /* make debugging available */ +#endif + +/* +** user known globals +*/ +int yydebug; /* set to 1 to get debugging */ + +/* +** driver internal defines +*/ +#define YYFLAG (-1000) + +/* +** static variables used by the parser +*/ +static YYSTYPE *yyv; /* value stack */ +static int *yys; /* state stack */ + +static YYSTYPE *yypv; /* top of value stack */ +static int *yyps; /* top of state stack */ + +static int yystate; /* current state */ +static int yytmp; /* extra var (lasts between blocks) */ + +int yynerrs; /* number of errors */ + +int yyerrflag; /* error recovery flag */ +int yychar; /* current input token number */ + + +/* +** yyparse - return 0 if worked, 1 if syntax error not recovered from +*/ +int +yyparse() +{ + register YYSTYPE *yypvt; /* top of value stack for $vars */ + unsigned yymaxdepth = YYMAXDEPTH; + + /* + ** Initialize externals - yyparse may be called more than once + */ + yyv = (YYSTYPE*)malloc(yymaxdepth*sizeof(YYSTYPE)); + yys = (int*)malloc(yymaxdepth*sizeof(int)); + if (!yyv || !yys) + { + yyerror( "out of memory" ); + return(1); + } + yypv = &yyv[-1]; + yyps = &yys[-1]; + yystate = 0; + yytmp = 0; + yynerrs = 0; + yyerrflag = 0; + yychar = -1; + + goto yystack; + { + register YYSTYPE *yy_pv; /* top of value stack */ + register int *yy_ps; /* top of state stack */ + register int yy_state; /* current state */ + register int yy_n; /* internal state number info */ + + /* + ** get globals into registers. + ** branch to here only if YYBACKUP was called. + */ + yynewstate: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + goto yy_newstate; + + /* + ** get globals into registers. + ** either we just started, or we just finished a reduction + */ + yystack: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + + /* + ** top of for (;;) loop while no reductions done + */ + yy_stack: + /* + ** put a state and value onto the stacks + */ +#if YYDEBUG + /* + ** if debugging, look up token value in list of value vs. + ** name pairs. 0 and negative (-1) are special values. + ** Note: linear search is used since time is not a real + ** consideration while debugging. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "State %d, token ", yy_state ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */ + { + /* + ** reallocate and recover. Note that pointers + ** have to be reset, or bad things will happen + */ + int yyps_index = (yy_ps - yys); + int yypv_index = (yy_pv - yyv); + int yypvt_index = (yypvt - yyv); + yymaxdepth += YYMAXDEPTH; + yyv = (YYSTYPE*)realloc((char*)yyv, + yymaxdepth * sizeof(YYSTYPE)); + yys = (int*)realloc((char*)yys, + yymaxdepth * sizeof(int)); + if (!yyv || !yys) + { + yyerror( "yacc stack overflow" ); + return(1); + } + yy_ps = yys + yyps_index; + yy_pv = yyv + yypv_index; + yypvt = yyv + yypvt_index; + } + *yy_ps = yy_state; + *++yy_pv = yyval; + + /* + ** we have a new state - find out what to do + */ + yy_newstate: + if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG ) + goto yydefault; /* simple state */ +#if YYDEBUG + /* + ** if debugging, need to mark whether new token grabbed + */ + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) ) + goto yydefault; + if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/ + { + yychar = -1; + yyval = yylval; + yy_state = yy_n; + if ( yyerrflag > 0 ) + yyerrflag--; + goto yy_stack; + } + + yydefault: + if ( ( yy_n = yydef[ yy_state ] ) == -2 ) + { +#if YYDEBUG + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + /* + ** look through exception table + */ + { + register int *yyxi = yyexca; + + while ( ( *yyxi != -1 ) || + ( yyxi[1] != yy_state ) ) + { + yyxi += 2; + } + while ( ( *(yyxi += 2) >= 0 ) && + ( *yyxi != yychar ) ) + ; + if ( ( yy_n = yyxi[1] ) < 0 ) + YYACCEPT; + } + } + + /* + ** check for syntax error + */ + if ( yy_n == 0 ) /* have an error */ + { + /* no worry about speed here! */ + switch ( yyerrflag ) + { + case 0: /* new error */ + yyerror( "syntax error" ); + goto skip_init; + yyerrlab: + /* + ** get globals into registers. + ** we have a user generated syntax type error + */ + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + yynerrs++; + skip_init: + case 1: + case 2: /* incompletely recovered error */ + /* try again... */ + yyerrflag = 3; + /* + ** find state where "error" is a legal + ** shift action + */ + while ( yy_ps >= yys ) + { + yy_n = yypact[ *yy_ps ] + YYERRCODE; + if ( yy_n >= 0 && yy_n < YYLAST && + yychk[yyact[yy_n]] == YYERRCODE) { + /* + ** simulate shift of "error" + */ + yy_state = yyact[ yy_n ]; + goto yy_stack; + } + /* + ** current state has no shift on + ** "error", pop stack + */ +#if YYDEBUG +# define _POP_ "Error recovery pops state %d, uncovers state %d\n" + if ( yydebug ) + (void)printf( _POP_, *yy_ps, + yy_ps[-1] ); +# undef _POP_ +#endif + yy_ps--; + yy_pv--; + } + /* + ** there is no state on stack with "error" as + ** a valid shift. give up. + */ + YYABORT; + case 3: /* no shift yet; eat a token */ +#if YYDEBUG + /* + ** if debugging, look up token in list of + ** pairs. 0 and negative shouldn't occur, + ** but since timing doesn't matter when + ** debugging, it doesn't hurt to leave the + ** tests here. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "Error recovery discards " ); + if ( yychar == 0 ) + (void)printf( "token end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "token -none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "token %s\n", + yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( yychar == 0 ) /* reached EOF. quit */ + YYABORT; + yychar = -1; + goto yy_newstate; + } + }/* end if ( yy_n == 0 ) */ + /* + ** reduction by production yy_n + ** put stack tops, etc. so things right after switch + */ +#if YYDEBUG + /* + ** if debugging, print the string that is the user's + ** specification of the reduction which is just about + ** to be done. + */ + if ( yydebug ) + (void)printf( "Reduce by (%d) \"%s\"\n", + yy_n, yyreds[ yy_n ] ); +#endif + yytmp = yy_n; /* value to switch over */ + yypvt = yy_pv; /* $vars top of value stack */ + /* + ** Look in goto table for next state + ** Sorry about using yy_state here as temporary + ** register variable, but why not, if it works... + ** If yyr2[ yy_n ] doesn't have the low order bit + ** set, then there is no action to be done for + ** this reduction. So, no saving & unsaving of + ** registers done. The only difference between the + ** code just after the if and the body of the if is + ** the goto yy_stack in the body. This way the test + ** can be made before the choice of what to do is needed. + */ + { + /* length of production doubled with extra bit */ + register int yy_len = yyr2[ yy_n ]; + + if ( !( yy_len & 01 ) ) + { + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = + yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + goto yy_stack; + } + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + } + /* save until reenter driver code */ + yystate = yy_state; + yyps = yy_ps; + yypv = yy_pv; + } + /* + ** code supplied by user is placed in this switch + */ + switch( yytmp ) + { + +case 2: +# line 179 "lua.stx" +{pc=basepc=maincode; nlocalvar=0;} break; +case 3: +# line 179 "lua.stx" +{maincode=pc;} break; +case 6: +# line 184 "lua.stx" +{pc=basepc=code; nlocalvar=0;} break; +case 7: +# line 185 "lua.stx" +{ + if (lua_debug) + { + align(Word); + code_byte(SETFUNCTION); + code_word(yypvt[-5].vWord); + code_word(yypvt[-4].vWord); + } + lua_codeadjust (0); + } break; +case 8: +# line 197 "lua.stx" +{ + if (lua_debug) code_byte(RESET); + code_byte(RETCODE); code_byte(nlocalvar); + s_tag(yypvt[-7].vWord) = T_FUNCTION; + s_bvalue(yypvt[-7].vWord) = calloc (pc-code, sizeof(Byte)); + memcpy (s_bvalue(yypvt[-7].vWord), code, (pc-code)*sizeof(Byte)); + } break; +case 11: +# line 210 "lua.stx" +{ + ntemp = 0; + if (lua_debug) + { + align(Word); code_byte(SETLINE); code_word(lua_linenumber); + } + } break; +case 15: +# line 223 "lua.stx" +{ + { + Byte *elseinit = yypvt[-2].pByte + sizeof(Word)+1; + if (pc - elseinit == 0) /* no else */ + { + pc -= sizeof(Word)+1; + /* if (*(pc-1) == NOP) --pc; */ + elseinit = pc; + } + else + { + *(yypvt[-2].pByte) = JMP; + *((Word *)(yypvt[-2].pByte+1)) = pc - elseinit; + } + *(yypvt[-4].pByte) = IFFJMP; + *((Word *)(yypvt[-4].pByte+1)) = elseinit - (yypvt[-4].pByte + sizeof(Word)+1); + } + } break; +case 16: +# line 242 "lua.stx" +{yyval.pByte = pc;} break; +case 17: +# line 244 "lua.stx" +{ + *(yypvt[-3].pByte) = IFFJMP; + *((Word *)(yypvt[-3].pByte+1)) = pc - (yypvt[-3].pByte + sizeof(Word)+1); + + *(yypvt[-1].pByte) = UPJMP; + *((Word *)(yypvt[-1].pByte+1)) = pc - yypvt[-6].pByte; + } break; +case 18: +# line 252 "lua.stx" +{yyval.pByte = pc;} break; +case 19: +# line 254 "lua.stx" +{ + *(yypvt[-0].pByte) = IFFUPJMP; + *((Word *)(yypvt[-0].pByte+1)) = pc - yypvt[-4].pByte; + } break; +case 20: +# line 261 "lua.stx" +{ + { + int i; + if (yypvt[-0].vInt == 0 || nvarbuffer != ntemp - yypvt[-2].vInt * 2) + lua_codeadjust (yypvt[-2].vInt * 2 + nvarbuffer); + for (i=nvarbuffer-1; i>=0; i--) + lua_codestore (i); + if (yypvt[-2].vInt > 1 || (yypvt[-2].vInt == 1 && varbuffer[0] != 0)) + lua_codeadjust (0); + } + } break; +case 21: +# line 272 "lua.stx" +{ lua_codeadjust (0); } break; +case 25: +# line 279 "lua.stx" +{ + { + Byte *elseinit = yypvt[-1].pByte + sizeof(Word)+1; + if (pc - elseinit == 0) /* no else */ + { + pc -= sizeof(Word)+1; + /* if (*(pc-1) == NOP) --pc; */ + elseinit = pc; + } + else + { + *(yypvt[-1].pByte) = JMP; + *((Word *)(yypvt[-1].pByte+1)) = pc - elseinit; + } + *(yypvt[-3].pByte) = IFFJMP; + *((Word *)(yypvt[-3].pByte+1)) = elseinit - (yypvt[-3].pByte + sizeof(Word)+1); + } + } break; +case 26: +# line 299 "lua.stx" +{yyval.vInt = nlocalvar;} break; +case 27: +# line 299 "lua.stx" +{ntemp = 0;} break; +case 28: +# line 300 "lua.stx" +{ + if (nlocalvar != yypvt[-3].vInt) + { + nlocalvar = yypvt[-3].vInt; + lua_codeadjust (0); + } + } break; +case 30: +# line 310 "lua.stx" +{ if (lua_debug){align(Word);code_byte(SETLINE);code_word(lua_linenumber);}} break; +case 31: +# line 312 "lua.stx" +{ + if (lua_debug) code_byte(RESET); + code_byte(RETCODE); code_byte(nlocalvar); + } break; +case 32: +# line 319 "lua.stx" +{ + align(Word); + yyval.pByte = pc; + code_byte(0); /* open space */ + code_word (0); + } break; +case 33: +# line 326 "lua.stx" +{ if (yypvt[-0].vInt == 0) {lua_codeadjust (ntemp+1); incr_ntemp();}} break; +case 34: +# line 329 "lua.stx" +{ yyval.vInt = yypvt[-1].vInt; } break; +case 35: +# line 330 "lua.stx" +{ code_byte(EQOP); yyval.vInt = 1; ntemp--;} break; +case 36: +# line 331 "lua.stx" +{ code_byte(LTOP); yyval.vInt = 1; ntemp--;} break; +case 37: +# line 332 "lua.stx" +{ code_byte(LEOP); code_byte(NOTOP); yyval.vInt = 1; ntemp--;} break; +case 38: +# line 333 "lua.stx" +{ code_byte(EQOP); code_byte(NOTOP); yyval.vInt = 1; ntemp--;} break; +case 39: +# line 334 "lua.stx" +{ code_byte(LEOP); yyval.vInt = 1; ntemp--;} break; +case 40: +# line 335 "lua.stx" +{ code_byte(LTOP); code_byte(NOTOP); yyval.vInt = 1; ntemp--;} break; +case 41: +# line 336 "lua.stx" +{ code_byte(ADDOP); yyval.vInt = 1; ntemp--;} break; +case 42: +# line 337 "lua.stx" +{ code_byte(SUBOP); yyval.vInt = 1; ntemp--;} break; +case 43: +# line 338 "lua.stx" +{ code_byte(MULTOP); yyval.vInt = 1; ntemp--;} break; +case 44: +# line 339 "lua.stx" +{ code_byte(DIVOP); yyval.vInt = 1; ntemp--;} break; +case 45: +# line 340 "lua.stx" +{ code_byte(CONCOP); yyval.vInt = 1; ntemp--;} break; +case 46: +# line 341 "lua.stx" +{ yyval.vInt = 1; } break; +case 47: +# line 342 "lua.stx" +{ code_byte(MINUSOP); yyval.vInt = 1;} break; +case 48: +# line 344 "lua.stx" +{ + code_byte(PUSHBYTE); + yyval.pByte = pc; code_byte(0); + incr_ntemp(); + code_byte(CREATEARRAY); + } break; +case 49: +# line 351 "lua.stx" +{ + *(yypvt[-2].pByte) = yypvt[-0].vInt; + if (yypvt[-1].vLong < 0) /* there is no function to be called */ + { + yyval.vInt = 1; + } + else + { + lua_pushvar (yypvt[-1].vLong+1); + code_byte(PUSHMARK); + incr_ntemp(); + code_byte(PUSHOBJECT); + incr_ntemp(); + code_byte(CALLFUNC); + ntemp -= 4; + yyval.vInt = 0; + if (lua_debug) + { + align(Word); code_byte(SETLINE); code_word(lua_linenumber); + } + } + } break; +case 50: +# line 374 "lua.stx" +{ + code_byte(CREATEARRAY); + yyval.vInt = 1; + } break; +case 51: +# line 378 "lua.stx" +{ lua_pushvar (yypvt[-0].vLong); yyval.vInt = 1;} break; +case 52: +# line 379 "lua.stx" +{ code_number(yypvt[-0].vFloat); yyval.vInt = 1; } break; +case 53: +# line 381 "lua.stx" +{ + align(Word); + code_byte(PUSHSTRING); + code_word(yypvt[-0].vWord); + yyval.vInt = 1; + incr_ntemp(); + } break; +case 54: +# line 388 "lua.stx" +{code_byte(PUSHNIL); yyval.vInt = 1; incr_ntemp();} break; +case 55: +# line 390 "lua.stx" +{ + yyval.vInt = 0; + if (lua_debug) + { + align(Word); code_byte(SETLINE); code_word(lua_linenumber); + } + } break; +case 56: +# line 397 "lua.stx" +{ code_byte(NOTOP); yyval.vInt = 1;} break; +case 57: +# line 398 "lua.stx" +{code_byte(POP); ntemp--;} break; +case 58: +# line 399 "lua.stx" +{ + *(yypvt[-2].pByte) = ONFJMP; + *((Word *)(yypvt[-2].pByte+1)) = pc - (yypvt[-2].pByte + sizeof(Word)+1); + yyval.vInt = 1; + } break; +case 59: +# line 404 "lua.stx" +{code_byte(POP); ntemp--;} break; +case 60: +# line 405 "lua.stx" +{ + *(yypvt[-2].pByte) = ONTJMP; + *((Word *)(yypvt[-2].pByte+1)) = pc - (yypvt[-2].pByte + sizeof(Word)+1); + yyval.vInt = 1; + } break; +case 61: +# line 412 "lua.stx" +{ code_byte(PUSHNIL); incr_ntemp();} break; +case 63: +# line 416 "lua.stx" +{code_byte(PUSHMARK); yyval.vInt = ntemp; incr_ntemp();} break; +case 64: +# line 417 "lua.stx" +{ code_byte(CALLFUNC); ntemp = yypvt[-3].vInt-1;} break; +case 65: +# line 419 "lua.stx" +{lua_pushvar (yypvt[-0].vLong); } break; +case 66: +# line 422 "lua.stx" +{ yyval.vInt = 1; } break; +case 67: +# line 423 "lua.stx" +{ yyval.vInt = yypvt[-0].vInt; } break; +case 68: +# line 426 "lua.stx" +{ yyval.vInt = yypvt[-0].vInt; } break; +case 69: +# line 427 "lua.stx" +{if (!yypvt[-1].vInt){lua_codeadjust (ntemp+1); incr_ntemp();}} break; +case 70: +# line 428 "lua.stx" +{yyval.vInt = yypvt[-0].vInt;} break; +case 73: +# line 435 "lua.stx" +{localvar[nlocalvar]=yypvt[-0].vWord; incr_nlocalvar();} break; +case 74: +# line 436 "lua.stx" +{localvar[nlocalvar]=yypvt[-0].vWord; incr_nlocalvar();} break; +case 75: +# line 439 "lua.stx" +{yyval.vLong=-1;} break; +case 76: +# line 440 "lua.stx" +{yyval.vLong=yypvt[-0].vWord;} break; +case 77: +# line 443 "lua.stx" +{ yyval.vInt = yypvt[-1].vInt; } break; +case 78: +# line 444 "lua.stx" +{ yyval.vInt = yypvt[-1].vInt; } break; +case 79: +# line 447 "lua.stx" +{ yyval.vInt = 0; } break; +case 80: +# line 448 "lua.stx" +{ yyval.vInt = yypvt[-0].vInt; } break; +case 81: +# line 451 "lua.stx" +{yyval.vInt=1;} break; +case 82: +# line 452 "lua.stx" +{yyval.vInt=yypvt[-2].vInt+1;} break; +case 83: +# line 456 "lua.stx" +{ + align(Word); + code_byte(PUSHSTRING); + code_word(lua_findconstant (s_name(yypvt[-0].vWord))); + incr_ntemp(); + } break; +case 84: +# line 463 "lua.stx" +{ + code_byte(STOREFIELD); + ntemp-=2; + } break; +case 85: +# line 469 "lua.stx" +{ yyval.vInt = 0; } break; +case 86: +# line 470 "lua.stx" +{ yyval.vInt = yypvt[-0].vInt; } break; +case 87: +# line 473 "lua.stx" +{ code_number(1); } break; +case 88: +# line 473 "lua.stx" +{yyval.vInt=1;} break; +case 89: +# line 474 "lua.stx" +{ code_number(yypvt[-1].vInt+1); } break; +case 90: +# line 475 "lua.stx" +{yyval.vInt=yypvt[-3].vInt+1;} break; +case 91: +# line 479 "lua.stx" +{ + code_byte(STOREFIELD); + ntemp-=2; + } break; +case 92: +# line 486 "lua.stx" +{ + nvarbuffer = 0; + varbuffer[nvarbuffer] = yypvt[-0].vLong; incr_nvarbuffer(); + yyval.vInt = (yypvt[-0].vLong == 0) ? 1 : 0; + } break; +case 93: +# line 492 "lua.stx" +{ + varbuffer[nvarbuffer] = yypvt[-0].vLong; incr_nvarbuffer(); + yyval.vInt = (yypvt[-0].vLong == 0) ? yypvt[-2].vInt + 1 : yypvt[-2].vInt; + } break; +case 94: +# line 499 "lua.stx" +{ + int local = lua_localname (yypvt[-0].vWord); + if (local == -1) /* global var */ + yyval.vLong = yypvt[-0].vWord + 1; /* return positive value */ + else + yyval.vLong = -(local+1); /* return negative value */ + } break; +case 95: +# line 507 "lua.stx" +{lua_pushvar (yypvt[-0].vLong);} break; +case 96: +# line 508 "lua.stx" +{ + yyval.vLong = 0; /* indexed variable */ + } break; +case 97: +# line 511 "lua.stx" +{lua_pushvar (yypvt[-0].vLong);} break; +case 98: +# line 512 "lua.stx" +{ + align(Word); + code_byte(PUSHSTRING); + code_word(lua_findconstant (s_name(yypvt[-0].vWord))); incr_ntemp(); + yyval.vLong = 0; /* indexed variable */ + } break; +case 99: +# line 520 "lua.stx" +{localvar[nlocalvar]=yypvt[-1].vWord; incr_nlocalvar();} break; +case 100: +# line 521 "lua.stx" +{localvar[nlocalvar]=yypvt[-1].vWord; incr_nlocalvar();} break; +case 101: +# line 524 "lua.stx" +{ code_byte(PUSHNIL); } break; +case 102: +# line 525 "lua.stx" +{ntemp = 0;} break; +case 104: +# line 528 "lua.stx" +{lua_debug = yypvt[-0].vInt;} break; + } + goto yystack; /* reset registers in driver code */ +} diff --git a/y_tab.h b/y_tab.h new file mode 100644 index 0000000000..b973d540c5 --- /dev/null +++ b/y_tab.h @@ -0,0 +1,35 @@ + +typedef union +{ + int vInt; + long vLong; + float vFloat; + Word vWord; + Byte *pByte; +} YYSTYPE; +extern YYSTYPE yylval; +# define NIL 257 +# define IF 258 +# define THEN 259 +# define ELSE 260 +# define ELSEIF 261 +# define WHILE 262 +# define DO 263 +# define REPEAT 264 +# define UNTIL 265 +# define END 266 +# define RETURN 267 +# define LOCAL 268 +# define NUMBER 269 +# define FUNCTION 270 +# define NAME 271 +# define STRING 272 +# define DEBUG 273 +# define NOT 274 +# define AND 275 +# define OR 276 +# define NE 277 +# define LE 278 +# define GE 279 +# define CONC 280 +# define UNARY 281 From 944fc7d7d95575f2b8023c1f3d4ac19e1369fc76 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 8 Jul 1994 12:00:00 +0000 Subject: [PATCH 02/97] Lua 1.1 --- Makefile | 34 +- README | 57 +- clients/lib/Makefile | 23 + iolib.c => clients/lib/iolib.c | 122 ++- mathlib.c => clients/lib/mathlib.c | 23 +- clients/lib/mathlib.h | 13 + strlib.c => clients/lib/strlib.c | 28 +- clients/lib/strlib.h | 13 + clients/lua/Makefile | 17 + clients/lua/README | 5 + clients/lua/lua.c | 28 + doc/lua.dvi | Bin 0 -> 40392 bytes doc/lua.ps | Bin 0 -> 131471 bytes doc/manual.dvi | Bin 0 -> 48832 bytes doc/manual.ps | Bin 0 -> 156347 bytes domake | 6 + fixed/iolib.c | 402 --------- fixed/lex_yy.c | 923 --------------------- fixed/lua.c | 55 -- floatingpoint.h | 1 - globals.lua | 5 - lua.h => include/lua.h | 2 +- lualib.h => include/lualib.h | 5 +- include/mm.h | 0 lex_yy.c | 923 --------------------- lua.c | 54 -- src/Makefile | 24 + hash.c => src/hash.c | 146 +++- hash.h => src/hash.h | 11 +- inout.c => src/inout.c | 33 +- inout.h => src/inout.h | 7 +- src/lex.c | 238 ++++++ opcode.c => src/opcode.c | 230 ++++-- opcode.h => src/opcode.h | 36 +- table.c => src/table.c | 270 +++--- src/table.h | 42 + y_tab.c => src/y.tab.c | 1242 ++++++++++++++++------------ src/y.tab.h | 37 + src/yacc/Makefile | 27 + src/yacc/exscript | 3 + src/yacc/lua.lex | 85 ++ src/yacc/lua.stx | 953 +++++++++++++++++++++ table.h | 39 - test.lua | 15 - array.lua => test/array.lua | 0 test/dump | 37 + test/loop.lua | 6 + save.lua => test/save.lua | 1 - sort.lua => test/sort.lua | 12 +- test/sort/q.lua | 51 ++ test/sort/sort.lua | 51 ++ test/split.lua | 18 + test/teste.lua | 22 + test/type.lua | 37 + type.lua | 35 - y_tab.h | 35 - 56 files changed, 3078 insertions(+), 3404 deletions(-) create mode 100644 clients/lib/Makefile rename iolib.c => clients/lib/iolib.c (77%) rename mathlib.c => clients/lib/mathlib.c (92%) create mode 100644 clients/lib/mathlib.h rename strlib.c => clients/lib/strlib.c (83%) create mode 100644 clients/lib/strlib.h create mode 100644 clients/lua/Makefile create mode 100644 clients/lua/README create mode 100644 clients/lua/lua.c create mode 100644 doc/lua.dvi create mode 100644 doc/lua.ps create mode 100644 doc/manual.dvi create mode 100644 doc/manual.ps create mode 100755 domake delete mode 100644 fixed/iolib.c delete mode 100644 fixed/lex_yy.c delete mode 100644 fixed/lua.c delete mode 100644 floatingpoint.h delete mode 100644 globals.lua rename lua.h => include/lua.h (97%) rename lualib.h => include/lualib.h (66%) create mode 100644 include/mm.h delete mode 100644 lex_yy.c delete mode 100644 lua.c create mode 100644 src/Makefile rename hash.c => src/hash.c (69%) rename hash.h => src/hash.h (65%) rename inout.c => src/inout.c (90%) rename inout.h => src/inout.h (79%) create mode 100644 src/lex.c rename opcode.c => src/opcode.c (81%) rename opcode.h => src/opcode.h (76%) rename table.c => src/table.c (57%) create mode 100644 src/table.h rename y_tab.c => src/y.tab.c (57%) create mode 100644 src/y.tab.h create mode 100644 src/yacc/Makefile create mode 100644 src/yacc/exscript create mode 100644 src/yacc/lua.lex create mode 100644 src/yacc/lua.stx delete mode 100644 table.h delete mode 100644 test.lua rename array.lua => test/array.lua (100%) create mode 100644 test/dump create mode 100644 test/loop.lua rename save.lua => test/save.lua (99%) rename sort.lua => test/sort.lua (84%) create mode 100644 test/sort/q.lua create mode 100644 test/sort/sort.lua create mode 100644 test/split.lua create mode 100644 test/teste.lua create mode 100644 test/type.lua delete mode 100644 type.lua delete mode 100644 y_tab.h diff --git a/Makefile b/Makefile index 8ed18bb5dd..10640e0d02 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,11 @@ -OBJS= hash.o inout.o lex_yy.o opcode.o table.o y_tab.o lua.o iolib.o mathlib.o strlib.o +# makefile for lua hierarchy -CFLAGS= -O2 -I. - -T= lua - -all: $T - -$T: $(OBJS) - $(CC) -o $@ $(OBJS) -lm - -A=-------------------------------------------------------------------------- -test: $T - @echo "$A" - ./$T sort.lua main - @echo "$A" - ./$T globals.lua | sort | column - @echo "$A" - ./$T array.lua - @echo "$A" - ./$T save.lua - @echo "$A" - ./$T test.lua retorno_multiplo norma +all: + (cd src; make) + (cd clients/lib; make) + (cd clients/lua; make) clean: - rm -f $T $(OBJS) core core.* - -diff: - diff . fixed | grep -v ^Only + (cd src; make clean) + (cd clients/lib; make clean) + (cd clients/lua; make clean) diff --git a/README b/README index 29ad01d58f..3b8ad6aab9 100644 --- a/README +++ b/README @@ -1,22 +1,47 @@ -This is Lua 1.0. It was never publicly released. This code is a snapshot of -the status of Lua on 28 Jul 1993. It is distributed for historical curiosity -to celebrate 10 years of Lua and is hereby placed in the public domain. +* What is Lua? + Lua is a simple, yet powerful, language for extending applications. + Lua has been developed by TeCGraf, the Computer Graphics Technology Group + of PUC-Rio, the Pontifical Catholic University of Rio de Janeiro, Brazil. + Dozens of industrial products developed by TeCGraf use Lua. -There is no documentation, except the test programs. The manual for Lua 1.1 -probably works for this version as well. +* Some features of Lua + Lua has a simple, pascal-like, syntax. + Variables need no declaration, but Lua has user-controlled type constructors. + Lua has powerful data description constructs (e.g., associative arrays). + Functions can receive a variable number of arguments and can return multiple + values. + Lua programs are compiled into bytecodes, which are then interpreted to + simulate a virtual machine. + Lua is written in ANSI C and is completely portable. -The source files for the lexer and parser have been lost: all that is left is -the output of lex and yacc. A grammar can be found inside y_tab.c in yyreds. +* Coming soon + Object-oriented extensions. + Lazy evaluation. -The code compiles and runs in RedHat 5.2 with gcc 2.7.2.3. It may not run in -newer systems, because it assumes that stdin and stdout are constants, though -ANSI C does not promise they are. If make fails, try using the fixed modules -provided in the "fixed" directory. To see the differences (which are really -quite minor), do "make diff". +* Installing + To make, simply type domake. + If make succeeds, you get an interpreter in ./bin/lua. + The libraries are in ./lib. The include files are in ./include. + You don't need the other directories for development. + There is documentation in ./doc and tests in ./test. + The documentation includes a reference manual and an article on the + design and implementation of Lua. + This distribution is biased towards SunOS 4 with gcc but it is simple to + change the Makefiles for other systems. -To see Lua 1.0 in action, do "make test". (The last test raises an error on -purpose.) +* Legal matters + Lua is not in the public domain; TeCGraf keeps its copyright. + Nevertheless, Lua is freely available for academic purposes by anonymous ftp + at ftp.icad.puc-rio.br:/pub/lua/lua-1.1.tar.Z. + For commercial purposes, please contact us. -Enjoy! +* Contacting the authors + Send your comments, bug reports and anything else to lhf@icad.puc-rio.br. + Please send me email if you download Lua so that we can know how far it goes. --- The Lua team, lua@tecgraf.puc-rio.br +-- +Luiz Henrique de Figueiredo email: lhf@icad.puc-rio.br +TeCGraf-Grupo de Tecnologia em Computacao Grafica, ITS, PUC-Rio +Rua Marques de Sao Vicente 225 voice: +55 21 529-9424 +22453-900 Rio de Janeiro, RJ, Brasil fax: +55 21 511-5645 +-- diff --git a/clients/lib/Makefile b/clients/lib/Makefile new file mode 100644 index 0000000000..4110a62f84 --- /dev/null +++ b/clients/lib/Makefile @@ -0,0 +1,23 @@ +# makefile for lualib + +INC= $(LUA)/include +LIB= $(LUA)/lib + +CC= gcc +CFLAGS= -Wall -O2 -I$(INC) $(DEFS) + +OBJS= iolib.o mathlib.o strlib.o +SLIB= $(LIB)/liblualib.a +DLIB= $(LIB)/liblualib.so.1.1 + +libs: $(SLIB) $(DLIB) + +$(SLIB): $(OBJS) + ar ruvl $@ $(OBJS) + ranlib $(SLIB) + +$(DLIB): $(OBJS) + ld -o $@ $(OBJS) + +clean: + rm -f $(OBJS) $(SLIB) $(DLIB) diff --git a/iolib.c b/clients/lib/iolib.c similarity index 77% rename from iolib.c rename to clients/lib/iolib.c index 174dd5018e..b972124b44 100644 --- a/iolib.c +++ b/clients/lib/iolib.c @@ -1,20 +1,21 @@ /* ** iolib.c ** Input/output library to LUA -** -** Waldemar Celes Filho -** TeCGraf - PUC-Rio -** 19 May 93 */ +char *rcs_iolib="$Id: iolib.c,v 1.4 1994/04/25 20:11:23 celes Exp $"; + #include #include #include #include +#include #ifdef __GNUC__ #include #endif +#include "mm.h" + #include "lua.h" static FILE *in=stdin, *out=stdout; @@ -109,6 +110,58 @@ static void io_writeto (void) } +/* +** Open a file to write appended. +** LUA interface: +** status = appendto (filename) +** where: +** status = 2 -> success (already exist) +** status = 1 -> success (new file) +** status = 0 -> error +*/ +static void io_appendto (void) +{ + lua_Object o = lua_getparam (1); + if (o == NULL) /* restore standart output */ + { + if (out != stdout) + { + fclose (out); + out = stdout; + } + lua_pushnumber (1); + } + else + { + if (!lua_isstring (o)) + { + lua_error ("incorrect argument to function 'appendto`"); + lua_pushnumber (0); + } + else + { + int r; + FILE *fp; + struct stat st; + if (stat(lua_getstring(o), &st) == -1) r = 1; + else r = 2; + fp = fopen (lua_getstring(o),"a"); + if (fp == NULL) + { + lua_pushnumber (0); + } + else + { + if (out != stdout) fclose (out); + out = fp; + lua_pushnumber (r); + } + } + } +} + + + /* ** Read a variable. On error put nil on stack. ** LUA interface: @@ -126,7 +179,7 @@ static void io_writeto (void) static void io_read (void) { lua_Object o = lua_getparam (1); - if (o == NULL) /* free format */ + if (o == NULL || !lua_isstring(o)) /* free format */ { int c; char s[256]; @@ -134,19 +187,31 @@ static void io_read (void) ; if (c == '\"') { - if (fscanf (in, "%[^\"]\"", s) != 1) + int c, n=0; + while((c = fgetc(in)) != '\"') { - lua_pushnil (); - return; + if (c == EOF) + { + lua_pushnil (); + return; + } + s[n++] = c; } + s[n] = 0; } else if (c == '\'') { - if (fscanf (in, "%[^\']\'", s) != 1) + int c, n=0; + while((c = fgetc(in)) != '\'') { - lua_pushnil (); - return; + if (c == EOF) + { + lua_pushnil (); + return; + } + s[n++] = c; } + s[n] = 0; } else { @@ -183,7 +248,16 @@ static void io_read (void) char f[80]; char s[256]; sprintf (f, "%%%ds", m); - fscanf (in, f, s); + if (fgets (s, m, in) == NULL) + { + lua_pushnil(); + return; + } + else + { + if (s[strlen(s)-1] == '\n') + s[strlen(s)-1] = 0; + } switch (tolower(t)) { case 'i': @@ -212,22 +286,25 @@ static void io_read (void) case 'i': { long int l; - fscanf (in, "%ld", &l); - lua_pushnumber(l); + if (fscanf (in, "%ld", &l) == EOF) + lua_pushnil(); + else lua_pushnumber(l); } break; case 'f': case 'g': case 'e': { float f; - fscanf (in, "%f", &f); - lua_pushnumber(f); + if (fscanf (in, "%f", &f) == EOF) + lua_pushnil(); + else lua_pushnumber(f); } break; default: { char s[256]; - fscanf (in, "%s", s); - lua_pushstring(s); + if (fscanf (in, "%s", s) == EOF) + lua_pushnil(); + else lua_pushstring(s); } break; } @@ -346,8 +423,8 @@ static void io_write (void) } /* -** Execute a executable program using "sustem". -** On error put 0 on stack, otherwise put 1. +** Execute a executable program using "system". +** Return the result of execution. */ void io_execute (void) { @@ -359,8 +436,8 @@ void io_execute (void) } else { - system(lua_getstring(o)); - lua_pushnumber (1); + int res = system(lua_getstring(o)); + lua_pushnumber (res); } return; } @@ -394,6 +471,7 @@ void iolib_open (void) { lua_register ("readfrom", io_readfrom); lua_register ("writeto", io_writeto); + lua_register ("appendto", io_appendto); lua_register ("read", io_read); lua_register ("write", io_write); lua_register ("execute", io_execute); diff --git a/mathlib.c b/clients/lib/mathlib.c similarity index 92% rename from mathlib.c rename to clients/lib/mathlib.c index b07c8c4754..c84af8cb81 100644 --- a/mathlib.c +++ b/clients/lib/mathlib.c @@ -1,17 +1,18 @@ /* ** mathlib.c -** Mathematica library to LUA -** -** Waldemar Celes Filho -** TeCGraf - PUC-Rio -** 19 May 93 +** Mathematics library to LUA */ +char *rcs_mathlib="$Id: mathlib.c,v 1.1 1993/12/17 18:41:19 celes Exp $"; + #include /* NULL */ #include #include "lua.h" +#define TODEGREE(a) ((a)*180.0/3.14159) +#define TORAD(a) ((a)*3.14159/180.0) + static void math_abs (void) { double d; @@ -35,7 +36,7 @@ static void math_sin (void) if (!lua_isnumber(o)) { lua_error ("incorrect arguments to function `sin'"); return; } d = lua_getnumber(o); - lua_pushnumber (sin(d)); + lua_pushnumber (sin(TORAD(d))); } @@ -49,7 +50,7 @@ static void math_cos (void) if (!lua_isnumber(o)) { lua_error ("incorrect arguments to function `cos'"); return; } d = lua_getnumber(o); - lua_pushnumber (cos(d)); + lua_pushnumber (cos(TORAD(d))); } @@ -63,7 +64,7 @@ static void math_tan (void) if (!lua_isnumber(o)) { lua_error ("incorrect arguments to function `tan'"); return; } d = lua_getnumber(o); - lua_pushnumber (tan(d)); + lua_pushnumber (tan(TORAD(d))); } @@ -76,7 +77,7 @@ static void math_asin (void) if (!lua_isnumber(o)) { lua_error ("incorrect arguments to function `asin'"); return; } d = lua_getnumber(o); - lua_pushnumber (asin(d)); + lua_pushnumber (TODEGREE(asin(d))); } @@ -89,7 +90,7 @@ static void math_acos (void) if (!lua_isnumber(o)) { lua_error ("incorrect arguments to function `acos'"); return; } d = lua_getnumber(o); - lua_pushnumber (acos(d)); + lua_pushnumber (TODEGREE(acos(d))); } @@ -103,7 +104,7 @@ static void math_atan (void) if (!lua_isnumber(o)) { lua_error ("incorrect arguments to function `atan'"); return; } d = lua_getnumber(o); - lua_pushnumber (atan(d)); + lua_pushnumber (TODEGREE(atan(d))); } diff --git a/clients/lib/mathlib.h b/clients/lib/mathlib.h new file mode 100644 index 0000000000..bdf2b4b82a --- /dev/null +++ b/clients/lib/mathlib.h @@ -0,0 +1,13 @@ +/* +** Math library to LUA +** TeCGraf - PUC-Rio +** $Id: mathlib.h,v 1.1 1993/12/17 18:41:19 celes Exp $ +*/ + + +#ifndef strlib_h + +void mathlib_open (void); + +#endif + diff --git a/strlib.c b/clients/lib/strlib.c similarity index 83% rename from strlib.c rename to clients/lib/strlib.c index efd01e9b23..037b84beaf 100644 --- a/strlib.c +++ b/clients/lib/strlib.c @@ -1,16 +1,16 @@ /* ** strlib.c ** String library to LUA -** -** Waldemar Celes Filho -** TeCGraf - PUC-Rio -** 19 May 93 */ +char *rcs_strlib="$Id: strlib.c,v 1.2 1994/03/28 15:14:02 celes Exp $"; + #include #include #include +#include "mm.h" + #include "lua.h" @@ -21,16 +21,18 @@ */ static void str_find (void) { - int n; - char *s1, *s2; + char *s1, *s2, *f; lua_Object o1 = lua_getparam (1); lua_Object o2 = lua_getparam (2); if (!lua_isstring(o1) || !lua_isstring(o2)) { lua_error ("incorrect arguments to function `strfind'"); return; } s1 = lua_getstring(o1); s2 = lua_getstring(o2); - n = strstr(s1,s2) - s1 + 1; - lua_pushnumber (n); + f = strstr(s1,s2); + if (f != NULL) + lua_pushnumber (f-s1+1); + else + lua_pushnil(); } /* @@ -59,13 +61,15 @@ static void str_sub (void) lua_Object o1 = lua_getparam (1); lua_Object o2 = lua_getparam (2); lua_Object o3 = lua_getparam (3); - if (!lua_isstring(o1) || !lua_isnumber(o2) || !lua_isnumber(o3)) + if (!lua_isstring(o1) || !lua_isnumber(o2)) { lua_error ("incorrect arguments to function `strsub'"); return; } - s = strdup (lua_getstring(o1)); + if (o3 != NULL && !lua_isnumber(o3)) + { lua_error ("incorrect third argument to function `strsub'"); return; } + s = lua_copystring(o1); start = lua_getnumber (o2); - end = lua_getnumber (o3); + end = o3 == NULL ? strlen(s) : lua_getnumber (o3); if (end < start || start < 1 || end > strlen(s)) - lua_pushstring (""); + lua_pushstring(""); else { s[end] = 0; diff --git a/clients/lib/strlib.h b/clients/lib/strlib.h new file mode 100644 index 0000000000..daa1f60365 --- /dev/null +++ b/clients/lib/strlib.h @@ -0,0 +1,13 @@ +/* +** String library to LUA +** TeCGraf - PUC-Rio +** $Id: strlib.h,v 1.1 1993/12/17 18:41:19 celes Exp $ +*/ + + +#ifndef strlib_h + +void strlib_open (void); + +#endif + diff --git a/clients/lua/Makefile b/clients/lua/Makefile new file mode 100644 index 0000000000..7bb74208d1 --- /dev/null +++ b/clients/lua/Makefile @@ -0,0 +1,17 @@ +# makefile for lua interpreter + +BIN= $(LUA)/bin +INC= $(LUA)/include +LIB= $(LUA)/lib + +CC= gcc +CFLAGS= -g -Wall -O2 -I$(INC) + +OBJS= lua.o +T=$(BIN)/lua + +$T: $(OBJS) + $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib -lm + +clean: + rm -f $T $(OBJS) diff --git a/clients/lua/README b/clients/lua/README new file mode 100644 index 0000000000..c529892a18 --- /dev/null +++ b/clients/lua/README @@ -0,0 +1,5 @@ +This client is a simple lua interpreter. +It either loads and executes the files named on the command line or reads +and executes lines from stdin. +Note that, in the second case, each line must contain a complete statement. +For instance, functions cannot span several lines. diff --git a/clients/lua/lua.c b/clients/lua/lua.c new file mode 100644 index 0000000000..c4b83cee90 --- /dev/null +++ b/clients/lua/lua.c @@ -0,0 +1,28 @@ +/* +** lua.c +** Linguagem para Usuarios de Aplicacao +*/ + +char *rcs_lua="$Id: lua.c,v 1.1 1993/12/17 18:41:19 celes Exp $"; + +#include + +#include "lua.h" +#include "lualib.h" + +void main (int argc, char *argv[]) +{ + int i; + iolib_open (); + strlib_open (); + mathlib_open (); + if (argc < 2) + { + char buffer[2048]; + while (gets(buffer) != 0) + lua_dostring(buffer); + } + else + for (i=1; iw}UtceYjz`DAt&LYc>RN02zO`PFODj$@veElzyI?*=bYUH zgim9WnKRGjfBpS0&vSm-f6{B;di%52_wirxW6RDStxr$aYiI9@UwU@E-I{5)&K|k& z!ZpJy&l_GnvTkI}%C&Fg!ISj#Z~N~U{~dnXUC%ps_{V*Hhu+=)lqViL`0ii-^gmBJ z*g1Ck=+V_nzV`X&^gU_wNA1tarRipKvv$wd7vZ@RIO#QR%utz4;1Ceh4HwNkR5H4lC0 z=}$hxP5i<)4gKsXeUE4P`g2NYy3{OPROWb(N-Op|}qiSWkS(=(1>|NdY%~y9v)p9%? zHImV|8aElDI#oY(_(^?zZuaNSe01gI>FnBeb!6o|yXKC);KT9g=0-GeU~{8A^OntL z)w_k=yII4oURSrKM;v*|KYF zFxjztbZBR#e(3#6{j570@BGAf&g}eh^Rwe}#SP5z_2|xalw27#Zfy6ix38Pp_Sh>s zZrrOXrMT8>#mTBw=MC~dYtCCebm7XC34`mo%cC09sWZyugUQB5)T~qwy~l0ytOp)? z(f<54Tdk3mM-Eh{CI%ZKVXHn^5`A8AF&run&$LTJjY@rZym9F8ip$ozG0uC=w|NB3fjB7DJ8=7f1j5JN?&SHn+n&{k^6?X=ExkaPYT1JB@^aON_N-TcS zBYxVPR!c+b&QFi)O3dkU3yX1ceQ?(cfgU5zR~?YSm;qZbeIxyx~K) znwUMfGj6u0>n2X~n3Sn3T(hPNL!5E{^{H=7ma zU)MSLM}IHfZ6>ukYO^od*Nbo&Nh|PkI@%+3>h>S`QQ*DVm~vdIG%*=0w}nlLONbBt zy;Yfx*LV7V`e`?4RBhI?A(MTL3f^csDxoM&+cEDmt)}Nz3*R>Rhn{M&H=;)3y_FWL zm`w(D&a%D)OtW$Yn)AW+MsBDY4|WUHCAB(s97*fVVofC7m^emUK+vd)!nEMcke_vL z=h%&RM~w>nnC%vyzq=GQ8nbdYl}1uWHTKm~skbf4xZ1MC*I?S4##)fekXb_12a`2D z%_GBp8dlmwFuwUe*-xTIjNxoYRqVKTN}a-QzA@g0qEU$rPnqSfw3-PU!^TIAR;AQt zV@Y!sE=BthnN!~`6*y?lLMtxv9J;2ZO!6 zjoW$q=A{jo5bt;MRGco`DQR9vG{)Z;B3Vj#_xs<^jL;(YhQnD6w0d z`&R^W6@q!{C9Q!?d7qgG6|iK?L9$O4!a2-xyi{`lhnyzydEA@wWtyXZ-i~`(iwwgUW1H5dMtFygvcpjDG8{1JU?m>|r zWB2kZF}$KvJonpIPk|LpTEc|d*JK1H`O>-gPH(|7n}*QJBqbOVBx_$HIPs-(VN7d^ z-3EyO!+iHE`w#}9w^D@#^F1abazFN9!%xYo8uh5ea8q-Ia&cc0H4!oq!33{~Otknr zx+!o0gL?G|=v^Ag5juE=ktaZ z>t#dcFWrul4jWqPA8CAyrG&9^8hn-Q%+Xd>!OtcP)$M=iT`b&Lk9v*uY+Hj}Xv93m z^!>*k-e#nbvULRegq;ZVTUzy6bhAwr@!G_;lQauOdX`{?JxP8paGE`~SOjW${Q zLx-Pr>Z=bbrrUUQ>2sG2zB7-}o3kS;|N04sI*&Vj^q#x~b&G#~RXY4zDzBJd*E!{R zUyw31Nl!o;>-Lwl2`+6E`T=dzio0-lD?;QdB@dLepL?3xV3!;{0<`@g+n)Aq6D27j6E z2s@joOb$0^oAbcg-MgAU-^<;`UGmaX>biuH#+bOt8P=o%=PqN;B3to}vhJNcw#B45-dMgdSjKT97Vq1*n$ z02mUI28W2W?5MgnMS(*U$ zWP>ih;^n}jW5ZWXHH|L5se==Cyaxk)avrN|El%E{krHCX2M;P=*3;;A; z@7>sj$u8ZI2-=0z7*hrCBZis-aYn;xF7s( z_xQG3UUMZ#ua3!!8zD$R?z_eJpJRjiClla%DyDqKg5*7uGCE1%8l2tIk`o*khkJjM z-=ZiGVnR!0vD(XrTT_hJ21{)&D?edM?jj=%Bpr|{E*{5a=|i>wj!SMUX=s`z3!7nI z1}&OOGt71i`!5)0(pd>YkFChAOjRZYw5u`1s3y@kuF(fV;Ntshm&(mDg`x?T{p$aM zBwCZOpP}x+IGnq%B^c6k6wrI{DFnz&NQk^>olX!PCRIe1dD$SO*dl@`OJXJi8+L42 z(J34}*)|(KXZ3z6Dd=3`fv%W`Ql0$7H}0B31>3B+*#G=?ty!0GAdav1LVY5Bwkpc@@Rkv99xDWW+I1(Z2V7yG{LMVwa*qRvs+$&)x_(85b zX|cL}NqvaWDw&;QFkJF<(ysYJi&Lb5#r z9@94o(g{dRP?Mvwc?lF=#OxN@Uob|4&eJ(lMGkHvXIa8pTv#DCEm#kd^NR0U#2tlc zq;HrmGpiL75}&blanRx=x0@2yX1%IxyS_Z3Vhm>~KpC@6|6P|LmUI1g-4IpxL360x z>{$qp(TI98Nqt6noSu2XI&~V0%uggB-Tnt}VOu>^%?r{X*&%8*CLK5dFN&$acMDr? zkX($nE7jHz2Fs5+uBt+h92)Stw+Ap|z!gY)WocV96=`vVlS->i-|Ll6LkY7+E}L}4 zmrnp4{q&dMk})ZNJSZ_+j2KyjSqcP+G*;#+2$r!nBG`IiLX0Aa&;^4nR-I7pq8y;y z8Zk$2pU59}3s9RYoOkt1)S6<&lV@G#lMrOD8ZdqRXN?Vo^R{D33F)0+lNPCh_ASjZ zG(nQ7rUVJ%QG>jMCes8cC|@vg=I{fg-4-LB%5nV5|C4nd?ezc4J49xQgrSsFN}JI1 z)Q9wWl~fU;?$B-xLnXtH=2_mvlDN{lxC|8h`Fq;6iD()gMImDVM=eI(A0puGHSp!v z-sBB5SfC6QoSCcU;@)YpJwa1^P|QzU{BFrDQ%&knP3l%vRhRs-ES~cO1}Js=x84wz zq=X}4j6Ge~Dg4Jy?86-2f)Yx}9!S`X6*`q&ddZ2YP(cr`-h}2u-VV-!@|3hJ{;yeA zdmsy-c!+;cJ(9v= z0Lf4^85;TFXSI55$a`0;4@m`A>D=XfA!hP@ud;ke@#P;@2~T*6oUj0*`~nDWan=L~ zmHh2C6IxgeCYQ~B->ZZttHS#=@cDo^#)U8Ddsy#GSYTF4(wSAdw*j+AL?4B`0z}?-mDE8&ZB0O5&Rz ziZ)vQ>5<(FY`XR#rzgS`wNL}We!#|V;m_WW9!1HuazD!gTtM0X=^o@T4;>d_)#E^8 zGT>%0K{G(amQx1>etF}@YGu5k3^+56Qc+x!A%93?o>BEltIZg-%i5n_qNK zYYJbHq$oK!2IkMnUn;%l4u8 zi1XAbmz8G1-q0stHtV8u;LT*kay3ltQ#Bz#2ucfk{`5H;I>j@{@+tRpfm}t#HR-6u3Gy9&#*z

lUJe^RjF%@5-d#!H1yxniqSeK7~O-gB2sdN(K+grv|B z;+$$cRIU$!yU1|$|LBe*jd+F#bf{gU`Cxu9IZ~MzLYQkqakUxqcl|$mnws*l`>`jB z49HyZP4~)d5OmAsyvEA0FP&jFw?;|gA|jLHcuuK%Sru{Y3+V~2Z{uotkO`M#we zRN@s#9(!^2FoQ}yd-LqW6S?I}|ApJ$4NS|bRHm$RIbg^9z}U5Nvly8azwdf`kv)2)-s7 zP6)yom`1Fn#O1t!xTLn1&Nm5g%d9l3o;FX{mW6bkMe`e~i1J6j8staPEk*FINw(5E zOfz3mGFh#Uqc$i|7`#WDTXEfH+wg*qF*|>^OwvQT6n`Ag1hb4RcMF9x{7`wKJKClU zgMDYd7W_a;xD~1%5k&{|*t{tqxF!O6?~p++qpHh-c#^}jZeiwoRzYbr@zhNc0@`h* zYDO7tWgCCce^BvwHVKb^-@;x^*aO7hwNruUVe@$8cZo~M%(G282y?7f-W z5OnuoB}(p_u6IZhmXVxJ-|g4T;|^c8bVH}`)Bi{%3N?V7vu0qWz6&fXn+l@ule^u* zt*cWPDtquLi|3~!14fR}3=%29uh7Q+j{Ok%ys42GiblP`_4I<4w+xk6j5yeSZ1^p^^} zX_AC$@oDNf#AZCodh`o=F-#+pXhQf^5XEW3(>}Zl`le_pol|Hzo3rpIB_Swh7miov zjLA|{x@j`XB?D3Vj~t$=q;|rmSe*6B{IO^y)0bMK{H#i{U>;Z_9X~xhLJl%*QhS1w zLy~Hyz!{vqQP26nU={^pisjF^Ag?@IBWEF9AUBr&vYaAf`pe$(_WTm4TGk1yS^-j# zkaCl)?-c)i#$qV1R~b{Y@4AKUZ(Go*#q8vk!gvTn{hPa#_jD+)u;WvR z6w)d&qHq(Q%V=w+U1AqtY8WC2@pw};#BSlQehstod&=#c;e6YOg9!I7CnRG^FqNee z0Anbufj?!L(d~PeqkL(?3_rG@CjVRG`qeJ3FFv-o{_Gb%a$G-8zX!>-Zs8}-lZ7&L zIWa4nk|zpmy7VA+kws55tZF8SV{gh!Xqy5)YzUJVO3V`gJeqiArVI{bF?>oy^ERmH z50A)QArhA4PdU*vy|prvygFzd{A2T^3DfLZ*tV@_Fvp>30iC{oliltx{yc%bXXs?q z7^g9mgx=#z)@6N<-0kl@&oD zVAKjyq~_52o6rE(d3)7CAzLU}F!HDMH;LK?V3f-aQHdz$@>+ zjeUCEYE^TBha?RxAK9Z$=3BiQl!+G&JnU?a1u z@))y@`*BO5MW^r0lYZ~brb$c%BJPF2afj`QAXFxB1W)%>S1C%j_|G@0Xz3SA2&V)> zXbC8#Vi6)nTqNdhxbwKjKa)JbKQHxIg!n;Vg4|hmG4=PGfiz}70 zXZ<)za^v{(lqnWo;~}e>M}8^Jbv4?Stl@LxfB(t?Qchj=EU;%MHp@5$}aBtmfF{ zd`3!QrQqJz=kk3X7f~f8rJb5OOTfs9q9mXcum!RG%Z_Zdzb^E^&?7=379t5DPD@=Px{JKE4>?~OT2@Rd?01Zh9mxcjam+vg{9Nx! zuFl3-;zY_g9E+oUNI7mal+-PJqN(LL^xyP(5t$nt%vaXwD<>*oGiTNpFxqT6fyUg~ zyK=b8ewX1cf~s1YrV4>;xA5)%$ZtGzH>8`FoEchjGf0v8x1bzqv`5FCTRZvbZ>BE8 zx;dxjD>Jz+L$S15xchD17gcDYF-PT2Kv_(noh0+(Z<-wv%CY!Ueblawsz&Q%Kvc2R zD{AV-0l$bk8pN{)tlTYp{3Kx)VebXmX6sq8EQzaorW98GKKWvvl=r^SMYst1wMNH4 zzh!xi%R)Ttfcc93w9#C0F2+q8;L$;=fr@eU@i?qBe1>yI9S~Q4@2JOL1gn zJ04Y+MIrex!*mO;Ta`PmCdlFY*Ia0lj-aLFr);_^fMd9*Kx6`&0Qy!)R2M_gv269- z;!`P0C#fmczaM!9=x|9*8CqXzu;DH1=W+@BTbf1`D|$Fn5Uf`&$Xmehg?k8EY(@Lf zAlB`_`xZ$sLSRKucq_dg!m?s)Qz^?-4fytgAFu?{6tbiys7(R_eu(oL_;k2Y*CBD<;pYV*%#j79?^lb8bz_!AkZBV5u+_w|!AFTKdzv z1nhK-pES#At&n%l_7pl|S+86gTMo%V;(*ch#!=q`kaZyAwv$;B3v$f&rEsy+_cx{a zz{y<_>7OjgBI@Km1cQUi%s)N8-2ba~u34ssmtBXnlYjEZEl%9E zu*PLKI4S;E{##jilppA& zhZdshWZhyJ*EJi!x?1&r50SYGvTqh0| z(^jK1lRE3LmWtcGKjHiXnJahtVXZ1i!#&>`=4bU)WgPJhH)y|wiPgxfhlk!}dcCC1 zD;k(ka-%03?1yd`jUJsBW0f-UJ*(cb~Z&OL|T^;&vh`cHf%Kl%*JPRkPTBB zl0Yur6r#1yfeo<6`i$!}rLyqn-kJp?OeQGD14sFb2S!$|TyZEA(8k(!?6TYcM|+@H z1|cDl>U4ga%6rGtGtviRB}*DSM;58fnLIlTm1tP49SLI?>tmo{Sn8^R^$JgFq3mb= zQQa<5fX1@vzVPDE3@)GQwi!Q~j}dHbOGA3_<_X^91QBbvesBx^!$2tiUus~mKKHzz zHeDvAlLuDeiMxfn4m&%pH9Kp}=Cz)DzFbJxKsONRGauMBg~0^T(ugQHZu2%K$UDgG zI-ri{#k{zTo|QqxW43Ulbs1MO<}ut8@@2n#C&^RIV>!hw;m1j327x>KfK|^Pd|A0 z@8tE&b_KmL8RnDLH6z}N*#fi^`*c{)Dwuw!CGQu$`P1f!I*3`UK zcqEMCLi$DfGR$bmbwR`!%DYzf6K_rawLBWtWoSx&Y{a0gpi}&lmwHQ=qgQ5onb5is zaBph7PK3mQN>k**YD_*Uli+eZ5vhkkPa&Y_2Rh>Cb(UMqbHSAYyCExOvIyn!=?fV& zixw*G(l4z(M+3(&*%+aXR9wv(V$;w2<245le{(Va22%Mnr03X^=SN`NFl^~O{#C!Y zsDmqBy~ckWI55!4oWnK_33Lk=-5~}5A2#j}UD69~)8X(NF4hI+z6&eVhZfh`HtyF> zeM(rp?&jujA17hR;Degp_W9CBJyLa>H|luV1DfWqys>!VqJi$llV3 zl;TeXyKIF#7p?ztekoS$QjW-<#=#J|HWlm&{z;b#<&d0yQM}{S&?akY970D2 zGo9mABQM~Cb3B7dWjN;4<&tOpk52p<#v7#w_u*6+%pD0B*lbWD!}1!eTfFOT$LD;} zhSQwT8i#5|L>Cw^{eHT~TRJeZdZq7wODDm>o%-3cSUySL^h3`ogG;_51q$gFrk><> z;Wlx?lP55}db{i#-l$BXm&LFT%Lj;;c6yWC&O3h3r|3L?{fzV8Qgn+ClJhcvPJ@a= ziYIC?p-1imzmS9jrCesuTM(7&4QA<@0^L&uX&*dQ>oRGw->FkrRCQLA??@Hx7orbB z2ZYJ)gOVay5E<6v>jiE?-;}U^uJDOBNP)82{W0R8|QUFL$mPYgY^`VQ&xj)jv_V(%I z^UJsV_~7A>1f%=AzDrRibXm0>4Noo85a0k5K_4pLJfQqeu*wJY{os`smndiIf#x*; z=9Sl}B&d(6TvG|;^MT2@)f{N9u-~2k<#i1H2i$CA#V$S$&$~38ez4L$V&=@x%2;&^ zzw>y%@o<7_@uq$MwKW77Kyqgnlib1$AlW zM_`2dGPkgBGneix@ck=tQ^8T1c9uywDa=fX$S)?Ry2XRHo{$YbFFIHJ#wYonP87xy z(`#r+v#H!O>Y!f+wz|GR9`h4qOT_-4auu$v8LQ2gGovW~DH~I+sJ!#E|H?IiI=RxZ z7tRoAnjBt0wX%4+c=eG{%PlEtS4t$54_KEX;MHen)hRK}?>k;AJ>oi8AwERD@CP_@ zbO^rVA~Lh#HdU!{nWqb8?XuMc1_0wucA0QgDXx$b*(E-HX-!^2;9_PUjt?6kmrhJ0 z{zAfGz%&=(og(5HIw^ZCPiW~|r8Zai{j;1y>lR-2M1w%|F$yBut%a0%ky)L3lz)mt z6S(es0z*c4bA8-A?sItavL`AiBo&~`->8B6X{Fkv0C5t3f4$@&S8I}zV7G!J4{ZXt z(;L}zwl|7d3^Y%H~XR~*B)}B zR4udK5id4q>h6rItk7jBH5b7Qr})a1h%Dee_q)vd!d*)Bv$>O|zh?%?w%aZ&f9}u! znjG5amf?wOc4;WP@&q)cL0KhIEHl-7m+xmhzk5=3i<+s-1=8C>knF-gvw#8@GFBlL zRK#a<0ytJb>5N>I7sO9tolP>}hT5weO$;lH9K6Wnz`oF9!^6q)i2QY^4Q{tt*?6IIAY!<0Sc%8!?j0-hv%1dietY5t@Qu$s07h#IObJ{ zZk6vs_0r-$zDLIQi0#u~;~JuiKp-;|jzz;+Y+yRQ_pJ0GH-sYxh}JlYc_I*~xOnpT zf{J;MRF2ZiJ*?q4IEkQNCeMBEy zxMzDmj*l?ETF3f{@2!OVI^*QneCffF%0&2XIb9FSJ5M?GKP! zX|5AqF4+%{X9C2;iyn6@T=4kvWy=$!(SD`B@b7dk2P1lY}8W&TepZ7C(}lpBHw)J3-a|Nc4X$b-%&C#6cm-4Eb5}$w$aqBR?mE?emXRiEYoMp zux<`>fpxUxiHcHaLb2u$8OoWkG#@_uH8smdKDfnK%w2IdcUfE-?sSW-w+1+dpi4s1TPf!FPS8GXU^85o<7Ys^ zJ<{_yV7f!eLDE`bAQON3naE$-mcLIZwB?K$u=bALAyI|?o`?LA9&(JtWS}+Tey2V@X z2UZ<_BN6-i<$Cj`b~!`5-%l6L@Ny}^y0$c^sq1_>ds0#X?aWtf==84}GP4n%QL<}+ zauD1387|Z7P1#j?=0r}I%8?oJGtwv7f6E4cdjp4z0Cz1K&$vwUK`z<=*2M|ONI_q~K1BggaCSO=DzeDp?P{kES=)$=8 z%^Zks-DJgQ7;)e_-K$5<{o{j|>U#Y~RO1$NyK4_Lwz_pS{THFBW{w{-9W9kGMQfc( zW;rO$r4kLTf?0F|K?N;8c?f`jnhNN;{hw+ZMyBZfBbvJy*xQgSkrtJm4P*vjA(XZh zn3r9!B(aofkcSl$U{|}F&2JFP_r$ksThQk|Z{=g(Yx>WBiMO#B!{jU1KVhZJs5(n1 zVX9kJ;mjINbl4jUee4UN4_ep3%RgAPmGzK5)`oRISVUViJq|-+PRw< z_&L{hKmRJY%JEp2_Hy&)JVTjkeZxmqB-vEV)wHnLx`>#sIYs|S+)(w68-|e^-7#!c zw_a(Mdq%8TYa-IE06u^KjIBR(c=26z^FWKjtz)?jVX3X(t0A8)M+gNz^;SfW9r1}& z!Ez!BZ1PnAA4h4OCsqVjtt%M!tg$3uDw$H(X`{CX@G~EAK@{eaY`s7Gri6y0f<}N4 zZg2G5TFR3(&U~a9aStKZKNqQ)1~M@`r(U(+(mFiTXxD~xBQ20IoD@$6rWV|A)Blqf zD-dQobNZpRxTALYML}4v@Jb8F+J)(`#KJxjhr$m1mad!&9A4M8 zsE^^lm)`v-czu^86Tf@_Jw+8$O;r;DHE={ChOO4NFs6)GE2?sB!sdFlY)fxU9@tqQ zZ-U}!SXqs!c-*0l?Q&WFx?n{zpw`+9=O~Y$Il9F=w@65kyy;}Ixzm^PHn}FC2g3S3 z%C2B-y;=snWX~9)*)A#Pp)AYp(XmaP;vGNS!NP&c-pp{5Bggi;#hYG|-ej`_nZaEV z&ku~!N-D~A#E$%WFboqHQObG#=0hDap*;Ky2zL0ok`Klg1Gt;_rjVAC6+_M)4hz= zZY2&#iTGJ{S6)P@Pc)*d-UD?^1GCQGjiWoZW_mlYQ|F#_MC!oRu$*SHp)sySRda?6 z{93Md&k8+uy|!||x4xV8`$1A0n@V`7VrAz5?D{K*LxFfMl}MJOUR7G@Q%B()7{o5C zybU_|?WkbfEnIx~HoY4pDwUG?fvqvc!}!3J5ps55qXfb(&JwGNH$1otF@TD&8Cxu@ zIa#-Rw90dgLTt};u8+bSt+bjKu4+&a3V;7Ay`;Qb{L|}9y6vw1eOO(}NR<8Z$!{-z za=Jhf5e_UuQqabc>PR}RD_#6lg2~l^gIHn?loTWY+It;q_D8>T`IZlX0)7y!UYWaG zm!&ZGZr#ke(2hZje|&Iz?sjFoq_*Z~r?a)Ah;E%lfRW29$^UDvwbC~m-HpS~s1YTd&3>^gjZ!^c!a zdP(t!%#X}_+VCeLcvoRrh%8sVK*EF2m@S7sgC7X*%1I70sBYQ`q_G8J!|b?o3b0|G zZ%bC!)p5kL9~m-;0_W8Bx{sbTQ*rDLE<0q%FvIvo5>Vov=Pl~y3&Flkcg5>}-9fzGEnG+q>2Np)1OM5!S<)8M0>&X4sKgcqXtcz*^)rwQy z!p48X#Fg!i{?J7L8li};ufUX)r6}vmjPqk1t)x~u^?GF~vD|9pQ${?jj)PPN-E~X$aG(61aQj?g|0W(y^q?ViEsM)1*pU6xiyWn0?$i%> zfkof{c5EE?#HLHIZrS_B)r`&^v^fP&zGs}#YnJG2Z`C=ZiER50Fpd=aQ7pW{8&Pi$v+hyF-gy=)kpK@r2zI zL=E8Z)BFC?cgXUhHTA`g(+xW@P|8|xRLI@EJ78EWyX1(solTwb!(2If$L_JqHgDa& zal=-nTb7N7V)UZVC-R?PxnbuOA~DH|MUR!jW1}0kZoPE(HY>~X*oIA)?;hLLS#j+9 ztNaf)Y}(}iHnwZ~&P)6f=q*|nEel;=7PMh;`akfq6NriRekk6-+a>3#gEW&8B0WXY zO2NUQ;9vT`a2h%Z^Fu@>M#wfLYlk>mK?aVN!dCj8l@Pqbknzn|Mxq~Q%bx$${6yhM zRbl0_BW!7&>tvt*MSlr`Vs^bl!Y<3g^{EWzUe`m-@q8WcWaj)}UTo8(H8taxA4sjc z7o8v`W~(@ai%CI9tdmrsBX|qviDgO|@3+A&&VIpmCdC5hDCOt$C&LPBzjY*IX}2)) z*V65|!pQAMa%`GkVfhH&I}-Nhud+qiWtP^`LXFvp_CT??r_2d9h>QyB^V9htj5STX zZwz3Hy!PWS$_ z-yUSGbwSqS9z%r1BjtUM5@e-H!i0z zf)1ExnrU;lDowgAL<6$s9G4AA2ZTOCd|(TwGMb@3x+$fOhrASZ3p?K7HwV{Xojb8^ zo7N2CAKJj1GxM&V5JCKICg4hH%{YFc9d6ND96EIc+@5RNqsu=K0^~+iW>dI_{jxk zd|~>+Ar@$K0>qgmtweylP~-xzot%bNPy2)4H|XntSeBOnHsO+#`cS$kBJ1Msg)@Sw z1H^rEeAkSfd=1s7+=Z-glP&3mUUN&NibBe$pKkSjs=B*{Dsq5KH|)3h)MBROzNmZy z|BCIXT<4@yUoSK=w*((cPQ^&T8$n=Zc1pS$*Ctz2puTTkRtfiIm`HVtr#?-}Zh75Y z5nG1Jtbps@CrDWHd4AyBcD&!9qz=m2{oDqottW%9G15CZdb1=dqJ5PK8`$$O+fTRu z-#Ihp(z(cLIvI%_vYU`v&9W!S?70bzA{aM|6Lf;t6@y`m9V*tz)_L9sffT#tra_U> ziHw|vl>9J;&nyNcp=MSZ>7z-5lK~dP{g58Vhe*sdr_L_#oMB?uU;@P}(;@ot$p!0%X6bMHN_HGvE=^I5?^p7f58IIUcCN~+ z9c9vQubo-B&cAj>PiuiGp0AOM|IQEH`9CXPqz$y7O|v1X6q9fN#XB{4I$N3ajzjl* zd}o6-HaPBNY=<6U5HAw@D%I*-;pIW^Nl=V?a23EX z4e_@^3)6IeM?Fh1t17_hq6|I=(6V%)BaL%p?kA?EG8ckct%pnDZJs?;e~$AsRZ)r4p?9EAfL44iDv~>LI~M9 za1}g1sl!@!%e5utD--S>`n>!GLRL81HuB9-z2GLIv}z$WS38Rt@d<9A1vZ&+;pmVV z4;2ei8C2ELuGKbqx3`>O=cax$&b#UK3Oc_vX==CdH~)KHGcG{LKFR64Pq+}zb`PVlA^kZg(uPt20l@q`p;Xq#2hMOngK|P)150!A0f27n3J?RgV9-X z)e9H~D*_Wq02mlaQn~CD|8r$tG-;0h%x8GsQ*~iWtrWvu_MsL&92xElg-sL6{LcCa zjZ+@qg*Aco?aFHx4X5V1Q!G3W!D4~DPU0o`yN`1M2S*Wpv$Z0ca@_d)L-E`B{&%G*DVbl{M@ZzV&W5f$u*zWRhu*u#cvmj%Ix7MR`8$ zSD(6WLoOFQ`ScIk*t`kCz3P;Cg(O4YB)JurSgKI~PSC^t3quAY*QOXU478GRx5?0r zYT?xeXrQ!qJf+;Z`2{;7#?3JZXAsG?`mPL6u;kMV3ggq5*zJGd#h&llf;!wBR<-pv zD7+yW?iR$%pjf&sYZt2PqC?0DDO}Bg_g+fbjM;uR{Y1iuJWDFLe}?zZq<&6&-L!pd z1=+yo@TPdF>utOx*W|%OSoapV@LNZkLqd?dnTuP0|BSpb0TQf%AW>HA!CiP-&b7b%8473K&^+YwZl8YxzxfDxtH>8Q{ZN=cRj9a?TSuyXv7^eCB&e z;@W+sDYYCNbXw^HXxUC1(}kfY-|^9_*c-4~14!aS_w;?Ky?f;0!u1w*C^XI5%@q#( z%3T8BL*0M-jGseU&=v~qZn5iS7jJfMJ!bptj=x4e&@~ncLz!rT5p{Cwez2p2>>9RL888lo8j~$Xy~*nBINpXL>_O znozZ#Rhbl6{l-mVb-wihmSg5|-h`L-5XI|JX7#H-7U` zGBofUS|JZ;Qn#>VPo4lUpVCx%pv>-{3JE62ZI)OLYtfzDIkIb`&aGrg84zH%@Zymi zmlbcM1_(LW_?5J!L2B+^*f^VH4NkgUCEO_{M@$TG!xI-2I5vKTC^wxQRxR)(mwg6? zSSal-WwiE+PT`6TCV%d@1s73L*!8~(E0f5e_#*a;f&t5xcu%S)BHY8APy>Rq}Fj+a!J%=2W2Wxd!2m*VI}%l=MN z+X(ea`6F4;1t(igWE#Q_NR2C(2IGjou|hd%-PiK^n>|DPbEs+WBnE|~m!81s_-p7X z6l+>WiaFG_X@xBY9mpD+%o$}Ci{&Z-Eo|ern6{>tSCH|cA2%d6v@vHuG&nvjBb^CI zx!%UCS%)eYXyZT8o@7H;^y*qTuzNV5Di08Vg?p9;S)cMhL9AY$PTv#12$ z)4hus3Z-5cQWDe+yZztYLZD2H<3(FTMCl_@5PzS->qwx zPE^!}+yARqiZY&P;p*Drb532jH>p#TGh|5By$>vWC06kzEm_bmzgf5**Fq^fVxSuV z^KUrxp2*K>tAim^-TqHLpS@HNMtAXD`szQe^Xnz!;0XjVO}_)z_bH-nP+1LR&p~8A zpPwC|+${`zXdj6Pp?re|LHTqf*k!1+BVBWP&5c~Wi>kO6Te*~=RSIebvB5Nkbi95# zpXcX8)Vqb}y~g1Z>6wf}T}P6hw|BvnSlGsM&$OYPY_MPSFl79~?NFkplmd4sJu9~j z?kprrkRG2Qzv=C2c55zUKwd%;uE};m#T=ho7G|QYOAXb?6JBa-cXEJ6j0VfO-U4Ht zUaF1|erZ@nS)E~eIg2-*U6D>vljMkXSt^6w(4gSnp_Uv`!&tpEKXgRa)9+We+U8GpO8oqd%Bk*(@7^wI zz+e-TQGZ~}HA5Xb{M_5$>iVxo>BFpINO3X_Vrx&bWtJ8(TL@2lBZr;2hp1)>&@~p6 z_MPC!5a?;{dAV@)V5%Am4)eInkq3o?)8dM%`$ejyt^((4jHmFlS|6)cRLSC@SOkQnu*%0!J`5otulOH#T zECJTKTYPAeU%6P1(6mf@LNr6I56@2VAySJF37zfp#xV&DF|TF0!%H)rqfmUPbMNV| zJ=mhV)4#@0YZZ0!3-mkD4a{f4QiaV1p`6y+n+zXz;&k4-bnBmUbrMlz$dt@$R=DKR zgIrzW?Q+w+x}~C*`lg;uKX5^Q2nly7{aSyrYxXmri{Vo{k}=cuNQ87(Sa1TiO50SG z{u7gNr`C_|3~&BMa%dK;oxKgN=A@}xIPWx+fLHwbZDg{GwWD`UcS1Gym@e22ekL7G z$g;j-au>=#PZo`I;q5l-Uyb^Dy-!>8x`nY{N=ASR7POwA*Cu;a3Y!UyaG0W|zZ29& z5mt7x+7^=HmCa9v7E^}cL-0wr|6_NCG2F6g6r?z9E#$lqNN&R35$Rg}F>YV^i13{u zQoWCnq&=-JGJe#u4WY>C`k9Dh5tOMK7v4y|kUB34#dF^ffo4v$ij zY4vtovTJ9uedEr9os%x^JN)bY|9a-34P(85(Mz`NxMXaFmD73ZlC6*Q*p5rKlD>P? z?(ZvF?;Tm`;@;C9TipBFS3Yvw`{2$L#2h;OR2>P!{LNoE-0lDGCvTwa)0`SiHVr3R z{N)7AJuU!DuH6ZsCugE259`OJF9B(**(<7jKc_w#a_JnftPw=bWFx*|T=i;k|6E0UAOg0WDR}UxI9gBm>4jo|`PA=yQML)=`slIMoWLd~k zvZ3>v?;O1Piq4W7J|5hgWFu^A-by?ycLVJvO)d($S{bXjsmmEbq`P;suC+mnHx6@W zMwxmX%BVN}4kp)fS;@8IV}#6vCnnpAJAEadj$UfSMIeJGGs2D4C*TUU({+uacdiyKldodnEPownGks$r$QjO}IMh;3a;y&P?=w?(cTM2s<@lnMT|^?By{L9VgTb6y6U{cmBTWdqgLQ1!8sKr`v!Ybz~0VF zUi#9|_=@$IOmBdlAM9yN=pIJwA=)d$h+Co7E1rDWFlIc-UQIcej1Ftpd^lEb-xLid zR}LqevFpU=gUQxmeZ86gRaPUe%4l4>nG(!1I=?)0Vd<5fUmQCY=>Q%osl9k0?Db7( zpj(_fRElPZtq7C2D>LFAAC8=jBgA;fY>MlA6H*H&jZ%9hXR986 z$!#+=9=}B{{r+TU#YtyCRhzL%35wY&VtBp|va5nYRu0(`2Zk z1e!1Qh^z)}a^mdgKY?jY7qAogxnOnfm89~-?tsi-Z|iXHvSH5W^m200yLz~1uPNn2 z@wsh-L#LWd<)Yd``Qi!?$A87@h;VBkX}ys}E71A+&M!AV8~a;9 z93sSOnrkE$Nz*`l&wMIQGO3D~}+MsPEIriq?TVmM{mJvy|rf^@=* zH9-`x;c#c?aN^F!3?{pV6FVPc%;1a+wB3i(xo0aG;^!x3zi72(>g~&S#^jlW2)Wp& zncnWL1}|nvwRF_9H1}G1baVsvvU32eJ}GiJkWObdC6rWAF#tU!L-Y94puDO zZoyHRV4>_3B#nohxbkL7mO$s7!aC%(p{pH@k7)6e?)-n#ds*S_`kXRjA}EPkwi(?6bb(*LQvsISm> z+R^h~bMMac`0{*L=Qtey2}|4fSV z=nLO8^s}d=={jve1yN8GS@pJb}ctrfe|MI)3J@Hckt

  • svn&b9A1zMK7Y_HMMe z{>M+>Z~XS}2OHo0;rAQg-QApC-CmyF%?bb&E^aSxH{P6H-p)2S`|-GYV$wNuCLBc@BV)AW@9?p`2Fnm`tswQY&^gC(VTx>$-0`o z-MEFFv(ezfuuwH?vG*S@H~#Q@(fy~(+1=gj=F&Y>RQ+~$f3iQ`+S=RM>sPntS9iYM+1aAjsI_|jcF^i>D}OnAdwMyqvek0mpI&`D zy?is9oqxK$JH7jOtJFr{EwVR)+=q{Mfqi!U;bM0C>AU~65*vRs_vBwr@BY0QTm1bG zcz<$m0LSw;^8EbGr|)jxAOg~FuI_Gr+OQgD=Wo8bJH5CR(D|F&PYS?-e{9A6owQJh zc9gsW6n+Dg zDRax!tG659{cwsx{c+>;=H~S0jqeUFsQ2Mkv<^OAT%I4kJH7d2kh9s%-vM-db#|@s zZ2aaJI5SoHLxSid-q3OR*8a&wd^TyeaKT$4vzA45qdE>jYyBmo7?Y~Es z$Dcl2fAA83w3UminPBGN;Mv)`Z!X?r!=Ff;pWdCO=$!VpezyFYvXc&XV?3D-%Afz#OOIqxgFNn~1GN~s@!ddLpKeco zR3pY4H`kY!8{da%C2?6a8R3s+KZRYmqb_?decyQ4nEl5M1=NKWDt|(JP$1>TQZyni zo&~YN)v!ErXhjw6+3DH4+4=0pi?f*!s>~e3NP}FM+c)2i=grB_4u@>S`ya9=`tkRK z?@w?4vT-xJr3abGoFiP&*%?|b_g1wAgZuO!x=0jo!5oUKJu0jDOUxO0<$G;)Y~^U} zs#wgNY!riwn-tgT^)WQotstooAKb?bI;DwCbv z=0AQ51!K;4K9T)BU3c?ZGItZjF80dGvmfJF{{H6rMq*J`Nt<_`zrXLhN8cSBUEkqL z8%*5hkDtD~`FJ_|Sv*YqMB-ls_phJchPCv}DxyDW>+;iw5pe$|-1nb8Yyddv zE7OxoUz;9R`mdy0@`hw9aZ9pQyc>~j0RILi13G`=^!s7P&!96YH}+xUR1|)=ri1<- zE7Zp^k{F@kw_U@jJGXv%s2bO`aolKmpf+|8x7B{7-gKa+C80>EISJR-s=8|`jW(Z9_sI>8N5Of4?Q)9+=LroKfT_fG2!mS1p3U*@ z)_8jKdV75IYJ0kI1m{{cd9`&ycyf~P$Z&IfvL`sAUn=}Xz)eB&WYchTvN_(KY)%jN zPb6tylD1A{Xz18F+&no}>QjmzN+73DlkjjDa&>%iID#8QA-2LfU#Lv><}^G_kt zGHA$)mR30cM#kYt?vg@v$9tQ*2}ONxoNy~)5o7X1qzT8nP;?ZEeuIR_k$@BRgnNctp=z4&I3exB zpglv_PpC~0S@>AY=LfK>&CiFC802w`_eKMH>>#&7jC_|Zi%=Pa0pS*D^aI2=hT*84 z>`Ss0U?WHaD4gUfBDKyyo^vHFo+EE^Dnt+<}8N+dNK^b zoLUu%1UM0n067g(*b*fmOWqE|Q&~15(P~UckQ1Dyg(3lOfJJ~<8XANTpocXG;v^7H z06NCUP?iwF3DfHk3A92r9vaAtt@f~NSeXlJSv*mgB4>ny+rejV9Mkvx;5cSCeV_0| z1o}`On$WG#P!y>`lFDK!9No`auh5JUgMqC zDWh>}UAkR#P!E`{Q&jymb3nyXY*7?R$TQ0Ld%Wyti>6ClX+EIGn-er(|7g6^I>VBv zY~0(zk4^W+$MhZfMRX;~>1cTJP`XzXh`yMwR zZXN?-M|5ZK7>(MS!eJ0N-sMM=9XhdHsUAnu=F~WOX`PHYMkkW$RVXV!TL2B8sW@oX zPPDpaOK)x-7>)-ai&>JIXmjex=5E4cL*!>zVrjxL2NDd!4*3Wo9No?kt65J8v8312 zlO~rgtR{dkIvTv3LBn_p3h$)?9ioaxb6sBZSb;VMfjp%UI$|YjsD%_#1NExg-QJ2k zNvz*7UJn1Zhx4Yd86VSxzmp|H>gLb9*lmdu0LYh7&U9~79-$W;#;GL1 z-PrFbp|F9ZCRNL$O>7{|YkEs4fbt0tPf)TG>}AS$XljQAHQkF+C6YRvplMvBuh#t| z$7NzuihAkuhVg{b9=k#v#L&(ejB`Zi5v8{^xlW9k8AC)M%;QK1LO{anJqBS_4ob-r zq9P|o1Tr}I3DN$b%T>tgUt+2l2TdRw$1$aKAddHu` zHY7U<<{;OK41@YJ!s1bd&EnPJ-cH)Ym2r-NWh5otT-V=^cfkAz%nx4eIv*>B5OPhd zwMWO+!G|Ff)usuz4o#0M)CwWXFlP3d5Z(=n4k{Oj0$t4{#Ox`LdN#Z=${1@qhhTm( zq7y4>BGKY_D25$y+>&Cp%yDyyX~87~%KWfyImpBywbB>BN~h<#d7`SrPyPXrgy z9V5Dws%`U~p?j))jg=~A#lcr^cMlKscE7&mn8Qcs1mkHZwklTiR~y~4MNa^dVSf!_c` z2i4*ZWZp!}uO*z7!mEXr&&P**n@IZzZMRd?Ngj(D!gU%F1y;$P19WpAh8^vXH;-Sz zv^I!7-TRAIhziwtKw_Q9Rl}hV1cpC>CLl7OTJ}du+bv zbba%NI|8e5+7_{f$Z8xE$Rq~4Bq+(*)B!p1v3U)l^9k3`JzRNJQg)j3znRBHUsjqrxc_Vb|u-9=gUpgRmaN#@pka>B0UsbJB7^w58Mc zXN&pKxCqRD3SscGdHU78F~C8a@f?!@P|ivSFltx^ionPZvtanve@<(*_WX(9E|9l? zsN|V$ZcPu+uW8NtbdHYQ_=6q_>OoIvs<4!S?I+7ueq&k455pKAvLYp78PXU1HbJG5 ztBVmN6Nc)dy{KLjwiRg^5t+?HIap@&ECHjiLpd)bELG1G@Xlmw6ejM6LS;*TbxeOz zVshTLOKS{_wpek3siMqpAmN^N{JT3sz3G$~L&zHS8=D+16E8L9- zP%$Y!Eho8o^2*sfiXD5;Y#L@`h&5#GHV#rq!!T_l2{0IhSQs@78L2H!l9p%<$xu_k z`VHenGYR&gzJ3BJ(gsgDz$39?gBeeMT-2 z1R7aOVC*Csaigrg3o4{n$SI)ihh#$GJUrfX&EdF4QDY{3+CHlT%*-r@H=)79U0pT| zV_|oTn>`b}p`sEOe!(fSl-4zeI@}J+Zo#-%6)igv?4!7_zQGJ!U`o~aa2teo`Kbek zEcvp&wFU88ER|Q|lgae(^%xb3ld=-c3_>~ez%f8>eTjmz9hJ>=Sq1?<=nlg$LvYft z6c$4FLx|_NA1-t-N@t4< zxm8yR8P^JMAqRR4Olsur@Mmkop9l?pRvG?!Rr|xhnb$@690(pmc>g(=Q~*(#15i7B zJ<0eU%;=mQg>9j@yW$u9lc;r{kSZy<#VSo&;C z;-Hb3#XQlJo{HmvV)>q%X@v*la%vU=9XmuBRik#%?YJ7NFcp^+xB5c37>l?Kv9=Sm z8I@Ac*AG zeSC@QVzHSTySo|_b7OVRdj|Xw#xeJ>;a6A=L%9&YzZB9mx5|JG?g@iUR^g^utebKn zBAAC1v)IrSnrV=Awn&6iZilP93iVpO-WjnEn z`%PEQ0)axKhjNy5g4u2r&76ZnSHU+L}+UDDDP**sMx~x*504jX_ zz(ZUx$ShoL9>M*?{p0aiROJ2U7+y>_nS2sDn5C1ikakHY1ei_KxF+GKox~eaP9zN- z659!D%1#)D6q!)m%X>lQV{1 znTJA)$ihY2qQoe{Zip)!7=dM-rIb=#j17|QrI7mKeQ^=m|^(N=IeC0$D>zU z*|!rHEX}piVG!q59UM7;Q5;!dZkSyGd4p0y1N$x|3mEz}x_(Q`%gLWev>%u_H!~{7|-Fs8Et%v0rVH$&# z*uoC3ku}!QtG&T(xH9%`^eNw{>Zp7shS=v-c)YyeenEf^t)2~V-i=Hgb=D@X@RN-L zI#EWK2$s=V#Jf%j(yF}oj$WkU5ZsdWPel@oX%#1x=b-%A&>87x3sHt!!GzP3Bf@Y4EZ98&O7IPCaTO%TfP-&OVfVa@)lwNi z1y27Ozi=dWCnpXGYg(hTXUtSgkFtZ3q?fLD2?COT1W+M-W}xq^kFp@Y2&H{V49*;u zMJ3b0Fa}{|WLa`%2M6gDri&B)7E4Q$HI4pqlV9vM$Ai?J>|KUAWl=2{}c_(L(m1!5%rs{j}PO>KGfq(DbEYUzvFd zh-irSwNcfCGITJ+M#7^QQPEnVMQSM4LnN{CKP-TDXj%F{9g|U8bE}oO3Tt()g>I7S z_Y%QN2@(tT5WF*AW#t;N&X=Wm2dh(KFea|;U93@ao*{nh0On{1jBbMe zL?MHwUc)PKMR=nOPB~SP%ek~A1bZ-SUz4JELaPU8&j}{r7w*P00oOLj6Z8Ul8qUa) z=@o8?{fRqSIJatZ;40u;h6RAo{~#%_UOE52(>x3bxnUeH zVP%gzwg8uNG6-Es2SmaQ1-+9)ahu96cr^sKq!ptfBOiErv$4mMMZ9q#kNd(wyLMWb zWal6@Shq4@s)S*5#-Nc67sO#RvAglCXPGC**c68@vEpI<+-V+WJO}XodSLe)08{%L z6sgDT$D=y4o+JEhmVcU>!2oYpL>f}gToWZoV`{00ti~M=uI9RoOX9IO90FjELt$$m z5~rbx0k@p-b>|rA;{foCja3zoUpH2HV;Pc8jztqFVg+)jj~Os3G2G}33gbT0+A=n> zZlywJP>)xyKX%T3pZfqGtMGXF6-j)SQ5n|;fi3)ps9@aOqhaO9B@7Ht-yy>?G7~Xa zr@=0zWFtj8Umi$xM)q(tw7SN0XP(it zh^*kE+RZbcidIMUej|Y~T7j5mQpFt^f0A5q$Jhj6SvRSZS4)>pz`cHMWSpS7r^6RO; zUeQ=!9k6kD)mx2Xij5_6l{ofcrr3k_;TDf%@P-WM531_m5@qGQ>MaB-R2vJza?t|* zn$YKziQMuJaLXCX=R?W_)&UcDnv6w4WOh4tO#lOVEYtNA;qGm-ck9)*2HqU3?N1o1 z9c0@|V6XrK{yUp&(Q?m;J!wYxP*u|7Dq0)^YWvhYZ-Y`$t|>(i@!2@Lr-jh^w4yS& zH_+19Pz`*8TFfl(>S*N(`8HKyv+D6{wxPY+-pkG;^nnWYXqj<39QJ(W7h+d4zx>>V z8(N@uu&3aeYF0K6gB2XF{mk)XZ04aWK<=OiqI9vMi?a*GbO!XoyyhgV17t0jFtebL zT({^vv>y)$!kVSXz0&GX!bJ_l9ljnZUcHUhAC)8_0?j3uy%kM$bl*qR<%$_9Y(o^R z9@T#3(xaj(OCTT#J*pCnAc0IXA*#?zz~JftZ3=4=g?*6*)s0~tMTnworlHA##^ctx8*$Lz!zZEw?sP7*3~G3O)ZwzM2;E>(^~4W$=)0v?|_L3w-dVc z8de&za7kGEnPDbrHrxsh-VieO3fl>3icrKN3qmL*g#RdTh14KtH5_6$xJ(tqZdeQK zO$~KKj1J1KQikC+L}k#;J+Q0;m12A@gvV6SZH}{-70~{38X-l~KrT`$j?F{yM8!q$ zUYM~e2&$2JtV^ANK?0pLxuXRAy~OA1PbmP`MXlBAoqo4urGCBQ)l>VhL$35)$t385PR zwb6V$-p|9ywm{F9IH!hC}6AR|qe48x+{7J**jl46=t+=IQx$bvb_{hqX1ZMT31V zh>e>yngJ)V<5-QW!+;6}$kF4Sj9f?;Z-0qs} z)LR$46vt~UrqX4GG15;g37!izF(?mW7e|*e7U!)(2hahw2Ev*eQ&jyl>T;$eu4_?d znJeVFA?ps*jV0pd`Vmu)&R@_w+4bJ4fHrVq7A_cNTEgJ8Vn`& zJq*#TkQ%PnKqb7eFg}a`hVfFVY~SS0fCpt03t4WPk!9*txz6QDDGM4Trr=Txk~v?* zC0E5z7rrv~N%^G~P|hU`I!0tBAIgp8o^huPQYD?6RE-B*!|F<-+_)3QEUimhyFt;z z20EQe;u1&toXWrp=K}H~=JxLcaq-f=$#M$9AwtC2)yb8Q4b7dt4nzpqY=riUo_9hxm&>-kS0D9tS;Liv#U541$AcU=bHzu&~D& z)ahK$sQY}XRhME&XVBVM{x!Zl66X%}{eq#N>>l&HbulQ9o&XQ!QfuOpDAqiZL(Z>u zNehqE_O*STOS0D~u_M@WN!(qFOY$yYajC}|libqbglj#HLJ_1OtJV~t*YObpXwSPM zax0nha!FWRxuo2zgiT!bNF1?ryKOPhXgi4h60vd(KpPcck9+>};?{?KIcA;oijly-HBCrK=TvEyqs8;~a81yQj+a3cum^bahpTcs#vMgcFd!6q@`=; z(b5IAGLO2W+7G22;cPcR!!)eZ41%^#x35n#TyL7{6n=f$cb>GZs7&HKX+ZPr{pZpO zqnGLFY>dL0AJcH*6SjQhyBqdO{O7;Ib~ zbP*%b(n9WF#fW)!vl8@UeQ<40W*cF%Vw5-Pg39MfHw>XiA&L3-#L>TrHX_L*)SR<_ zDL{OWq}P36r!kw7TC6}gADR&7Y~f#j;oUl-F-Cx{Kb1fnDv z*6`O!pR=M^Gua$1kBx$=Iu*_WC9D>jI2jAALtlz*RbOX~TzDu3tpMtA185$D=%&aaY<~SGZf^QhMr@baEc~f#T1$U}O zOLf*QWiC}&fLVZ!>e@(MY@;L~hjl7>wNm;YY=S~kK_RI*n4GOr0{G6l1$m{ToM zHWBNskhk%1xraq%qctMSLWRQwOO>XB7L;V<0Pj{Fe+zyK7Ez8DqO1>vUn|0O3(_|p zfgLw4vir~7A?bENaJ*Bdm-k|1P5^7>ai%w0u2U;)-pG@9n(ClAHq z#dVLRSivr3eBHU=z7!y$h!k4PPPiKX^CWOhOKRqX{-n241PCn}NmufO804N-@M-0= z*slQ?>uiF>GD@%-ON>?EYKbwr=g>ewso5&6*<`4~bb8%p!Y3}V=9D3Dl88OU<9y11 z12iBEBLA4-x>Tw;oSuT(W`rYVqKO4&-lM=YzUE#G*P8a90|MJs6|?e)}&cVTky ze(Tkg&aN6!5ALV7j#`b)K}x)HgsNdGO5BWv{MA%^)Jc3)@f)|n7)|ZHX)9Bmk@9IN-Po!e(l0di7^GSLx0Y&xG?H#WhUpCLWCQ?Bhsi5x=ceP(ih6hw z9Rs-O@SRDZ%P&1Gw4~X%Z8~yTPOB%(66Iz_dQBS3=@2Dy05RR9vy_&m_FP1CNMb$a z95Zc3&mW{iN0VCc6(6=O@Zv$lw&hYj9wY_=ka;S7XgFQHX&~gh;R;H&0@fJ~hjrkS zCSpaQo0Pp<4zO;iK|gnLP#0;NA#WXsDBw7Y(j>Rj99Hy#&GMV*lbi8;Qoik{4qtR$ zDHiqBDh~M4Qjt>fK)L#F)x6b~_o*zojUlBcRuO^Rv`o+0*hlfCGT9#5hWXtU<%VnU zFXYm299$X>b3=VnK_R>i3T6J{UtCrZinqMDsV9NcLM9!|nyiNYqBg)g zcIqnmfHWFsJDcQ6=k}VEtb640=dS8lYyn)70^Bl}c_PgX4PW+0Kk@iq9(bGb(W!&i z-cjAp%bQVp_{Z-y3< z1xVi5v=ZV5xq7gN`yKo0X$a*8yzg-Hot6FlwoxT6aa7nerBv)$p?cOT#6I~n2d8|w zr|cd)Ic02Nn2#xuvV6U!=3eL;-Rk93sLB8e!JCi<{}`!KIGfk_e9sn+*4HpI39p?M z>}=9oQwKIClx-Qk$$Tz}$5X@hT#7EBwpq9c6CY6aU+;7Z6Y|108Qz|gueNFiP$BKg zxrRic@~n_{LW3`MqepcC0c5h}0-z%47H~r;d|FuLt8Vrp)l&@sfI_mN5bSN4mr-W; zH)pp!Ks6Xe1sDF|HlgsCdI@~Kkp!Po>4ybid0*C_e65w=egsA ze*0FsVt4grzOIof0^sQ_!*n8@E7omIL=gSN{QGGKS+rFn;8tyY$=Xi02E=`!kLS>{ zNu@86gAVorEFQEM!%RqhSL*l(zF;D}Z!JEhLi`0q?uTj#_*ZB(VEHg2J5|+_>c?70 zyD4dyPCy1wfw1(9S*9JNZ``w>I2+~cEgtU= ze4Ff3!~4(k#yS%Z98`$th{I6gFz$gkv_4dz#;!E$5#<+9m_1ft`I;85v*Zgz{Ir{m8 ztue_^ZJY9n=z&x^u!k={Uito2XuY4=^TKYQ4KKzgHJMhYRL^7O`Tj;896=D}Y(iV4 zU9dVe&x;@NC7%P-P#^djKFgQRv>tG@f5m``c6^QQCL>ZZRYRYc7Ilqx{aX{{TpmmA zVO6Ng!mUw8L?!fUtU7iFuKjhh=mmBG=XBSNe`?0P5hk_(Fm&Y!Va&BEw6KpbOF(Tn zo1Q{&WepF8OV%GfFKx%@+lzDC@YEU1bkp~Z;|h3w9LDC2#2`_|ZOEuewmvPCtGzNj z0gyn!nVV;XY$EnPDf;#VGVYg|(=z6pVwp?4&K~J_Cq&|C|JWUbJF&PO5?=S3f-A9*+L$>FwpgW>6+`vx6}Z2N=Y+?1?0|AJEu=C}m1w8_sE?f$d; z;Sq~a`Oc?r|2-ZtwoDVw=~sUaZ~9LT^RxE`&)VF^c}Shd&03c;8QFTLV)d7|;4`z; zPoV!8!*RW$!d5`s&yVI&5qxSrGQtIQN9Y!KZX6AMYQ^4AViYiMTIKBt!2}E5@&zb) z6}LvL>N9p=>{p?jq7or2t&mg3k`;mk_zy!~_iiuANSDyp&aZ?#bjVR*NGJ}pFjbpV z?wenb5|bH6T0OO}8&N_n_&3FWaZ{{K;kB^aH0bneoY5<97C;5fi)DU&+dZEBt$`OTmorW715b-M?UI7;f+J7>!<}aU6KrV?bDw zq~c_8FO5}0jfZj|Rs`V?k1xw3L%brJvNbI$4;D5#H?U1ZoJHBE1CWPBk3oO|Z9XRZ zr;ENlMl;la$f?b4LToWB;Yp@1J(T=|eM5a3jLNHgk#O_hQsR=>eB}njvl`gHQnW7D(3lhX-o0x zp?tIh-;cwX@M3n9?1Xz0>Zeaz=Ao?u~6_{IZ;(8#(yH#Wc2QQJom*P!)^__8=t2cH~khL;s z_ZXyLN#zld?J-EDC|U3VFPUcaqbOMUSYS;0Cex7HrxsSa+noRo_Eww@csyaeebww{| z+m79a*^q_$a^JjcF<69|sx0M-%|%d0eGxZYyA1Bdt$L&tMHyz$WEbO;<3)p|clTN> z<}NVon0HF%EzKc?Puw>TFK{06CZ)qG==NF!V(NI=dnHpw1M#`h*f{CNu9QR{h&;6QP0W5>O+V$lX z-BUdlgWdD~Hg~EK++MxQI&3MLzBWXVUkhRg;g zS$X)=4Fq711wyTpAk0S(HZg(2>T=7e_6sUr>c995cv}A!bt~Q@wY-= z{t8}C4|)86@*RTUr-Xt5(=s2eOX1x%>VQn-jPk z#m7MfD%xN$rA*>Tk^C44l4vn2Dx9RyBXOxfM)Mj2-E$PBHxSn#DyWx>f*e7BrJ4z< zj&JvK)jGraONo`BUt5lGb&vmLkahTapLPH7=FVq^a-W6vP+Lo_SfoCNXin zxLaSVZ(+p(DZ&O{ieO5MPq#~m2T*A$m8m2dDv6n2nX+U31;BJDrM#a7$lAaGpFDm& z$wM8r(g|l!1h`ThksI6_3oGCpiDE&){-Ut6?h7h&k3R_aeipTrRB%;`Ig1e?DE?Rb zmU?)i9-ZJtv1MZSLOcBivEZ`eqao$ViyneGR$mRI7b{+MBv33}fr>W5l~+ew#xz&H zU@CJ(8Y%yig2KR^z-B?ISOxD=gnm=u&2OJrOzpDLtv?3l88Kc9W(k z*}gJ|;N`+&eW)BeREPVVJYL~BSG|Gq1aLN)d)B4+6~ZJd%MiNgY!To~jpkK#Izm^?(4@~*pYeMEju|m;6V=12AqzAaOh{`zoH{w`>7vk^CBDK$ek0C zGJ|h+Nc@%%IlNhBOoQQQNu2XiE(+G=MV#th7ane;Rb(4uO6Dsi+q9{aHq!uv3Eq%> zuz$oomU_=8ju2YviMB^W?mKftHu?#U7GkRoo`xZp$e}PixEEI4TGnVF3UsYDKORDX zV&CBryW>#7{!Jz-tkLp?8pa3hFI%pBy?7oH;CZ3xUeR1%CG_rtID?-{2rlckQ(w8aCdEcqpDDH>}hs?D&QWG_;0aVi$DllO_3pytRuaN!6 zmF`t#!TK@nVcB|qlCR~h6kX#X0NCR?6RceD$!KiSKM`2S4d#O;R zGO2l3W3VMJ{mey-WH*Lx^Qwa=OED$5;=aFnaI&b3+$71tExBemF#X zpkWbmQywqZ6nf~V;+h1vIEI&bd)m%)mmMjuU+wsIUf+p^zvPQD4pdeTUb)sT+pWZz zvXc#liwi@aX#nNvF1Q=Amc|^b@aD+HDArUM@9;r*pB{MqYBvwQlv6FeK$3Di&s;Gy zW80)isc+tmPV}adyt15RR&ll?7CxzCh4wv&s=ZC~-=Fi{1siP&;r` zn>A|g6Ts3@q_bP^doK|;cWb%qxk9gEgZIO{Fw?;$&?@9j_w$p|z58LkLcvifxUFc6 z<~;aE6#YD84UF1v zg=6qtu?D)ErGL1-@~i= zg%5yZNEqd*5UoO~9cH57I^MX7TDZzcwv*r*B0T{iU45lhnz%Gg!9jo_ra)*PpLYRu zKdPP3PbbtFp(QpqK1%4E0)@(l53&gzxPpjf2{fRq0Z!-t&_J3{rK4%^V*HvA*JOId zDakxUMOX$e6F64FFYqO+AcjEKfP)m;To=Z14#$W?YhWPhmQ#mN65%?aYlZ&CJS!e9 z-ir_O0Xl+;57`GQw_6P7j`L-`MZC+W&n+-*)4U#U?NOo}2T;Wdt>6#nuX)cz3)3 zI6{e9w=}U;O=C)8Pa18;7Re%kwJwzVUMCN`0xcI{&Ae!;38KIeqFrgmGDCw}O>1EH zj99Y(fXEY8deOgo$3Y5gpqk+X)F4-}Hir}8a=P}vyk3>0n*AXl0*;VI1s6}(1Y7>= z;n3Fy@ZK3)2#t$6pvPm&;5l|)PN3DQF%pthWLpAk110q%|p53SUmzGtko7! zPgb}FR8Qmz2jDntj6N#; zRADr%L{&vf3x^knMWVy%TOr=(V5)1MM~Ve2V8Lz}4*c@|CbxvezW;3QYksb%e-!}h zcVxVY>wTGNzSHL-?c$0;kz3FC&2PIrr_#e^V_HiXiRy8d#P_#YMpH5H1{}5ifHEYf zZYOYS^z|#gC(LqNJPyi)@F)Qb&;Ui-bTmX3sa%I>3iV|Y919py-jFgZeN&&4VaNqa z2$XW-quCzmrWjKA&D$N8!ChY4&xU1A(6lmsH8@idt3)9RKLau`r`a1{+4JMw}7^N$WIsX<*L{qVE!hYVUFwO(%@y-DvCKM)Y{juQ9dN^G6 z9Kc5X4CBQhkLrS}=<7ll#k!FpPk`3R(sWtIa|ENMu=2gO_DFx+7uP@$*&9AW^rKgw zpmfTjdY2yZ;37Npcp$p&XNs|Ow9KM0@4!w5nU&#U%O`L*C=y*yilgP}byV6*SXu8I)%_^A#Y?&QFX`j$wedrcsM}G_ckf zDfF3tX#GqHrQD2hV2g_fq~Vof$u!pYcXI}EAZ8bq@l5q)aDkTiJswisPD_quTZ&y^ z02R<`pjxYz5$d8BUu6t!!5CnIk1ya6xxuKbaQbXmwFql`BRB?4!j6xv(NsMfEOF1! z>4gO$h&o{#D&)1hvj~{UFJb=O`b}@-T~u

    #G((5#pbRXff$}3?EWGd1|Qgho+`g z$e_J~&+d?&saOoCacf;EsGA8RV-OiKmb6_`Qww`ganzS^uye7a#2kHv`;>qlip%RD zWCs9CYjQq8*nF?9IZuIRrv@=_9u7ry*%v%i{z>4hTq?Q}HuWw^Y7+4!Ajb*{LOlrH zVzT_NO+4lQ>76S!gtDt2MS6{4;Op@92D%cExC(X^Cz!JhlV9&!i>75AcwM|9aE!8&5PX?P%>|E3obh))YvhK43FCuhn23|abG;w@B ztnO=F(P}kV>!tK-f~<6-rpgSOc^KTF&^o*d>n8b7<92PpN#M(q5gi@aedz zRDz}#sd}f4=!m|FAe1*oTL@!bf?<%i0zD7v`iCbdD72YchSps6o zq`h?ra3pOTLV#)tz;MU9aEy&IB+O`UMT(e$EGgeq%wdWjb@D8hr$FP9setjB1@zPr zENv?`$3tyQ#A)ttOtvSCV_&mj_tlmU|G9fV+xuSgzMl!W`Aur@F$r+iZQKZ-HxYiW zD08>z5$_8+ezolw&QVoHR=j(K{DZMyN6bz`)@Pt~$9L|ecrA-bWX*!=L*n#)l#(gY zK{zH2*^1RyxJxh9Xu7%z#rfXz5auA$enB>Z+u9K3!MI@v3&}}XQcIY(CxaZ_8RrT; z{a)*Dc6hR<-Y2x}1kjc!(nh8LXHAECdC?_pA!(*GYJzA{a3ypkEEm+M9>!s{4#tXB zT3oE#6`;pam26%Z9O;2Y8CcZJ3z`Vkx0n}C;d?1Vx`@!{V38zU4ez}ev#QOVk5@Z9 z7c*bZ%mRlziUwjApag~_2%%^mCLhNJFM_}T^&z6cJRMxvD>{X5h$&L%VT_*zDN1D_ z4Q9#UVF>=2#sGwNVSsqBgazC_XRwW3#C9|adFo`d-^Q>3^GguEIk10iEe;^Yk1G?^ zY!%=;UXeuh4E9%op)T;+5Wa-}gj(?Oi@vx*j%;__YzS0u92-3r205G-g%U#57>ieC z5|!40fJj)8*D=>*w-~_!9W(KF=N!%FG_h z%`);hRCP1Abs>;q@P+GH!{kD^vyUtUCySAxW}&)iHT6-HdfWN(cj#@ga`2|4eT#mo z(*!|3=v;)LuHmAAMq$g5`@r34T{GPkRTiGS)bRJ(HuKM<~|a&gqc}^ zN&{S7IR@PZ+ku9kl1JalCafVx>sY{|1hjdhpVG4b1c^GgMLf%yhVljzE0j;j4G~LQuq||?< z*-SU7uqtoD$dv@Ppfhk_SSe~Sm+(Gj{~~?$3NTfKGOQC-P1!i_YBM3cVXQWU_LbOj z=Jz;D37lIu*m;pMg}CMA-|Nx5@Ao}NkC~`ny*ahYbim=%V>9{gpkxCSkNUxH3KeX z5WWi7RFXuc!okTF4%QF%)syq;YIs|Q8!l(2lg6t}opft`O-hw6Hr`L=OZOlLt}VHg zYK|HF9c6N`;3wXu%9fW??W#&_C*&c^Lf5@icXTLXE2oNeCYuT`Hz$B=NwKKRMapK9 zrzTe_${Qidt}rl)T&X;6hkquImRyeXaG*|NtaBm>7jwFeSi;Par=i?ww)gH&o394tT#GRi@ zF`~+Oj~xZcC3^n38iWya3`;S5@!ZbA*q>}F&V+V?#PuEE5o(w(lyGN5Bw>(xSn1eh z&C;uzth8Ti0+mQ@n4Z*E>nG_2^XWzgS;DLd!P1w}lV4MTl7Ms%0Ra1dNC2aU;B}Cz8jm7i0{*i3M-%*hX78vW*Dp1#(Bwxi9Y@| zw!zQF0I-~Z6iI;FxteK4`^A1rlPZr(ODg=>d0*%kxW`lD=8$MM6?@Dl`Wk~KulBO6 z7T$pHfJ=>(WZGV}X;^3{C2?6x2%i=ldrGQ2N_bb;**eX^yUw?y7DU8?lDA03(+8yt zo|3Aeo@kPa7Mo0+WUiz_UGkogLKLWID@dmyc2LqkYkfiwQEc`t@O4NigX8{%-g>z# zWYpRaZa5=OIuhS>FYbC=YfF*zMfr)%(-9bpFE(V%x>Y3-MEB`T*^j3l&z{uG2FGXi0y<}=<}FHb6zo@((M^w z5HyI@LXW4$b5^Ts9`lSkT|HmNMoX^d*PDO1P^JpWr=~(k1heyzbnhdJVHYQn+ zxPczE_p5EGGbVQWIZdssb7xG>QmZLJWq>%T+9G%cvd&RB4}5d zo0KS-HLtWFTJ+OgoS(X`+XThM50oZ~q+J50@4IxGz#NADE|XRST36RX~9Zn+MO^z*H5#Y``u ztO>f*^IU*UN59)*yp7YEv?{U!PO32u!8OLf?ZyQ(r{NdY2@fCJDil`)$I<)6Zq??s z;Rz|#ppJ#A?`XC;@<~rqtmrpzbnb<|x+1n7!`1r+F(S)FMBHFQMdR@{#5Pd~B0>ol z13T!Ml7o0DNLZvM-V<5g{fp7EbL4!s5o-P&3E{_A=0Zdvcs!1ZI$58#DXf3wg$~AdiH;8A?R*ew-Et zEmmgI(k{GXyLLFh4HBB569FK1KDYRyN&9{>+D~cr8r#-x3?MrTs9Ma!2*ZR%vZb5Z zmGLcwMR+ap=R)pSVgR5-NE?n=>s?nFqUVEB?gj3jt1fW46Wj;!kKdM8@WOmJ%xhwK z+LYEo8SBma!!VNb5prTi*C?Nf&QvJ_?In&<0Kr3cZWXZY;FQ z&sF>S$oi;dsIF#9;vjAXLq&i;5}Cjw#5ZAK4>7&i-I*S53Q9;kA;z;+N+)xozVm(d zjosx1^0_hgl+rHlnvkbP2s=ZlEaN!Z%zW7FYC1hu^;-{1MM9%=iR$EDSWP}2hB5K* za4KtQ-1yFByZW;396p+#&qGgnO|#rUkjDJd0G@p*h849kMw^A#Tx80~I)-s*9cEAjlSo_Ms}*-&C}NRveS?^bio(9u z>kv`BmejP2wK0_(-$UX9Il+0X#+{BQ#-N|qb4o`ROo%1T z^XMvZje^>U1{arh>3CaQEp74EYY*OISgflTyoq4xWcvm$=YZr`#Kn6EQ4Zk^{4B8< zkB}p<=euor+GTT^U336e(WB!-_V%6^wbn6N*NLVdAO~Ti_Aw- z&{J&}^LehRp6~Ptr(@Rn>uHes`gF7VqK`&H9sCY$#B=*EYyuckIwAEG)KW&#Ixo;D zkq%M*T+BAwhW$OeZx6Awep)31`9cc>`0qnBnOtLrHVEsVm$uGwTFl!s74>9Al(!Gj z3g@}lGSI1hy1yu(b`>&?ph;E=GmIn7NG3KQE|I;o)0zn9=aUO9@!2>8QE?b+jh^>7 z=Bn63Qo9*4t*1udOwCFlD937S9gjg=)<4Mbdg~PD@%TW>86K8U7)^=PBm+v`?I64i z`t7Ynwzm29A(Y~%!PC7E&Tw@l1ZxN+++klS;Cx8#a4Srx?Z;`O*wVwI^ntKepK+WR z_;#KcZV$b=*;||E?v@q-DojB{C|e^HTTn4nzRO|FG3&wu4NC+^g|Y#T8daEgCirxs zOQ}w$UDS%lp=)-^wfxV3(wtxi3?GUKD6y=ke)>qA_Pn)BM2L7QWH`b!mXLptAoDP< z<O_k-_lC{XIU1 zp6?;6=SS_S?(8%JD&t_6Us~9laPn=FIi}5&S9my7P&Kx{7Xp#1+$)9D9hGD_Z_oue zGg9@j3;vxOC&d$O2!!(a4+B6%)`3=~95i{EJX@cqXe?_AY@*%mDZT}dP^5&(ae8c3)yX*9qD+LZJqC;7?mUj5kU$?b6`hOGQ>vpaZGovT zRgT*#^gN~ok8&X-Iv(@@iBx{qA%`)abb1-T6Q?CI5;lt6Ly z#(@%ESSyQa;}h;MvJl}HnjIIzC=N%Z6<1FWn`)zm36%zbiQ#Qx8d{1`pqy8n?TMT( zVsy*`Q5<6N^E`Um7Y*le&tH`5^%k+_IRGfU!r=L_^b1ZN1fgtuIpi+P)~l&o1<3aW zP6&CCs>UJ>(4ejW=BW_7nz^|A+*Bj>K0xqEkM6>2Pu<66wYmAC#(jXFue?mCpuz5b z=4u|;-Q!{Qb;{@cS5v<}YZ-sRS6+U_uO#qH0CNP6u@86O^}EbV>QU_M;{KAjx$mzB zq_~=CB_+KY*`sl{Sk5g?lmoEUMQW~0XbD@2SEht!^kjbpK;T05$ zs6$V37+g5{3#k9o4*Zp>W|VX$;>3gr=HI;Rn$0~s58;anTZ1fe-Tv9tWsw(DQB5lMh2dm;BC|d zoUA#^9=#f7NQ@pM&b$&iDduIr@-_azIGjR#3Ebu3SAsW zC-B9Dq;T<}$J=~MB?Y!4VFb|Pwl|VH zMuEt%IFLYUDP}Aj4TCv>>@$jC1o#C~k7*^4TI@A7yN1*Z4|%5wZ&ul7vuV8-vEWjI z<_WQALO5lZnfpT_X!PK%f%`rWJ%rED>2Mi%OYc$)y-jIe%)bgIubx0?=#zM2)y( z(lKk82J;9)Qh1|QiNamV=0YHKOU&4k@G6Wr^|0hD!dSH)M_TK|0cwo~>uJ-TKQ9^( zweffuG9y`lF4i>_3SPb{zEG{DEKE`phn(Df1LLt2rgdV)zQ8Q^+MJ0;_NUVIbFZ|YY3mOEecYqUOA846JbTE#o&mS!?&Pkl(m zc^F@^oMo9W%>i8L)i6W@!3R?yL?L>JE~w-(>;))yK(ZJeG4z+;4li zU1&A-QGXvNS&dmeA7zw5VmY4H9GRu7%$3>5kRAW`V&3$j^I*-cV#a@!fQ($Y7iVJz zhL9N7vddJE6@wzNZPbGa$|CP+jql_{**JDGmX=}cTCeBcVNZ-HB&J6j#G`b*$pEe8 zxOO8t=BfN1`>0KTM>$CMIIrgrNX(8nMo#Q#Lqj(X8J-VaDpdl+QV_zamDM!PQd62q z+oP)vflQ&aL=gW(W{(wr>%!-8hHL9C3=7Tyf}+rSL%m^<35rhWa}rd^?5HY6;nG-u759VGI`KrGg1XwgH2R<$bj@^2&c9;5~kqqLXPY`q; zh|>x70=+^5&;TwPP^>@|lR)oruUBIw&K4O}@cucplbI!AVwZ?@ns#Xf>sLYR!%~SKZekUNQWUTr7=PprXsEK zi3Lu5S)@8VZm!fP)cPV1cNx-kmuGS$!#QZ?4l!2DC<0KcaTXnlv%n3KUlU6!$8!NS zWpmD8ZQYDR{-eALmAvw!Tv697qDnkF7P&8~xV~Nu2r6kSBe(I=Tj z=aL(B0R{TnCStT9(iC4X$@Oy;O3k@d)u(Li;bT^+ie`Bo(}q`sum!TfszUIHy0$PyK(9Q3^mi1? z)Jwf8oR@)Bl&tYb4=uvfD~vPDA|g_uAg5sE6p)Q?H8A0ZdR|`lmkn+?fw}h@Ec5gu zH#yc9mj>K$qNk==u6$mF$IEvi{z5?if9$?oIRD@Cj;+>*)1!j}SB~nXfOuaO(|a12 z3aZ3Wr@CLWy}*tDe)KH%6~ zVlW^M`o?1RNDR23oIB-qEiRSPrhq->aY**P;ap_CiqD`R@%Sij^4sQaS(c;%%|^Lc zybGKK?+UPRxDgJVLLh9UPFPyC+uE*WJi4K-#-WhwpO2f#KU8oPa6j(|^jM*DZ1bdx zbmBpa1UzX-k}MBZqvAMM`P^BOl4wn1-S(^f{aUZ2OmFt z#8S>1mK!J7Z4^#8c8PW|TA(b2iiLdVHawjYmj%_Zae7is-j7R$sv;a?XL(CJKVH{B zc-JxL7!`&M<6sU2$P-G^dCp0U@EZ$wc(t&TCsFMw3*_Z%YTKV2i+)orw8$tjqB`hV zpm71!A`2~dVif3Pf?Jf4Axxp^))%4qeq|ZcV_vOU0$~4Pj(OZW>3K$B@p*G<`?tj< zN5!zNFj&OhTn5$xij3d%G;%d0&aK63peQeRMO%0wELg#P`5m6$->%m+Nu9Y~te9$^ z%Q<7gR$NaJvAfLD1IkicCMCP!N&P3DkDgj^xm@^96RUAaVsPQPRH=9)bt%1b$P5ilzvQ-8 zqqEUqQ*Au5oLP$gcwVLw!Ee||ZmcZhfbj7M(X$w)Hd_i|A~dCfU!yMfz>Sh%iaTj{ zYbm%k)$CC)0ows4KcHn%Ypzeo<(4fPb2J=C+0WNey|qO!-NJ63l8Z$Syz9x&rwWWU z%X`SR-VMM|?SeBUonYeiOgo2*~ zRM&ZX^wSDHty~7#<0HJq>w|;ztT1NqSMpyU4$D>A?=XGQ-{y4dH5lyIu9ybmi=nN@ z;R)bCBa8rz`t%R1F1w2KIg2i#Nv_AuRVtZHv0_{d&P%=G1N!nHA9O;o9Q2?v)X_zF zroQ2c^&K{lj+_#87A4a}bM29{riN8=u5_*9(nXtBbDw@q3$y)aS6p9DaL;OgJ(v!K zLGdq#n|Ep-z-?=ban$SAY%wj@_$2?5E_T_$e2stkf5QB`Sie4Qf?WlasVev;`&7&%l^t){yDZYHq~tw{3uHuXSGpH_<`xz;A z(?4E$(ek>~0>et>b4LqOYS0qy%t?ku{e#rTuY@%VesQ_+5SGNBgtcwB#2&Aj1hjs= zDQ`)jd{_5cnU(>|#%en{&}bD|1R*=c@&tS*h&I5w#W-%;)c-EU@p#Ip^1ou*xdJ#1 z`G85a*fD{)VA|u>okJ`{IFSx%VOKe7Ntb=%?&rxsKjlJdi8vpxBV~o-vd;!XbnXLW$ugMX{kIL%libklFTPQ6meQPS}L^{IuY{xbkvc-o&{x z(%bTQO8cl7aue?;zX=5nkPS<6D5v4HE8Ic5 zp7Q;_vi5qp;%eK^K7U}=8Ein~bMY$ic_M6y8_&i_&Pb@Sz0OwwSgtR)^#EO+)-ij7 zETc0;EAhh^QAE$so=6^d5|QllB;(2JlkDkB3H0>&vB-T<#r5^(s0@YB%Ajlqd-~kAmS^p6M;$w#FUyO2|!ISVo%B@JZ!LzMXGz3VGW=ZxWKMD zTlunQLFw8JqOFxV)?ONN#mY3+O-#}rV2c-u7c~*FUWa8BiR2*SdruR-D@xC^^J+Zd zu@!D`&aTc!|L_mTSLeUGxxT!9OZs5;_TuXM+1^qle!cO({eE_Pefjb3 z;`(YsC;W%mACE51?lyj~^u|A3&hGAJHyhuz_;2rKH?xgTAFe-aRL;_5Bs zPd|LPyf{nkTWW6bjNju5v#XnnzkZxi`h52C;>F3u+mEx0 zo7wsGuYmgdm)9?@f0*68eE;I^n)Ba~ydJ&yczb$z@&5Mg-Os-Q&3}9O%`T8mFVAQ1 zPj6n1rQ~pSIlJZB$;IWnYn$HQ+1{Y(ix+=*dHG^?_|G?|Z$AC=&BqTfM}K`GWEy{4 z*Uqk#%f%_@v-bpt*Y7`kygU69-s|NzlL^4j{^!f{7pK=R$Gf8+Ui|aTpV;`zl^t>T z6C3T$PJi`s?AdSr@cpmg$nXBo!*70n5iEB2%ID87eg_dRTCHtB%+9$wmWK0d8cemf zFMj_~6#nJ(=C24{=bXn!OiLI#pTNp%-WfTS?^wax_tNMS2s%F?)q0} z^7QZjbaD3buP;u|zy0vh#5Xq=*WdndBa5fgeWm;M#p@q#?`}@d?!J9FfvAm>H;4$P zHxg&JXEzr=P*slKp?V?|y+dKpyLXj2nya7mlm?!wfq&jOnV~?ZFFy!b3gy#nl-0AJ zDL=bIl|InMH79>lWo9>TK3@JxH21dlk-=PbFHqeZ04((O?ULR?#6BE;eR=op`s3So zFWH;`Nrk~%F}P6APC@&_%{48a&CWmGoL-_Ky@_9e%f%f9-ksjQd^37+etLHrMD|4l z+Tq8CSlD=s4BwodU0hz=UCeHkN?BrRz6jHhZ!@yniyvQ(p!M=+5cqgIJBRoSuNETb zAI}0*+myiD*^hEY++gwP?O#BK@@JPHW33qW{*DL%=?09?uCG+)w-6&34ejmh%Ie>I z_;?fE-o|R7=9^Nwo1YOg)I#EbsJ9C3U4adPs^<+*Np6d0HI zNge2W(xt%>dbqplB;FU^`{3PF`>%k$xxUri=<`0D-Uu^_d>hX|rk-K1kibylj#u%# zmM3v8$M4Y)wG6J7wJzy2)-`IHj}g96MJRvAuRAjugqFCn_p`IptBYHC2=hcu!A^EW zztm$D4^X9#48Kr|({pM<4XSt-KYV+Ecbs8WH*Zhrlr(DG9GtwvT>kU)ToX*euKsJ_ zYrKWbyU|d?A1tbyx{T{)pOUD5y#3hyJzPD-`~9kT*Gxb>T2~el7An4`jmcI?21P2b zy=oR~>lBOLb%VGIpCo_ufPiJ}mZFIUZPD#xTQ~1d|8sT~-J5qPqm%QYrM!Hjl;7U( z;Is=nxS0lry(ufriucPXU(M<_S9iF>n-|>+X>&Z<@5MI`IBsSy|Dx-ZbnK0;CnE;C zaK|2_I4!);M@;-Z;{D-LXEX2!G`OX@Cu9}Ez@1Dl_I z1qO5Yah0>0a#5WqXlYZSVs*57U}Fq0Xro#88}+B|1E9YbU|dG_H?FZCWMa->RMGs7P_m}xAaD9TA)Tw9rM`j;hn;hHY- z6jFI{^-abgN&{X<$noHMoIXk_PBY%pZ9b4t{<+bV>Jsz#8g-2%O@9?P)`hj}~%+i+g*$*Gz z{^_OX;B__on@CMIcXmOl4|Bk(jil!E4`dvsPIwB18vop8X6Raz?k#d86smaRP27YAiNp5##MY|{6Wn>4JI?6zQ6wXpQoSx`SgyF z*X<|Rw=tRQio&6T#+kE}cbd~gbK>)vKT!Q>X=oKZ@t9!fAP+6Hx6j0n)27DfGue72 z0xuYWm;0b!KxN_cZFJ!5B8saVXXlg@mo0kUpS#lp)=N4&ddi#GH)rB!v6;3AsLKlm zu+9hVm~YYTx0t0G_wMxOJY&)LUQs-s{q^H1-ly9e?K%J+2;=r!v?{&+zrCXe!}rJbbmGI4VSos1wNpEbKP_t|4J*2>*w4Y)tDX2MrZFLh^0x+n;H(Q+iS+t z=MG^q2BW7r7pIH4p5Y;!AH3%JUC`n4qo5=7_}g21yEiZF8gxddSJzyEeuv{rs=IJ! zDp1EiQnMGPYFcg%MJ+qOK&`guw6C0TghLC1YT{L3JG)|(2~K8peP;75T`jKkX4bj~ zyNlw!#ftf}>aX6nY<8VR^pUq-)v-rZ zs5DexQ3HGW^*(P~w8OPHB2aY3rUzI|)!q)~X}a#wd{Ss9YC}5zceoE-8bbeg_m%+> z)Lcb&yHjU4b`4y+xnNC)dCKgCQ%Fd%$7rrMT04*p#wnq3b%QA#GoX?-SI!wU(PhTg z?84i$sa)`M*CmKQXbqUkY4r-lxjru!C)t0|*x5~_MkD&4K1-M3cc&MZI)Tjcu5s&n3EBWt}Uoy6^n9xio93@fcpytkHSe}8_~RbaWgx+ zetUKCpNIl>a0#cTQ*ML8n>)_5ljw{~YGAUp>7eg!mVV~SHLqVg1ir)7Vhy;)Xoqd3 z@24MUw!MIW!ez{&U{Krzc2=n6ItCx3jM*3x;LilLIxcb$Tf;cvh!t-fsyRPe?0VJ# z1Ke}~uFhpl)~A#*c+u+x(R3?)>4jnQynhL6aD}lpt;_`neJ;&9W_mXqw?w;fEuh1$ zZqQ-QehF*OU;OD$tc2V#^oOvyxc-Y5z%wkq1l*tLIQMq{8({yH1qjvwA#pe(b+!U! z^seJSz0@_vcwmh(V%1AIfhgSzJYnSYrynlf{uj%=KfSoZlxC;Sy+_-7;xvf1 zM*7%cd49r`>UJH0qoB-JP~Eb;4Drq{Ztw68=}WPhTM)oygFr^|w{)i;@Ca*0(crSP zEiT=;$Y9nJuya&|u`C@AIWfp37ctP9TR__+ipz>g1_Zdf!j!rnGapm4IH?tdW$|mh zd{Rd&7Us9`of#Ee(;uz#RP-e~UH;cMx4#zD)RE!F3Bw*9w}0tks*AO&>bqD}yM1}1 zlV##%Uos!Z-LggrN7IWjdU<1))fSrifE|q5y0+p+%@A7{;UY!mdM~$GCCvEn5)q+2 zj)f4l=JdYir>@*&ffpGSNB`sd|9TsI94u~}WK!_v;_bJ$Ki~ER(7(L+m+!y%H{5_UW2OZr$+-}imM3kc<3S*bcT^*Is)K?;7^X2g~!Nxl-i0@?L`b|JvAq(n~4}Hx4W&`{r^$Awp5k;ghTvnW95A_n2@`}83g;yHh=q$4CZm?~{qex_YfD40=gYrx&DH7A+1XV%u)%pYbKJMYG_iH1L}tq` z`3z=DbRHvAMtsJFGL6Y;8a}FeJ+Qnu2i9Um$|o$z;8p+#=g@6@4v`TIYXJ$X->}H^ ze$hg`cwTM{##@rr(7N#R#Mua8OyI@YXBBgA$i6$v>yWe|(!lk*>oiNAZ5E_Xo)jB0 z`6^e^h+&V)yD4K8upHl%HH7zT>{kIDth6iJ+!im*7aaT&NTst=waT@{$HXJgo{RC- zpS?&pp9Iac04Q9E=ue2V&6xlVMk)H@+r<;st^G_DveEs|xw^TYi!G>KbG#9%JvbONI!SSv$Z!3lL_Q%>MCq3a_L&G8=!JJbss|0;`$+bPote~5$Xo~t8V<2mq@+5saeohFafh7Y z&4e9fJ+f;^pBO5fG=smC}P`3JXd6H;yab`k^=+rXOeyj9> z4Xhy;z5fvihE*@j^ zq)|oImOhZDPWsO$O-fiGGNf`%cZFH?DLD- zLN-+Ma&vyRtekF7A&U-%tgN8e*yWBKAr=#KT#l=u=Bpd%7b_PosXSmMMIjz?JH~L2 zT{pn7IS7SP4>3|e4c~@x9!%xLV4QD6w}a1RCVwv0lMvu1^KIfCe!MwvReWw4+3sQa zkqH4AM79(oa7#SrXsv>jW!Lkz8w!mjvhOaiw+G$Glq>$|_K_WchS?V3_BBG4AI%26 z{vXB7?>8?oH^{K1n?0Tp4AFzGSf`{4G}y>Al>#}4)UtXLq2!7sd+GNQ0#8zuK&;7* z*RU-sl37?AiMcqlmWwSa2HfK2l(o?TeA05MaSd3t0tshh^Ry~#6?)1Rp%6SZYW^;H zXLgotJ-wh^08W%rO=3DT|C(VxhUeH40=gdTVFGOz&|n~+x@u{vtm>q&?nONF&GPJe z9k#>c_MBHsLc55WDoE7H&u;+N+|WSnGyeT<|8zelL9>uDg8|gsz!;wGCnb)2vCI(! zq3;GkQG*b+yTJ~92~blvkoxGx?YJj(IFw?=Y_7U;zKCYwHD$aZ=Pba&B(ZZA7Oq(& z?n0r}8N~DA9AsHA;| zkdVp&;3ON+Fu?-Icv#h7f(e^0%qCWz3eLPG1I_g_b+7y&M7xPSHJCPzXpUMFq?3*f zHkY0c(g`eTwiH+*Lru^`=y&$as0rQ=NeZ@w@ZDb7`CZvKA3&y7bPT?XxJP}i=;Sin zQF^ExH|H^d$!C0Z|B8KHkAH#13SPgzHk6yT9vgjdXZuBfFksSP_f1q#?joa2O@mkime6!et5eZze$3S_X9URt9wI6Y_9D$iOBWryPLGqYHD51Tlm4kax=?@WWa&$gNN)yjHK2}7-?PpzkjoOx! z{R?idtZ08mqA0E4xIMVJ-ys`W9(aODJfW}a--RigG$J-j-WtNfjE1XL3BCQ z)eOcd7bM(dM8FlXgb=cXx%PCXq{Zn+ss0udNH?OL*F`3C||k z{C5S0EnB`kw))YIrRo%oQii@V$r`88vgoEYxPwaY3IJm4F|U@DzYX$f2dC9wBl^5=ja7VP?MBL zi|6m@-Tte;;$1P|C+*J@t>N4O;#fl)FrPx|>vB#Ii07htdwGrd1NRSmPd2C2C`y2Q zpWMbqJ@!rPa0?F++oaW{b#A5JFW^BIDoe7lCC=-CEYKIH-k(VKA+U$AST}kZkRGGb zdWU*G^B0+u@QeM4oCC42qp|kH3$zpZF{GepO(zjS(|0V_UsWPD3}{sG3S7!kVFsFc zbV;8O_lb19qHt&Zn5VvB18s>*4=S)s>50h|zn7+bgt$Qw1T_qy=)#rJdqU3$Rm8Sy zm5JW8p}pOdRy);sJlZWz3K87Ok2pX!D}}1FqxHj!bpnK5JfJgG!}^Z=)B4Rht(5%( zP!UWyUPrLc*N@Jwj`-Ps_%iHo-=_sFrd$czN^g5Nm*6hkjG+l=kG2V8{BxQ~x~rLQ zP~hvdF|xrvuqZI(C#80CcD+RZS>-KWyk5wEpM+-4yho&d>(Mq=aI`;=r7DSI%!ax$u#@LQ8B< zj%!H{Z5F#!G-gu8PNh(n{?cS544KgiFd==4)01&8y}~`2Rg~QBA_y@4Oo(Svq*C3$ zbA*cz^ANOqhOX8c?MH_(tRV7qD;zDpJpYBm6KdqOUI=}{bSsC4H|3-_U9$r^iNz&k zrgd#a&68$CDQAeJ{8mF)-VdQDXLWLR@e1(xUYE7323D0YH zhJRcwAGED2yv^p)hnkL0pZ6xA5;0`zujEC`oS*q@jU>xtM*<9DUxl=T{yQvC(U9)t zP;%sOX(G&8WABI{#a9}sF`YOjN(W$p5wi`-t*bY23Kn9Q2=1i}r2kmxY zskYqHiRzh-Dfg8WM4AWV`6Uujm4Hx^me3w69FDxjthkLLb{(I!+%Uiz8zkRicuDSx zJlQ4KI%_f3UG{GWnrGLw=w%=EDYT1USj<7_?_VqH;OPdLOzRGf;Qr0#btm0y-l|rV zu$ddEM$x`@zCOoXF{>q(?XHvkjwRJ*S*d|4HX`tj-y5{x7io>cXvoYm=|QE-iik%1 zhj8h$t0_?fl@mKHzd0={svuNKSOgrPJ(}lUrk15z@tDYKUkM6@sssS8F1;!Ma_8;4 zB^=gs)Dlb9rW?qfY8|aMy|j-9hk4~pqVDKHOV-H=FNKm-8el)>(Sk)ShwEa43XN%Q zY$_w%yCl5>huq>PED~vK$;{$R5?B4$-$ttb+-lA>yHvM4%H!QM%+dqOY&v{&*Nnjq zVPBa9*t~yiAXw%=yQn#ko)<*6Ez8ysM952e^JCXX|_5)31kE)SlGJq=rDB0?Z zozQcyYz$=#)OX9w;rxpd+;TJ3N;>u4V4!Yc8~z`{ykR45ZN)lQ`dLeK3j(;}v|{RD zzOZ=_4r{`~!USrFAp8G|-nOsQZ&h;8bW)|`kl!BH9lk#Y%&Y%8@acBAswoRcKaTpp zV$1@AX-+W{sHHjWE?#M!?n5q_(nr!Q4am_ym;?WJDkNg5bM%qFORW_#*cu{d7spzvJrWTPV1RF;QfvcDUBz8eOOsOKPKOXV0O< z)%Ktj{_(U`fQlNv1JOi%jlKi{sL%2|hAhDk1Q@@VJZFFSLYE`qIA6Hkhv?S+W}?wN zBbu{yE6=$73BO&*Gm8k9pdiMyGSa-_}-WF*+sbVK#X{AW?+Wz(aH~0vVp$p^*`_cgoWetncis zK22dEsNvQ(143RFfcjkldh=5k)e=H@gX6nU<&kT`l-bv)1YK5V+AgV-y9;VyC(!J7 z6xcaF<;K!G7^!1D^jPwXQv#?19BR9lNvu1}89uFXG0oI8de~aq3}iH_Usv~fgg>}@ zuc!SYljC-AQaKx;ZDLgf0lGfc*+p5gdWD*-$l*EiRh(>t ze|l?VD0{YN%JU8rD#*VQ>Pj>bXk>iJRwc88FM=I|&6SSZ<(O2r4xY31+td1VaaYwU z+uH&UCMjk-fo^7&I3XxXw@nhHPYS2DeMZ;!-)If&>`xD{(jS))M00&ge=Dkj0`Rt8 z6K(TWLDmyzGJlp466REwsA_fDYZjCCDx9G}C?c8`q9dHO{jyJ|R1fU|SbUF$Cs;KW zZ&f~2ovG}^rv15#uPR&6l1Clf38SE01jfDE zLuR-`EZO=^M?US=El7NOPTsR=Ph{k7Pp|NS1#nN)dRk1|1EDdfA}hhVyjmp{+8BL@VB-ZQ=v|<0wf9# zXs2*uL6H_4C{cx-;Z9c>*(zKn1(%E(> z)vjO)Y}3m?BIC^XCb$K?L}H>Pjys4k_ctp9BweH1h-yzwjxDtu-R@_wG^88byKWhb z;a07UF9Ar|H^Jp9+jHN(O;969W%fdZu*9-*cAp1v14JaT!gIr9f!{2*ExBGWb+>6A zSXzPL`J+qRR-7%;*}8lOzBhJvB|dY8?@4-`FDtjdn{)jmm32$#13gy(gfx!BbrW3G zil?hSIDzpav+mvl%uhj?WIOLRDTr@ex5AJlV<}@}Hb*XDz}!|VR~jRe^kR*qa9!Ws z7_#u7Co!jnD-UjRhnIOKv4sg}>P?UwLyGHAz0*AfoUKPl+M}A95!N@eSxSxit(Gzo z$n+H_An|6<>pt*rHj&sa$?7}%1tVsMPq0-lUuLuV2Hm?Qfyq(mokE|mu35_TV9{le z&4(@GKyFr{(!CiS{1_qDD8}gY;}@^}5(3JpnC3WZs6ucB=|3W=f}o!mfhBdKWl3SEYzj`h z7HtIikdY1efgU*nXSE4k%wY3;-C^nG2E9P<(||a@Di{#019RY>)Aob})v+3^+d9W? z zq}Y%q5pGw%0UEevWf-eI!(DXVYDp7n%;}T_t)Ot0+KR-lwnU&tBU39Bt3X|X%!1ZX z4m~(cSkXBPV3qD{v{*jPYIAe7nqH;CGcJ9t&w|jJw_XZ&mi*Y{p2$*xL5&zYmklTk zGjyo_P0CW+=i(8}&CSPBIMoEI7kun+HLY-fPnz4t;F4(17~7cic=7V7S&yQrbwr*J zU9k}r9w4!r)>v7s_u*m+g<1k#lByf?1xv$UPG7*vx2TJpdxBk;1=o|e_91EbYif}I z+-5WO`SR70yaIu_8A>Bl+#I3(|ElDbf|%vI(y zl%=d#NqKQ+ zt6B6`WYS02By&@-99a(rkgVh?Q|`JxjgrmRCj==E+czq46NTFNiOQ&AhcyCJ`bXLg zHj&AvkpZ!gw95UC_1Ozj);6ctFhuWLvI6P1vJsxb6Az}@N?{+t0e9p_68P5#V0HsR z4|cZ!L@Q5+^Hz=PJCr-RKxLCyLBx;El(fqDT3R`x9XAOA)!gmSq^j4tEf{Zr;zRjj z8aI3H50d7cBlsQ}X>EF9NW_taQSDm`{J~k3QpFjmH2V+o+<3iM+}1HVx^eBTf}*P% zl72iht@VPm{h#jn&3ivrTB!WVKTOH8ifz<$e)yf1w>v4>CwEd1VZhi%h)|iJfIq5T zYd|%1WCT0)jq$loEWHcl;H7#27lI~tE#WnE=K1`Sa`mN*o2dhy}UN0-*HPxsG1q`Mk3)lR=%p72vr3LHJ( z`wUf?ok#Zs!`@!tt-*3TumF21>3USHY!f6yX&NqZm&P#@wx;!>gQj>gOzvp{EGXPP zIJmj2^Ud%QCF=mlf}P^7dBMVotorO0Ffr}sMy7k2SXYcBSh*_;duT`AP?xNbgBN_5`lkjfRbp;$w&g~d^10dEc z82Wp)@ZroYsl>K$Rz~&*0=P@%QrNNDJZqwPZ1=TwIHqM5Mw4q0pF?jT=@HQ?2;G?l zt=B??(vcrK1#OjpFkYNjHvdA)JB+^; zqUD86KXdqLHgCTx z8-VbHkF#auUWW{^0Z$X+0;YX18Wtv$sx}qkPVInD@D(Pl82dOm4D9=BkcQ=ll&uS( zHD{UAQ47Uy1|3DeQI%7k)dt-}Xnm?%pYVWdYVUE0biY8lMa8f2K0!77>pofJ+OV#c z7;E(g>^=EcH-D^CH!3hCd0E0xlGZC132ET1YXD-elwzT}I;8AUY6%bsFz8FKH|7>p zqU;vxIwnyHaXrNXAj8nqjKha}5|zfO`ehOf*FW(_*Pn&Em>IoVWpCYXxf4tA)4jv} z_bc9QgKPnbwiiAAMoqXL!eW|a^cfWg+9(UU^NVq!CBDCoosHJ#E-7x2z)A} z#Rq4O)MTmM5@Hjx8<+1hW@2O042H!pu8DJA)QktktZ?xkeri4%Suz74d%V6Mgliy2 z#4*0|;qT?vWApVk{g9d!NlZXHq(<;(msIvbEY-A!J9(Hc$q^VzEE&b;iPl4jV-V#9K`BjrzyHdOeu8e9w!-Y!p6oTR)Wulm$73lH4qlW zesvB(MeHxNV~U|4*{_qaUB`=i?>V4%@hghxjW!=Lm7;?#X#P^A9-*7o1!3%L$jXVv&W;n%Pv#L!YyRJ44f#>ijx`<96)hZugK zVNk|E&JYzGx!wZQRrU%|`?QKz! zCac=DPwUVr3-6IdOa9t;B0s!zQpUrh>-WQ ze9fk(Y8B}gS}Aj-W{^rr>TXT5?y|Rp#^73!Syeo|DZjhEC^ueBSzV6cP4nYT(^{6{ zxrd z#Y%vNse2GtnX%d<{EL^NRz+l>@iK-*g$hQ(Gwt>)`1K%Kn{7wv@^41|@UjIT)+3ia z+Njy#-U!G3i$=5QtlL(h?<6`0GihuCYYJb^q_f(+yLJbujAUZ6vrub3=IZ`o4{Z}R zR#u?wMGnDmoeli9RoawW!LFH}Yw|?S%m~6e;Kv@Fd8W94WX-^Bl}aSZvzD_$VO(F~ zpTjA*gFkUWMubUA*|71k*bw!t4jhB~GFf~PFAk4GX=cgIARn_o%qWjN;qLeWwhU7_ z8+Fo}TRU6YQoQ3ojEGs^4(pyr#JitRZ(nIrI;z+|>B`wLdt+Z(-9iQ6e|Zk}a0WT+ zAb$nwQBGg5u2d>}SM7+vZY7O6<-nt3L`t3nxid*ZRxKYKJqXK?G0&c)kiwe;xNMTK zUgO0*8`^~&#S%8;wB&e(lr?ADj_oyWB3VEXHUoPKQZWu$vv(|6i@$Pi_S(Ap@q!l@ zOe1B8m%B+8tyGGp#^Pj>R{t<`vapZbgVcEBuXjYBTlQ;YqIy7B|dx zp(MFxr>LgU_S|`887L;ZwNU4prU#lh=SBG0GG_M{TQ|1+Ua&P<%jlEi*b{BTIPEYov zgpD>_G(?4wal)J3-RSM<;-7k}@1`l!duKQM4^Hppk_xfWcD`h2j!PXDN zZyTTN&CC1TWfMs9SS6tY_GbUT z8H1kg@_bz1CeE|EFpj`H{48|wmP~&w)LJ7@N~@9f2lJZjX5(76f6l2@OoM#4W2Z0^ znI|y-l+ys`7^&7LA>ToDWUFmMz3-GY`m6^j+O%s6h5^~tA){+bFUzy|ydL$<&aSM) z0vJJf*q?NNEf7)mbV2OCD_Z+ypQKdz+Ws|7>ez37Zm$o>csC3j;!6IDG_+_ZGJbH> z;>hw;ihWKU^%Ag;{{^)`rTiJu&={dSN3Z>^cn1B5JmH*cJ4UnZW_AZs zCO`QsYrC`i&70h+4%ox{DoiNjS8vS%kOLyTUCGy?W~6J;En5Y?wF545Lwk1NEt_42 zU(6x%%5$d;bz^5+X$$<$_jyL8)gU&lXZAQ7O7TVRXeJ+{xpVZ_WuN=r?4~w*YKLv< zhJnA;zVTcD?dqr!e9$scZymgm@4FABE7DW-X`jr}lFl^ZkBbIUh*4Zq0K_zCTx%luyCU7KK zRj1V+NyYUkx8OxQ$-3PVfujB0n zKTX1)9W;SwLuDxQxVI7v4|{j?*d)Z**pw*0pL-gGZg$ro7nn$q1kuCmyKO^HIuBHR z-hjozlo5pR=9>SujtIx3#&ALuC1d9^aH?Oowz)C4ip-9f32LIH@gPXSuJ6Ke|V^Hl8<>2zGc!pshV%%4+lC{YWB~8{3kFlAwa7v{{kfM;Oj*{@Hfh0zN zt%#TCos{}##HTfTHnUs@}Nv@)7{VPlMDR_O3l;FHWV?HHZM2-7k zWam*}gU9a3p5?q`kc(k?$>-pCgmNsKb=A!)zdW%H-A?PKFqdYN8()!BEfw*1$W~ud z0W6XTpi(bt2RIs#X~ho6ec2LZuiY%ORs)*xm4oGFdpDB3Abo&4>?!ckp>cI@_Od+D zSpmpad#%QlOM>*I@zGfr-Ms-1LFdXOmts~_-3#v}Jk{_w0BGYX@)cDsq>SX$oR3nN zjSXS4{GMqHd$`J1v*U^*&7^aESxV_I&}JI`oWqA?_JGlLck>16UauDG>!la>{Fn}A z!G9rtkU}J%zmJzwtYE5KIoP1b5w+?1^oI}1@AkGwmHIu2qH3ZJhO{rMeK%(~D*u7p zLLJ%p&Bu?|JW0V_o0nPs+b=GRA{)`PO3H#vFP9aVEofPnt#Q&Im#N3zHHzCT^vlJk zLL|u)&K(vdJ1LpB|E_K9q*&b-_4lla9^+|EIV&M&=4(PxnXG5VH#bJQnSzmRi z{%Efo&1X*jQS_%gMJC&Hw35^(vL_-NIKpSHq__x(Yz##9tt3~sN%}Y3#O9&WpX+s1 z;SEE)?Ucl>SnP2I|2$8u#0?RJ)+wPaX)olJs?}g)l^i}El8v<1D+${1h03a$5NJI( z-(!yLsbhnnr`m{h_+TEGc#2-yD%exME%Q6Il|hTpR17yAKMA%5rOUGFLmO>Ru`jc) zXC{?tEm+lTWAMg9OVU%%Kuy*xBXQ+h1i3RY4cW+ym3hLur4aWFfPra1(cObKYTV75 z1)kk6&)?M2@BnqI(E@op!7a-%#xf@F78NqSfr+-D^ASM9k`7UcZ`(iw7)5(Z9L%Z^ zE+Ik!-Vusw1CDYmEHQuazHhI((K@HO^&|msh;S(*ii?nR4Aj>LT3F%r1V_E4lT$&$(d4?_pnh;wQ0=jgrI*$2=CTFYJy+ ztz!56!}y+vBt=yDYZz9wH=bF#$PaE6_b4`XK|}xuf9h<}D0$=*^X3+)1M4(iN8!QZ z*4b1IY&mcVnn-ZpeQ58qX>$Pm_5Rs=Vt1BNe)KR6GQv;t3=o?U%Pk$5Q=X0&F6`;I zxkMqPndi)xH4tg(vPiTKWU+ND*8#9s%op!EiRyq!CYU$qwQH%Ee>ijEJjq zk&9eUV+B#tMQU0u;A$UO=33p3d7h<6sb+0CNxs2!HW%||vzznvYr6V)`qYTcOcjk%W$JedvH)<;YPL&;?NR@jlIY$Q+@*rz_Rw>&MU)OG=wo;)&zhOZy7hheR z9Y$d;Pd@x`@#-q6G7RC?XSkEkZw}=u|9u2BvKkfNZMH4Z>Bu$K2{N!bqYBML{kGL_ zgw+tp3sg=El-)QC`f?xPov)YeGbT#EN|PBgXd<;b$$xzM{0kU9##O`F)`!jOihPSR zrzED=x*RW_^|woADNlL5=9>?HPV2|1LX$q~ybyECm&<$&4iVn*V9s%2C~{A7tfo{+ zY7dduj%mh;+nQH`j_SRhoKqVYl9dL(r9G&!vmVwcPhc?3D~uJz5t(7`@nt3-%PZES zC_z&8%|NpGGtv>qxxd226RsoB0y%l8t*!d{nC zYo*?oY)Y#;Ov*N}n%;US8Q}PC%{M9Ylr4v*9h7@(Z-xF9CxuJGDY87AKEA6} zO>qMH$gMf>rHgu6ZMuYf{$Tsk>8; zL7EK1G?|AjAZ6BT!&o1ke9ZlizVhm0mc6ATzUTdp8F4WOMkOWCQ}rtGO2CEL8qV9XOGFV`_sr$_{wuZ&(mB5YgQ( zVZm&%_>WS6f0ACq%rvNkAw&^7P{Bw!wKCS)lZbP*bvfj*#vhNqCKw7iY`J(IM6KP& z!V7m&5(xC{!-uL$*ftuj?WH)2=M4y;>)l}r{pb+pATMD&0br66Z`pqrj1=fj6^?dd zrmWs@)m*F+5q(X?OOx0=UJUh-?#C%QByMP2FFd``PR|PjE{}@c4M!uIF&Zvr7EH!q zoh~>9S@Em&D@LRdna(h1+nm6nmiE%D;jH1tju zGp(>VgM*vcob@y|pet+7e*pqlSSR?@aC)-*Fj;LV;8(3BxJYAWqf$yr<2u3Ee1?^R?&iv!h znI7-i*HGL(es|?!(03V)z5oR++^Am<;LirK%afvO2iZ2H2MiKxG@iy)iJpSC?3dvR ziP}z*SXl|X-qe{}dR4vfnnK0vdPE6KEN1l9kKbLkDE-7Acn|5DirX30jCsrOq!Ry~ z9B+EoqknrDx}%t2kdwM*!Fk1cebzR;EX~n-V8O&D-VV;2Nvh85-++-#u(vf9YL#o= zeQ2-t#Ko9$STI8lXlW*J74glaXb8k1@NwJqv=^nCiX))>I{+b1d zjmLH6>EhXs&;Rt*H{XB$*dse)jE?AO4(@ zMjOPsdi_DWSH11&>6351`Qwk@JaUtoxQ_GaCwUNQgVi!a)LGm-Q8 zi|>EjpZCh=gI(bCC0+CR=-AbXCW}?44R$>^=;CCRw&$5^I@r zZzl~^pJ!8AoDrwl&YSnVRg-{k5jTT_GJKP?#c}n) zA}P1Yi7bp=wqp-dZf{C;d}vF^h$wNXrrBSTchfRetvn!viP@&rg>7}be3EALVkCOe z?n$mEySG*-foQni{$VbM{7f)m(m;LH;il%G&uq}5iljXP=j_$*v7Nv}z0V!Os>8lB zKq*%4XL6Oosdf*uc)FO&MQ76Mq(oWKZ*WFaSX)Q_kibdEL6In4&t+L&Av+dk- zA~>T47BX?0P3iXnI+2A=SjugZ$YH02adu4v%kpjqu|m5q_DNFAr^2b6SP{zXpG~9u z`2g?^-g{e_N9KI_?(;Nm3zC_r|h`prB#boaFoN z`)4I{rXUgU9!;*$)aG>fW-Sf|7`S3T|8atZ9pAf^AbI==@a9&6WJNjR5Md|;u1JeX zE|0ub30}X?5ze>Ezm0ULImr=D&n>REskgypU2p~siB$kTG-<0avOTc$xX!F6v|E7- zZR6Vw7V32$*9fFGNXF#gz{2bP>gWX87$*SLN?`Yjm{Lbv1@R9KY#TZS>!yBSRD5E3Sa#gGqU%pjfVI2 z4e1mvJG`IsfX8H$WBL=ckm6O4xxcqZ+yyrD8mp|~wf8VEoBf`%^ zB`8Ui>Ddwf`Ey;{M2!}_xAbJ$D-?ylEznKm?SwJvzjzV}QKG9up@EM}HVtgYu^>(EvXYF9#ssKv! zY+RpMM62Oo8Ras~C~Q%)imGVibrpHZP_&WG>D)vk>JULQ8ll`=R5OC^`0{P6biG)q z;c!F&bIOOUDwa2p5CDrzOf;lb%I~_{-B3hW_+^7HvELzGu5=*XkEA$rSQ+KLq!~}r z4lgRCMID<_9l^9#(z>oBNt_>#({F@NSes@&hHf??;le=)AWa~JzX0Qa0go4NTE`~1 zwm4{AwU8y+ItgcKalf}(&&!_x_`fbOKo-T^mAeN{OOd+-k)wcqG#fUQwzG(We%dcf zH;|-WH^)Hp0a?vndy9g|M31nhmLzZcihS*SonL>rW1n(g*>PXlqyfZP1Li`Cy?JA0 zh(_U4j~D5j#?BZxHIOxT(Ryf^=FV`lunahZWV%e31hk8(N^f~ucQhwl(UcaONd0Z1 zh^&mZmUr_RvIZ>IbdK;W87rY$oexVAr~qz)DYP5iLEbb!!T%#}`j{5d9h6s2eUDNz zNQ&pxLf8h)YMGMCsm8T<_bByQl(L?Wm zwBUVCXwiv{pl#F}sJQm^h{Ek;NIcKYW?Q#X(9etnk5mj3)08Vvjd+IK_=!ef5Qg6} z{kA;zx0AMxLitg9&3nCp3hjT>qQSbBQRue{@NT`X8HkzJ-wEnP>Txm5x?s_AIQ8sR zhSnQUJEt%O9&=QqBLihC@F5$#cxnn?X*NgNG3LiDkeu^Vb}Cj)HrhK%Q)&zHe3cnC zX}>3+O*SfK(u!_jJ=;UwYLs%CrEwdY&~BB<7nRtR9Aqlck?&^9(k0RMe&tiS*ri1u zJDb$ob6?!!V+`vNnbA3iJ`0d?yClY-DD5d-P8fow#myUTv7;RQ2Jsh#6NHkJ;|rW# zRgPZt5tk{JUjyw5(_`w; ztrRv*NSliFR_Ln6r`$sPU9al&75FvnzKp>!CC!#-YhyQku1xn95VvWU*wob-t5(-m zv?U^j&c{tUJ3E5rEVGkY?~GNnYM$Y39T}4dvO8lgKM7+BfU@{wn+dT7rW2cX^8%ta zjD3E9!{Z#u7uR|g9@-D%mib+E^kICh$VB}+F0WLyhP_kY?PWi&bBPDCP+CcRgA~GV z3UG}3rs}mWRCpI-)^qw$=Y(NC_9tdmZ?A*wIFf8M({ z9@hB(BdUeNY-f5L>OW17<2f}S)t0*_*c(%}4Fs`!Y67B%V6O;Oa%&>A?QkkN-i`sdZnbx7brsGqx^Z>|X2d{-<#K08MqmjQ z6EU<2sxM;L6UH>c0_*i+sW36EjvqsR3DXpyaI-+8@gZyL({E zkiu3I-I6KW5-|TKKUQ>~BVj?eGg)AX)A?juhUP-R4ad{qh};VjRaK?DCcv!bRZP^* zi6G53CnDnzl6II8fuo;K#Jx*J3C?IATqVlY_Z%BFXh`giRvU?P45_=uM*+qS7q8kZ z99(m0%>?&SHq|>)@bLWcnkknLKd_DrO#ORjh z8+Pk@0g-kl)rkui)iA&B6hzo4|*P z#^q>&l}8x#Q6imzKa!cTJoI28%N(&c%Mg2gjFSjdFA-4lfMFYI>*x z<6P6|**mkI2{Vg@67&x{1X#j`yUvsN}v4f{fi~GL-xQm=!s9%BZ3? zwT5Q4ir&%0GuRR#$JMO#(>sb6QJ8@R!*;lIyF;LSnvr&?c1cw>J50A|n~jVD^H*g7 zhjF8msg!`siJ`9NVd#Rh2e_7Q(Wlk=n#dqTP)=S2^O^1-Sb{LH!X?MbO)LRSryb#$ zCP8Y58~zcpDg%B^_J9uU}N zt9S!rq_>k$7_|*fn*j}IqYOZ zBcHst&1GJlU1XRy4kukViepzK;yJj~XNbBb{gr1Xxd;WST`JWW6mn&vR=UcOpi3bs z^!C1T(5KW?65F~?x(J<0eEDXb|E*vBdjH&4+47As4j3VG;x5)Eb@D_MRTyZ`_7ECd zRiew&1fsLhorkhT(@{)%BKTEM-U!qns&dxjbQ+Da!ya`x?%aSnLjpUixplT4L+pc_ z={~%;seUiRc(ibw@aLN~Ueuhl_;&GCdym{*rs{#3GB)Uz|Bq0kvXHI&ejE}(RZx`K z@@ec5%J$Si-u*TU$%qe*l8s$^}w*hpc z_i45+3{2bhoN}HiQ!gp|SdR<+%AErJeGz8MJIAtd!E}gBg2pV17Gm=CU$KWZMb?c; z0Hm5ye!q~G+aO53UVG2MxnjDb-O)&Okw}1~N zIw?MIFj>%eO?Z@pd<{RCj!f>yrJ3XEmW4aUBXEId$}csu{B9Tw_gwX7O{{%Z0-@@I zx7V4_<&xKn^J4}^>Nh?0M6u~$Io_uRx9ZSo_Str^o;6T0`L0QQdp>75y8~i!bK-a> z=(@wF&SyuQd47{Z+Te3bS7E932vuAV$3!yY0-0mz7PhmkZ1(5`ZlE^_tts8{2xu;^Ls{ z%KN8pMW9lECbkBO zjV;qP6A513c-TWvK#Y+;RA0qXvqP;Wt*7+tLX45yOlB|F^g_E0>luO->#Od6; z;4f~=Z{DZ4vFm(}*;%#9G`7yq^|F0H3U)H@aW#FjUJ?){>S5zDGae=trZK1sHRQDd z7qJuCjmRxz@!qV;9(FDraF_!e+X%8!c84I+y9bxcObxGu3m|7avXld?La#x)%cGr- zEo-KT851u?OydMkFBVaeHu=uu!6vZ%mW%~a$t8q;vj#hSD(YsRc*Vxs<{{hMmR}W`mr+BDOC*F4d;7Z zrDe>|c>DxlApI6Xnx@9VCErd=uUyW;;yg4=wCTgRYKEBv6ET;L&28}}hK>3%GAm#{ zoE>(DBDJ2S^%swc7!-ZQ*OBO3?ieE@##{zcp1p2Wc&H^d3gGsFz34?g4p{D!&+l!kFEyh<|zq?O& z7l|}S1jq-cMqo7a(F6AB@WH#AgZ0bh#e-Luzx#I|b@S@q8TQBz{j5 zIP#!{25~azV(68^LiVJ90)JCplii@GnXywqSM*a`l$}K6t!mKGXD@nlf-Y7@Rm-R? zNbS%m3_8$=v^*`(@nO%teDMQ&`~BxX+~;-gd@T{&%ZHm=_Z_3!Zu8_h6un$L{qnnK zUs7B_!sUw0@g84(Gu?z!4Vx=>*+4R8w=uQ&^vh>oep4lyf7n0DonG;dkK6gP4PfN0 z{MpIkhiN2C#3Tc5ju+oD=D}d@37G5ZRLJwi1OEEDL7l5N;IK8C)rj|B{r~{t2hSDS zuZub0CmO?qO!Qxk5gH@0ZW0=J~UL%-4(m@FNrkLl|;n5H3$rLzGah%E{u%{dK|IU;bRfiaS(M z>JNrd?T1uY&UU=!6S|2xgSZ}jygK7ug?XW~CmmSCUMSz$(&2|n+H>I78qYac?`L+TV^!(zuqZYJDi1^MInb*Ow ze{nB%QlxIlQU=)t8?Uh=n;TW+=(TXZ3(EPh`S4Mevg=G<8G1mcQMSG>nN588ti@R^ z_=$z3ABswwxId>YXG`kTKBW~Grcg&J;H78Al)r9<>xnx1^jpb-yvG#_NZ#HqGQ(Q( zF7?HujSVCPyNdkpWqvADax{FEO8Re?@$ImBzQgs7KRsR>A@6vVkMC`yGaI|Mmy;o= z)RO01|E=`sOBYi<$M&Mx$QBli{p4CFjWDJP`QI`OJ6`74P?(qhTe)6QSS)^|#5jE5=k*JBnY&jBzsr>*$r5$-wCn2e zqAO{5zOh@S)VoUhcq2Qow!u(bDBIlqu(cIRHy))lTMh)0zgI);xl_J%t0OZ%Ezmk5s_~Fa{`Y--j5!0zPq+)j0fA?u}?D50e ziL_iTzHtEXpJbF%kk^=>c5-vX6xl-zC~>*_1RE(rX$hZS-281{VTQzG(yQ0N=mbpM zB^RG8zG}qF^E0im9^@-V^}c+_SpD_XG!FhBTe^Qy#{s!9`HAK%5+}mFwbp%QA_HAL z*ndY~W@=$xeYnrya2|Md@d`*Fthm14m_f*Y7|b@a0g<7j5)Z+)kTjb03e6I)#;M?{2> zXERW}i))7ATlu#;Q9$X{iY@LYKz+j*mv1~7`i6PHDC~9{rw^1%yYZam9CM^!y*piO zZGYHq`u1ozN8SBwSccn+fkK)xG=ut9G;t{3`rbn|K-e@Lgy%a^fgp3X?ammeI~p6F zK8i=YAUkGFS5e*qy!mp51BBHmub{jn3}I}eAjHgTNG>XCk)TqiGdN;vYz z<&eGsfmm!c1snHPRM1>WQzaF5ZDTJkFyZig1A71wfZIjw+lzBEh(?-8LJ`EhUOZhw z^Z!NIJ)nmNUG7&p=uip9sWA=sqv`-h+~)0nf9#7avHsa3gRE;R=}{5unP`lH`gq5{ z=j(G!&)eYA_4M-*^cxOOy~_{rK^A^q%)PH%|>XRMu)hgx6q|L55CF zP;CPUGcbZGv%gWbzM)Kcy7(8a!@YPoaI!YvfBM4_1-nd+PVg{$(`Fr@aO4CvHF4-h z9C6Iccl)R9rF7WSX6FPy_3la>}AXLSw>=e{^xe!bBPt$8y2J}!P><;Gw(4r#ix=cPU+>T7^ZkA&O|YJG ze*gU9qms;gKezY&_IZE*bKU_ryygC5R&?=``^m!Ruda-ZRm#ub7`^iOm5KWJME&^# z%aFHtNHcL|M9gQ zjTd}naPRW7r+-oJI^x{-*}wUNW7UCWKfEX!j;c|4Flx?URzJT`zU9qVP83RUWjL;n zM)CS;Wu#gd8!MJa;&p}c$V6cziq}mPrgj}$dT57!-qLl~^XUaz0%12?C!Nub)r@%6~}6Wx4ySJ8c$A5-E~-3mu7hD^cm|Wimz$% z)Ok_4TD)>1iie{3oZ`qtRIElrm8q#a_1rsG{QMP-C+1&LC=Eqpg{q!k9hIUQPnJe` zXxEV^yhqQy@1CRf{?*HVefeb9Q`wFF*^U-}Ze!z#6W$%IKDSyJZssn&`09B5#j6)x zR1EXK^@dMW+4H&2)t>wGL}_%mFCNqyXBGzwL;d3ugNv%gO8@5Slzw(y{NL8H-Y2j9 z_1DiY-16S)q_(tVSzjy^PVMReMsMl*!Y|kEJ@(nZS$IjZn*#^OHg6wT{NSq1wR*KM zSfASU^fTw}Xmr1!`8i;(|G*pW#<*2`rfBnC29A!5{6~Hn$F&33ub#PM~tQHMWH6s&t9cB=zfUSNdYSsF+jd|;SY0DH!r3#C0tHniTjRXm{8r!_}*0xp@l|^e|W`SfVF4k-DXr)$< zS8E;*l77G9+PaWdDAg(qifU0A`0;$LG8Vhy~J~sEMGppRq!*91ll@`UKAh zs;^Df>d{#L)UK6l-wFc%Wy9|u+%PeA%g=Wl+4%j&i2?*Lwd-jYyx0yYj5X#hIs3@Q zAI?1{YR;Q1OpF!c67!2!#ze=__IgyVU9dQG@%P90#ooy$>>V>g*bL=oP)+#uXi0g$`p)@j4uC=1=5hPKmwT7bBL@fYz zs8ACXjaQ51!QyxU;vWP_gKW9+r^lv_Z2a+OijI6vV0!@_UC6{7Fj;=qb)mjG#>A6>|JIO<*?ylTf$3}9}G-2 zj{4IrpyiD#>($CF6Q3QLFs7Qi=jbcnWCPm<(tnvqB+Q47+kE@^-`!6MQ=1qcZ&j-G zcqA%=!jcfy8jOYzGxobMv}o$CLvOp?7Lzb&=D#_TFxa+YeKZ~_)C*pQj2p*8KE+b8 zUW{t}jf1y-e{DTxcUp>#RV2@zT(%)?fJh?P@^>HU1>1*?n_I9Q^n)LYinq0d#vnsC zwTBeGa?QH__`H6e7ICs-s-K#<-NO=2ujr3WA@w;?C3%Cy zy!}JR)j5PF4-c5YI;^`PWaL*gIBv1?VUysc;^u0h8rHx3+uN$eI-&#?idXl?XGIcX zrY2gOZwV+2U|_?Se_JOUWva5#Hd`)N1n_45A5TFF7UEY+{4ESzcUt4XpI=?9Blt^` z@iul{scxyodyjv-tNXOBr+Q+B((1*5#e1T$&CMsqKMva?;f6G0n{Bb2WbMuj0$Gg})^44sW| zFKk9ju=T|?p;V))(TKRbiq6SD;}acA8}IOtopJLmqBsG4u!2nKZyeZr(#FwhWnyGh z=lADDLpO65-O46cH*yzUn@q7Y6m{s({K?f`2$ZBIE^!g|}8Y&(l z^Gzg%G!i=5I`h;=k!bNChpVTM9-OGvD`UmiL_;E24_&kE0@c8Fqkuqk71t(hT4`m@ z7Z1bQ(KeWWO9$~@Uxavvs}V#1jIatOjHPRp;W`N078k1GoqKzM<<9)|MHY>>7O`gF zJ9dcnYUwzwa;1gBta9>tBr$MM`G0L3jatSPi#*^wE15x~0|YZfq%TC*WvGl5$}JhN z{90%^lom@usqtT-Tq(CE$11>PxIWIlD`Qi;o+)W{*znDJd%pLx)3f8V#(Zv&)YUy9BhroTd=Uk0aK~u0jyaIrDlH3 z%^kd8!Yo6k`LS0?V3m>B*z-_RjLj(iHliIVmdhd_=v$v*!=hnY=oft$I2s`MHOD2n zs?wtH{cctfwHLu3c3V^)3bY0>H1n(1x*hU`gh2{cz7d}~rhx*A;}azSiOlWf$QXln zGrThCw-)4PW@~+ZUxE=&j%rg*1|TMcI};(X-$*B%oLQMb%F$$mJ!fK^HGxx*^DWK? zvxoDY>p(yMx&O9xXGRRk!a!!5MULVbEWsk;FHE|#uUaKoO~zYWUT7K3*J>E)PGbtP zVWSgeh|R1jv_Q0dyi^=4)=T&+6EASnG6rk>{O^j@dup(A3B}IunMG@TJ9F1Oz9DjE z`qKWT{ipOoY3(b|icq+b!E`|t@n5LPCxIG;%f1$5;DPGSR+>Nn?jAM`6yTUW!`^P^ zEu|Vq-qOS6VyPX#C2}xok-8f8+#%dwqwVxKOXp*y@y_X)vFHbIv8_J|MIxZFTNK$ZtAWhE_)Hq z@7w=y1MGgpx=ooirgk)5a@z~{zVNt(eYa<2No{gq@k7V)?Zt0?)$pFc==H`yU;FAq zSKuK3Y)>GZM%OnEd1!=HrU2V5AAEj$Rb$>w=O+7W&b#U6v4T-C&Oxg#4<<|}s)9&Q z;yhtCFt|XhT9Ia$_t`gyhQ|unB4#s)Mho!*#3MuOcL{NHb7I4xQIOZoT>W0~=+wLC zV&VRRSBxUq3MupidasX%5H{D`?I@z;I67>~`Ep^`!UCUE1DW6jjTbQ*82`*s_S>BI zn^7&E8Ep?pfMp^=988PD~=9x4lH92%(nykTMvMEKi7@-_(OF`xc`rai|Q;q!nc^E09t4=muwGpRbavYx_)k?5Z zGxtBf3raEAC(DH~Sppb`by1&5Zls2fMD#c2UvTy%vXz4k6@=F)iWsw{-f}}~VCK8G zn~|Bw1G!Q*fuM{)Lqr5&h4ZDj%I;xsDJ{p++kmp4%mWM?NFu0D&_@zUW0oNf|4@bn z5}6!!EfipgZ`8PEuK7j{twmc|1-jl`s1*m3X@WvN4MX);dnAsC5#9FDJ>`k9%{yfa zSKECtoGt#*Z-HF(`|9i;Sb)`*ydb`Tyge1{smn}3JRSI~5AM03h#o$CUK`MJq_{3g zFL%g{TYcg*4{(Z2Fk)l%_HM&!_8|>eRHSC(#F9`AO1Q&Zl<~vzNP>!>=68|IYmnV@ z0cVr+jEJ`F9&T47=R^Y@s2%GPWpQW)Zjf$A-&7RI>5VbL#++`g*7{;pDIDSf6Sw7% z=mci{#bXibx;zpD`#B<@VB0ry(FWlIF((;BBrujVS%ey_)lvuqys+ah_F1$_lWGz4 zZGgKJf?`VoAyzPR1?Ge6-}1r^MULEQ4vez~3$oclbwq(LC#3+Sfh#kyBx*Gxf}}7U z&l5?SDAh4y^WQkei^s5wbj|#wFZ7B^OenU&8c2idu0fP_!OLNy#*R|1KjRjYIV%HxRt=yac z_^QI)T?eA$^iO*3)c2$38c*9@*!%R#KfUP-T~Fb2{nK~LKfS8focC}4-C+=|VG%Bc zD9^g!oW6MPGw%7|EniAT5PPjnF28Sh?@^z+qVe(U$Mxd!`wKg}KDzwAk@(XNXN#qW z#$-+0Uub>0TPo|np0P>4UuvWRHc;{wHh}i-FT|e~^zR$yiTg&-*^5@b|HP@rQw|;Q z^AW@hGfwR~gc#`kg$4^UGZOHSu6Y?CykD}B1AlteU>y&lgx`JId*JY+HWm_Or;N=QGPOf-4Bh6fsxhy_-9^0+ABM!E!peKN~D+v#iC1azJ-Ke&#YBIMOcxys)e47cTw^oWnC&X=?-Ni|QR4EQYWe8BO=-uS- z=rdL$MkS2Eez0;S3=Mo(4md<;9na?Vs8$bxZKEvKB@bsoVDg@``^b;kZnc`s(7__> zT3EJP#Z;5wz4lkmeW>+eDpw2A2VTOZo=>qngz2S76C%olf!~PSr3qr8QXth@Gk?Vw zbz+MnICUkD`@|f3^m??B-}!xWr=8+KbBx)NrbH~oAg{!9IA9D~K@w6HQ?U%n{LEtJp2;X2ie-*BAJ_KMiq?> zi;;&Y_~&eDA)lQIC{es1Dh2s23E0fN=yMX}3L^m`B=d(a;;@PBV!=kKuPOrA&K*_} zZjA;wxdjtNqtbTMg?`Np?GQ7Wlo_r#i9d90Vnpew-NSM$rVE=E>d}RlCj20J{QO>s z9^AWSNy7+u08=44VpxW42NyGEDw`W!J3o1atW4C?L(dcfg@Z(2gTnb|+;B;U0S0O4 zncyY_vUCxyow-Gi34_ht;hzQVpq?zCu>}wu14i%Jy(*BnFx%HsvSKV!AWX_pP|z-% z>I1r^ZID?Zo~$*PF_k%f)pUtw{)C@%P>=LRe%%61<2_w*!zA;HX5uZNOO~wSUKR$$ zINCCHKI#Ek0e6D3>P+L& zs6psvoi`e%b|ukt7i8HzT=QOWCMM-5u@r4DLdPMPw%tHhBVz!`6bCKk1m&{kb1%Bl zhxQkL_Ujkikt9=HXn)DKm-Z9ff6k8^>zEMH-pF6qwYpNi^^UHsghOKU@1}M=<2_Hf zcoK6q=l$+*DJc{IRw2o-8eX6owh7&X;sOcP)J8JH&xQ&<{m4Vob=^0~!WU;t1y z7${K6yf8t!0PQzu2$#UEDU5`o`R$5TavU*l>!WA{o~RhUoxKzn#tATbOD^CHw>a_X zNzdj_xsCInFc4qWIx)gRz2&gms#jWt7D&Tj0Zb<4Uxg-xkuX`xBZ?>b)In9@I&{LD zwn-6gUV|7i%5`nYE=BHa&_$D#RUjl0Hof1qAt_LUkyfW|#HK zP~65O-Snj(L`1>!S0@LmMRFgse(s6~AmVbQV`|295y0s;L&|IZ%BBf5J)6=w;u~6# z)kgXmSvdclWPJ*RgMpjC!xS3HW1Z*WGdqt1sEsQO%Ayj3OZ6sfn-###eEktYlsw>T z{<-LQB;(0@kH=~?Mhq)=*9pI}c$P2VRqff+H%1y3P{JPiRO46pgPR20Mx_FZeEs?& zwqgIp%!hV{>?EAB+cTbh_4M&0?S&om7-!IKxhK!wDaMq_uMhh*g*OZ{A7kin#ZLB~ zSbjg;FdjMjs5v|_Q^D{YaW!~u)zB4KCJG?j(N&+iCsENeLLDFel=omHq`iK@N-*i% zVdTyK-dW@_p%wuI>9}vOD@hYbYJcnq9>e}nnL_HlQO^Tak#hOw0$GS#%BF=0@8WgI zHX*HGc?bpKpvM3%7!aq@?G7<8v1eoAGBk5P`lzHvy*P%ph>^?RTu>sdBWc?i(NjhU zh%|Gr>T~LRPr*PGnLpS#;JA0Uad<}G4xvkUYeJF;=30laMky+f)JI{u&pmIg5vqrS zMGjJE0U>~C0HUM`4$9;rh#|3s$BLP!^6WG&L}xOw3v+bA!(|iZGK*q%6n$(a%=-h1gXd zkziOFv&4RoaL(dXvXDn3Lo)o9<}MM+OMVY=1WuI#u9Q)c#Ira#W}c64d#;o}VJRad zo060_{gR`_)UaT`yiTD*>R7BqOC|`4imh4M2@4?W(E<5~yDq4d7bS8q*&xGbt{I!l z;8$jZo4#V^?e1YY59Cxp7+?-D8}kfYSx3nh=O_;6F2W-j7m{-dEgkc(&vVxN!^)Fk zxxe7fcbvt@SG{TQmfiI&3A9%=a`_)@c2h!jTbjA~hd?tb$8xL_po-Q9EXQAngRfeL zA#Yg$)}ZTv!QIa=wVaO081x}%hIeIBRRwmzN47MnC{eX&1oR!>!BmA&tZpST^OH4Rc(3s~w5L_qu*NC1%4TJ%Tzy6Ti ze??toFB;{+C=#9)mT;0KXeQXgSQ4JkK8G%5CfJN#IPz5JmgRhRRAzdGk@@RLQ2KLU=l`i zF?Hj>`7dEi60|vPQm1s`i0u}uH0d2^DNC@*Re26zOfxs{!=;Egp6qOZ`+_UQXDJoJ z6F|ePKgJm>tHlx7+inQ7_pWtkDe9!PsL=E&A4}O#J{t`CNFfBM*RO1JCv|Kb3aIYs zAh{PD@iJJyP={L1yy6Q+ZLhfWk9)Qjs#;}01lR6f*-c%M654!{P#G!N@YKG8HSVF| zc6T2md8%>1qEGsCtE0ZFH{rdh3~A$+0(LF3Wtq$<=tYhJpQh=mS>a+Hhzcx`e^!-J z9wNAt88vMFl%w24J|YK9JEUl*R3gLXW<{bbqwP>3@d`8=oKDe= zB@3m_kz$g*Q+I{Bm+9?&O?==<{LIO|c)Q<9+hz5e`O}USQ6(F&P*5X(*&+Hgp{&$c zKzeoP^SJE{PC^LM*{SmdD>~D_mt0xdL299R$t&u>lIjhP+A6`P=6qBOz=`9%L!HFl zu{ojL+2pjm;|`Gq0YD*rZ@$IIYxT7c?9r?<2x-O>jB&KL$IO6tXGp`-^wV>Ihh~@FaUT1%=h|;ak^=+kmNpI56fD z)oE6b+unvk+9=l~P2~rrh+fgiA0d{Es%BxQ%&tV|?qO*eWp1QSP|Z$S1=7mItF&JK z1*^_qV^MmUvR=TLJhn)u40dAah3ck-de8!$Gc+KkFhXy2r7UrWR&V5&?AVZK^^7kH zT{m;r{xe#6$ch%^OnA{FaiXK6_bP*pNwp98|uM6(Wq$2mi(;G4+_iA@j&Exb;Tq`{#`uziSq6fAn|g}F z+8kb{XE#ygLPoL!pi{OzD62lWC4Ojlj}PF@yXbjlTs&-1JuTH5+#&(qzSQqjOQ;~n z4S;d8tGEwmTgjU>Fe--fir=^_m*RM<8u`<=fkYV^&HU+aSE?#-tEaeBv|2$SG#cC` ztl&Ft4BlG$aY&~4@p4)c?ktdwCIm#sc%_{}7zaj*#o z46xItb{+McUw2A;R8oNwABUn9c2Mn%kNGr#GBK^wMll4Y#A(0HJMGFXhE( ziPei;EZWI7$*KSh1Cy->CMJ@cl0<8Vt7Cdn8D;ZdPBA)IXYPwq4@-8OopE(!ip&;_CbIrs3XCDnZ3m#O76w$Qt(vwBKblj*Z=n~U@YGDA1|3fI*1 zY1L1gx^vfae)1U+({BntL)1KX<0pemJ?(wVjF>LGv-B`);ptiM{bzfIEU-aMJgO7F zNYh%CE*_7Us}fk5r(o91WM)H1W(Av728t>fWwc7%9ed(G*rc7qWEp1}9OIauUB^D< zp&hsU>bCaU;pV(A9*m@g7@R4v&vB(@iDv)ydJN1^v{Pek`G{!QkiMb_Zq|rHBOia} zZa)vRq6M=N2V81us3}|t1WO%pX93d zTslG(53T7F{a1^~Xw4t_6auDI8K<6$4H5Ecd856xIgVN#xK}*mdyiDA9tSl`hj?fr zI0Z*n+YZh^sHIF?HXGk6%%t=T+e8h{2=x<1RaJ9R6V`ze5R$PuPw_UVs=)T+XUU>j zY|iA48mi+I#lSHkE{Z50vH;*d=uHFShGA?UZnQY3*Wy%Y1IrFqlPS_%lWBM7$0`%% z)1{|d29@;bH7nzl9*S+5Ccws(IMT9!GNd+r}m@x@y>- z>6PsyoUl>u=2;h+n+)=-K+1$iCX$GOnn`FTaK+5XvL2@Dr>;k?4wF+2w8`V0HdmbwalV&MGf>r7Ptzu?RJDj0_XG;P;vk5L>H(F_p)9+ z-QV9{2;)3-JABB)0-$n3A-aXluON@fu}a962l_OtNu`myhw*j><59C%SU>jqQH2D4 zbSu$``VjtUnNIAqYWB5FPBrDVo@zw0hX}TC^p~fCLL5SX%0J*zD^girKlq!6k*jj* za{&UeyXspxuFuBDqeRpBi%fL|OQm*CDfwV7HOE)|rb77TM2#@-h(Auy zA1C?Ike~{TPTWbzw`W3jOK-fW<$ntY^xD#yKv^t0;caniBEm#ptWs4>wGZhmGvIA( z{Aus21qCU7=m>-mvy)wy7OQRCiLPGOcn9q6oiV(bQ!^W1u z8Qdq++fdOat|nS96ZZ4^=1`x_Aw%OiS*Wa;_n^=;GJMv6%Ir@6j>hO)-erEmwKsmJ z-F>F{3AhU}ktm{SjRUTFoDh|{4A|)4@qpFO*)ZX580MezMvKHIaZYCzSeln|5pMC& zrU067Cnlz}a_y>Y@e%oP1R`{wDOJMQBk3TMrjT+ya#22AGxyu?`j~w1`Rq`HW?rK} z=7VRiC0}i|H2fDCj6(J5EIdCH)L-!5TYGTubS0D^zJ^E)SVXNfO-x z1%{R{?*#z~4v7Z1T}d3K-eGKMH`VuIm57l#N<>2H3(41c`}ef0m3ykUau3=M6PHI$ zzjH1tH**2-FCdFe=F!_-#7pBnI*J9G2oE^-O?L|$2mG+yP6*^vk9HD>;{eWR)L~0g zd#=!lkJ@f+;3YY!&XSKT(zft&L)1JdJ zI8S85LnH0ZfI`PpgcdTB*$mm3kUdM~Oo#~`|M5rcnHj?zcr$5Jqd0i5tNouo>FEyd zt5=dc-Y_hf;rB9C_3S>_Yu?L3zcM@tMO{Z6~=n&=)Jm zc=BsKyrB)j8rwV+;kZjykQ#9|Hv@V7aX(4VlHTB%4d1NK`?tGq2K>YJ*`)jIWdGT4 zk3Q}7fBF6Bqp(XXv9&JbF4I_4p5YCb0PizpAOe#?HkZsnV|OI4|LTKV_o0SkzT~Lk z@F&{cn>;O)1kxY?5@NU%Qt%ZM3LbSnB&4QONx@`Efj=8vANY+Zfgg)R8+y631+=q> z@-Plq+O%-%z{0+G;nuASFBQOKrT$-{Xw$%@4j-C2gQiVOlFyff&u2%D+qDX7i-TP1 zuUaB>Hqr0W+*xBGI4#t!Q;sPgFr_mKhDaH(N%cEMvr2Vmgs)5_Cz>bT$>G@?9iHT3Zu_cH|#+G&cUzl}0mL z-nCl+J|S9RNM~1A(L>g@@Fa8m^X?H<*w+wCW)3oGm?LhMzHV}9`r8xABln?pPVZ`; zhtY(4ani4q(xpX8rJV{_7q$12)R#W>xEpVMt&nl=!>+cQNPR7gfL;pYbuTs1Kn^b0 zjPBA{dQrBK|M_d$*!hW@GV?lFBmb@YRwR5BwMIIdS^AhxKE2q?fA08R+<$3F!`S@ z43_F@&LuP`31ph17Sf4A<~|!*+8eHw6e*aC)A&{o|k#+SsgL<1h9zH zuFXNmQ}={cW^Q6Z$R{gZye=7JhR{aH0R$l0LRXRSy%poRf|gmm%J3Z0`s~RYOyX}U z-TQF(SOVL;2GUL@{Kr)q;p^a11z<%JR7Ch%2;};m{yNetkZR4`G4GRawm>14jI7Yn zY->>Mi2xJpd=u(hJi`|E<`(2kuL{?XL%$!S;7n%pf(BS^ffN@+gtwdhUevT?z?{x^E{`11^0nl(RFp^zvkV zGyakS6Lf>{quxf-C9c?x>YCxlesr;Q!g6IsM9X=^6(}@vFI&Tet#mfWr5>v;3u`+H z_@WQYqmM2|*qBeE5Lsu%e_uX|`U|=txuLLgv z>gAhtTVFR`FB?=~PT?q$eec-DmAEan7FjOJ0LWJrHUkXOmMA9QMFZ8yCAIV4EHOwE zwsK3>9*@S8El%UR8dAy)J>P$BW-Y(EciIz1C?JTOJ3n2Y94C`8EPvPOg4pdcJ|W%l zimb8MezCXq)ca*WelB`o4r|Y%31*N3iDa+PY+%+9?D1Vv-#RTU(pO=# zdXRHPrQ{R}7XLjjL}-(J#>XQby{9amwyGvnnd>TPHjB6U3$}tsPuxy}r5;FLz!vEa zx~1%@&1f5`IX$~6)DE+Yum&qscc|0nL4CiaQgq9T5w2;e9qN{{XGd$VIWGLFs{_Y1 zRg?&I#*~p7aR`)WB(LDa!>c=P;^}5C1{XU380^Vq$W0lx3QiNcTT0wG<E8p4Dcknb~tdc0AWGhv^Q;?989{<95azq(CprjxDa)@QIqSks*BGGG#|P zzaInqb=Q@R2Q&BUX}i%XcusRbF)@&_JW0(eZ=M|^ZzWR^xTJT5nhtqe$|Of%gqE|T zYOTeA;EaG0)a}eYvhB|w%x$dIGo2V66!A3X*Pr%h4%%_9W`1}*Zbo_s-wHp7!hL>C zy7@-F`7%zTXTuQ^2WfHK!&k99{0Zy@dZE+K-uz)UbI^0&)|r!{A$`*FKxy~f(0}^e zwM*Q&GhrZ952Z0uvIwS}M7&GZx}1b1RFScWaOIzj-`Amk$j*i~xZLrj|J|Y9^6|&! znP%?2duP|2Ed0KvaMr0S<&4s;%zQ9Z6Zu5H9lfI=n_Em2rLW2MTGB7=y&QELziB*C zmkPK@UB3R08|6C%2h=DcWy-jX-4(1WVtzM`hr%wbCaE>2!V?l|hZvUnOQFI%#VN>v zD?5ss9+&tES!@UQnber@^UnO~y?>q{@kdXe7Y+c+?RwE%lsJkojYCyw8VzaYF1uz% zfSWkfw&OCCm>c^?ky}_Lp^!j^)Llb_j#z{p1q?oanjjklz5`SuzC3P1S|?QZ$}$Ks z;8Q5t)MJE}1D^(QwR8Rj5B@p8xRz?TT2J}Lflm&Q#NPFr>SzgP?c-Jmmnk@m>gR-o zeEXTu@aF&^&D<+*sCtu#Tm*UvsF|-ur-5g6#2Zo>tD*`Gbe%HMauOF#&oy$dtOQjj zlTK(#{>~`Kgfd-NU%^!0ac71HMjLe4JDd)S-Fp%l(`S65HtMycl$KMV7)#~Z>?A$x z=-e!dL~7RNdN?6}bwV<|lu(T#WptVfE@Ji-Yc&zdVkOArA7X$%@3jGS2l zd*bE{Eley81k#n`fZuw15qz!-vK{8Sys0b4<$#r<>=k1lup&|GFi{zY*F9aaD&323 zleokIRNdkhipH+F*++-7muK<$l9%ZO3&`2YYJO%8A!fJB!Fajvwy4Pi?t&~L_0`P% z>Shb;S@kyQF$%+^wLbm|XKo{y)cg;7OY}pa3-{%KZ|e61Ccengv{r_$V#~?dt#m|X zENtVga=jAa9bWce2dAVd9NLO4<|Hiaa9O&-;9RJ7R{4`zsF_mo_Hyqz>itXm@$>2r z&*3?mM@_WEbyGP%8^p@HfXU0b$8>*}^~TG@0MeQw#kmZ^;qJDT=lWEp_lShSq?7tA z8Go;-6w*6y+e{~4Ex=07jCIo~Sds=iNTd4bh_fi$>DHWg7HCcFe5nH4TC7aeNZuq^ zl}dIpM#$s}lZAGIFPCWpZC1C_=c1xOl8OJHktVjX->qDgL_&1z7A@d*s{%UlB;p0}5oB zA=V^GBOJKMLS`~6TAJZ5W~S1)V(@NkZtC^dY~)ZO6Kr6 zJ}1lFk&z(7pIT*QIFKzO@q1(52Q-K%%AlZ%>Iqf8Cu$K|9PIQof7wTVVRu@0p(KM4 z*Q&Ww5+x}aPr~_QAJ~V4IpgWy*&i|{)_?kUjFioWQGY@gS_vd0Kf(prB{@-$e#3#T zT`mZEpP3Dqli&kob-HXK2PfR9(3M}Bke1V7Gug(GRHx^donuy-S~bFbO^$r+=Q&j~ zzw!M2C7IStdNE&mA2I<%lV~_OwH{1%Sduu;UHxKrO%5qag}y?pK7#KBXg2wpt!e4Z zx6b?2Cw+PqoJn4~;C&{K8sgDD>o)CT#W6Jk5$gO}jAnZ?Ev7 z18DsVKQ*@ssy6d!hT(*4G}DRa>t@tdN~bmEPyR^Ig%S_?xo9ZK{aO6YsLBg;zbcu! zX8z}EW|6o$sF%7O89JiXy?s09pMEvK7%F1bP&2F&GKydNqkapHIiZj#8-X+ZdTt@v zx7sIWyS`=-H@R-!}@Mc&W*6(clSzIizxw3Z*TLSuCk^^I_Ou{ zUQX8r{4S+w=$`0Cw0kXJ$wQr$AgOhNF%&G1kj-_l0&O3;_Z*c(_(pjC+^pElZ^IOq zd__to(uLB6f)Q2NKAMHiBv&!eGipkfbTOg1BYdyRb(Qh)7}>?Ffsz8gie92PMXEfdhYU#n-A^@F}Ye8wmi2^8?THvMkasTXJf%i`6|l;`dUmmysI%X(bNPD zL@L_<3^+3#mrNvJrPJbN^8Y$ShP!o(zk6NRT!JDsXp(njVce(Nrys> zzB_XGb-6@`Zsb4mc{~l9#%NcMeqE~Nl@Oj zb+TWQ4hxu5}smdx1;0CAP!@IzYhX1VQbbwbjmg9_e!>2Hm%HOq`t zKbk?{jH;N_#uVit z#)bnco47I`GK5!BrlHE7w6RL?gB%t}3`7|w691-w0TJvzwyv#hwysPTDBi^j5dF@O zaep@R>#C|f(H&|7$bg_mG|kx3%#w^cAhxwxM+`UK)YB~&j^9BjEB!83%7&r2Nd+l0GSbfdw0Ak-%l@VN$ z;xlJAT4ND$l!_RlWS-z-1e)`&G;~J}E|;%i%^n7!nc{E;vho+c-|4Q5DuOnyzTRl* z!W$A=vPMa!98K7b;hRghX1zEYH^X{RMd$|qvWU>!LRPT|3yZ@H1#U4)o6V5p;-?wJ zV)<+TLc-v+`Q1Bp>S;5a(T4!F)-t*YJO9BbQT|Rwr?65usB}f>T#k9^iuu;4^PTj? zdA@KXp3_y`F^=NDAd{3`*R*PoRP1i5TTNp6z9LGqrw=N|Wmlc(?pY1lnPM5QQXQGO=!V<($`ype zQ4zd@>bt4Ge0$>*&X<78=9Wl)Q)Lbm~e-p6wZ(3-X+NlGSAL+OqMj>1)?}tF3TO>!GNi( zWE6MSv!rC9Ck@t}Lh<9jU*qcg03XiU+SNWlY)J*u@ssxgx_hjvO$>oDTx(SYIx{d3lAMW4^W%%0|2=aE^-cbm4 zs(;l*!WjFy9(RQ{+CIi0Tc;-}L-W9LH`?-FOOzEP8j=t2mX!vYm)w~D{NFhnkp@!; z8nK-db#(S9VkIH$$*=K`VHzpjlmMPyRaey3)^%UYz4qE^3&T{X&hTi!dNqLqbX;$N zB)dh;qkn<8%ygPH**l>Y?2nP&)wT6?PiCeErDia4NaiM80HDA2_mz(Z*^!={ewrbO z>ti>w9e(~L?X_w0dd>qka*uq;IwB>}+IHsf))dH`iZTk%#IFzaS`f=F@X3FWi`2}0 z?6=8gQ)!e`K#HHhl>)B_6zkFIt}P-$d}NXE#M58D7HnpXT}4WTTwB;1%uoWaj{1mb zV3t6M9`}J@C-L~eMq|dE@TloL7m-!a+zGl)yBQf4%mB9ZzrF+&IYT`mp=&-2ry(o0 z`!RmZzb@W&f)Q-NkgoR7+nB@dhAWBqe?83FoXKdHluO>{ z@cnAXVE6uQO8X4Gx`aqsDo7Q@`BSR&BY$pxYEFw*Jelb{?qPS_1R}m8P~*V+Pu-a4 zkVd|8xzL?pz^p8Ull4P^nsqzZuPWV0?Z=TSMFt2diAYcU@-ZfL@yb9R)|Xhi&Mx74 z=5d{0q^)Y^LX-Tqck=w>HG871Le{@6v^p~zra|A4<) zjkK|A!-1|*!R}X(6OM_^q@H1kcpyV%vdofd9kM>x^FSD6rVsD9(VbCmf+t^1i=UKB zUiBl{MKUch_7N5sZrDfaAJSwhfqIrCn*jLX$Ja_EpfBAke~?WXYp|KW`QO;T#%qr{ zP|};&Vc2Jtcjmve0Sa)$%r51FLk@(5Z6HSW?N`&YPKS^>=L){td8@dOpm_ZJj^)4^ zWaDc`y^|YQ(Y=lV_w&dDlf_*EDOFPzhD;Ko9C`i^8X(c5xWiNYKSiazmcvAS#MSU< z3GXiI@9&iK^ZxbS3DP=rw}Qble0C3i*C_vpJvyvbkj@4aoeh(W0Z9wjcqf5e3FlT> z3>8eSDfm}^7q3tG5q!Go5UVy^w!M5UsNq43%?!PY^u#k-+`aliOybs%h3iZn$Zz8P zB0oZOPUuss^`5`uma3&$zB-w-p4ehZuAuBOJls`{4eigLCAXV z%I1j?nr4o$#b1nry`;$JRNQ+e@aqN;o5eEQRzWa3hINW>`vF;4Lg zdud=eMlpHihpSssn?h@*G$@rwxLO6K&g^4qOHZ|^s;RkPn~xkRlqWMMiMgrtJ9F(R z>t9TFqlUT>*E78dzOa(+*}rpJnEg95F=qcNNerlw!ZEcU?|4fWhIO0QVmZtD(EYQl zU)MW_Wxekq0_wV_c7WTm(fpcyGtv3-mm?*+>ndJfYUDpak zvp5m-7F2ekK+{W3mcTKQbr=B;c6$NXIovrc(ljAJn4nA|$lKwD6=Z>B-?(1mfff5A zm!$XPU5Smw6Wr%=?&1s>VrILfMX7U%Gfx!MP|$-=YxLjt+;&;C)e zCVj{>4?UUZzxT#z4NzNVCeVMhmj26J_GblI5l=Il{-Z6~f7uNG1sa-o+BRu#{*XWI z_mu@H=b3yX#-iA7v@(XdIyqLENFCHfa&s+o^64Hm_WsA6^MAP^iBkI}gueNRy5wj^ zzaElrq*B%k^w8vz2+4WbD0~Jxsf)9D=>R)ZS=tt8j9=RAWMp!pZiSw0T$JpK8 z4wc5iFot}U7z8p=4sWBK)2GX3*)qV1r=cI$`ZwF&30YhZqI&vx3eZf&T3c`(b#-U7 z^<-}o9=3lr;f@>TvI!NT_%^E#I*7Y2*;RaXutZFg<*@3x!tSnjqPlN~Cz zr#;H-7qYG9Ekq@D=5D*mSucB(yHmG{s9bNgx#g{d;M<;qp65zt6%)p;_A3wC3ZMBa z{-M7$dtK}LyLoLTq7#9*te^x6`v9dDCr8ep%dr<7-xw>n2eCq&Lz{h$Pf$QE5#w&$ zn?=I(cH3UPLa>@BXA)@xf{d_oN--Y5e+d`r%|vxU5d6hE=b=`A8tCR z;p4BU;c(3s3eF=Zu!lH-D(A2I5@3XW!es{{Sp?e>{+IvgF#>}^{^V0Weo6+WW^1qu z58Dht9mO&{IjvHK2}~I?8&ER`%0Lw}oLJ41f;E5Cs$`)gUG#rSLYZAO4m_a@llZG` zz|o&{+GDzzdtfgj%q}Y$gkbgdHwoK+zAE!E%P2p$g(X z{l*NSXAp1xj<;rD-N=9Md7VrCg|KcM^ySfw*)W-3E@K2Q33r**wPFSxArOdBLP_ol zrFd5nIG!{`9`b2(iU(ttO~^*3x9D^$p>VtG8L((Pf+&oh}!WFOI zwJOt)*IUSm^324}YyQmOSVeulYRr5`V|CSO$SR1cAP)H$MCdELJjw68k&8xlhM=4! zCvaOHX;0fW+ve`owiL%{<3vVzi#qUQnVAR$V2W6x%@6wYij6Ai53V*7#@?0rkBba zDSLp76{@9TCd=KpF`&UH&P_sbql1FU<75Kt8QN)pgonTJa&230o6)h{4&1_e zu@ImL@(OsEHsXSY14sZfAkh~dz<%$tS;AdZCvX&R&6KXX$BB9!RXWLaEj?pXIq9GY zG~EmLrq6Jfw#=KF~AMUPo>&;r&#@!o;S2Y%IeJas*t)ZGAmd9(Sk#IjU6UTSY%v+VR-^kKczwrc`4u9sh}u51tsRf; z8kDa7ZFr$9ISJ=lcdoNDclB?5HENnWs?o}Xz&0T%dYMqD8a%$1znre1irFrz=99i4 z;Aj=Lsl#r3A|E7;d}gG$Nlc42Y*oLQzIb+y&)xmDgyU_9Q}W4_5|TyqzcG_%WHX4o z6EMT_f%<-UU55y;qIyr;e!L*r%r7`UxkifS7k_zbV`kmtlU+6l+y&PXlOyNGrHP7;};hU#7opI@=u}e4g&kz#2-r)qo z^cisD!IysxJJW|3g+P^*(qzNLCY+fx0#Mdh5=?`ixBj5+>C@Fn8Y%MjJJr`zbSHkv z4(H@Y_|9ZD;w8xlg%d*z>P#pQD!qC|dXID&QTB z`iYu2aQRQqq4bd@EnvkG@4-InNq6bh=fjikG7jZcKqq%dGEHD zCa6)LAagTXJlz5j)5j|-pD9A*Jq;8gZXoi|p#E@;OUHK>8)75nKlXWo&sK=*yUN(x zc65E2Jh(EHQtMU`m{j-yeg*0q2Osgrwe)z>H54AsWJYBa3=(Z3i>4F!9aCSa^c+oa ziFr&=FxqF;izcoZzzqu+!Ag5x^t#)X!6 z@4)w7|B;Pds=Cs@0|&?I^?@bdvFe*|1Jc-jrTidM&ukVXn+hu}SvKKAV z2fQIxkcU7)xe-;-%*(C*siM74I=gbQSEaSAs{#iDC!8B?_bXu&>NkXiese(s0-eyn zG4Hg818lSP#ICf$P^}n3sMD|)QM-DFBr4~~!0j|ChiO?qx#UV+7Q9xNaBiuxxlp4_B=4_zFHi^>4!7D4U6;s}@55nasfm?LD zGA^DNhIvZM&RSv+laO`Ms&ma=>MQLtyD{6!xU^{B*_|V!<7D;+p)kFtcPKwZxe+5i z!xx~8G(mqOO|r07RdS?=DKBI~*opj|tJewD4CM@*>IvtF{Ue-rubP8!OeY5<38vL( ztgX*&`WiY(BnVceByvj0&Xq4 zXaiq}j@Cd?ueM-g2!4KefW74W0Qh*C4Iu0}VQ6g6de&~r{Ulfr9Tztx~snz;v$GOcIT zLD=z#Vg^I*wgw70z^Fmr`ZYOVR5EkN z$3V4`?r&J{=U~yKx7hqfFzGs*sXM_-xQ0?VOG0Du)J2#p zQLuF=Th%<7ub=l1JBWv}4Si=NFO6sZ>2APVwjR4|Q)Mt=CjUnAg13;8;UaGab!bU=)mepUZZ!4~cHN?-J)$igzO z_MX0fYVW>5vF~1=Y?m7 z3U#?pdg0QTISA8?w`6b0Nxq29|Fg8QF-|5mZ61*0&e^Z%CgF8n7pX#77p~Ig#k=Zx zoLZIPN}oy|E>l9>T};=}Im1=@@4O$c;L5ZxQCvB&!d{qoLhR}i&8l+umBEnf3&7(; zl?j!RGJ-Vb5VKmhTD~ZyH?#S&5=x~`L0v%Qc(6it=X)nOF8`Y^i)tO znjJ67GBZ8J6Hn~L8eJJLHdM3tRoalAapk~03+t5%H~F|cotyxm2h7Bmv+wSOy(

  • 8 - Lua Stand-alone
  • Acknowledgments @@ -77,8 +83,11 @@

    Reference Manual of the Programming Language
    + Last update: -Fri Jul 10 15:10:14 EST 1998 +Wed Jul 7 13:36:24 EST 1999 by lhf. + + diff --git a/doc/luac.html b/doc/luac.html index 1948e7abe2..92d9ddf1e8 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -1,35 +1,20 @@ - -LUAC 1 "06 February 1998" + + + +LUAC man page + + + +

    NAME

    luac - Lua compiler

    SYNOPSIS

    luac [ --c -| --u -] [ --D -name -] [ --d -] [ --l -] [ --O -] [ --o -filename +options ] [ --p -] [ --q -] [ --v -] [ --V +filenames ] -sourcefile ...

    DESCRIPTION

    luac is the Lua compiler. @@ -43,10 +28,16 @@

    DESCRIPTION

    The main advantages of pre-compiling chunks are: faster loading, protecting source code from user changes, +and off-line syntax error detection. The binary files created by luac -are portable to all known architectures. +are portable to all architectures. +

    +Pre-compiling does not imply faster execution +because in Lua chunks are always compiled into bytecodes before being executed. +luac +simply allows those bytecodes to be saved in a file for later execution.

    luac produces a single output file containing the bytecodes @@ -71,16 +62,26 @@

    DESCRIPTION

    Binary files produced by differents runs of luac +(even in different machines) can be combined into one large file, using cat(1). -The result is still a valid binary file, +The result is still a valid binary file and can be loaded with a single call to lua_dofile or dofile.

    +The internal format of the binary files produced by +luac +may change when a new version of Lua is released. +We try to maintain compatibility even for binary files, +but sometimes it cannot be done. +So, +save the source files of all Lua programs that you precompile. +

    OPTIONS

    +Options must be separate.

    -c compile (this is the default). @@ -89,26 +90,44 @@

    OPTIONS

    undump, i.e., load and list the given binary files. If no files are given, then luac undumps luac.out. -

    --D "name" -predefine symbol -name -for conditional compilation. +Listing a binary file is useful to learn Lua's virtual machine. +Listing is also useful to test the integrity of binary files: +corrupted files will probably generate errors when undumped. +To test without listing, use +-q. +For a thourough integrity test, +use +-t.

    -d turn debugging on. Individual chunks may still control the generation of debug information with $debug and $nodebug. +If debugging is on, then listings show the names of the local variables. +

    +-D "name" +predefine symbol +name +for conditional compilation. +By default, +luac +does +not +predefine any symbols, +not even the built-in functions.

    -l produce a listing of the compiled bytecode for Lua's virtual machine. This is the default when undumping.

    --O -optimize code. -Debug information is removed, -duplicate constants are coalesced. +-n +Save numbers in native format. +By default, +numbers are saved in text form, +for maximum portability. +Binary files with numbers in native format are slightly faster to load, +but are not completely portable.

    -o "filename" output to @@ -117,14 +136,33 @@

    OPTIONS

    luac.out. The output file cannot be a source file.

    +-O +optimize. +Debug information is removed +and +duplicate constants are coalesced. +

    -p -parse sources files but does not generate any output file. +parse sources files but do not generate any output file. Used mainly for syntax checking.

    -q quiet; produces no listing. This is the default when compiling.

    +-t +perform a thourough integrity test when undumping. +Code that passes this test is completely safe, +in the sense that it will not break the interpreter. +However, +there is no guarantee that such code does anything sensible. +(None can be given, because the halting problem is unsolvable.) +

    +-U "name" +undefine symbol +name +for conditional compilation. +

    -v print version information.

    @@ -135,7 +173,7 @@

    FILES

    luac.out default output file -

    "SEE ALSO"

    +

    SEE ALSO

    lua(1)
    "Reference Manual of the Programming Language Lua" @@ -148,11 +186,9 @@

    "SEE ALSO"

    #6 (1996) 635-652.

    DIAGNOSTICS

    Error messages should be self explanatory. -

    BUGS

    -Inherits any bugs from Lua, -but Lua has no bugs...

    AUTHORS

    L. H. de Figueiredo, R. Ierusalimschy and W. Celes (lua@tecgraf.puc-rio.br) + diff --git a/doc/luac.man b/doc/luac.man index e5c90738de..818448b8f5 100644 --- a/doc/luac.man +++ b/doc/luac.man @@ -1,35 +1,14 @@ -.\" $Id: luac.man,v 1.11 1998/07/01 14:51:45 lhf Exp $ -.TH LUAC 1 "01 July 1998" +.\" luac.man,v 1.17 1999/07/07 16:02:07 lhf Exp +.TH LUAC 1 "1999/07/07 16:02:07" .SH NAME luac \- Lua compiler .SH SYNOPSIS .B luac [ -.B \-c -| -.B \-u -] [ -.B \-d -] [ -.B \-D -.I name -] [ -.B \-l -] [ -.B \-o -.I filename -] [ -.B \-O +.I options ] [ -.B \-p -] [ -.B \-q -] [ -.B \-v -] [ -.B \-V +.I filenames ] -.IR sourcefile " ..." .SH DESCRIPTION .B luac is the Lua compiler. @@ -43,10 +22,16 @@ in Lua. The main advantages of pre-compiling chunks are: faster loading, protecting source code from user changes, +and off-line syntax error detection. The binary files created by .B luac -are portable to all known architectures. +are portable to all architectures. +.LP +Pre-compiling does not imply faster execution +because in Lua chunks are always compiled into bytecodes before being executed. +.B luac +simply allows those bytecodes to be saved in a file for later execution. .LP .B luac produces a single output file containing the bytecodes @@ -71,16 +56,26 @@ option. .LP Binary files produced by differents runs of .B luac +(even in different machines) can be combined into one large file, using .BR cat (1). -The result is still a valid binary file, +The result is still a valid binary file and can be loaded with a single call to .B lua_dofile or .BR dofile . .LP +The internal format of the binary files produced by +.B luac +may change when a new version of Lua is released. +We try to maintain compatibility even for binary files, +but sometimes it cannot be done. +So, +save the source files of all Lua programs that you precompile. +.LP .SH OPTIONS +Options must be separate. .TP .B \-c compile (this is the default). @@ -89,6 +84,21 @@ compile (this is the default). undump, i.e., load and list the given binary files. If no files are given, then luac undumps .BR luac.out . +Listing a binary file is useful to learn Lua's virtual machine. +Listing is also useful to test the integrity of binary files: +corrupted files will probably generate errors when undumped. +To test without listing, use +.BR \-q . +For a thourough integrity test, +use +.BR \-t . +.TP +.B \-d +turn debugging on. +Individual chunks may +still control the generation of debug information with +$debug and $nodebug. +If debugging is on, then listings show the names of the local variables. .TP .BI \-D " name" predefine symbol @@ -101,21 +111,17 @@ does predefine any symbols, not even the built-in functions. .TP -.B \-d -turn debugging on. -Individual chunks may -still control the generation of debug information with -$debug and $nodebug. -If debugging is on, then listings show the names of the local variables. -.TP .B \-l produce a listing of the compiled bytecode for Lua's virtual machine. This is the default when undumping. .TP -.B \-O -optimize code. -Debug information is removed, -duplicate constants are coalesced. +.B \-n +Save numbers in native format. +By default, +numbers are saved in text form, +for maximum portability. +Binary files with numbers in native format are slightly faster to load, +but are not completely portable. .TP .BI \-o " filename" output to @@ -124,14 +130,33 @@ instead of the default .BR luac.out . The output file cannot be a source file. .TP +.B \-O +optimize. +Debug information is removed +and +duplicate constants are coalesced. +.TP .B \-p -parse sources files but does not generate any output file. +parse sources files but do not generate any output file. Used mainly for syntax checking. .TP .B \-q quiet; produces no listing. This is the default when compiling. .TP +.B \-t +perform a thourough integrity test when undumping. +Code that passes this test is completely safe, +in the sense that it will not break the interpreter. +However, +there is no guarantee that such code does anything sensible. +(None can be given, because the halting problem is unsolvable.) +.TP +.BI \-U " name" +undefine symbol +.I name +for conditional compilation. +.TP .B \-v print version information. .TP @@ -155,11 +180,9 @@ http://www.tecgraf.puc-rio.br/lua/ #6 (1996) 635-652. .SH DIAGNOSTICS Error messages should be self explanatory. -.SH BUGS -Inherits any bugs from Lua, -but Lua has no bugs... .SH AUTHORS L. H. de Figueiredo, R. Ierusalimschy and W. Celes .I (lua@tecgraf.puc-rio.br) +.\" EOF diff --git a/doc/manual.html b/doc/manual.html index 8707ec2007..8c157c2b53 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,9 +1,12 @@ -Lua 3.1 Reference Manual +Lua 3.2 Reference Manual - -

    Lua 3.1 Reference Manual

    + +

    Lua 3.2 Reference Manual

    + +

    +


    @@ -14,10 +17,6 @@

    1 - Introduction

    facilities. Lua is intended to be used as a light-weight, but powerful, configuration language for any program that needs one. -Lua has been designed and implemented by -W. Celes, -R. Ierusalimschy and -L. H. de Figueiredo.

    Lua is implemented as a library, written in C. Being an extension language, Lua has no notion of a ``main'' program: @@ -48,15 +47,17 @@

    2 - Environment and Chunks

    All statements in Lua are executed in a global environment. This environment, which keeps all global variables, -is initialized at the beginning of the embedding program and -persists until its end. +is initialized with a call from the embedding program to +lua_open and +persists until a call to lua_close, +or the end of the embedding program. Optionally, a user can create multiple independent global environments (see Section 5.1).

    The global environment can be manipulated by Lua code or by the embedding program, which can read and write global variables -using functions from the API library that implements Lua. +using API functions from the library that implements Lua.

    Global variables do not need declaration. Any variable is assumed to be global unless explicitly declared local @@ -79,7 +80,7 @@

    2 - Environment and Chunks

    When a chunk is executed, first all its code is pre-compiled, then the statements are executed in sequential order. All modifications a chunk effects on the global environment persist -after its end. +after the chunk end.

    Chunks may also be pre-compiled into binary form; see program luac for details. @@ -104,7 +105,7 @@

    3 - Types and Tags

    string, function, userdata, and table. Nil is the type of the value nil, whose main property is to be different from any other value. -Number represents real (double precision floating point) numbers, +Number represents real (double-precision floating-point) numbers, while string has the usual meaning. Lua is eight-bit clean, and so strings may contain any 8-bit character, @@ -160,7 +161,7 @@

    3 - Types and Tags

    Each of the types nil, number and string has a different tag. All values of each of these types have this same pre-defined tag. Values of type function can have two different tags, -depending on whether they are Lua or C functions. +depending on whether they are Lua functions or C functions. Finally, values of type userdata and table can have as many different tags as needed (see Section 4.8). @@ -200,7 +201,7 @@

    4.1 - Lexical Conventions

    and is a reserved word, but And and \'and (if the locale permits) are two other different identifiers. As a convention, identifiers starting with underscore followed by -uppercase letters should not be used in regular programs. +uppercase letters are reserved for internal variables.

    The following strings denote other tokens:

    @@ -211,7 +212,7 @@ 

    4.1 - Lexical Conventions

    Literal strings can be delimited by matching single or double quotes, and can contain the C-like escape sequences '\a' (bell), -'\b' (back space), +'\b' (backspace), '\f' (form feed), '\n' (new line), '\r' (carriage return), @@ -251,9 +252,9 @@

    4.1 - Lexical Conventions

    Numerical constants may be written with an optional decimal part, and an optional decimal exponent. -Examples of valid numerical constants are: +Examples of valid numerical constants are

    -       4     4.0     0.4     4.57e-3     0.3e12
    +       3     3.0     3.1416  314.16e-2   0.31416E1
     

    @@ -280,7 +281,7 @@

    4.2 - The Pre-processor

    Particularly, a $endinput may occur inside a $if; in that case, even the matching $end is not parsed.

    -A cond part may be: +A cond part may be

    nil
    - always false.
    1
    - always true. @@ -298,11 +299,7 @@

    4.3 - Coercion

    Any arithmetic operation applied to a string tries to convert that string to a number, following the usual rules. Conversely, whenever a number is used when a string is expected, -that number is converted to a string, according to the following rule: -if the number is an integer, it is written without exponent or decimal point; -otherwise, it is formatted following the %g -conversion specification of the printf function in the -standard C library. +that number is converted to a string, in a reasonable format. For complete control on how numbers are converted to strings, use the format function (see Section 6.2).

    @@ -313,12 +310,13 @@

    4.4 - Adjustment

    Functions in Lua can return many values. Because there are no type declarations, +when a function is called the system does not know how many values a function will return, or how many parameters it needs. Therefore, sometimes, a list of values must be adjusted, at run time, to a given length. If there are more values than are needed, -then the last values are thrown away. +then the excess values are thrown away. If there are more needs than values, then the list is extended with as many nil's as needed. Adjustment occurs in multiple assignment (see Section 4.5.2) @@ -376,7 +374,7 @@

    4.5.2 - Assignment

    Before the assignment, the list of values is adjusted to the length of the list of variables (see Section 4.4).

    -A single name can denote a global or a local variable, +A single name can denote a global variable, a local variable, or a formal parameter:

     var ::= name
    @@ -414,15 +412,14 @@ 

    4.5.3 - Control Structures

    -stat ::= while exp1 do block end 
    | repeat block until exp1
    | if exp1 then block {elseif} [else block] end -elseif ::= elseif exp1 then block +stat ::= while exp1 do block end
    | repeat block until exp1
    | if exp1 then block {elseif exp1 then block} [else block] end

    A return is used to return values from a function or from a chunk. Because they may return more than one value, -the syntax for a return statement is: +the syntax for a return statement is

     ret ::= return [explist1] [sc]
     
    @@ -457,7 +454,7 @@

    4.5.5 - Local Declarations

    4.6 - Expressions

    4.6.1 - Basic Expressions

    -Basic expressions are: +Basic expressions are
     exp ::= '(' exp ')'
     exp ::= nil
    @@ -477,7 +474,7 @@ 

    4.6.1 - Basic Expressions

    variables are explained in Section 4.5.2; upvalues are explained in Section 4.7; function definitions (function) are explained in Section 4.6.9; -function call are explained in Section 4.6.8. +function calls are explained in Section 4.6.8.

    An access to a global variable x is equivalent to a call getglobal('x'); @@ -535,7 +532,7 @@

    4.6.3 - Relational Operators

    Otherwise, the ``order'' tag method is called (see Section 4.8).

    4.6.4 - Logical Operators

    -The logical operators are: +The logical operators are
                  and   or   not
    @@ -589,7 +586,7 @@ 

    4.6.7 - Table Constructors

    Constructors can be used to create empty tables, or to create a table and initialize some fields.

    -The general syntax for constructors is: +The general syntax for constructors is

     tableconstructor ::= '{' fieldlist '}'
     fieldlist ::= lfieldlist | ffieldlist | lfieldlist ';' ffieldlist | ffieldlist ';' lfieldlist
    @@ -597,17 +594,17 @@ 

    4.6.7 - Table Constructors

    ffieldlist ::= [ffieldlist1]

    -The form lfieldlist1 is used to initialize lists. +The form lfieldlist1 is used to initialize lists:

     lfieldlist1 ::= exp {',' exp} [',']
     
    The expressions in the list are assigned to consecutive numerical indices, starting with 1. -For example: +For example,
        a = {"v1", "v2", 34}
     
    -is equivalent to: +is equivalent to
       do
         local temp = {}
    @@ -623,11 +620,11 @@ 

    4.6.7 - Table Constructors

    ffieldlist1 ::= ffield {',' ffield} [','] ffield ::= '[' exp ']' '=' exp | name '=' exp
    -For example: +For example,
        a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
     
    -is equivalent to: +is equivalent to
       do
         local temp = {}
    @@ -649,7 +646,7 @@ 

    4.6.7 - Table Constructors

    x = {;} x = {'a', 'b',} x = {type='list'; 'a', 'b'} - x = {f(0), f(1), f(2),; n=3} + x = {f(0), f(1), f(2),; n=3,}

    @@ -678,6 +675,7 @@

    4.6.8 - Function Calls

    except that simpleexp is evaluated only once.

    +Arguments have the following syntax:

     args ::= '(' [explist1] ')'
     args ::= tableconstructor
    @@ -707,33 +705,33 @@ 

    4.6.8 - Function Calls

    (syntactically denoted by the non-terminal exp), then no adjustment is made. Note that the only place that can hold many values -is the last expression (or the only one) in an assignment +is the last (or the only) expression in an assignment or in a return statement; see examples below.
    -      f();  -- adjusted to 0
    -      g(x, f());     -- f() is adjusted to 1
    -      a,b,c = f(), x;   -- f() is adjusted to 1 result (and c gets nil)
    -      a,b,c = x, f();   -- f() is adjusted to 2
    -      a,b,c = f();   -- f() is adjusted to 3
    -      return f();   -- returns all values returned by f()
    +      f();               -- adjusted to 0
    +      g(x, f());         -- f() is adjusted to 1
    +      a,b,c = f(), x;    -- f() is adjusted to 1 result (and c gets nil)
    +      a,b,c = x, f();    -- f() is adjusted to 2
    +      a,b,c = f();       -- f() is adjusted to 3
    +      return f();        -- returns all values returned by f()
     

    4.6.9 - Function Definitions

    -The syntax for function definition is: +The syntax for function definition is

     function ::= function '(' [parlist1] ')' block end
     stat ::= function funcname '(' [parlist1] ')' block end
     funcname ::= name | name '.' name
     
    -The statement: +The statement
           function f (...)
             ...
           end
     
    -is just syntactic sugar for: +is just syntactic sugar for
           f = function (...)
                 ...
    @@ -769,8 +767,8 @@ 

    4.6.9 - Function Definitions

    instead, it collects any extra arguments into an implicit parameter, called arg. This parameter is always initialized as a table, -with a field n with the number of extra arguments, -and the extra arguments at positions 1, 2, ... +with a field n whose value is the number of extra arguments, +and the extra arguments at positions 1, 2, ...

    As an example, suppose definitions like:

    @@ -795,21 +793,21 @@ 

    4.6.9 - Function Definitions

    then the function returns with no results.

    There is a special syntax for defining methods, -that is, functions that have an implicit extra parameter self. +that is, functions that have an implicit extra parameter self:

     function ::= function name ':' name '(' [parlist1] ')' block end
     
    Thus, a declaration like
    -function v:f (...)
    -  ...
    -end
    +      function v:f (...)
    +        ...
    +      end
     
    is equivalent to
    -v.f = function (self, ...)
    -  ...
    -end
    +      v.f = function (self, ...)
    +        ...
    +      end
     
    that is, the function gets an extra formal parameter called self. Note that the variable v must have been @@ -842,19 +840,19 @@

    4.7 - Visibility and Upvalues

    Here are some examples:

    -a,b,c = 1,2,3   -- global variables
    -function f (x)
    -  local b   -- x and b are local to f
    -  local g = function (a)
    -    local y  -- a and y are local to g
    -    p = a   -- OK, access local 'a'
    -    p = c   -- OK, access global 'c'
    -    p = b   -- ERROR: cannot access a variable in outer scope
    -    p = %b  -- OK, access frozen value of 'b' (local to 'f')
    -    p = %c  -- OK, access frozen value of global 'c'
    -    p = %y  -- ERROR: 'y' is not visible where 'g' is defined
    -  end  -- g
    -end  -- f
    +      a,b,c = 1,2,3   -- global variables
    +      function f (x)
    +        local b       -- x and b are local to f
    +        local g = function (a)
    +          local y     -- a and y are local to g
    +          p = a       -- OK, access local 'a'
    +          p = c       -- OK, access global 'c'
    +          p = b       -- ERROR: cannot access a variable in outer scope
    +          p = %b      -- OK, access frozen value of 'b' (local to 'f')
    +          p = %c      -- OK, access frozen value of global 'c'
    +          p = %y      -- ERROR: 'y' is not visible where 'g' is defined
    +        end           -- g
    +      end             -- f
     

    @@ -863,7 +861,7 @@

    4.7 - Visibility and Upvalues

    4.8 - Tag Methods

    Lua provides a powerful mechanism to extend its semantics, -called Tag Methods. +called tag methods. A tag method is a programmer-defined function that is called at specific key points during the evaluation of a program, allowing the programmer to change the standard Lua behavior at these points. @@ -874,10 +872,10 @@

    4.8 - Tag Methods

    in the event (see Section 3). The function settagmethod changes the tag method associated with a given pair (tag, event). -Its first parameter is the tag, the second is the event name -(a string, see below), +Its first parameter is the tag, the second parameter is the event name +(a string; see below), and the third parameter is the new method (a function), -or nil to restore the default behavior. +or nil to restore the default behavior for the pair. The function returns the previous tag method for that pair. Another function, gettagmethod, receives a tag and an event name and returns the @@ -893,7 +891,7 @@

    4.8 - Tag Methods

    the real behavior is hard coded in the interpreter, and it is much more efficient than this simulation. All functions used in these descriptions -(rawgetglobal, tonumber, call, etc) +(rawgetglobal, tonumber, call, etc.) are described in Section 6.1.

    @@ -1137,7 +1135,7 @@

    4.8 - Tag Methods

    ``gc'':
    -called when Lua is garbage collecting an object. +called when Lua is ``garbage collecting'' an object. This method cannot be set for strings, numbers, functions, and userdata with default tag. For each object to be collected, @@ -1165,29 +1163,27 @@

    4.9 - Error Handling

    all Lua actions start from C code in the host program calling a function from the Lua library. Whenever an error occurs during Lua compilation or execution, -the error method is called, +function _ERRORMESSAGE is called +(provided it is different from nil), and then the corresponding function from the library (lua_dofile, lua_dostring, lua_dobuffer, or lua_callfunction) is terminated, returning an error condition.

    -The only argument to the error method is a string +The only argument to _ERRORMESSAGE is a string describing the error. -The default method prints this message to stderr. -If needed, it is possible to change the error method with the -function seterrormethod, -which gets the new error handler as its only parameter -(see Section 6.1). -The standard I/O library uses this facility to redefine the error method, -using the debug facilities (see Section 7), -in order to print some extra information, +The default definition for this function calls _ALERT, +which prints the message to stderr (see Section 6.1). +The standard I/O library redefines _ERRORMESSAGE, +and uses the debug facilities (see Section 7) +to print some extra information, such as the call stack.

    To provide more information about errors, Lua programs should include the compilation pragma $debug. -When an error occurs in a program compiled with this option, +When an error occurs in a chunk compiled with this option, the I/O error routine is able to print the number of the lines where the calls (and the error) were made.

    @@ -1229,6 +1225,8 @@

    5.1 - Managing States

    typedef struct lua_State lua_State; extern lua_State *lua_state;
    +The variable lua_state is the only C global variable in +the Lua library.

    Before calling any API function, this state must be initialized. @@ -1255,19 +1253,19 @@

    5.1 - Managing States

    calling lua_open. An easy way to do that is defining an auxiliary function:
    -lua_State *lua_newstate (void) {
    -  lua_State *old = lua_setstate(NULL);
    -  lua_open();
    -  return lua_setstate(old);
    -}
    +      lua_State *lua_newstate (void) {
    +        lua_State *old = lua_setstate(NULL);
    +        lua_open();
    +        return lua_setstate(old);
    +      }
     
    This function creates a new state without changing the current state of the interpreter. -Note that any new state is built with all predefined functions, +Note that any new state is created with all predefined functions, but any additional library (such as the standard libraries) must be explicitly open in the new state, if needed.

    -If necessary, a state may be released: +If necessary, a state may be released by calling

     void lua_close (void);
     
    @@ -1281,14 +1279,14 @@

    5.1 - Managing States

    lua_close has no effect.

    If you are using multiple states, -you may find useful the following function, +you may find useful to define the following function, which releases a given state:

    -void lua_freestate (lua_State *st) {
    -  lua_State *old = lua_setstate(st);
    -  lua_close();
    -  if (old != st) lua_setstate(old);
    -}
    +      void lua_freestate (lua_State *st) {
    +        lua_State *old = lua_setstate(st);
    +        lua_close();
    +        if (old != st) lua_setstate(old);
    +      }
     

    @@ -1316,7 +1314,7 @@

    5.2 - Exchanging Values between C and Lua

    int lua_iscfunction (lua_Object object); int lua_isuserdata (lua_Object object);
    -All macros return 1 if the object is compatible with the given type, +These functions return 1 if the object is compatible with the given type, and 0 otherwise. The function lua_isnumber accepts numbers and numerical strings, whereas @@ -1356,7 +1354,8 @@

    5.2 - Exchanging Values between C and Lua

    If you do not know whether a string may contain zeros, you can use lua_strlen to get the actual length. Because Lua has garbage collection, -there is no guarantee that such pointer will be valid after the block ends +there is no guarantee that the pointer returned by lua_getstring +will be valid after the block ends (see Section 5.3).

    lua_getcfunction converts a lua_Object to a C function. @@ -1415,7 +1414,7 @@

    5.3 - Garbage Collection

    The second structure, C2lua, is an abstract stack. Pushing elements into this stack -is done with the following functions and macros: +is done with the following functions: @@ -1433,7 +1432,7 @@

    5.3 - Garbage Collection

    All of them receive a C value, convert it to a corresponding lua_Object, and leave the result on the top of C2lua. -Particularly, functions lua_pushlstring and lua_pushstring +In particular, functions lua_pushlstring and lua_pushstring make an internal copy of the given string. Function lua_pushstring can only be used to push proper C strings (that is, strings that do not contain zeros and end with a zero); @@ -1518,9 +1517,6 @@

    5.4 - Executing Lua Code

    used in error messages and debug information. If name is NULL, Lua gives a default name to the chunk. -In files this name is the file name, -and lua_dostring uses a small prefix -of the string as the chunk name.

    These functions return, in structure lua2C, any values eventually returned by the chunks. @@ -1565,7 +1561,7 @@

    5.5 - Manipulating Lua Objects

     lua_Object lua_gettable (void);
     
    -pops from the stack C2lua a table and an index, +pops a table and an index from the stack C2lua, and returns the contents of the table at that index. As in Lua, this operation may trigger a tag method. To get the real value of any table index, @@ -1579,7 +1575,7 @@

    5.5 - Manipulating Lua Objects

    To store a value in an index, the program must push the table, the index, and the value onto C2lua, -and then call the function: +and then call the function
     void lua_settable (void);
    @@ -1636,9 +1632,9 @@ 

    5.6 - Calling Lua Functions

    lua_pushnumber(4); /* 3rd argument */ lua_callfunction(lua_getglobal("f")); /* call Lua function */ lua_pushobject(lua_getresult(1)); /* push first result of the call */ - lua_setglobal("a"); /* sets global variable 'a' */ - lua_pushobject(lua_getresult(2)); /* push second result of the call */ - lua_setglobal("b"); /* sets global variable 'b' */ + lua_setglobal("a"); /* set global variable 'a' */ + lua_pushobject(lua_getresult(2)); /* push second result of the call */ + lua_setglobal("b"); /* set global variable 'b' */

    Some special Lua functions have exclusive interfaces. @@ -1651,19 +1647,11 @@

    5.6 - Calling Lua Functions

    If the C function has been called from Lua, then the corresponding Lua execution terminates, as if an error had occurred inside Lua code. -Otherwise, the whole program terminates with a call to exit(1). -The message is passed to the error handler method. +Otherwise, the whole host program terminates with a call to exit(1). +The message is passed to the error handler function, +_ERRORMESSAGE. If message is NULL, -the error handler method is not called. -

    -The error handler method (see Section 4.9) can be -changed with: -

    -lua_Object lua_seterrormethod (void);
    -
    -This function sets the object at the top of C2lua -as the new error method, -and returns the old error method value. +then _ERRORMESSAGE is not called.

    Tag methods can be changed with:

    @@ -1722,12 +1710,13 @@ 

    5.7 - C Functions

    many results.

    When a C function is created, -it is possible to associate some upvalues to it; +it is possible to associate some upvalues to it, +thus creating a C closure; then these values are passed to the function whenever it is called, as common arguments. To associate upvalues to a function, first these values must be pushed on C2lua. -Then the function: +Then the function

     void lua_pushcclosure (lua_CFunction fn, int n);
    @@ -1792,7 +1781,7 @@ 

    6 - Predefined Functions and Libraries

    that are implemented directly through the standard API. Therefore, they are not necessary to the language, and are provided as separate C modules. -Currently there are three standard libraries: +Currently, there are three standard libraries:
    • string manipulation;
    • mathematical functions (sin, log, etc); @@ -1809,17 +1798,16 @@

      6 - Predefined Functions and Libraries

      6.1 - Predefined Functions

      -

      call (func, arg [, mode [, errmethod]])

      +

      call (func, arg [, mode [, errhandler]])

      -This function calls function func with +Calls function func with the arguments given by the table arg. The call is equivalent to
      -      func(arg[1], arg[2], ..., arg[arg.n])
      +      func(arg[1], arg[2], ..., arg[n])
       
      -If arg.n is not defined, -then Lua stops getting arguments at the first nil value. +where n is the result of getn(arg) (see Section 6.1).

      By default, all results from func are just returned by the call. @@ -1833,6 +1821,7 @@

      call (func, arg [, mode [, errmethod]])

       a = call(sin, {5})                --> a = 0.0871557 = sin(5)
       a = call(max, {1,4,5; n=2})       --> a = 4 (only 1 and 4 are arguments)
      +a = call(max, {1,4,5; n=2}, "p")  --> a = {4; n=1}
       t = {x=1}
       a = call(next, {t,nil;n=2}, "p")  --> a={"x", 1; n=2}
       
      @@ -1842,14 +1831,15 @@

      call (func, arg [, mode [, errmethod]])

      the error is propagated. If the string mode contains "x", then the call is protected. -In this mode, function call does not generate an error, -whatever happens during the call. +In this mode, function call does not propagate an error, +regardless of what happens during the call. Instead, it returns nil to signal the error -(besides calling the appropriated error method). +(besides calling the appropriated error handler).

      -If provided, errmethod is temporarily set as the error method, -while func runs. -As a particular case, if errmethod is nil, +If provided, +errhandler is temporarily set as the error function +_ERRORMESSAGE, while func runs. +In particular, if errhandler is nil, no error messages will be issued during the execution of the called function.

      collectgarbage ([limit])

      @@ -1858,13 +1848,13 @@

      collectgarbage ([limit])

      An optional argument, limit, is a number that makes the next cycle occur only after that number of new objects have been created. -If absent, Lua uses an adaptive algorithm to set -this limit. +If limit is absent or equal to 0, +Lua uses an adaptive algorithm to set this limit. collectgarbage is equivalent to the API function lua_collectgarbage.

      dofile (filename)

      -This function receives a file name, +Receives a file name, opens the file, and executes the file contents as a Lua chunk, or as pre-compiled chunks. When called without arguments, @@ -1877,7 +1867,7 @@

      dofile (filename)

      dofile is equivalent to the API function lua_dofile.

      dostring (string [, chunkname])

      -This function executes a given string as a Lua chunk. +Executes a given string as a Lua chunk. If there is any error executing the string, dostring returns nil. Otherwise, it returns the values returned by the chunk, @@ -1893,7 +1883,7 @@

      newtag ()

      newtag is equivalent to the API function lua_newtag.

      next (table, index)

      -This function allows a program to traverse all fields of a table. +Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. It returns the next index of the table and the @@ -1911,8 +1901,9 @@

      next (table, index)

      Therefore, the function only considers fields with non nil values. The order in which the indices are enumerated is not specified, even for numeric indices -(to traverse a table in numeric order, use a counter). -If the table is modified in any way during a traversal, +(to traverse a table in numeric order, +use a counter or the function foreachi). +If the table indices are modified in any way during a traversal, the semantics of next is undefined.

      This function cannot be written with the standard API. @@ -1925,67 +1916,35 @@

      nextvar (name)

      Similarly to next, it returns the name of another variable and its value, or nil if there are no more variables. -There can be no assignments to global variables during the traversal; +There can be no creation of new global variables during the traversal; otherwise the semantics of nextvar is undefined.

      This function cannot be written with the standard API.

      -

      foreach (table, function)

      -Executes the given function over all elements of table. -For each element, the function is called with the index and -respective value as arguments. -If the function returns any non-nil value, -the loop is broken, and the value is returned -as the final value of foreach. -

      -This function could be defined in Lua: -

      -function foreach (t, f)
      -  local i, v = next(t, nil)
      -  while i do
      -    local res = f(i, v)
      -    if res then return res end
      -    i, v = next(t, i)
      -  end
      -end
      -
      -

      -

      foreachvar (function)

      -Executes function over all global variables. -For each variable, -the function is called with its name and its value as arguments. -If the function returns any non-nil value, -the loop is broken, and the value is returned -as the final value of foreachvar. -

      -This function could be defined in Lua: -

      -function foreachvar (f)
      -  local n, v = nextvar(nil)
      -  while n do
      -    local res = f(n, v)
      -    if res then return res end
      -    n, v = nextvar(n)
      -  end
      -end
      -
      -

      tostring (e)

      -This function receives an argument of any type and +Receives an argument of any type and converts it to a string in a reasonable format. For complete control on how numbers are converted, use function format.

      print (e1, e2, ...)

      -This function receives any number of arguments, +Receives any number of arguments, and prints their values using the strings returned by tostring. This function is not intended for formatted output, but only as a quick way to show a value, -for instance for error messages or debugging. +for instance for debugging. See Section 6.4 for functions for formatted output.

      + +

      _ALERT (message)

      +Prints its only string argument to stderr. +All error messages in Lua are printed through this function. +Therefore, a program may redefine it +to change the way such messages are shown +(for instance, for systems without stderr). +

      tonumber (e [, base])

      -This function receives one argument, +Receives one argument, and tries to convert it to a number. If the argument is already a number or a string convertible to a number, then tonumber returns that number; @@ -2002,7 +1961,7 @@

      tonumber (e [, base])

      type (v)

      -This function allows Lua to test the type of a value. +Allows Lua to test the type of a value. It receives one argument, and returns its type, coded as a string. The possible results of this function are "nil" (a string, not the value nil), @@ -2013,12 +1972,12 @@

      type (v)

      and "userdata".

      tag (v)

      -This function allows Lua to test the tag of a value (see Section 3). +Allows Lua to test the tag of a value (see Section 3). It receives one argument, and returns its tag (a number). tag is equivalent to the API function lua_tag.

      settag (t, tag)

      -This function sets the tag of a given table (see Section 3). +Sets the tag of a given table (see Section 3). tag must be a value created with newtag (see Section 6.1). It returns the value of its first argument (the table). @@ -2027,21 +1986,21 @@

      settag (t, tag)

      assert (v [, message])

      -This function issues an ``assertion failed!'' error +Issues an ``assertion failed!'' error when its argument is nil. This function is equivalent to the following Lua function:
      -function assert (v, m)
      -  if not v then
      -    m = m or ""
      -    error("assertion failed!  " .. m)
      -  end
      -end
      +      function assert (v, m)
      +        if not v then
      +          m = m or ""
      +          error("assertion failed!  " .. m)
      +        end
      +      end
       

      error (message)

      -This function calls the error handler and then terminates +Calls the error handler and then terminates the last protected function called (in C: lua_dofile, lua_dostring, lua_dobuffer, or lua_callfunction; @@ -2064,7 +2023,7 @@

      rawsettable (table, index, value)

      and value is any Lua value.

      rawsetglobal (name, value)

      -This function assigns the given value to a global variable. +Assigns the given value to a global variable. The string name does not need to be a syntactically valid variable name. Therefore, @@ -2073,7 +2032,7 @@

      rawsetglobal (name, value)

      Function rawsetglobal returns the value of its second argument.

      setglobal (name, value)

      -This function assigns the given value to a global variable, +Assigns the given value to a global variable, or calls a tag method. Its full semantics is explained in Section 4.8. The string name does not need to be a @@ -2081,42 +2040,197 @@

      setglobal (name, value)

      Function setglobal returns the value of its second argument.

      rawgetglobal (name)

      -This function retrieves the value of a global variable. +Retrieves the value of a global variable. The string name does not need to be a syntactically valid variable name.

      getglobal (name)

      -This function retrieves the value of a global variable, +Retrieves the value of a global variable, or calls a tag method. Its full semantics is explained in Section 4.8. The string name does not need to be a syntactically valid variable name.

      -

      seterrormethod (newmethod)

      - - -Sets the error handler (see Section 4.9). -newmethod must be a function or nil, -in which case the error handler does nothing. -Returns the old error handler. -

      settagmethod (tag, event, newmethod)

      -This function sets a new tag method to the given pair (tag, event). +Sets a new tag method to the given pair (tag, event). It returns the old method. If newmethod is nil, settagmethod restores the default behavior for the given event.

      gettagmethod (tag, event)

      -This function returns the current tag method +Returns the current tag method for a given pair (tag, event).

      copytagmethods (tagto, tagfrom)

      -This function copies all tag methods from one tag to another; +Copies all tag methods from one tag to another; it returns tagto.

      + +

      getn (table)

      +Returns the ``size'' of a table, when seen as a list. +If the table has an n field with a numeric value, +this is its ``size''. +Otherwise, the size is the largest numerical index with a non-nil +value in the table. +This function could be defined in Lua: +
      +      function getn (t)
      +        if type(t.n) == 'number' then return t.n end
      +        local max = 0
      +        local i = next(t, nil)
      +        while i do
      +          if type(i) == 'number' and i>max then max=i end
      +          i = next(t, i)
      +        end
      +        return max
      +      end
      +
      +

      +

      +

      foreach (table, function)

      +Executes the given function over all elements of table. +For each element, the function is called with the index and +respective value as arguments. +If the function returns any non-nil value, +the loop is broken, and the value is returned +as the final value of foreach. +

      +This function could be defined in Lua: +

      +      function foreach (t, f)
      +        local i, v = next(t, nil)
      +        while i do
      +          local res = f(i, v)
      +          if res then return res end
      +          i, v = next(t, i)
      +        end
      +      end
      +
      +

      +

      +

      foreachi (table, function)

      +Executes the given function over the +numerical indices of table. +For each index, the function is called with the index and +respective value as arguments. +Indices are visited in sequential order, +from 1 to n, +where n is the result of getn(table) (see Section 6.1). +If the function returns any non-nil value, +the loop is broken, and the value is returned +as the final value of foreachi. +

      +This function could be defined in Lua: +

      +      function foreachi (t, f)
      +        local i, n = 1, getn(t)
      +        while i <= n do
      +          local res = f(i, t[i])
      +          if res then return res end
      +          i = i+1
      +        end
      +      end
      +
      +

      +

      foreachvar (function)

      +Executes function over all global variables. +For each variable, +the function is called with its name and its value as arguments. +If the function returns any non-nil value, +the loop is broken, and the value is returned +as the final value of foreachvar. +

      +This function could be defined in Lua: +

      +      function foreachvar (f)
      +        local n, v = nextvar(nil)
      +        while n do
      +          local res = f(n, v)
      +          if res then return res end
      +          n, v = nextvar(n)
      +        end
      +      end
      +
      +

      +

      tinsert (table [, pos] , value)

      +

      +Inserts element value at table position pos, +shifting other elements to open space. +The default value for pos is n+1 +(where n is the result of getn(table) (see Section 6.1)) +so that a call tinsert(t,x) inserts x at the end +of table t. +

      +This function also sets or increments the field n of the table, +to n+1. +

      +This function is equivalent to the following Lua function, +except that the table accesses are all raw (that is, without tag methods): +

      +      function tinsert (t, ...)
      +        local pos, value
      +        local n = getn(t)
      +        if arg.n == 1 then
      +          pos = n+1; value = arg[1]
      +        else
      +          pos = arg[1]; value = arg[2]
      +        end
      +        t.n = n+1;
      +        while n >= pos do
      +          t[n+1] = t[n]
      +          n = n-1
      +        end
      +        t[pos] = value
      +      end
      +
      +

      +

      tremove (table [, pos])

      +

      +Removes from table the element at position pos, +shifting other elements to close the space. +Returns the value of the removed element. +The default value for pos is n +(where n is the result of getn(table) (see Section 6.1)), +so that a call tremove(t) removes the last element +of table t. +

      +This function also sets or decrements the field n of the table, +to n-1. +

      +This function is equivalent to the following Lua function, +except that the table accesses are all raw (that is, without tag methods): +

      +      function tremove (t, pos)
      +        local n = getn(t)
      +        pos = pos or n
      +        local value = t[pos]
      +        if n<=0 then return end
      +        while pos < n do
      +          t[pos] = t[pos+1]
      +          pos = pos+1
      +        end
      +        t[n] = nil
      +        t.n = n-1
      +        return value
      +      end
      +
      +

      +

      sort (table [, comp])

      +Sorts table elements in a given order, in-place, +from table[1] to table[n], +where n is the result of getn(table) (see Section 6.1). +If comp is given, +it must be a function that receives two table elements, +and returns true when the first is less than the second +(so that not comp(a[i+1], a[i]) will be true after the sort). +If comp is not given, +the standard < Lua operator is used instead. +

      +Function sort returns the (sorted) table. +

      6.2 - String Manipulation

      @@ -2127,7 +2241,7 @@

      6.2 - String Manipulation

      strfind (str, pattern [, init [, plain]])

      -This function looks for the first match of +Looks for the first match of pattern in str. If it finds one, then it returns the indices on str where this occurrence starts and ends; @@ -2203,7 +2317,7 @@

      strchar (i1, i2, ...)

      format (formatstring, e1, e2, ...)

      -This function returns a formatted version of its variable number of arguments +Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. @@ -2212,9 +2326,8 @@

      format (formatstring, e1, e2, ...)

      and h are not supported, and there is an extra option, q. This option formats a string in a form suitable to be safely read -back by the Lua interpreter; -that is, -the string is written between double quotes, +back by the Lua interpreter: +The string is written between double quotes, and all double quotes, returns and backslashes in the string are correctly escaped when written. For instance, the call @@ -2241,7 +2354,7 @@

      format (formatstring, e1, e2, ...)

      g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string. -Note that the * modifier can be simulated by building +The * modifier can be simulated by building the appropriate format string. For example, "%*g" can be simulated with "%"..width.."g". @@ -2273,30 +2386,29 @@

      gsub (s, pat, repl [, n])

      For instance, when n is 1 only the first occurrence of pat is replaced.

      -See some examples below: +Here are some examples:

      -  x = gsub("hello world", "(%w%w*)", "%1 %1")
      +  x = gsub("hello world", "(%w+)", "%1 %1")
         --> x="hello hello world world"
       

      - x = gsub("hello world", "(%w%w*)", "%1 %1", 1) + x = gsub("hello world", "(%w+)", "%1 %1", 1) --> x="hello hello world"

      - x = gsub("hello world from Lua", "(%w%w*)%s*(%w%w*)", "%2 %1") + x = gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") --> x="world hello Lua from"

      - x = gsub("home = $HOME, user = $USER", "$(%w%w*)", getenv) + x = gsub("home = $HOME, user = $USER", "%$(%w+)", getenv) --> x="home = /home/roberto, user = roberto" (for instance)

      - x = gsub("4+5 = $return 4+5$", "$(.-)%$", dostring) + x = gsub("4+5 = $return 4+5$", "%$(.-)%$", dostring) --> x="4+5 = 9"

      - local t = {name="lua", version="3.1"} - x = gsub("$name - $version", "$(%w%w*)", function (v) return %t[v] end) - --> x="lua - 3.1" + local t = {name="lua", version="3.2"} + x = gsub("$name - $version", "%$(%w+)", function (v) return %t[v] end) + --> x="lua - 3.2"

      t = {n=0} - gsub("first second word", "(%w%w*)", - function (w) %t.n = %t.n+1; %t[%t.n] = w end) + gsub("first second word", "(%w+)", function (w) tinsert(%t, w) end) --> t={"first", "second", "word"; n=3}

      @@ -2308,24 +2420,25 @@

      Character Class:

      a character class is used to represent a set of characters. The following combinations are allowed in describing a character class:
      -
      x
      (where x is any character not in the list ()%.[*-?) +
      x
      (where x is any character not in the list +^$()%.[]*+-?) - represents the character x itself.
      .
      - (a dot) represents all characters.
      %a
      - represents all letters. -
      %A
      - represents all non letter characters. +
      %c
      - represents all control characters.
      %d
      - represents all digits. -
      %D
      - represents all non digits.
      %l
      - represents all lower case letters. -
      %L
      - represents all non lower case letter characters. +
      %p
      - represents all punctuation characters.
      %s
      - represents all space characters. -
      %S
      - represents all non space characters.
      %u
      - represents all upper case letters. -
      %U
      - represents all non upper case letter characters.
      %w
      - represents all alphanumeric characters. -
      %W
      - represents all non alphanumeric characters. -
      %x
      (where x is any non alphanumeric character) - +
      %x
      - represents all hexa-decimal digits. +
      %z
      - represents the character with representation 0. +
      %x
      (where x is any non alphanumeric character) - represents the character x. -This is the standard way to escape the magic characters ()%.[*-?. +This is the standard way to escape the magic characters ()%.[]*-?. +It is strongly recommended that any control character (even the non magic), +when used to represent itself in a pattern, should be preceded by a %.
      [char-set]
      - Represents the class which is the union of all characters in char-set. @@ -2343,13 +2456,16 @@

      Character Class:

      represents the complement of char-set, where char-set is interpreted as above.
      +For all classes represented by single letters (%a, %c, ...), +the correspondent upper-case letter represents the complement of the class. +For instance, %S represents all non-space characters.

      The definitions of letter, space, etc. depend on the current locale. In particular, the class [a-z] may not be equivalent to %l. The second form should be preferred for more portable programs.

      Pattern Item:

      -a pattern item may be: +a pattern item may be
      • a single character class, @@ -2357,12 +2473,16 @@

        Pattern Item:

      • a single character class followed by *, which matches 0 or more repetitions of characters in the class. -These repetition items will always match the longest possible sequence. +These repetition items will always match the longest possible sequence; +
      • +a single character class followed by +, +which matches 1 or more repetitions of characters in the class. +These repetition items will always match the longest possible sequence;
      • a single character class followed by -, which also matches 0 or more repetitions of characters in the class. Unlike *, -these repetition items will always match the shortest possible sequence. +these repetition items will always match the shortest possible sequence;
      • a single character class followed by ?, which matches 0 or 1 occurrence of a character in the class; @@ -2441,14 +2561,16 @@

        6.3 - Mathematical Functions

        returns a pseudo-random real number in the range [0,1). When called with a number n, random returns a pseudo-random integer in the range [1,n]. +When called with two arguments, l and u, +random returns a pseudo-random integer in the range [l,u].

        6.4 - I/O Facilities

        -All input and output operations in Lua are done over two -file handles, one for reading and one for writing. +All input and output operations in Lua are done, by default, +over two file handles, one for reading and one for writing. These handles are stored in two Lua global variables, called _INPUT and _OUTPUT. The global variables @@ -2461,12 +2583,39 @@

        6.4 - I/O Facilities

        A file handle is a userdata containing the file stream FILE*, and with a distinctive tag created by the I/O library. -

        +Whenever a file handle is collected by the garbage collector, +its correspondent stream is automatically closed.

        Unless otherwise stated, all I/O functions return nil on failure and some value different from nil on success.

        +

        openfile (filename, mode)

        +

        +This function opens a file, +in the mode specified in the string mode. +It returns a new file handle, +or, in case of errors, nil plus a string describing the error. +This function does not modify either _INPUT or _OUTPUT. +

        +The string mode can be any of the following: +

        +
        "r"
        read mode; +
        "w"
        write mode; +
        "a"
        append mode; +
        "r+"
        update mode, all previous data is preserved; +
        "w+"
        update mode, all previous data is erased; +
        "a+"
        append update mode, previous data is preserved, + writing is only allowed at the end of file. +
        +The string mode may also have a b at the end, +which is needed in some systems to open the file in binary mode. +

        +

        closefile (handle)

        +

        +This function closes the given file. +It does not modify either _INPUT or _OUTPUT. +

        readfrom (filename)

        This function may be called in two ways. @@ -2519,52 +2668,81 @@

        writeto (filename)

        appendto (filename)

        -This function opens a file named filename and sets it as the +Opens a file named filename and sets it as the value of _OUTPUT. Unlike the writeto operation, this function does not erase any previous content of the file. If this function fails, it returns nil, plus a string describing the error.

        -Note that function writeto is -available to close an output file opened by appendto. -

        remove (filename)

        -This function deletes the file with the given name. +Deletes the file with the given name. If this function fails, it returns nil, plus a string describing the error.

        rename (name1, name2)

        -This function renames file named name1 to name2. +Renames file named name1 to name2. +If this function fails, it returns nil, +plus a string describing the error. +

        +

        flush ([filehandle])

        +

        +Saves any written data to the given file. +If filehandle is not specified, +flushes all open files. If this function fails, it returns nil, plus a string describing the error.

        +

        seek (filehandle [, whence] [, offset])

        +

        +Sets and gets the file position, +measured in bytes from the beginning of the file, +to the position given by offset plus a base +specified by the string whence, as follows: +

        +
        "set"
        base is position 0 (beginning of the file); +
        "cur"
        base is current position; +
        "end"
        base is end of file; +
        +In case of success, function seek returns the final file position, +measured in bytes from the beginning of the file. +If the call fails, it returns nil, +plus a string describing the error. +

        +The default value for whence is "cur", +and for offset is 0. +Therefore, the call seek(file) returns the current +file position, without changing it; +the call seek(file, "set") sets the position to the +beginning of the file (and returns 0); +and the call seek(file, "end") sets the position to the +end of the file, and returns its size. +

        tmpname ()

        -This function returns a string with a file name that can safely +Returns a string with a file name that can safely be used for a temporary file. The file must be explicitly removed when no longer needed.

        -

        read ([filehandle] [readpattern])

        +

        read ([filehandle,] readpattern1, ...)

        -This function reads the file _INPUT, -or from filehandle if this argument is given, -according to a read pattern, which specifies how much to read; -characters are read from the input file until -the read pattern fails or ends. -The function read returns a string with the characters read, +Reads file _INPUT, +or filehandle if this argument is given, +according to read patterns, which specify how much to read. +For each pattern, +the function returns a string with the characters read, even if the pattern succeeds only partially, or nil if the read pattern fails and the result string would be empty. -When called without parameters, +When called without patterns, it uses a default pattern that reads the next line (see below).

        A read pattern is a sequence of read pattern items. An item may be a single character class -or a character class followed by ? or by *. +or a character class followed by ?, by *, or by +. A single character class reads the next character from the input if it belongs to the class, otherwise it fails. A character class followed by ? reads the next character @@ -2573,6 +2751,9 @@

        read ([filehandle] [readpattern])

        A character class followed by * reads until a character that does not belong to the class, or end of file; since it can match a sequence of zero characters, it never fails. +A character class followed by + reads until a character that +does not belong to the class, or end of file; +it fails if it cannot read at least one character. Note that the behavior of read patterns is slightly different from the regular pattern matching behavior, where a * expands to the maximum length such that @@ -2585,26 +2766,27 @@

        read ([filehandle] [readpattern])

        Characters matching a skip are read, but are not included in the resulting string.

        -Following are some examples of read patterns and their meanings: -

          -
        • "." returns the next character, or nil on end of file. -
        • ".*" reads the whole file. -
        • "[^\n]*{\n}" returns the next line +There are some predefined patterns, as follows: +
          +
          ``*n''
          reads a number; +this is the only pattern that returns a number instead of a string. +
          ``*l''
          returns the next line (skipping the end of line), or nil on end of file. This is the default pattern. -
        • "{%s*}%S%S*" returns the next word +It is equivalent to the pattern "[^\n]*{\n}". +
          ``*a''
          reads the whole file. +It is equivalent to the pattern ".*". +
          ``*w''
          returns the next word (maximal sequence of non white-space characters), -skipping spaces if necessary, -or nil on end of file. -
        • "{%s*}[+-]?%d%d*" returns the next integer -or nil if the next characters do not conform to an integer format. -
        +skipping spaces if necessary, or nil on end of file. +It is equivalent to the pattern "{%s*}%S+". +

    write ([filehandle, ] value1, ...)

    -This function writes the value of each of its arguments to the +Writes the value of each of its arguments to file _OUTPUT, -or to filehandle if this argument is given, +or to filehandle if this argument is given. The arguments must be strings or numbers. To write other values, use tostring or format before write. @@ -2613,21 +2795,21 @@

    write ([filehandle, ] value1, ...)

    date ([format])

    -This function returns a string containing date and time +Returns a string containing date and time formatted according to the given string format, following the same rules of the ANSI C function strftime. When called without arguments, it returns a reasonable date and time representation that depends on -the host system and the locale. +the host system and on the locale.

    clock ()

    -This function returns an approximation of the amount of CPU time +Returns an approximation of the amount of CPU time used by the program, in seconds.

    exit ([code])

    -This function calls the C function exit, +Calls the C function exit, with an optional code, to terminate the program. The default value for code is 1. @@ -2694,12 +2876,16 @@

    7.1 - Stack and Function Information

    Three other functions produce extra information about a function:

    -void lua_funcinfo (lua_Object func, char **filename, int *linedefined);
    +void lua_funcinfo (lua_Object func, char **source, int *linedefined);
     int lua_currentline (lua_Function func);
     char *lua_getobjname (lua_Object o, char **name);
     
    -lua_funcinfo gives the file name and the line where the -given function has been defined. +lua_funcinfo gives the source and the line where the +given function has been defined: +If the function was defined in a string, +source is that string; +If the function was defined in a file, +source starts with a @ followed by the file name. If the ``function'' is in fact the main code of a chunk, then linedefined is 0. If the function is a C function, @@ -2708,21 +2894,30 @@

    7.1 - Stack and Function Information

    The function lua_currentline gives the current line where a given function is executing. It only works if the function has been compiled with debug -information (see Section 4.9). +information. When no line information is available, lua_currentline returns -1.

    +The generation of debug information is controled by an internal flag, +which can be switched with +

    +int lua_setdebug (int debug);
    +
    +This function sets the flag and returns its previous value. +This flag can also be set from Lua (see Section 4.9). +

    Function lua_getobjname tries to find a reasonable name for a given function. Because functions in Lua are first class values, they do not have a fixed name: Some functions may be the value of many global variables, while others may be stored only in a table field. -Function lua_getobjname first checks whether the given -function is a tag method. -If so, it returns the string "tag-method", +Function lua_getobjname checks whether the given +function is a tag method or the value of a global variable. +If the given function is a tag method, then lua_getobjname +returns the string "tag-method", and name is set to point to the event name. -Otherwise, if the given function is the value of a global variable, +If the given function is the value of a global variable, then lua_getobjname returns the string "global", and name points to the variable name. If the given function is neither a tag method nor a global variable, @@ -2736,6 +2931,8 @@

    7.2 - Manipulating Local Variables

    local variables of a given activation record. They only work if the function has been compiled with debug information (see Section 4.9). +Moreover, for these functions, a local variable becomes +visible in the line after its definition.
     lua_Object lua_getlocal (lua_Function func, int local_number, char **name);
     int lua_setlocal (lua_Function func, int local_number);
    @@ -2766,17 +2963,17 @@ 

    7.3 - Hooks

    The Lua interpreter offers two hooks for debugging purposes:
     typedef void (*lua_CHFunction) (lua_Function func, char *file, int line);
    -extern lua_CHFunction lua_callhook;
    +lua_CHFunction lua_setcallhook (lua_CHFunction func);
     

    typedef void (*lua_LHFunction) (int line); -extern lua_LHFunction lua_linehook; +lua_LHFunction lua_setlinehook (lua_LHFunction func);

    -The first one is called whenever the interpreter enters or leaves a +The first hook is called whenever the interpreter enters or leaves a function. When entering a function, its parameters are a handle to the function activation record, -plus the file and the line where the function is defined (the same -information which is provided by lua_funcinfo); +plus the file and the line where the function is defined +(the same information which is provided by lua_funcinfo); when leaving a function, func is LUA_NOOBJECT, file is "(return)", and line is 0.

    @@ -2785,12 +2982,131 @@

    7.3 - Hooks

    Its only parameter is the line number (the same information which is provided by the call lua_currentline(lua_stackedfunction(0))). -This second hook is only called if the active function +This second hook is called only if the active function has been compiled with debug information (see Section 4.9).

    A hook is disabled when its value is NULL, which is the initial value of both hooks. +Both lua_setcallhook and lua_setlinehook +set their corresponding hooks and return their previous values. +

    +

    +

    + +

    7.4 - The Reflexive Debugger Interface

    +

    +The library ldblib provides +the functionallity of the debugger interface to Lua programs. +If you want to use this library, +your host application must open it, +calling lua_dblibopen. +

    +You should exert great care when using this library. +The functions provided here should be used exclusively for debugging +and similar tasks (e.g. profiling). +Please resist the temptation to use them as a +usual programming tool. +They are slow and violate some (otherwise) secure aspects of the +language (e.g. privacy of local variables). +As a general rule, if your program does not need this library, +do not open it. +

    +

    +

    funcinfo (function)

    +

    +This function returns a table with information about the given function. +The table contains the following fields: +

    +
    kind
    : may be "C", if this is a C function, +"chunk", if this is the main part of a chunk, +or "Lua" if this is a Lua function. +

    +

    source
    the source where the function was defined. +If the function was defined in a string, +source is that string; +If the function was defined in a file, +source starts with a @ followed by the file name. +

    +

    def_line
    the line where the function was defined in the source +(only valid if this is a Lua function). +

    +

    where
    can be "global" if this function has a global name, +or "tag-method" if this function is a tag method handler. +

    +

    name
    if where = global, +name is the global name of the function; +if where = tag-method, +name is the event name of the tag method. +
    +

    +

    getstack (index)

    +

    +This function returns a table with informations about the function +running at level index of the stack. +Index 0 is the current function (getstack itself). +If index is bigger than the number of active functions, +the function returns nil. +The table contains all the fields returned by funcinfo, +plus the following: +

    +
    func
    the function at that level. +
    current
    the current line on the function execution; +this will be available only when the function is +precompiled with debug information. +

    +

    getlocal (index [, local])

    +

    +This function returns information about the local variables of the +function at level index of the stack. +It can be called in three ways. +When called without a local argument, +it returns a table, which associates variable names to their values. +When called with a name (a string) as local, +it returns the value of the local variable with that name. +Finally, when called with an index (a number), +it returns the value and the name of the local variable +with that index. +(The first parameter has index 1, and so on, +until the last active local variable.) +In that case, the function returns nil if there is no local +variable with the given index. +The specification by index is the only way to distinguish +homonym variables in a function. +

    +

    setlocal (index, local, newvalue)

    +

    +This function changes the values of the local variables of the +function at level index of the stack. +The local variable can be specified by name or by index; +see function getlocal. +

    +

    setcallhook (hook)

    +

    +Sets the function hook as the call hook; +this hook will be called every time the interpreter starts and +exits the execution of a function. +When Lua enters a function, +the hook is called with the function been called, +plus the source and the line where the function is defined. +When Lua exits a function, +the hook is called with no arguments. +

    +When called without arguments, +this function turns off call hooks. +

    +

    setlinehook (hook)

    +

    +Sets the function hook as the line hook; +this hook will be called every time the interpreter changes +the line of code it is executing. +The only argument to the hook is the line number the interpreter +is about to execut. +This hook is called only if the active function +has been compiled with debug information (see Section 4.9). +

    +When called without arguments, +this function turns off line hooks.

    @@ -2866,6 +3182,18 @@

    Incompatibilities with Previous Versions

    some differences had to be introduced. Here is a list of all these incompatibilities.

    +

    Incompatibilities with version 3.1

    +
      +
    • +In the debug API, the old variables lua_debug, +lua_callhook and lua_linehook now live inside lua_state. +Therefore, they are no longer directly accessible, and must be +manipulated only through the new functions lua_setdebug, +lua_setcallhook and lua_setlinehook. +

      +

    • Old pre-compiled code is obsolete, and must be re-compiled. +
    +

    Incompatibilities with version 3.0

      @@ -2877,7 +3205,7 @@

      Incompatibilities with version 3.0

      library before calling Lua does not need to be modified.

    • Function dostring no longer accepts an optional second argument, -with a temporary error method. +with a temporary error handler. This facility is now provided by function call.

    • Function gsub no longer accepts an optional fourth argument @@ -2898,11 +3226,13 @@

      Incompatibilities with version 3.0

    -


    + Last update: -Fri Jul 10 15:10:14 EST 1998 +Wed Jul 7 13:36:24 EST 1999 by lhf. + + diff --git a/doc/readme.html b/doc/readme.html new file mode 100644 index 0000000000..dd75b1d137 --- /dev/null +++ b/doc/readme.html @@ -0,0 +1,31 @@ + + +Lua documentation + + + + +
    +

    Lua documentation

    + + + +
    + +Last update: +Wed Jul 7 13:24:17 EST 1999 +by lhf. + + + + diff --git a/etc/README b/etc/README index fda602db52..002190aeff 100644 --- a/etc/README +++ b/etc/README @@ -5,9 +5,9 @@ bin2c.c run with lua_dobuffer. This allows C programs to include all necessary Lua code, even in precompiled form. - Even if code is include in source form, bin2c is useful because it + Even if the code is included in source form, bin2c is useful because it avoids the hassle of having to quote special characters in C strings. - Example of usage: run bin2c file1 file2 ... > init.h. The in your C + Example of usage: Run bin2c file1 file2 ... > init.h. Then, in your C program, just do #include "init.h" anywhere in the *body* of a function. This will be equivalent to calling lua_dofile("file1"); lua_dofile("file2"); ... @@ -17,7 +17,8 @@ min.c setfallback.lua An implementation of fallbacks on top of tag methods. - Useful if you have Lua code written for version 2.5 or earlier. + Useful if you have Lua code written for version 2.5 or earlier, + which uses setfallback. If you have C code that uses lua_setfallback, then define LUA_COMPAT2_5 before building Lua (see config). diff --git a/etc/bin2c.c b/etc/bin2c.c index 349b7eee3c..fca82a556d 100644 --- a/etc/bin2c.c +++ b/etc/bin2c.c @@ -2,15 +2,16 @@ * bin2c.c * convert binary files to byte arrays * Luiz Henrique de Figueiredo (lhf@tecgraf.puc-rio.br) -* 25 Jun 98 10:55:12 +* 24 Nov 98 12:15:27 */ #include #include +#include void dump(FILE* f, int n) { - printf("static unsigned char B%d[]={\n"); + printf("static unsigned char B%d[]={\n",n); for (n=1;;n++) { int c=getc(f); @@ -49,6 +50,7 @@ void emit(char* fn, int n) int main(int argc, char* argv[]) { + printf("/* code automatically generated by bin2c -- DO NOT EDIT */\n"); printf("{\n"); if (argc<2) { @@ -58,6 +60,9 @@ int main(int argc, char* argv[]) else { int i; + printf("/* #include'ing this file in a C program is equivalent to calling\n"); + for (i=1; i @@ -8,45 +8,41 @@ #include "lua.h" #include "luadebug.h" -static FILE* P; /* output file */ +static FILE* LOG; /* output file */ static int L=0; /* indentation level */ static void linehook(int line) { - fprintf(P,"%*sLINE(%d)\t-- %d\n",L,"",line,L); + fprintf(LOG,"%*sLINE(%d)\t-- %d\n",L,"",line,L); } static void callhook(lua_Function func, char* file, int line) { - fprintf(P,"%*sCALL('%s',%d)\t-- %d\n",L,"",file,line,L); + fprintf(LOG,"%*sCALL('%s',%d)\t-- %d\n",L,"",file,line,L); if (line==0 && strcmp(file,"(return)")==0) --L; else ++L; } -void start_trace(void) +void start_trace(FILE* logfile) { - lua_linehook=linehook; - lua_callhook=callhook; - lua_debug=1; -#if 0 - P=fopen("trace.out","w"); -#else - P=stderr; -#endif + lua_setlinehook(linehook); + lua_setcallhook(callhook); + lua_setdebug(1); + LOG=logfile; } void stop_trace(void) { - lua_linehook=NULL; - lua_callhook=NULL; - lua_debug=0; - fclose(P); + lua_setlinehook(NULL); + lua_setcallhook(NULL); + lua_setdebug(0); + fclose(LOG); } int main(void) { int rc; lua_open(); - start_trace(); + start_trace(stderr); rc=lua_dofile(0); stop_trace(); return rc; diff --git a/include/lauxlib.h b/include/lauxlib.h index e4d46fb515..28a4664798 100644 --- a/include/lauxlib.h +++ b/include/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.9 1998/06/19 16:14:09 roberto Exp $ +** $Id: lauxlib.h,v 1.12 1999/03/10 14:19:41 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -28,7 +28,11 @@ char *luaL_check_lstr (int numArg, long *len); #define luaL_opt_string(n, d) (luaL_opt_lstr((n), (d), NULL)) char *luaL_opt_lstr (int numArg, char *def, long *len); double luaL_check_number (int numArg); +#define luaL_check_int(n) ((int)luaL_check_number(n)) +#define luaL_check_long(n) ((long)luaL_check_number(n)) double luaL_opt_number (int numArg, double def); +#define luaL_opt_int(n,d) ((int)luaL_opt_number(n,d)) +#define luaL_opt_long(n,d) ((long)luaL_opt_number(n,d)) lua_Object luaL_functionarg (int arg); lua_Object luaL_tablearg (int arg); lua_Object luaL_nonnullarg (int numArg); @@ -42,6 +46,8 @@ int luaL_newbuffer (int size); void luaL_oldbuffer (int old); char *luaL_buffer (void); int luaL_findstring (char *name, char *list[]); +void luaL_chunkid (char *out, char *source, int len); +void luaL_filesource (char *out, char *filename, int len); #endif diff --git a/include/lua.h b/include/lua.h index bce5a2c7f8..f46b2e1d6b 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.23 1998/06/18 16:51:53 roberto Exp $ +** $Id: lua.h,v 1.32 1999/05/11 20:29:19 roberto Exp $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -11,8 +11,8 @@ #ifndef lua_h #define lua_h -#define LUA_VERSION "Lua 3.1" -#define LUA_COPYRIGHT "Copyright (C) 1994-1998 TeCGraf, PUC-Rio" +#define LUA_VERSION "Lua 3.2" +#define LUA_COPYRIGHT "Copyright (C) 1994-1999 TeCGraf, PUC-Rio" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" @@ -20,19 +20,18 @@ #define LUA_ANYTAG (-1) -typedef void (*lua_CFunction) (void); -typedef unsigned int lua_Object; - typedef struct lua_State lua_State; extern lua_State *lua_state; +typedef void (*lua_CFunction) (void); +typedef unsigned int lua_Object; + void lua_open (void); void lua_close (void); lua_State *lua_setstate (lua_State *st); lua_Object lua_settagmethod (int tag, char *event); /* In: new method */ lua_Object lua_gettagmethod (int tag, char *event); -lua_Object lua_seterrormethod (void); /* In: new method */ int lua_newtag (void); int lua_copytagmethods (int tagto, int tagfrom); @@ -90,6 +89,9 @@ lua_Object lua_rawgettable (void); /* In: table, index */ int lua_tag (lua_Object object); +char *lua_nextvar (char *varname); /* Out: value */ +int lua_next (lua_Object o, int i); + /* Out: ref, value */ int lua_ref (int lock); /* In: value */ lua_Object lua_getref (int ref); @@ -101,29 +103,23 @@ long lua_collectgarbage (long limit); /* =============================================================== */ -/* some useful macros/derived functions */ +/* some useful macros/functions */ -int (lua_call) (char *name); #define lua_call(name) lua_callfunction(lua_getglobal(name)) -void (lua_pushref) (int ref); #define lua_pushref(ref) lua_pushobject(lua_getref(ref)) -int (lua_refobject) (lua_Object o, int l); #define lua_refobject(o,l) (lua_pushobject(o), lua_ref(l)) -void (lua_register) (char *n, lua_CFunction f); #define lua_register(n,f) (lua_pushcfunction(f), lua_setglobal(n)) -void (lua_pushuserdata) (void *u); #define lua_pushuserdata(u) lua_pushusertag(u, 0) -void (lua_pushcfunction) (lua_CFunction f); #define lua_pushcfunction(f) lua_pushcclosure(f, 0) -int (lua_clonetag) (int t); #define lua_clonetag(t) lua_copytagmethods(lua_newtag(), (t)) +lua_Object lua_seterrormethod (void); /* In: new method */ /* ========================================================================== ** for compatibility with old versions. Avoid using these macros/functions @@ -162,7 +158,7 @@ lua_Object lua_setfallback (char *event, lua_CFunction fallback); /****************************************************************************** -* Copyright (c) 1994-1998 TeCGraf, PUC-Rio. All rights reserved. +* Copyright (c) 1994-1999 TeCGraf, PUC-Rio. All rights reserved. * * Permission is hereby granted, without written agreement and without license * or royalty fees, to use, copy, modify, and distribute this software and its @@ -192,5 +188,6 @@ lua_Object lua_setfallback (char *event, lua_CFunction fallback); * The Lua language and this implementation have been entirely designed and * written by Waldemar Celes Filho, Roberto Ierusalimschy and * Luiz Henrique de Figueiredo at TeCGraf, PUC-Rio. +* * This implementation contains no third-party code. ******************************************************************************/ diff --git a/include/luadebug.h b/include/luadebug.h index 36726f7fb6..1dc9f206ea 100644 --- a/include/luadebug.h +++ b/include/luadebug.h @@ -1,5 +1,5 @@ /* -** $Id: luadebug.h,v 1.2 1998/06/19 16:14:09 roberto Exp $ +** $Id: luadebug.h,v 1.6 1999/03/04 21:17:26 roberto Exp $ ** Debugging API ** See Copyright Notice in lua.h */ @@ -17,17 +17,18 @@ typedef void (*lua_LHFunction) (int line); typedef void (*lua_CHFunction) (lua_Function func, char *file, int line); lua_Function lua_stackedfunction (int level); -void lua_funcinfo (lua_Object func, char **filename, int *linedefined); +void lua_funcinfo (lua_Object func, char **source, int *linedefined); int lua_currentline (lua_Function func); char *lua_getobjname (lua_Object o, char **name); lua_Object lua_getlocal (lua_Function func, int local_number, char **name); int lua_setlocal (lua_Function func, int local_number); +int lua_nups (lua_Function func); -extern lua_LHFunction lua_linehook; -extern lua_CHFunction lua_callhook; -extern int lua_debug; +lua_LHFunction lua_setlinehook (lua_LHFunction func); +lua_CHFunction lua_setcallhook (lua_CHFunction func); +int lua_setdebug (int debug); #endif diff --git a/include/lualib.h b/include/lualib.h index 583f1b5408..c7187868d3 100644 --- a/include/lualib.h +++ b/include/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.4 1998/06/19 16:14:09 roberto Exp $ +** $Id: lualib.h,v 1.6 1999/05/05 19:23:11 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -10,12 +10,13 @@ #include "lua.h" - void lua_iolibopen (void); void lua_strlibopen (void); void lua_mathlibopen (void); +void lua_dblibopen (void); +void lua_userinit (void); /* To keep compatibility with old versions */ @@ -28,7 +29,8 @@ void lua_mathlibopen (void); /* Auxiliary functions (private) */ -int luaI_singlematch (int c, char *p, char **ep); +char *luaI_classend (char *p); +int luaI_singlematch (int c, char *p, char *ep); #endif diff --git a/src/lapi.c b/src/lapi.c index 9db0278c13..0a5b99db52 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.25 1998/06/05 22:17:44 roberto Exp $ +** $Id: lapi.c,v 1.47 1999/06/22 20:37:23 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -25,17 +25,16 @@ char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" - "$Autores: " LUA_AUTHORS " $"; + "$Authors: " LUA_AUTHORS " $"; -TObject *luaA_Address (lua_Object o) -{ - return Address(o); +TObject *luaA_Address (lua_Object o) { + return (o != LUA_NOOBJECT) ? Address(o) : NULL; } -static int normalized_type (TObject *o) +static lua_Type normalized_type (TObject *o) { int t = ttype(o); switch (t) { @@ -71,12 +70,8 @@ void luaA_packresults (void) } -int luaA_passresults (void) -{ - luaD_checkstack(L->Cstack.num); - memcpy(L->stack.top, L->Cstack.lua2C+L->stack.stack, - L->Cstack.num*sizeof(TObject)); - L->stack.top += L->Cstack.num; +int luaA_passresults (void) { + L->Cstack.base = L->Cstack.lua2C; /* position of first result */ return L->Cstack.num; } @@ -88,24 +83,29 @@ static void checkCparams (int nParams) } -static lua_Object put_luaObject (TObject *o) -{ +static lua_Object put_luaObject (TObject *o) { luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); L->stack.stack[L->Cstack.base++] = *o; return L->Cstack.base; /* this is +1 real position (see Ref) */ } -static lua_Object put_luaObjectonTop (void) -{ +static lua_Object put_luaObjectonTop (void) { luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); L->stack.stack[L->Cstack.base++] = *(--L->stack.top); return L->Cstack.base; /* this is +1 real position (see Ref) */ } -lua_Object lua_pop (void) -{ +static void top2LC (int n) { + /* Put the 'n' elements on the top as the Lua2C contents */ + L->Cstack.base = (L->stack.top-L->stack.stack); /* new base */ + L->Cstack.lua2C = L->Cstack.base-n; /* position of the new results */ + L->Cstack.num = n; /* number of results */ +} + + +lua_Object lua_pop (void) { checkCparams(1); return put_luaObjectonTop(); } @@ -131,7 +131,7 @@ int lua_callfunction (lua_Object function) else { luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); set_normalized(L->stack.stack+L->Cstack.base, Address(function)); - return luaD_protectedrun(MULT_RET); + return luaD_protectedrun(); } } @@ -150,12 +150,12 @@ lua_Object lua_settagmethod (int tag, char *event) } -lua_Object lua_seterrormethod (void) -{ - TObject temp = L->errorim; +lua_Object lua_seterrormethod (void) { + lua_Object temp; checkCparams(1); - L->errorim = *(--L->stack.top); - return put_luaObject(&temp); + temp = lua_getglobal("_ERRORMESSAGE"); + lua_setglobal("_ERRORMESSAGE"); + return temp; } @@ -167,34 +167,26 @@ lua_Object lua_gettable (void) } -lua_Object lua_rawgettable (void) -{ +lua_Object lua_rawgettable (void) { checkCparams(2); if (ttype(L->stack.top-2) != LUA_T_ARRAY) lua_error("indexed expression not a table in rawgettable"); - else { - TObject *h = luaH_get(avalue(L->stack.top-2), L->stack.top-1); - --L->stack.top; - if (h != NULL) - *(L->stack.top-1) = *h; - else - ttype(L->stack.top-1) = LUA_T_NIL; - } + *(L->stack.top-2) = *luaH_get(avalue(L->stack.top-2), L->stack.top-1); + --L->stack.top; return put_luaObjectonTop(); } -void lua_settable (void) -{ +void lua_settable (void) { checkCparams(3); - luaV_settable(L->stack.top-3, 1); + luaV_settable(L->stack.top-3); + L->stack.top -= 2; /* pop table and index */ } -void lua_rawsettable (void) -{ +void lua_rawsettable (void) { checkCparams(3); - luaV_settable(L->stack.top-3, 0); + luaV_rawsettable(L->stack.top-3); } @@ -373,14 +365,11 @@ void luaA_pushobject (TObject *o) incr_top; } -void lua_pushobject (lua_Object o) -{ +void lua_pushobject (lua_Object o) { if (o == LUA_NOOBJECT) lua_error("API error - attempt to push a NOOBJECT"); - else { - set_normalized(L->stack.top, Address(o)); - incr_top; - } + set_normalized(L->stack.top, Address(o)); + incr_top; } @@ -426,22 +415,108 @@ void lua_settag (int tag) break; default: luaL_verror("cannot change the tag of a %.20s", - luaO_typenames[-ttype((L->stack.top-1))]); + luaO_typename(L->stack.top-1)); } L->stack.top--; } +TaggedString *luaA_nextvar (TaggedString *g) { + if (g == NULL) + g = (TaggedString *)L->rootglobal.next; /* first variable */ + else { + /* check whether name is in global var list */ + luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected"); + g = (TaggedString *)g->head.next; /* get next */ + } + while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ + g = (TaggedString *)g->head.next; + if (g) { + ttype(L->stack.top) = LUA_T_STRING; tsvalue(L->stack.top) = g; + incr_top; + luaA_pushobject(&g->u.s.globalval); + } + return g; +} + + +char *lua_nextvar (char *varname) { + TaggedString *g = (varname == NULL) ? NULL : luaS_new(varname); + g = luaA_nextvar(g); + if (g) { + top2LC(2); + return g->str; + } + else { + top2LC(0); + return NULL; + } +} + + +int luaA_next (Hash *t, int i) { + int tsize = nhash(t); + for (; ilinehook; + L->linehook = func; + return old; +} + +lua_CHFunction lua_setcallhook (lua_CHFunction func) { + lua_CHFunction old = L->callhook; + L->callhook = func; + return old; +} + +int lua_setdebug (int debug) { + int old = L->debug; + L->debug = debug; + return old; +} + +/* }====================================================== */ -/* Hooks */ -lua_CHFunction lua_callhook = NULL; -lua_LHFunction lua_linehook = NULL; + +/* +** {====================================================== +** Debug interface +** ======================================================= +*/ lua_Function lua_stackedfunction (int level) @@ -457,6 +532,12 @@ lua_Function lua_stackedfunction (int level) } +int lua_nups (lua_Function func) { + TObject *o = luaA_Address(func); + return (!o || normalized_type(o) != LUA_T_CLOSURE) ? 0 : o->value.cl->nelems; +} + + int lua_currentline (lua_Function func) { TObject *f = Address(func); @@ -465,8 +546,7 @@ int lua_currentline (lua_Function func) } -lua_Object lua_getlocal (lua_Function func, int local_number, char **name) -{ +lua_Object lua_getlocal (lua_Function func, int local_number, char **name) { /* check whether func is a Lua function */ if (lua_tag(func) != LUA_T_PROTO) return LUA_NOOBJECT; @@ -477,7 +557,7 @@ lua_Object lua_getlocal (lua_Function func, int local_number, char **name) if (*name) { /* if "*name", there must be a LUA_T_LINE */ /* therefore, f+2 points to function base */ - return Ref((f+2)+(local_number-1)); + return put_luaObject((f+2)+(local_number-1)); } else return LUA_NOOBJECT; @@ -508,18 +588,17 @@ int lua_setlocal (lua_Function func, int local_number) } -void lua_funcinfo (lua_Object func, char **filename, int *linedefined) -{ +void lua_funcinfo (lua_Object func, char **source, int *linedefined) { if (!lua_isfunction(func)) - lua_error("API - `funcinfo' called with a non-function value"); + lua_error("API error - `funcinfo' called with a non-function value"); else { TObject *f = luaA_protovalue(Address(func)); if (normalized_type(f) == LUA_T_PROTO) { - *filename = tfvalue(f)->fileName->str; + *source = tfvalue(f)->source->str; *linedefined = tfvalue(f)->lineDefined; } else { - *filename = "(C)"; + *source = "(C)"; *linedefined = -1; } } @@ -534,31 +613,37 @@ static int checkfunc (TObject *o) char *lua_getobjname (lua_Object o, char **name) { /* try to find a name for given function */ - set_normalized(L->stack.top, Address(o)); /* to be accessed by "checkfunc */ - if ((*name = luaT_travtagmethods(checkfunc)) != NULL) - return "tag-method"; - else if ((*name = luaS_travsymbol(checkfunc)) != NULL) + set_normalized(L->stack.top, Address(o)); /* to be accessed by "checkfunc" */ + if ((*name = luaS_travsymbol(checkfunc)) != NULL) return "global"; + else if ((*name = luaT_travtagmethods(checkfunc)) != NULL) + return "tag-method"; else return ""; } +/* }====================================================== */ + + /* -** ======================================================= +** {====================================================== ** BLOCK mechanism ** ======================================================= */ -void lua_beginblock (void) -{ - if (L->numCblocks >= MAX_C_BLOCKS) - lua_error("too many nested blocks"); +#ifndef MAX_C_BLOCKS +#define MAX_C_BLOCKS 1000 /* arbitrary limit */ +#endif + + +void lua_beginblock (void) { + luaM_growvector(L->Cblocks, L->numCblocks, 1, struct C_Lua_Stack, + "too many nested blocks", MAX_C_BLOCKS); L->Cblocks[L->numCblocks] = L->Cstack; L->numCblocks++; } -void lua_endblock (void) -{ +void lua_endblock (void) { --L->numCblocks; L->Cstack = L->Cblocks[L->numCblocks]; luaD_adjusttop(L->Cstack.base); @@ -566,8 +651,7 @@ void lua_endblock (void) -int lua_ref (int lock) -{ +int lua_ref (int lock) { int ref; checkCparams(1); ref = luaC_ref(L->stack.top-1, lock); @@ -577,32 +661,12 @@ int lua_ref (int lock) -lua_Object lua_getref (int ref) -{ +lua_Object lua_getref (int ref) { TObject *o = luaC_getref(ref); return (o ? put_luaObject(o) : LUA_NOOBJECT); } - -/* -** ======================================================= -** Derived functions -** ======================================================= -*/ -int (lua_call) (char *name) { return lua_call(name); } - -void (lua_pushref) (int ref) { lua_pushref(ref); } - -int (lua_refobject) (lua_Object o, int l) { return lua_refobject(o, l); } - -void (lua_register) (char *n, lua_CFunction f) { lua_register(n, f); } - -void (lua_pushuserdata) (void *u) { lua_pushuserdata(u); } - -void (lua_pushcfunction) (lua_CFunction f) { lua_pushcfunction(f); } - -int (lua_clonetag) (int t) { return lua_clonetag(t); } - +/* }====================================================== */ @@ -611,17 +675,15 @@ int (lua_clonetag) (int t) { return lua_clonetag(t); } ** API: set a function as a fallback */ -static void do_unprotectedrun (lua_CFunction f, int nParams, int nResults) -{ - StkId base = (L->stack.top-L->stack.stack)-nParams; +static void do_unprotectedrun (lua_CFunction f, int nParams, int nResults) { luaD_openstack(nParams); - L->stack.stack[base].ttype = LUA_T_CPROTO; - L->stack.stack[base].value.f = f; - luaD_call(base+1, nResults); + (L->stack.top-nParams)->ttype = LUA_T_CPROTO; + (L->stack.top-nParams)->value.f = f; + luaD_calln(nParams, nResults); } -lua_Object lua_setfallback (char *name, lua_CFunction fallback) -{ + +lua_Object lua_setfallback (char *name, lua_CFunction fallback) { lua_pushstring(name); lua_pushcfunction(fallback); do_unprotectedrun(luaT_setfallback, 2, 1); diff --git a/src/lapi.h b/src/lapi.h index ca9a11739d..638a847fc7 100644 --- a/src/lapi.h +++ b/src/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 1.2 1998/06/19 16:14:09 roberto Exp $ +** $Id: lapi.h,v 1.4 1999/02/23 14:57:28 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -16,5 +16,7 @@ TObject *luaA_Address (lua_Object o); void luaA_pushobject (TObject *o); void luaA_packresults (void); int luaA_passresults (void); +TaggedString *luaA_nextvar (TaggedString *g); +int luaA_next (Hash *t, int i); #endif diff --git a/src/lauxlib.c b/src/lauxlib.c index 0a972af04f..db929c4f90 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.12 1998/06/19 16:14:09 roberto Exp $ +** $Id: lauxlib.c,v 1.17 1999/03/11 18:59:19 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -10,9 +10,10 @@ #include /* Please Notice: This file uses only the official API of Lua -** Any function declared here could be written as an application -** function. With care, these functions can be used by other libraries. +** Any function declared here could be written as an application function. +** With care, these functions can be used by other libraries. */ + #include "lauxlib.h" #include "lua.h" #include "luadebug.h" @@ -27,12 +28,13 @@ int luaL_findstring (char *name, char *list[]) { return -1; /* name not found */ } -void luaL_argerror (int numarg, char *extramsg) -{ +void luaL_argerror (int numarg, char *extramsg) { + lua_Function f = lua_stackedfunction(0); char *funcname; - lua_getobjname(lua_stackedfunction(0), &funcname); + lua_getobjname(f, &funcname); + numarg -= lua_nups(f); if (funcname == NULL) - funcname = "???"; + funcname = "?"; if (extramsg == NULL) luaL_verror("bad argument #%d to function `%.50s'", numarg, funcname); else @@ -109,3 +111,23 @@ void luaL_verror (char *fmt, ...) lua_error(buff); } + +void luaL_chunkid (char *out, char *source, int len) { + len -= 13; /* 13 = strlen("string ''...\0") */ + if (*source == '@') + sprintf(out, "file `%.*s'", len, source+1); + else if (*source == '(') + strcpy(out, "(C code)"); + else { + char *b = strchr(source , '\n'); /* stop string at first new line */ + int lim = (b && (b-source)Mbuffnext+(size) > L->Mbuffsize) Openspace(size) -static void Openspace (int size) -{ +static void Openspace (int size) { lua_State *l = L; /* to optimize */ - int base = l->Mbuffbase-l->Mbuffer; - l->Mbuffsize *= 2; - if (l->Mbuffnext+size > l->Mbuffsize) /* still not big enough? */ - l->Mbuffsize = l->Mbuffnext+size; - l->Mbuffer = luaM_realloc(l->Mbuffer, l->Mbuffsize); - l->Mbuffbase = l->Mbuffer+base; + size += EXTRABUFF; + l->Mbuffsize = l->Mbuffnext+size; + luaM_growvector(l->Mbuffer, l->Mbuffnext, size, char, arrEM, MAX_INT); } -char *luaL_openspace (int size) -{ +char *luaL_openspace (int size) { openspace(size); return L->Mbuffer+L->Mbuffnext; } -void luaL_addchar (int c) -{ - openspace(BUFF_STEP); - L->Mbuffer[L->Mbuffnext++] = c; +void luaL_addchar (int c) { + openspace(1); + L->Mbuffer[L->Mbuffnext++] = (char)c; } -void luaL_resetbuffer (void) -{ - L->Mbuffnext = L->Mbuffbase-L->Mbuffer; +void luaL_resetbuffer (void) { + L->Mbuffnext = L->Mbuffbase; } -void luaL_addsize (int n) -{ +void luaL_addsize (int n) { L->Mbuffnext += n; } -int luaL_getsize (void) -{ - return L->Mbuffnext-(L->Mbuffbase-L->Mbuffer); +int luaL_getsize (void) { + return L->Mbuffnext-L->Mbuffbase; } -int luaL_newbuffer (int size) -{ - int old = L->Mbuffbase-L->Mbuffer; +int luaL_newbuffer (int size) { + int old = L->Mbuffbase; openspace(size); - L->Mbuffbase = L->Mbuffer+L->Mbuffnext; + L->Mbuffbase = L->Mbuffnext; return old; } -void luaL_oldbuffer (int old) -{ - L->Mbuffnext = L->Mbuffbase-L->Mbuffer; - L->Mbuffbase = L->Mbuffer+old; +void luaL_oldbuffer (int old) { + L->Mbuffnext = L->Mbuffbase; + L->Mbuffbase = old; } -char *luaL_buffer (void) -{ - return L->Mbuffbase; +char *luaL_buffer (void) { + return L->Mbuffer+L->Mbuffbase; } diff --git a/src/lbuiltin.c b/src/lbuiltin.c index 0fd39f70d1..c88ccd41e8 100644 --- a/src/lbuiltin.c +++ b/src/lbuiltin.c @@ -1,5 +1,5 @@ /* -** $Id: lbuiltin.c,v 1.32 1998/06/29 18:24:06 roberto Exp $ +** $Id: lbuiltin.c,v 1.59 1999/06/17 17:04:03 roberto Exp $ ** Built-in functions ** See Copyright Notice in lua.h */ @@ -23,11 +23,18 @@ #include "ltm.h" #include "lua.h" #include "lundump.h" +#include "lvm.h" -static void pushstring (TaggedString *s) -{ +/* +** {====================================================== +** Auxiliary functions +** ======================================================= +*/ + + +static void pushtagstring (TaggedString *s) { TObject o; o.ttype = LUA_T_STRING; o.value.ts = s; @@ -35,209 +42,126 @@ static void pushstring (TaggedString *s) } -static void nextvar (void) -{ - TObject *o = luaA_Address(luaL_nonnullarg(1)); - TaggedString *g; - if (ttype(o) == LUA_T_NIL) - g = (TaggedString *)L->rootglobal.next; - else { - luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected"); - g = tsvalue(o); - /* check whether name is in global var list */ - luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected"); - g = (TaggedString *)g->head.next; - } - while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ - g = (TaggedString *)g->head.next; - if (g) { - pushstring(g); - luaA_pushobject(&g->u.s.globalval); +static real getsize (Hash *h) { + real max = 0; + int i; + for (i = 0; inode+i; + if (ttype(ref(n)) == LUA_T_NUMBER && + ttype(val(n)) != LUA_T_NIL && + nvalue(ref(n)) > max) + max = nvalue(ref(n)); } - else lua_pushnil(); + return max; } -static void foreachvar (void) -{ - TObject f = *luaA_Address(luaL_functionarg(1)); - GCnode *g; - StkId name = L->Cstack.base++; /* place to keep var name (to avoid GC) */ - ttype(L->stack.stack+name) = LUA_T_NIL; - L->stack.top++; - for (g = L->rootglobal.next; g; g = g->next) { - TaggedString *s = (TaggedString *)g; - if (s->u.s.globalval.ttype != LUA_T_NIL) { - ttype(L->stack.stack+name) = LUA_T_STRING; - tsvalue(L->stack.stack+name) = s; /* keep s on stack to avoid GC */ - luaA_pushobject(&f); - pushstring(s); - luaA_pushobject(&s->u.s.globalval); - luaD_call((L->stack.top-L->stack.stack)-2, 1); - if (ttype(L->stack.top-1) != LUA_T_NIL) - return; - L->stack.top--; - } - } +static real getnarg (Hash *a) { + TObject index; + TObject *value; + /* value = table.n */ + ttype(&index) = LUA_T_STRING; + tsvalue(&index) = luaS_new("n"); + value = luaH_get(a, &index); + return (ttype(value) == LUA_T_NUMBER) ? nvalue(value) : getsize(a); } -static void next (void) -{ - lua_Object o = luaL_tablearg(1); - lua_Object r = luaL_nonnullarg(2); - Node *n = luaH_next(luaA_Address(o), luaA_Address(r)); - if (n) { - luaA_pushobject(&n->ref); - luaA_pushobject(&n->val); - } - else lua_pushnil(); +static Hash *gethash (int arg) { + return avalue(luaA_Address(luaL_tablearg(arg))); } - -static void foreach (void) -{ - TObject t = *luaA_Address(luaL_tablearg(1)); - TObject f = *luaA_Address(luaL_functionarg(2)); - int i; - for (i=0; inhash; i++) { - Node *nd = &(avalue(&t)->node[i]); - if (ttype(ref(nd)) != LUA_T_NIL && ttype(val(nd)) != LUA_T_NIL) { - luaA_pushobject(&f); - luaA_pushobject(ref(nd)); - luaA_pushobject(val(nd)); - luaD_call((L->stack.top-L->stack.stack)-2, 1); - if (ttype(L->stack.top-1) != LUA_T_NIL) - return; - L->stack.top--; - } - } -} +/* }====================================================== */ -static void internaldostring (void) -{ - long l; - char *s = luaL_check_lstr(1, &l); - if (*s == ID_CHUNK) - lua_error("`dostring' cannot run pre-compiled code"); - if (lua_dobuffer(s, l, luaL_opt_string(2, NULL)) == 0) - if (luaA_passresults() == 0) - lua_pushuserdata(NULL); /* at least one result to signal no errors */ -} +/* +** {====================================================== +** Functions that use only the official API +** ======================================================= +*/ -static void internaldofile (void) -{ - char *fname = luaL_opt_string(1, NULL); - if (lua_dofile(fname) == 0) - if (luaA_passresults() == 0) - lua_pushuserdata(NULL); /* at least one result to signal no errors */ +/* +** If your system does not support "stderr", redefine this function, or +** redefine _ERRORMESSAGE so that it won't need _ALERT. +*/ +static void luaB_alert (void) { + fputs(luaL_check_string(1), stderr); } -static void to_string (void) { - lua_Object obj = lua_getparam(1); - char *buff = luaL_openspace(30); - TObject *o = luaA_Address(obj); - switch (ttype(o)) { - case LUA_T_NUMBER: - lua_pushstring(lua_getstring(obj)); - return; - case LUA_T_STRING: - lua_pushobject(obj); - return; - case LUA_T_ARRAY: { - sprintf(buff, "table: %p", (void *)o->value.a); - break; - } - case LUA_T_CLOSURE: { - sprintf(buff, "function: %p", (void *)o->value.cl); - break; - } - case LUA_T_PROTO: { - sprintf(buff, "function: %p", (void *)o->value.tf); - break; - } - case LUA_T_CPROTO: { - sprintf(buff, "function: %p", (void *)o->value.f); - break; - } - case LUA_T_USERDATA: { - sprintf(buff, "userdata: %p", o->value.ts->u.d.v); - break; - } - case LUA_T_NIL: - lua_pushstring("nil"); - return; - default: - LUA_INTERNALERROR("invalid type"); +/* +** Standard implementation of _ERRORMESSAGE. +** The library "iolib" redefines _ERRORMESSAGE for better error information. +*/ +static void error_message (void) { + lua_Object al = lua_rawgetglobal("_ALERT"); + if (lua_isfunction(al)) { /* avoid error loop if _ALERT is not defined */ + char buff[600]; + sprintf(buff, "lua error: %.500s\n", luaL_check_string(1)); + lua_pushstring(buff); + lua_callfunction(al); } - lua_pushstring(buff); } -static void luaI_print (void) { - TaggedString *ts = luaS_new("tostring"); +/* +** If your system does not support "stdout", just remove this function. +** If you need, you can define your own "print" function, following this +** model but changing "fputs" to put the strings at a proper place +** (a console window or a log file, for instance). +*/ +#ifndef MAXPRINT +#define MAXPRINT 40 /* arbitrary limit */ +#endif + +static void luaB_print (void) { + lua_Object args[MAXPRINT]; lua_Object obj; - int i = 1; - while ((obj = lua_getparam(i++)) != LUA_NOOBJECT) { - luaA_pushobject(&ts->u.s.globalval); - lua_pushobject(obj); - luaD_call((L->stack.top-L->stack.stack)-1, 1); - if (ttype(L->stack.top-1) != LUA_T_STRING) + int n = 0; + int i; + while ((obj = lua_getparam(n+1)) != LUA_NOOBJECT) { + luaL_arg_check(n < MAXPRINT, n+1, "too many arguments"); + args[n++] = obj; + } + for (i=0; istack.top-1)); - L->stack.top--; + if (i>0) fputs("\t", stdout); + fputs(lua_getstring(obj), stdout); } - printf("\n"); -} - - -static void luaI_type (void) -{ - lua_Object o = luaL_nonnullarg(1); - lua_pushstring(luaO_typenames[-ttype(luaA_Address(o))]); - lua_pushnumber(lua_tag(o)); + fputs("\n", stdout); } -static void tonumber (void) -{ - int base = luaL_opt_number(2, 10); +static void luaB_tonumber (void) { + int base = luaL_opt_int(2, 10); if (base == 10) { /* standard conversion */ lua_Object o = lua_getparam(1); - if (lua_isnumber(o)) - lua_pushnumber(lua_getnumber(o)); + if (lua_isnumber(o)) lua_pushnumber(lua_getnumber(o)); + else lua_pushnil(); /* not a number */ } else { char *s = luaL_check_string(1); - unsigned long n; + long n; luaL_arg_check(0 <= base && base <= 36, 2, "base out of range"); n = strtol(s, &s, base); - while (isspace(*s)) s++; /* skip trailing spaces */ + while (isspace((unsigned char)*s)) s++; /* skip trailing spaces */ if (*s) lua_pushnil(); /* invalid format: return nil */ else lua_pushnumber(n); } } -static void luaI_error (void) -{ +static void luaB_error (void) { lua_error(lua_getstring(lua_getparam(1))); } - -static void luaI_assert (void) -{ - lua_Object p = lua_getparam(1); - if (p == LUA_NOOBJECT || lua_isnil(p)) - luaL_verror("assertion failed! %.100s", luaL_opt_string(2, "")); -} - - -static void setglobal (void) -{ +static void luaB_setglobal (void) { char *n = luaL_check_string(1); lua_Object value = luaL_nonnullarg(2); lua_pushobject(value); @@ -245,8 +169,7 @@ static void setglobal (void) lua_pushobject(value); /* return given value */ } -static void rawsetglobal (void) -{ +static void luaB_rawsetglobal (void) { char *n = luaL_check_string(1); lua_Object value = luaL_nonnullarg(2); lua_pushobject(value); @@ -254,51 +177,111 @@ static void rawsetglobal (void) lua_pushobject(value); /* return given value */ } -static void getglobal (void) -{ +static void luaB_getglobal (void) { lua_pushobject(lua_getglobal(luaL_check_string(1))); } -static void rawgetglobal (void) -{ +static void luaB_rawgetglobal (void) { lua_pushobject(lua_rawgetglobal(luaL_check_string(1))); } -static void luatag (void) -{ +static void luaB_luatag (void) { lua_pushnumber(lua_tag(lua_getparam(1))); } +static void luaB_settag (void) { + lua_Object o = luaL_tablearg(1); + lua_pushobject(o); + lua_settag(luaL_check_int(2)); + lua_pushobject(o); /* return first argument */ +} + +static void luaB_newtag (void) { + lua_pushnumber(lua_newtag()); +} + +static void luaB_copytagmethods (void) { + lua_pushnumber(lua_copytagmethods(luaL_check_int(1), + luaL_check_int(2))); +} + +static void luaB_rawgettable (void) { + lua_pushobject(luaL_nonnullarg(1)); + lua_pushobject(luaL_nonnullarg(2)); + lua_pushobject(lua_rawgettable()); +} + +static void luaB_rawsettable (void) { + lua_pushobject(luaL_nonnullarg(1)); + lua_pushobject(luaL_nonnullarg(2)); + lua_pushobject(luaL_nonnullarg(3)); + lua_rawsettable(); +} + +static void luaB_settagmethod (void) { + lua_Object nf = luaL_nonnullarg(3); + lua_pushobject(nf); + lua_pushobject(lua_settagmethod(luaL_check_int(1), luaL_check_string(2))); +} + +static void luaB_gettagmethod (void) { + lua_pushobject(lua_gettagmethod(luaL_check_int(1), luaL_check_string(2))); +} -static int getnarg (lua_Object table) -{ - lua_Object temp; - /* temp = table.n */ - lua_pushobject(table); lua_pushstring("n"); temp = lua_rawgettable(); - return (lua_isnumber(temp) ? lua_getnumber(temp) : MAX_INT); +static void luaB_seterrormethod (void) { + lua_Object nf = luaL_functionarg(1); + lua_pushobject(nf); + lua_pushobject(lua_seterrormethod()); +} + +static void luaB_collectgarbage (void) { + lua_pushnumber(lua_collectgarbage(luaL_opt_int(1, 0))); } -static void luaI_call (void) -{ +/* }====================================================== */ + + +/* +** {====================================================== +** Functions that could use only the official API but +** do not, for efficiency. +** ======================================================= +*/ + +static void luaB_dostring (void) { + long l; + char *s = luaL_check_lstr(1, &l); + if (*s == ID_CHUNK) + lua_error("`dostring' cannot run pre-compiled code"); + if (lua_dobuffer(s, l, luaL_opt_string(2, s)) == 0) + if (luaA_passresults() == 0) + lua_pushuserdata(NULL); /* at least one result to signal no errors */ +} + + +static void luaB_dofile (void) { + char *fname = luaL_opt_string(1, NULL); + if (lua_dofile(fname) == 0) + if (luaA_passresults() == 0) + lua_pushuserdata(NULL); /* at least one result to signal no errors */ +} + + +static void luaB_call (void) { lua_Object f = luaL_nonnullarg(1); - lua_Object arg = luaL_tablearg(2); + Hash *arg = gethash(2); char *options = luaL_opt_string(3, ""); lua_Object err = lua_getparam(4); - int narg = getnarg(arg); + int narg = (int)getnarg(arg); int i, status; if (err != LUA_NOOBJECT) { /* set new error method */ lua_pushobject(err); err = lua_seterrormethod(); } /* push arg[1...n] */ - for (i=0; istack.top++) = *luaH_getint(arg, i+1); status = lua_callfunction(f); if (err != LUA_NOOBJECT) { /* restore old error method */ lua_pushobject(err); @@ -312,7 +295,7 @@ static void luaI_call (void) else lua_error(NULL); } - else { /* no errors */ + else { /* no errors */ if (strchr(options, 'p')) luaA_packresults(); else @@ -321,91 +304,306 @@ static void luaI_call (void) } -static void settag (void) -{ - lua_Object o = luaL_tablearg(1); - lua_pushobject(o); - lua_settag(luaL_check_number(2)); - lua_pushobject(o); /* returns first argument */ +static void luaB_nextvar (void) { + TObject *o = luaA_Address(luaL_nonnullarg(1)); + TaggedString *g; + if (ttype(o) == LUA_T_NIL) + g = NULL; + else { + luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected"); + g = tsvalue(o); + } + if (!luaA_nextvar(g)) + lua_pushnil(); } -static void newtag (void) -{ - lua_pushnumber(lua_newtag()); +static void luaB_next (void) { + Hash *a = gethash(1); + TObject *k = luaA_Address(luaL_nonnullarg(2)); + int i = (ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1; + if (luaA_next(a, i) == 0) + lua_pushnil(); } -static void copytagmethods (void) -{ - lua_pushnumber(lua_copytagmethods(luaL_check_number(1), - luaL_check_number(2))); +static void luaB_tostring (void) { + lua_Object obj = lua_getparam(1); + TObject *o = luaA_Address(obj); + char buff[64]; + switch (ttype(o)) { + case LUA_T_NUMBER: + lua_pushstring(lua_getstring(obj)); + return; + case LUA_T_STRING: + lua_pushobject(obj); + return; + case LUA_T_ARRAY: + sprintf(buff, "table: %p", (void *)o->value.a); + break; + case LUA_T_CLOSURE: + sprintf(buff, "function: %p", (void *)o->value.cl); + break; + case LUA_T_PROTO: + sprintf(buff, "function: %p", (void *)o->value.tf); + break; + case LUA_T_CPROTO: + sprintf(buff, "function: %p", (void *)o->value.f); + break; + case LUA_T_USERDATA: + sprintf(buff, "userdata: %p", o->value.ts->u.d.v); + break; + case LUA_T_NIL: + lua_pushstring("nil"); + return; + default: + LUA_INTERNALERROR("invalid type"); + } + lua_pushstring(buff); } -static void rawgettable (void) -{ - lua_pushobject(luaL_nonnullarg(1)); - lua_pushobject(luaL_nonnullarg(2)); - lua_pushobject(lua_rawgettable()); +static void luaB_type (void) { + lua_Object o = luaL_nonnullarg(1); + lua_pushstring(luaO_typename(luaA_Address(o))); + lua_pushnumber(lua_tag(o)); } +/* }====================================================== */ -static void rawsettable (void) -{ - lua_pushobject(luaL_nonnullarg(1)); - lua_pushobject(luaL_nonnullarg(2)); - lua_pushobject(luaL_nonnullarg(3)); - lua_rawsettable(); + + +/* +** {====================================================== +** "Extra" functions +** These functions can be written in Lua, so you can +** delete them if you need a tiny Lua implementation. +** If you delete them, remove their entries in array +** "builtin_funcs". +** ======================================================= +*/ + +static void luaB_assert (void) { + lua_Object p = lua_getparam(1); + if (p == LUA_NOOBJECT || lua_isnil(p)) + luaL_verror("assertion failed! %.100s", luaL_opt_string(2, "")); } -static void settagmethod (void) -{ - lua_Object nf = luaL_nonnullarg(3); - lua_pushobject(nf); - lua_pushobject(lua_settagmethod((int)luaL_check_number(1), - luaL_check_string(2))); +static void luaB_foreachi (void) { + Hash *t = gethash(1); + int i; + int n = (int)getnarg(t); + TObject f; + /* 'f' cannot be a pointer to TObject, because it is on the stack, and the + stack may be reallocated by the call. Moreover, some C compilers do not + initialize structs, so we must do the assignment after the declaration */ + f = *luaA_Address(luaL_functionarg(2)); + luaD_checkstack(3); /* for f, ref, and val */ + for (i=1; i<=n; i++) { + *(L->stack.top++) = f; + ttype(L->stack.top) = LUA_T_NUMBER; nvalue(L->stack.top++) = i; + *(L->stack.top++) = *luaH_getint(t, i); + luaD_calln(2, 1); + if (ttype(L->stack.top-1) != LUA_T_NIL) + return; + L->stack.top--; + } } -static void gettagmethod (void) -{ - lua_pushobject(lua_gettagmethod((int)luaL_check_number(1), - luaL_check_string(2))); +static void luaB_foreach (void) { + Hash *a = gethash(1); + int i; + TObject f; /* see comment in 'foreachi' */ + f = *luaA_Address(luaL_functionarg(2)); + luaD_checkstack(3); /* for f, ref, and val */ + for (i=0; inhash; i++) { + Node *nd = &(a->node[i]); + if (ttype(val(nd)) != LUA_T_NIL) { + *(L->stack.top++) = f; + *(L->stack.top++) = *ref(nd); + *(L->stack.top++) = *val(nd); + luaD_calln(2, 1); + if (ttype(L->stack.top-1) != LUA_T_NIL) + return; + L->stack.top--; /* remove result */ + } + } } -static void seterrormethod (void) -{ - lua_Object nf = luaL_functionarg(1); - lua_pushobject(nf); - lua_pushobject(lua_seterrormethod()); +static void luaB_foreachvar (void) { + GCnode *g; + TObject f; /* see comment in 'foreachi' */ + f = *luaA_Address(luaL_functionarg(1)); + luaD_checkstack(4); /* for extra var name, f, var name, and globalval */ + for (g = L->rootglobal.next; g; g = g->next) { + TaggedString *s = (TaggedString *)g; + if (s->u.s.globalval.ttype != LUA_T_NIL) { + pushtagstring(s); /* keep (extra) s on stack to avoid GC */ + *(L->stack.top++) = f; + pushtagstring(s); + *(L->stack.top++) = s->u.s.globalval; + luaD_calln(2, 1); + if (ttype(L->stack.top-1) != LUA_T_NIL) { + L->stack.top--; + *(L->stack.top-1) = *L->stack.top; /* remove extra s */ + return; + } + L->stack.top-=2; /* remove result and extra s */ + } + } +} + + +static void luaB_getn (void) { + lua_pushnumber(getnarg(gethash(1))); +} + + +static void luaB_tinsert (void) { + Hash *a = gethash(1); + lua_Object v = lua_getparam(3); + int n = (int)getnarg(a); + int pos; + if (v != LUA_NOOBJECT) + pos = luaL_check_int(2); + else { /* called with only 2 arguments */ + v = luaL_nonnullarg(2); + pos = n+1; + } + luaV_setn(a, n+1); /* a.n = n+1 */ + for ( ;n>=pos; n--) + luaH_move(a, n, n+1); /* a[n+1] = a[n] */ + luaH_setint(a, pos, luaA_Address(v)); /* a[pos] = v */ +} + + +static void luaB_tremove (void) { + Hash *a = gethash(1); + int n = (int)getnarg(a); + int pos = luaL_opt_int(2, n); + if (n <= 0) return; /* table is "empty" */ + luaA_pushobject(luaH_getint(a, pos)); /* result = a[pos] */ + for ( ;posstack.top) = *luaA_Address(f); + *(L->stack.top+1) = *a; + *(L->stack.top+2) = *b; + L->stack.top += 3; + luaD_calln(2, 1); + } + else { /* a < b? */ + *(L->stack.top) = *a; + *(L->stack.top+1) = *b; + L->stack.top += 2; + luaV_comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); + } + return ttype(--(L->stack.top)) != LUA_T_NIL; +} + +static void auxsort (Hash *a, int l, int u, lua_Object f) { + while (l < u) { /* for tail recursion */ + TObject *P; + int i, j; + /* sort elements a[l], a[(l+u)/2] and a[u] */ + if (sort_comp(f, luaH_getint(a, u), luaH_getint(a, l))) /* a[l]>a[u]? */ + swap(a, l, u); + if (u-l == 1) break; /* only 2 elements */ + i = (l+u)/2; + P = luaH_getint(a, i); + if (sort_comp(f, P, luaH_getint(a, l))) /* a[l]>a[i]? */ + swap(a, l, i); + else if (sort_comp(f, luaH_getint(a, u), P)) /* a[i]>a[u]? */ + swap(a, i, u); + if (u-l == 2) break; /* only 3 elements */ + P = L->stack.top++; + *P = *luaH_getint(a, i); /* save pivot on stack (for GC) */ + swap(a, i, u-1); /* put median element as pivot (a[u-1]) */ + /* a[l] <= P == a[u-1] <= a[u], only needs to sort from l+1 to u-2 */ + i = l; j = u-1; + for (;;) { + /* invariant: a[l..i] <= P <= a[j..u] */ + while (sort_comp(f, luaH_getint(a, ++i), P)) /* stop when a[i] >= P */ + if (i>u) lua_error("invalid order function for sorting"); + while (sort_comp(f, P, luaH_getint(a, --j))) /* stop when a[j] <= P */ + if (jstack.top--; /* remove pivot from stack */ + /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ + /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */ + if (i-l < u-i) { + j=l; i=i-1; l=i+2; + } + else { + j=i+1; i=u; u=j-2; + } + auxsort(a, j, i, f); /* call recursively the smaller one */ + } /* repeat the routine for the larger one */ +} + +static void luaB_sort (void) { + lua_Object t = lua_getparam(1); + Hash *a = gethash(1); + int n = (int)getnarg(a); + lua_Object func = lua_getparam(2); + luaL_arg_check(func == LUA_NOOBJECT || lua_isfunction(func), 2, + "function expected"); + luaD_checkstack(4); /* for Pivot, f, a, b (sort_comp) */ + auxsort(a, 1, n, func); + lua_pushobject(t); } +/* }}===================================================== */ + /* -** ======================================================= +** ====================================================== */ + + + +#ifdef DEBUG +/* +** {====================================================== ** some DEBUG functions ** ======================================================= */ -#ifdef DEBUG -static void mem_query (void) -{ +static void mem_query (void) { lua_pushnumber(totalmem); lua_pushnumber(numblocks); } -static void countlist (void) -{ +static void query_strings (void) { + lua_pushnumber(L->string_root[luaL_check_int(1)].nuse); +} + + +static void countlist (void) { char *s = luaL_check_string(1); GCnode *l = (s[0]=='t') ? L->roottable.next : (s[0]=='c') ? L->rootcl.next : (s[0]=='p') ? L->rootproto.next : L->rootglobal.next; @@ -418,8 +616,7 @@ static void countlist (void) } -static void testC (void) -{ +static void testC (void) { #define getnum(s) ((*s++) - '0') #define getname(s) (nome[0] = *s++, nome) @@ -428,7 +625,7 @@ static void testC (void) char nome[2]; char *s = luaL_check_string(1); nome[1] = 0; - while (1) { + for (;;) { switch (*s++) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': @@ -454,11 +651,17 @@ static void testC (void) case '=': lua_setglobal(getname(s)); break; case 's': lua_pushstring(getname(s)); break; case 'o': lua_pushobject(reg[getnum(s)]); break; - case 'f': (lua_call)(getname(s)); break; + case 'f': lua_call(getname(s)); break; case 'i': reg[getnum(s)] = lua_gettable(); break; case 'I': reg[getnum(s)] = lua_rawgettable(); break; case 't': lua_settable(); break; case 'T': lua_rawsettable(); break; + case 'N' : lua_pushstring(lua_nextvar(lua_getstring(reg[getnum(s)]))); + break; + case 'n' : { int n=getnum(s); + n=lua_next(reg[n], (int)lua_getnumber(reg[getnum(s)])); + lua_pushnumber(n); break; + } default: luaL_verror("unknown command in `testC': %c", *(s-1)); } if (*s == 0) return; @@ -466,13 +669,12 @@ static void testC (void) } } +/* }====================================================== */ #endif -/* -** Internal functions -*/ -static struct luaL_reg int_funcs[] = { + +static struct luaL_reg builtin_funcs[] = { #ifdef LUA_COMPAT2_5 {"setfallback", luaT_setfallback}, #endif @@ -480,46 +682,54 @@ static struct luaL_reg int_funcs[] = { {"testC", testC}, {"totalmem", mem_query}, {"count", countlist}, + {"querystr", query_strings}, #endif - {"assert", luaI_assert}, - {"call", luaI_call}, - {"collectgarbage", luaI_collectgarbage}, - {"dofile", internaldofile}, - {"copytagmethods", copytagmethods}, - {"dostring", internaldostring}, - {"error", luaI_error}, - {"foreach", foreach}, - {"foreachvar", foreachvar}, - {"getglobal", getglobal}, - {"newtag", newtag}, - {"next", next}, - {"nextvar", nextvar}, - {"print", luaI_print}, - {"rawgetglobal", rawgetglobal}, - {"rawgettable", rawgettable}, - {"rawsetglobal", rawsetglobal}, - {"rawsettable", rawsettable}, - {"seterrormethod", seterrormethod}, - {"setglobal", setglobal}, - {"settagmethod", settagmethod}, - {"gettagmethod", gettagmethod}, - {"settag", settag}, - {"tonumber", tonumber}, - {"tostring", to_string}, - {"tag", luatag}, - {"type", luaI_type} + {"_ALERT", luaB_alert}, + {"_ERRORMESSAGE", error_message}, + {"call", luaB_call}, + {"collectgarbage", luaB_collectgarbage}, + {"copytagmethods", luaB_copytagmethods}, + {"dofile", luaB_dofile}, + {"dostring", luaB_dostring}, + {"error", luaB_error}, + {"getglobal", luaB_getglobal}, + {"gettagmethod", luaB_gettagmethod}, + {"newtag", luaB_newtag}, + {"next", luaB_next}, + {"nextvar", luaB_nextvar}, + {"print", luaB_print}, + {"rawgetglobal", luaB_rawgetglobal}, + {"rawgettable", luaB_rawgettable}, + {"rawsetglobal", luaB_rawsetglobal}, + {"rawsettable", luaB_rawsettable}, + {"seterrormethod", luaB_seterrormethod}, + {"setglobal", luaB_setglobal}, + {"settag", luaB_settag}, + {"settagmethod", luaB_settagmethod}, + {"tag", luaB_luatag}, + {"tonumber", luaB_tonumber}, + {"tostring", luaB_tostring}, + {"type", luaB_type}, + /* "Extra" functions */ + {"assert", luaB_assert}, + {"foreach", luaB_foreach}, + {"foreachi", luaB_foreachi}, + {"foreachvar", luaB_foreachvar}, + {"getn", luaB_getn}, + {"sort", luaB_sort}, + {"tinsert", luaB_tinsert}, + {"tremove", luaB_tremove} }; -#define INTFUNCSIZE (sizeof(int_funcs)/sizeof(int_funcs[0])) +#define INTFUNCSIZE (sizeof(builtin_funcs)/sizeof(builtin_funcs[0])) -void luaB_predefine (void) -{ +void luaB_predefine (void) { /* pre-register mem error messages, to avoid loop when error arises */ luaS_newfixedstring(tableEM); luaS_newfixedstring(memEM); - luaL_openlib(int_funcs, (sizeof(int_funcs)/sizeof(int_funcs[0]))); + luaL_openlib(builtin_funcs, (sizeof(builtin_funcs)/sizeof(builtin_funcs[0]))); lua_pushstring(LUA_VERSION); lua_setglobal("_VERSION"); } diff --git a/src/ldo.c b/src/ldo.c index f7a9f27d93..bf840bf4b7 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.27 1998/06/19 18:47:06 roberto Exp $ +** $Id: ldo.c,v 1.45 1999/06/22 20:37:23 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include #include +#include "lauxlib.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" @@ -17,6 +18,7 @@ #include "lobject.h" #include "lparser.h" #include "lstate.h" +#include "lstring.h" #include "ltm.h" #include "lua.h" #include "luadebug.h" @@ -27,42 +29,33 @@ #ifndef STACK_LIMIT -#define STACK_LIMIT 6000 +#define STACK_LIMIT 6000 /* arbitrary limit */ #endif -/* -** Error messages -*/ - -static void stderrorim (void) -{ - fprintf(stderr, "lua error: %s\n", lua_getstring(lua_getparam(1))); -} - +#define STACK_UNIT 128 -#define STACK_UNIT 128 +#ifdef DEBUG +#undef STACK_UNIT +#define STACK_UNIT 2 +#endif -void luaD_init (void) -{ +void luaD_init (void) { L->stack.stack = luaM_newvector(STACK_UNIT, TObject); L->stack.top = L->stack.stack; L->stack.last = L->stack.stack+(STACK_UNIT-1); - ttype(&L->errorim) = LUA_T_CPROTO; - fvalue(&L->errorim) = stderrorim; } -void luaD_checkstack (int n) -{ +void luaD_checkstack (int n) { struct Stack *S = &L->stack; if (S->last-S->top <= n) { StkId top = S->top-S->stack; - int stacksize = (S->last-S->stack)+1+STACK_UNIT+n; - S->stack = luaM_reallocvector(S->stack, stacksize, TObject); + int stacksize = (S->last-S->stack)+STACK_UNIT+n; + luaM_reallocvector(S->stack, stacksize, TObject); S->last = S->stack+(stacksize-1); S->top = S->stack + top; if (stacksize >= STACK_LIMIT) { /* stack overflow? */ @@ -78,8 +71,7 @@ void luaD_checkstack (int n) /* ** Adjust stack. Set top to the given value, pushing NILs if needed. */ -void luaD_adjusttop (StkId newtop) -{ +void luaD_adjusttop (StkId newtop) { int diff = newtop-(L->stack.top-L->stack.stack); if (diff <= 0) L->stack.top += diff; @@ -94,38 +86,35 @@ void luaD_adjusttop (StkId newtop) /* ** Open a hole below "nelems" from the L->stack.top. */ -void luaD_openstack (int nelems) -{ +void luaD_openstack (int nelems) { luaO_memup(L->stack.top-nelems+1, L->stack.top-nelems, nelems*sizeof(TObject)); incr_top; } -void luaD_lineHook (int line) -{ +void luaD_lineHook (int line) { struct C_Lua_Stack oldCLS = L->Cstack; StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack; L->Cstack.num = 0; - (*lua_linehook)(line); + (*L->linehook)(line); L->stack.top = L->stack.stack+old_top; L->Cstack = oldCLS; } -void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn) -{ +void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn) { struct C_Lua_Stack oldCLS = L->Cstack; StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack; L->Cstack.num = 0; if (isreturn) - (*lua_callhook)(LUA_NOOBJECT, "(return)", 0); + (*L->callhook)(LUA_NOOBJECT, "(return)", 0); else { TObject *f = L->stack.stack+base-1; if (tf) - (*lua_callhook)(Ref(f), tf->fileName->str, tf->lineDefined); + (*L->callhook)(Ref(f), tf->source->str, tf->lineDefined); else - (*lua_callhook)(Ref(f), "(C)", -1); + (*L->callhook)(Ref(f), "(C)", -1); } L->stack.top = L->stack.stack+old_top; L->Cstack = oldCLS; @@ -137,28 +126,26 @@ void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn) ** Cstack.num is the number of arguments; Cstack.lua2C points to the ** first argument. Returns an index to the first result from C. */ -static StkId callC (lua_CFunction f, StkId base) -{ - struct C_Lua_Stack *CS = &L->Cstack; - struct C_Lua_Stack oldCLS = *CS; +static StkId callC (lua_CFunction f, StkId base) { + struct C_Lua_Stack *cls = &L->Cstack; + struct C_Lua_Stack oldCLS = *cls; StkId firstResult; int numarg = (L->stack.top-L->stack.stack) - base; - CS->num = numarg; - CS->lua2C = base; - CS->base = base+numarg; /* == top-stack */ - if (lua_callhook) + cls->num = numarg; + cls->lua2C = base; + cls->base = base+numarg; /* == top-stack */ + if (L->callhook) luaD_callHook(base, NULL, 0); (*f)(); /* do the actual call */ - if (lua_callhook) /* func may have changed lua_callhook */ + if (L->callhook) /* func may have changed callhook */ luaD_callHook(base, NULL, 1); - firstResult = CS->base; - *CS = oldCLS; + firstResult = cls->base; + *cls = oldCLS; return firstResult; } -static StkId callCclosure (struct Closure *cl, lua_CFunction f, StkId base) -{ +static StkId callCclosure (struct Closure *cl, lua_CFunction f, StkId base) { TObject *pbase; int nup = cl->nelems; /* number of upvalues */ luaD_checkstack(nup); @@ -172,24 +159,25 @@ static StkId callCclosure (struct Closure *cl, lua_CFunction f, StkId base) } -void luaD_callTM (TObject *f, int nParams, int nResults) -{ +void luaD_callTM (TObject *f, int nParams, int nResults) { luaD_openstack(nParams); *(L->stack.top-nParams-1) = *f; - luaD_call((L->stack.top-L->stack.stack)-nParams, nResults); + luaD_calln(nParams, nResults); } /* -** Call a function (C or Lua). The parameters must be on the L->stack.stack, -** between [L->stack.stack+base,L->stack.top). The function to be called is at L->stack.stack+base-1. -** When returns, the results are on the L->stack.stack, between [L->stack.stack+base-1,L->stack.top). +** Call a function (C or Lua). The parameters must be on the stack, +** between [top-nArgs,top). The function to be called is right below the +** arguments. +** When returns, the results are on the stack, between [top-nArgs-1,top). ** The number of results is nResults, unless nResults=MULT_RET. */ -void luaD_call (StkId base, int nResults) -{ +void luaD_calln (int nArgs, int nResults) { + struct Stack *S = &L->stack; /* to optimize */ + StkId base = (S->top-S->stack)-nArgs; + TObject *func = S->stack+base-1; StkId firstResult; - TObject *func = L->stack.stack+base-1; int i; switch (ttype(func)) { case LUA_T_CPROTO: @@ -214,23 +202,23 @@ void luaD_call (StkId base, int nResults) TObject *im = luaT_getimbyObj(func, IM_FUNCTION); if (ttype(im) == LUA_T_NIL) lua_error("call expression not a function"); - luaD_callTM(im, (L->stack.top-L->stack.stack)-(base-1), nResults); + luaD_callTM(im, (S->top-S->stack)-(base-1), nResults); return; } } /* adjust the number of results */ - if (nResults != MULT_RET) + if (nResults == MULT_RET) + nResults = (S->top-S->stack)-firstResult; + else luaD_adjusttop(firstResult+nResults); /* move results to base-1 (to erase parameters and function) */ base--; - nResults = L->stack.top - (L->stack.stack+firstResult); /* actual number of results */ for (i=0; istack.stack+base+i) = *(L->stack.stack+firstResult+i); - L->stack.top -= firstResult-base; + *(S->stack+base+i) = *(S->stack+firstResult+i); + S->top -= firstResult-base; } - /* ** Traverse all objects on L->stack.stack */ @@ -243,59 +231,50 @@ void luaD_travstack (int (*fn)(TObject *)) -static void message (char *s) -{ - TObject im = L->errorim; - if (ttype(&im) != LUA_T_NIL) { +static void message (char *s) { + TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval); + if (ttype(em) == LUA_T_PROTO || ttype(em) == LUA_T_CPROTO || + ttype(em) == LUA_T_CLOSURE) { + *L->stack.top = *em; + incr_top; lua_pushstring(s); - luaD_callTM(&im, 1, 0); + luaD_calln(1, 0); } } /* ** Reports an error, and jumps up to the available recover label */ -void lua_error (char *s) -{ +void lua_error (char *s) { if (s) message(s); if (L->errorJmp) - longjmp(*((jmp_buf *)L->errorJmp), 1); + longjmp(L->errorJmp->b, 1); else { - fprintf (stderr, "lua: exit(1). Unable to recover\n"); + message("exit(1). Unable to recover.\n"); exit(1); } } -/* -** Call the function at L->Cstack.base, and incorporate results on -** the Lua2C structure. -*/ -static void do_callinc (int nResults) -{ - StkId base = L->Cstack.base; - luaD_call(base+1, nResults); - L->Cstack.lua2C = base; /* position of the luaM_new results */ - L->Cstack.num = (L->stack.top-L->stack.stack) - base; /* number of results */ - L->Cstack.base = base + L->Cstack.num; /* incorporate results on L->stack.stack */ -} - /* ** Execute a protected call. Assumes that function is at L->Cstack.base and ** parameters are on top of it. Leave nResults on the stack. */ -int luaD_protectedrun (int nResults) -{ - jmp_buf myErrorJmp; - int status; +int luaD_protectedrun (void) { volatile struct C_Lua_Stack oldCLS = L->Cstack; - jmp_buf *volatile oldErr = L->errorJmp; + struct lua_longjmp myErrorJmp; + volatile int status; + struct lua_longjmp *volatile oldErr = L->errorJmp; L->errorJmp = &myErrorJmp; - if (setjmp(myErrorJmp) == 0) { - do_callinc(nResults); + if (setjmp(myErrorJmp.b) == 0) { + StkId base = L->Cstack.base; + luaD_calln((L->stack.top-L->stack.stack)-base-1, MULT_RET); + L->Cstack.lua2C = base; /* position of the new results */ + L->Cstack.num = (L->stack.top-L->stack.stack) - base; + L->Cstack.base = base + L->Cstack.num; /* incorporate results on stack */ status = 0; } - else { /* an error occurred: restore L->Cstack and L->stack.top */ + else { /* an error occurred: restore L->Cstack and L->stack.top */ L->Cstack = oldCLS; L->stack.top = L->stack.stack+L->Cstack.base; status = 1; @@ -308,18 +287,20 @@ int luaD_protectedrun (int nResults) /* ** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load */ -static int protectedparser (ZIO *z, int bin) -{ +static int protectedparser (ZIO *z, int bin) { + volatile struct C_Lua_Stack oldCLS = L->Cstack; + struct lua_longjmp myErrorJmp; volatile int status; TProtoFunc *volatile tf; - jmp_buf myErrorJmp; - jmp_buf *volatile oldErr = L->errorJmp; + struct lua_longjmp *volatile oldErr = L->errorJmp; L->errorJmp = &myErrorJmp; - if (setjmp(myErrorJmp) == 0) { + if (setjmp(myErrorJmp.b) == 0) { tf = bin ? luaU_undump1(z) : luaY_parser(z); status = 0; } - else { + else { /* an error occurred: restore L->Cstack and L->stack.top */ + L->Cstack = oldCLS; + L->stack.top = L->stack.stack+L->Cstack.base; tf = NULL; status = 1; } @@ -334,9 +315,9 @@ static int protectedparser (ZIO *z, int bin) } -static int do_main (ZIO *z, int bin) -{ +static int do_main (ZIO *z, int bin) { int status; + int debug = L->debug; /* save debug status */ do { long old_blocks = (luaC_checkGC(), L->nblocks); status = protectedparser(z, bin); @@ -345,10 +326,11 @@ static int do_main (ZIO *z, int bin) else { unsigned long newelems2 = 2*(L->nblocks-old_blocks); L->GCthreshold += newelems2; - status = luaD_protectedrun(MULT_RET); + status = luaD_protectedrun(); L->GCthreshold -= newelems2; } } while (bin && status == 0); + L->debug = debug; /* restore debug status */ return status; } @@ -364,23 +346,24 @@ void luaD_gcIM (TObject *o) } -int lua_dofile (char *filename) -{ +#define MAXFILENAME 260 /* maximum part of a file name kept */ + +int lua_dofile (char *filename) { ZIO z; int status; int c; int bin; + char source[MAXFILENAME]; FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); if (f == NULL) return 2; - if (filename == NULL) - filename = "(stdin)"; c = fgetc(f); ungetc(c, f); bin = (c == ID_CHUNK); if (bin) f = freopen(filename, "rb", f); /* set binary mode */ - luaZ_Fopen(&z, f, filename); + luaL_filesource(source, filename, sizeof(source)); + luaZ_Fopen(&z, f, source); status = do_main(&z, bin); if (f != stdin) fclose(f); @@ -388,40 +371,15 @@ int lua_dofile (char *filename) } -#define SIZE_PREF 20 /* size of string prefix to appear in error messages */ -#define SSIZE_PREF "20" - - -static void build_name (char *str, char *name) { - if (str == NULL || *str == ID_CHUNK) - strcpy(name, "(buffer)"); - else { - char *temp; - sprintf(name, "(dostring) >> \"%." SSIZE_PREF "s\"", str); - temp = strchr(name, '\n'); - if (temp) { /* end string after first line */ - *temp = '"'; - *(temp+1) = 0; - } - } -} - - int lua_dostring (char *str) { - return lua_dobuffer(str, strlen(str), NULL); + return lua_dobuffer(str, strlen(str), str); } int lua_dobuffer (char *buff, int size, char *name) { - char newname[SIZE_PREF+25]; ZIO z; - int status; - if (name==NULL) { - build_name(buff, newname); - name = newname; - } + if (!name) name = "?"; luaZ_mopen(&z, buff, size, name); - status = do_main(&z, buff[0]==ID_CHUNK); - return status; + return do_main(&z, buff[0]==ID_CHUNK); } diff --git a/src/ldo.h b/src/ldo.h index 0e981fbc7d..01eec54092 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.4 1997/12/15 16:17:20 roberto Exp $ +** $Id: ldo.h,v 1.6 1999/06/22 20:37:23 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -35,9 +35,9 @@ void luaD_adjusttop (StkId newtop); void luaD_openstack (int nelems); void luaD_lineHook (int line); void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn); -void luaD_call (StkId base, int nResults); +void luaD_calln (int nArgs, int nResults); void luaD_callTM (TObject *f, int nParams, int nResults); -int luaD_protectedrun (int nResults); +int luaD_protectedrun (void); void luaD_gcIM (TObject *o); void luaD_travstack (int (*fn)(TObject *)); void luaD_checkstack (int n); diff --git a/src/lfunc.c b/src/lfunc.c index fae59667ce..7494e2cd1b 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 1.9 1998/06/19 16:14:09 roberto Exp $ +** $Id: lfunc.c,v 1.10 1999/03/04 21:17:26 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -31,7 +31,7 @@ TProtoFunc *luaF_newproto (void) TProtoFunc *f = luaM_new(TProtoFunc); f->code = NULL; f->lineDefined = 0; - f->fileName = NULL; + f->source = NULL; f->consts = NULL; f->nconsts = 0; f->locvars = NULL; diff --git a/src/lgc.c b/src/lgc.c index f982a829b1..e153ce8c04 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.18 1998/03/09 21:49:52 roberto Exp $ +** $Id: lgc.c,v 1.23 1999/03/04 21:17:26 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -29,23 +29,18 @@ static int markobject (TObject *o); */ -int luaC_ref (TObject *o, int lock) -{ +int luaC_ref (TObject *o, int lock) { int ref; if (ttype(o) == LUA_T_NIL) ref = -1; /* special ref for nil */ else { for (ref=0; refrefSize; ref++) if (L->refArray[ref].status == FREE) - goto found; - /* no more empty spaces */ { - int oldSize = L->refSize; - L->refSize = luaM_growvector(&L->refArray, L->refSize, struct ref, - refEM, MAX_INT); - for (ref=oldSize; refrefSize; ref++) - L->refArray[ref].status = FREE; - ref = oldSize; - } found: + break; + if (ref == L->refSize) { /* no more empty spaces? */ + luaM_growvector(L->refArray, L->refSize, 1, struct ref, refEM, MAX_INT); + L->refSize++; + } L->refArray[ref].o = *o; L->refArray[ref].status = lock ? LOCK : HOLD; } @@ -163,21 +158,13 @@ static void strmark (TaggedString *s) } -static void protomark (TProtoFunc *f) -{ +static void protomark (TProtoFunc *f) { if (!f->head.marked) { - LocVar *v = f->locvars; int i; f->head.marked = 1; - if (f->fileName) - strmark(f->fileName); + strmark(f->source); for (i=0; inconsts; i++) markobject(&f->consts[i]); - if (v) { - for (; v->line != -1; v++) - if (v->varname) - strmark(v->varname); - } } } diff --git a/src/lib/Makefile b/src/lib/Makefile index 70db660f97..5d8664c9ab 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -7,8 +7,8 @@ include $(LUA)/config # actually only used in liolib.c EXTRA_DEFS= $(POPEN) -OBJS= liolib.o lmathlib.o lstrlib.o -SRCS= liolib.c lmathlib.c lstrlib.c +OBJS= linit.o ldblib.o liolib.o lmathlib.o lstrlib.o +SRCS= linit.c ldblib.c liolib.c lmathlib.c lstrlib.c T= $(LIB)/liblualib.a diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c new file mode 100644 index 0000000000..388a2f2d74 --- /dev/null +++ b/src/lib/ldblib.c @@ -0,0 +1,217 @@ +/* +** $Id: ldblib.c,v 1.5 1999/03/04 21:17:26 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#include "lauxlib.h" +#include "lua.h" +#include "luadebug.h" +#include "lualib.h" + + + +static void settabss (lua_Object t, char *i, char *v) { + lua_pushobject(t); + lua_pushstring(i); + lua_pushstring(v); + lua_settable(); +} + + +static void settabsi (lua_Object t, char *i, int v) { + lua_pushobject(t); + lua_pushstring(i); + lua_pushnumber(v); + lua_settable(); +} + + +static lua_Object getfuncinfo (lua_Object func) { + lua_Object result = lua_createtable(); + char *str; + int line; + lua_funcinfo(func, &str, &line); + if (line == -1) /* C function? */ + settabss(result, "kind", "C"); + else if (line == 0) { /* "main"? */ + settabss(result, "kind", "chunk"); + settabss(result, "source", str); + } + else { /* Lua function */ + settabss(result, "kind", "Lua"); + settabsi(result, "def_line", line); + settabss(result, "source", str); + } + if (line != 0) { /* is it not a "main"? */ + char *kind = lua_getobjname(func, &str); + if (*kind) { + settabss(result, "name", str); + settabss(result, "where", kind); + } + } + return result; +} + + +static void getstack (void) { + lua_Object func = lua_stackedfunction(luaL_check_int(1)); + if (func == LUA_NOOBJECT) /* level out of range? */ + return; + else { + lua_Object result = getfuncinfo(func); + int currline = lua_currentline(func); + if (currline > 0) + settabsi(result, "current", currline); + lua_pushobject(result); + lua_pushstring("func"); + lua_pushobject(func); + lua_settable(); /* result.func = func */ + lua_pushobject(result); + } +} + + +static void funcinfo (void) { + lua_pushobject(getfuncinfo(luaL_functionarg(1))); +} + + +static int findlocal (lua_Object func, int arg) { + lua_Object v = lua_getparam(arg); + if (lua_isnumber(v)) + return (int)lua_getnumber(v); + else { + char *name = luaL_check_string(arg); + int i = 0; + int result = -1; + char *vname; + while (lua_getlocal(func, ++i, &vname) != LUA_NOOBJECT) { + if (strcmp(name, vname) == 0) + result = i; /* keep looping to get the last var with this name */ + } + if (result == -1) + luaL_verror("no local variable `%.50s' at given level", name); + return result; + } +} + + +static void getlocal (void) { + lua_Object func = lua_stackedfunction(luaL_check_int(1)); + lua_Object val; + char *name; + if (func == LUA_NOOBJECT) /* level out of range? */ + return; /* return nil */ + else if (lua_getparam(2) != LUA_NOOBJECT) { /* 2nd argument? */ + if ((val = lua_getlocal(func, findlocal(func, 2), &name)) != LUA_NOOBJECT) { + lua_pushobject(val); + lua_pushstring(name); + } + /* else return nil */ + } + else { /* collect all locals in a table */ + lua_Object result = lua_createtable(); + int i; + for (i=1; ;i++) { + if ((val = lua_getlocal(func, i, &name)) == LUA_NOOBJECT) + break; + lua_pushobject(result); + lua_pushstring(name); + lua_pushobject(val); + lua_settable(); /* result[name] = value */ + } + lua_pushobject(result); + } +} + + +static void setlocal (void) { + lua_Object func = lua_stackedfunction(luaL_check_int(1)); + int numvar; + luaL_arg_check(func != LUA_NOOBJECT, 1, "level out of range"); + numvar = findlocal(func, 2); + lua_pushobject(luaL_nonnullarg(3)); + if (!lua_setlocal(func, numvar)) + lua_error("no such local variable"); +} + + + +static int linehook = -1; /* Lua reference to line hook function */ +static int callhook = -1; /* Lua reference to call hook function */ + + +static void dohook (int ref) { + lua_LHFunction oldlinehook = lua_setlinehook(NULL); + lua_CHFunction oldcallhook = lua_setcallhook(NULL); + lua_callfunction(lua_getref(ref)); + lua_setlinehook(oldlinehook); + lua_setcallhook(oldcallhook); +} + + +static void linef (int line) { + lua_pushnumber(line); + dohook(linehook); +} + + +static void callf (lua_Function func, char *file, int line) { + if (func != LUA_NOOBJECT) { + lua_pushobject(func); + lua_pushstring(file); + lua_pushnumber(line); + } + dohook(callhook); +} + + +static void setcallhook (void) { + lua_Object f = lua_getparam(1); + lua_unref(callhook); + if (f == LUA_NOOBJECT) { + callhook = -1; + lua_setcallhook(NULL); + } + else { + lua_pushobject(f); + callhook = lua_ref(1); + lua_setcallhook(callf); + } +} + + +static void setlinehook (void) { + lua_Object f = lua_getparam(1); + lua_unref(linehook); + if (f == LUA_NOOBJECT) { + linehook = -1; + lua_setlinehook(NULL); + } + else { + lua_pushobject(f); + linehook = lua_ref(1); + lua_setlinehook(linef); + } +} + + +static struct luaL_reg dblib[] = { + {"funcinfo", funcinfo}, + {"getlocal", getlocal}, + {"getstack", getstack}, + {"setcallhook", setcallhook}, + {"setlinehook", setlinehook}, + {"setlocal", setlocal} +}; + + +void lua_dblibopen (void) { + luaL_openlib(dblib, (sizeof(dblib)/sizeof(dblib[0]))); +} + diff --git a/src/lib/linit.c b/src/lib/linit.c new file mode 100644 index 0000000000..be57aae7ae --- /dev/null +++ b/src/lib/linit.c @@ -0,0 +1,17 @@ +/* +** $Id: linit.c,v 1.1 1999/01/08 16:49:32 roberto Exp $ +** Initialization of libraries for lua.c +** See Copyright Notice in lua.h +*/ + +#include "lua.h" +#include "lualib.h" + + +void lua_userinit (void) { + lua_iolibopen(); + lua_strlibopen(); + lua_mathlibopen(); + lua_dblibopen(); +} + diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 15ea6587d0..d833cec54c 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 1.21 1998/06/18 17:04:28 roberto Exp $ +** $Id: liolib.c,v 1.41 1999/06/23 13:48:39 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -20,6 +20,7 @@ #ifndef OLD_ANSI #include #else +/* no support for locale and for strerror: fake them */ #define setlocale(a,b) 0 #define LC_ALL 0 #define LC_COLLATE 0 @@ -31,10 +32,12 @@ #endif -#define CLOSEDTAG 2 -#define IOTAG 1 +#define IOTAG 1 + +#define FIRSTARG 2 /* 1st is upvalue */ + +#define CLOSEDTAG(tag) ((tag)-1) /* assume that CLOSEDTAG = iotag-1 */ -#define FIRSTARG 3 /* 1st and 2nd are upvalues */ #define FINPUT "_INPUT" #define FOUTPUT "_OUTPUT" @@ -43,262 +46,371 @@ #ifdef POPEN FILE *popen(); int pclose(); +#define CLOSEFILE(f) {if (pclose(f) == -1) fclose(f);} #else +/* no support for popen */ #define popen(x,y) NULL /* that is, popen always fails */ -#define pclose(x) (-1) +#define CLOSEFILE(f) {fclose(f);} #endif -static int gettag (int i) -{ - return lua_getnumber(lua_getparam(i)); -} - -static void pushresult (int i) -{ +static void pushresult (int i) { if (i) lua_pushuserdata(NULL); else { lua_pushnil(); lua_pushstring(strerror(errno)); + lua_pushnumber(errno); } } -static int ishandler (lua_Object f) -{ +/* +** {====================================================== +** FILE Operations +** ======================================================= +*/ + +static int gettag (void) { + return (int)lua_getnumber(lua_getparam(IOTAG)); +} + + +static int ishandle (lua_Object f) { if (lua_isuserdata(f)) { - if (lua_tag(f) == gettag(CLOSEDTAG)) + int tag = gettag(); + if (lua_tag(f) == CLOSEDTAG(tag)) lua_error("cannot access a closed file"); - return lua_tag(f) == gettag(IOTAG); + return lua_tag(f) == tag; } else return 0; } -static FILE *getfile (char *name) -{ + +static FILE *getfilebyname (char *name) { lua_Object f = lua_getglobal(name); - if (!ishandler(f)) + if (!ishandle(f)) luaL_verror("global variable `%.50s' is not a file handle", name); return lua_getuserdata(f); } -static FILE *getfileparam (char *name, int *arg) -{ - lua_Object f = lua_getparam(*arg); - if (ishandler(f)) { +static FILE *getfile (int arg) { + lua_Object f = lua_getparam(arg); + return (ishandle(f)) ? lua_getuserdata(f) : NULL; +} + + +static FILE *getnonullfile (int arg) { + FILE *f = getfile(arg); + luaL_arg_check(f, arg, "invalid file handle"); + return f; +} + + +static FILE *getfileparam (char *name, int *arg) { + FILE *f = getfile(*arg); + if (f) { (*arg)++; - return lua_getuserdata(f); + return f; } else - return getfile(name); + return getfilebyname(name); +} + + +static void closefile (FILE *f) { + if (f != stdin && f != stdout) { + int tag = gettag(); + CLOSEFILE(f); + lua_pushusertag(f, tag); + lua_settag(CLOSEDTAG(tag)); + } +} + + +static void io_close (void) { + closefile(getnonullfile(FIRSTARG)); +} + + +static void gc_close (void) { + FILE *f = getnonullfile(FIRSTARG); + if (f != stdin && f != stdout && f != stderr) { + CLOSEFILE(f); + } } -static void closefile (char *name) -{ - FILE *f = getfile(name); - if (f == stdin || f == stdout) return; - if (pclose(f) == -1) - fclose(f); - lua_pushobject(lua_getglobal(name)); - lua_settag(gettag(CLOSEDTAG)); +static void io_open (void) { + FILE *f = fopen(luaL_check_string(FIRSTARG), luaL_check_string(FIRSTARG+1)); + if (f) lua_pushusertag(f, gettag()); + else pushresult(0); } -static void setfile (FILE *f, char *name, int tag) -{ +static void setfile (FILE *f, char *name, int tag) { lua_pushusertag(f, tag); lua_setglobal(name); } -static void setreturn (FILE *f, char *name) -{ - int tag = gettag(IOTAG); - setfile(f, name, tag); - lua_pushusertag(f, tag); +static void setreturn (FILE *f, char *name) { + if (f == NULL) + pushresult(0); + else { + int tag = gettag(); + setfile(f, name, tag); + lua_pushusertag(f, tag); + } } -static void io_readfrom (void) -{ +static void io_readfrom (void) { FILE *current; lua_Object f = lua_getparam(FIRSTARG); if (f == LUA_NOOBJECT) { - closefile(FINPUT); + closefile(getfilebyname(FINPUT)); current = stdin; } - else if (lua_tag(f) == gettag(IOTAG)) + else if (lua_tag(f) == gettag()) /* deprecated option */ current = lua_getuserdata(f); else { char *s = luaL_check_string(FIRSTARG); current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); - if (current == NULL) { - pushresult(0); - return; - } } setreturn(current, FINPUT); } -static void io_writeto (void) -{ +static void io_writeto (void) { FILE *current; lua_Object f = lua_getparam(FIRSTARG); if (f == LUA_NOOBJECT) { - closefile(FOUTPUT); + closefile(getfilebyname(FOUTPUT)); current = stdout; } - else if (lua_tag(f) == gettag(IOTAG)) + else if (lua_tag(f) == gettag()) /* deprecated option */ current = lua_getuserdata(f); else { char *s = luaL_check_string(FIRSTARG); - current = (*s == '|') ? popen(s+1,"w") : fopen(s,"w"); - if (current == NULL) { - pushresult(0); - return; - } + current = (*s == '|') ? popen(s+1,"w") : fopen(s, "w"); } setreturn(current, FOUTPUT); } -static void io_appendto (void) -{ - char *s = luaL_check_string(FIRSTARG); - FILE *fp = fopen (s, "a"); - if (fp != NULL) - setreturn(fp, FOUTPUT); - else - pushresult(0); +static void io_appendto (void) { + FILE *current = fopen(luaL_check_string(FIRSTARG), "a"); + setreturn(current, FOUTPUT); } + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +/* +** We cannot lookahead without need, because this can lock stdin. +** This flag signals when we need to read a next char. +*/ #define NEED_OTHER (EOF-1) /* just some flag different from EOF */ -static void read_until (FILE *f, int lim) { - int l = 0; - int c; - for (c = getc(f); c != EOF && c != lim; c = getc(f)) { - luaL_addchar(c); - l++; +static int read_pattern (FILE *f, char *p) { + int inskip = 0; /* {skip} level */ + int c = NEED_OTHER; + while (*p != '\0') { + switch (*p) { + case '{': + inskip++; + p++; + continue; + case '}': + if (!inskip) lua_error("unbalanced braces in read pattern"); + inskip--; + p++; + continue; + default: { + char *ep = luaI_classend(p); /* get what is next */ + int m; /* match result */ + if (c == NEED_OTHER) c = getc(f); + m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); + if (m) { + if (!inskip) luaL_addchar(c); + c = NEED_OTHER; + } + switch (*ep) { + case '+': /* repetition (1 or more) */ + if (!m) goto break_while; /* pattern fails? */ + /* else go through */ + case '*': /* repetition (0 or more) */ + while (m) { /* reads the same item until it fails */ + c = getc(f); + m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); + if (m && !inskip) luaL_addchar(c); + } + /* go through to continue reading the pattern */ + case '?': /* optional */ + p = ep+1; /* continues reading the pattern */ + continue; + default: + if (!m) goto break_while; /* pattern fails? */ + p = ep; /* else continues reading the pattern */ + } + } + } + } break_while: + if (c != NEED_OTHER) ungetc(c, f); + return (*p == '\0'); +} + + +static int read_number (FILE *f) { + double d; + if (fscanf(f, "%lf", &d) == 1) { + lua_pushnumber(d); + return 1; } - if (l > 0 || c == lim) /* read anything? */ - lua_pushlstring(luaL_buffer(), l); + else return 0; /* read fails */ +} + + +#define HUNK_LINE 1024 +#define HUNK_FILE BUFSIZ + +static int read_line (FILE *f) { + /* equivalent to: return read_pattern(f, "[^\n]*{\n}"); */ + int n; + char *b; + do { + b = luaL_openspace(HUNK_LINE); + if (!fgets(b, HUNK_LINE, f)) return 0; /* read fails */ + n = strlen(b); + luaL_addsize(n); + } while (b[n-1] != '\n'); + luaL_addsize(-1); /* remove '\n' */ + return 1; +} + + +static void read_file (FILE *f) { + /* equivalent to: return read_pattern(f, ".*"); */ + int n; + do { + char *b = luaL_openspace(HUNK_FILE); + n = fread(b, sizeof(char), HUNK_FILE, f); + luaL_addsize(n); + } while (n==HUNK_FILE); } + static void io_read (void) { + static char *options[] = {"*n", "*l", "*a", ".*", "*w", NULL}; int arg = FIRSTARG; FILE *f = getfileparam(FINPUT, &arg); - char *p = luaL_opt_string(arg, NULL); - luaL_resetbuffer(); - if (p == NULL) /* default: read a line */ - read_until(f, '\n'); - else if (p[0] == '.' && p[1] == '*' && p[2] == 0) /* p = ".*" */ - read_until(f, EOF); - else { - int l = 0; /* number of chars read in buffer */ - int inskip = 0; /* to control {skips} */ - int c = NEED_OTHER; - while (*p) { - switch (*p) { - case '{': - inskip++; - p++; - continue; - case '}': - if (inskip == 0) - lua_error("unbalanced braces in read pattern"); - inskip--; - p++; - continue; - default: { - char *ep; /* get what is next */ - int m; /* match result */ - if (c == NEED_OTHER) c = getc(f); - if (c == EOF) { - luaI_singlematch(0, p, &ep); /* to set "ep" */ - m = 0; - } - else { - m = luaI_singlematch(c, p, &ep); - if (m) { - if (inskip == 0) { - luaL_addchar(c); - l++; - } - c = NEED_OTHER; - } - } - switch (*ep) { - case '*': /* repetition */ - if (!m) p = ep+1; /* else stay in (repeat) the same item */ - continue; - case '?': /* optional */ - p = ep+1; /* continues reading the pattern */ - continue; - default: - if (m) p = ep; /* continues reading the pattern */ - else - goto break_while; /* pattern fails */ - } - } - } - } break_while: - if (c >= 0) /* not EOF nor NEED_OTHER? */ - ungetc(c, f); - if (l > 0 || *p == 0) /* read something or did not fail? */ - lua_pushlstring(luaL_buffer(), l); - } + char *p = luaL_opt_string(arg++, "*l"); + do { /* repeat for each part */ + long l; + int success; + luaL_resetbuffer(); + switch (luaL_findstring(p, options)) { + case 0: /* number */ + if (!read_number(f)) return; /* read fails */ + continue; /* number is already pushed; avoid the "pushstring" */ + case 1: /* line */ + success = read_line(f); + break; + case 2: case 3: /* file */ + read_file(f); + success = 1; /* always success */ + break; + case 4: /* word */ + success = read_pattern(f, "{%s*}%S+"); + break; + default: + success = read_pattern(f, p); + } + l = luaL_getsize(); + if (!success && l==0) return; /* read fails */ + lua_pushlstring(luaL_buffer(), l); + } while ((p = luaL_opt_string(arg++, NULL)) != NULL); } +/* }====================================================== */ + -static void io_write (void) -{ +static void io_write (void) { int arg = FIRSTARG; FILE *f = getfileparam(FOUTPUT, &arg); int status = 1; char *s; long l; while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL) - status = status && (fwrite(s, 1, l, f) == l); + status = status && ((long)fwrite(s, 1, l, f) == l); pushresult(status); } -static void io_execute (void) -{ +static void io_seek (void) { + static int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static char *modenames[] = {"set", "cur", "end", NULL}; + FILE *f = getnonullfile(FIRSTARG); + int op = luaL_findstring(luaL_opt_string(FIRSTARG+1, "cur"), modenames); + long offset = luaL_opt_long(FIRSTARG+2, 0); + luaL_arg_check(op != -1, FIRSTARG+1, "invalid mode"); + op = fseek(f, offset, mode[op]); + if (op) + pushresult(0); /* error */ + else + lua_pushnumber(ftell(f)); +} + + +static void io_flush (void) { + FILE *f = getfile(FIRSTARG); + luaL_arg_check(f || lua_getparam(FIRSTARG) == LUA_NOOBJECT, FIRSTARG, + "invalid file handle"); + pushresult(fflush(f) == 0); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Other O.S. Operations +** ======================================================= +*/ + +static void io_execute (void) { lua_pushnumber(system(luaL_check_string(1))); } -static void io_remove (void) -{ +static void io_remove (void) { pushresult(remove(luaL_check_string(1)) == 0); } -static void io_rename (void) -{ +static void io_rename (void) { pushresult(rename(luaL_check_string(1), luaL_check_string(2)) == 0); } -static void io_tmpname (void) -{ +static void io_tmpname (void) { lua_pushstring(tmpnam(NULL)); } -static void io_getenv (void) -{ +static void io_getenv (void) { lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */ } @@ -308,12 +420,11 @@ static void io_clock (void) { } -static void io_date (void) -{ - time_t t; - struct tm *tm; +static void io_date (void) { + char b[256]; char *s = luaL_opt_string(1, "%c"); - char b[BUFSIZ]; + struct tm *tm; + time_t t; time(&t); tm = localtime(&t); if (strftime(b,sizeof(b),s,tm)) lua_pushstring(b); @@ -322,8 +433,7 @@ static void io_date (void) } -static void setloc (void) -{ +static void setloc (void) { static int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; static char *catnames[] = {"all", "collate", "ctype", "monetary", @@ -334,115 +444,140 @@ static void setloc (void) } -static void io_exit (void) -{ +static void io_exit (void) { lua_Object o = lua_getparam(1); exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1); } +/* }====================================================== */ + + -static void io_debug (void) -{ - while (1) { +static void io_debug (void) { + for (;;) { char buffer[250]; fprintf(stderr, "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0) return; - if (strcmp(buffer, "cont\n") == 0) return; + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return; lua_dostring(buffer); } } -static void lua_printstack (FILE *f) -{ + +#define MESSAGESIZE 150 +#define MAXMESSAGE (MESSAGESIZE*10) + + +#define MAXSRC 60 + + +static void errorfb (void) { + char buff[MAXMESSAGE]; int level = 1; /* skip level 0 (it's this function) */ lua_Object func; + sprintf(buff, "lua error: %.200s\n", lua_getstring(lua_getparam(1))); while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) { char *name; int currentline; - char *filename; + char *chunkname; + char buffchunk[MAXSRC]; int linedefined; - lua_funcinfo(func, &filename, &linedefined); - fprintf(f, (level==2) ? "Active Stack:\n\t" : "\t"); + lua_funcinfo(func, &chunkname, &linedefined); + luaL_chunkid(buffchunk, chunkname, sizeof(buffchunk)); + if (level == 2) strcat(buff, "Active Stack:\n"); + strcat(buff, " "); + if (strlen(buff) > MAXMESSAGE-MESSAGESIZE) { + strcat(buff, "...\n"); + break; /* buffer is full */ + } switch (*lua_getobjname(func, &name)) { case 'g': - fprintf(f, "function %s", name); + sprintf(buff+strlen(buff), "function `%.50s'", name); break; case 't': - fprintf(f, "`%s' tag method", name); + sprintf(buff+strlen(buff), "`%.50s' tag method", name); break; default: { if (linedefined == 0) - fprintf(f, "main of %s", filename); + sprintf(buff+strlen(buff), "main of %.70s", buffchunk); else if (linedefined < 0) - fprintf(f, "%s", filename); + sprintf(buff+strlen(buff), "%.70s", buffchunk); else - fprintf(f, "function (%s:%d)", filename, linedefined); - filename = NULL; + sprintf(buff+strlen(buff), "function <%d:%.70s>", + linedefined, buffchunk); + chunkname = NULL; } } if ((currentline = lua_currentline(func)) > 0) - fprintf(f, " at line %d", currentline); - if (filename) - fprintf(f, " [in file %s]", filename); - fprintf(f, "\n"); + sprintf(buff+strlen(buff), " at line %d", currentline); + if (chunkname) + sprintf(buff+strlen(buff), " [%.70s]", buffchunk); + strcat(buff, "\n"); + } + func = lua_rawgetglobal("_ALERT"); + if (lua_isfunction(func)) { /* avoid error loop if _ALERT is not defined */ + lua_pushstring(buff); + lua_callfunction(func); } -} - - -static void errorfb (void) -{ - fprintf(stderr, "lua: %s\n", lua_getstring(lua_getparam(1))); - lua_printstack(stderr); } static struct luaL_reg iolib[] = { -{"setlocale", setloc}, -{"execute", io_execute}, -{"remove", io_remove}, -{"rename", io_rename}, -{"tmpname", io_tmpname}, -{"getenv", io_getenv}, -{"date", io_date}, -{"clock", io_clock}, -{"exit", io_exit}, -{"debug", io_debug}, -{"print_stack", errorfb} + {"_ERRORMESSAGE", errorfb}, + {"clock", io_clock}, + {"date", io_date}, + {"debug", io_debug}, + {"execute", io_execute}, + {"exit", io_exit}, + {"getenv", io_getenv}, + {"remove", io_remove}, + {"rename", io_rename}, + {"setlocale", setloc}, + {"tmpname", io_tmpname} }; + static struct luaL_reg iolibtag[] = { -{"readfrom", io_readfrom}, -{"writeto", io_writeto}, -{"appendto", io_appendto}, -{"read", io_read}, -{"write", io_write} + {"appendto", io_appendto}, + {"closefile", io_close}, + {"flush", io_flush}, + {"openfile", io_open}, + {"read", io_read}, + {"readfrom", io_readfrom}, + {"seek", io_seek}, + {"write", io_write}, + {"writeto", io_writeto} }; -static void openwithtags (void) -{ - int iotag = lua_newtag(); - int closedtag = lua_newtag(); + +static void openwithtags (void) { int i; + int iotag = lua_newtag(); + lua_newtag(); /* alloc CLOSEDTAG: assume that CLOSEDTAG = iotag-1 */ for (i=0; i=0) ? pos : len+pos+1; } -static void str_sub (void) -{ +static void str_sub (void) { long l; char *s = luaL_check_lstr(1, &l); - long start = posrelat(luaL_check_number(2), l); - long end = posrelat(luaL_opt_number(3, -1), l); - if (1 <= start && start <= end && end <= l) + long start = posrelat(luaL_check_long(2), l); + long end = posrelat(luaL_opt_long(3, -1), l); + if (start < 1) start = 1; + if (end > l) end = l; + if (start <= end) lua_pushlstring(s+start-1, end-start+1); else lua_pushstring(""); } -static void str_lower (void) -{ +static void str_lower (void) { long l; int i; char *s = luaL_check_lstr(1, &l); @@ -69,8 +67,7 @@ static void str_lower (void) } -static void str_upper (void) -{ +static void str_upper (void) { long l; int i; char *s = luaL_check_lstr(1, &l); @@ -84,7 +81,7 @@ static void str_rep (void) { long l; char *s = luaL_check_lstr(1, &l); - int n = (int)luaL_check_number(2); + int n = luaL_check_int(2); luaL_resetbuffer(); while (n-- > 0) addnchar(s, l); @@ -92,38 +89,42 @@ static void str_rep (void) } -static void str_byte (void) -{ +static void str_byte (void) { long l; char *s = luaL_check_lstr(1, &l); - long pos = posrelat(luaL_opt_number(2, 1), l); + long pos = posrelat(luaL_opt_long(2, 1), l); luaL_arg_check(0level; i++) - lua_pushlstring(cap->capture[i].init, cap->capture[i].len); + for (i=0; ilevel; i++) { + int l = cap->capture[i].len; + if (l == -1) lua_error("unfinished capture"); + lua_pushlstring(cap->capture[i].init, l); + } } -static int check_cap (int l, struct Capture *cap) -{ +static int check_cap (int l, struct Capture *cap) { l -= '1'; if (!(0 <= l && l < cap->level && cap->capture[l].len != -1)) lua_error("invalid capture index"); @@ -152,8 +154,7 @@ static int check_cap (int l, struct Capture *cap) } -static int capture_to_close (struct Capture *cap) -{ +static int capture_to_close (struct Capture *cap) { int level = cap->level; for (level--; level>=0; level--) if (cap->capture[level].len == -1) return level; @@ -162,14 +163,25 @@ static int capture_to_close (struct Capture *cap) } -static char *bracket_end (char *p) -{ - return (*p == 0) ? NULL : strchr((*p=='^') ? p+2 : p+1, ']'); +char *luaI_classend (char *p) { + switch (*p++) { + case ESC: + if (*p == '\0') + luaL_verror("incorrect pattern (ends with `%c')", ESC); + return p+1; + case '[': + if (*p == '^') p++; + if (*p == ']') p++; + p = strchr(p, ']'); + if (!p) lua_error("incorrect pattern (missing `]')"); + return p+1; + default: + return p; + } } -static int matchclass (int c, int cl) -{ +static int matchclass (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; @@ -180,57 +192,63 @@ static int matchclass (int c, int cl) case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; case 'z' : res = (c == '\0'); break; default: return (cl == c); } - return (islower((unsigned char)cl) ? res : !res); + return (islower(cl) ? res : !res); } -int luaI_singlematch (int c, char *p, char **ep) -{ + +static int matchbracketclass (int c, char *p, char *end) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < end) { + if (*p == ESC) { + p++; + if ((p < end) && matchclass(c, (unsigned char)*p)) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < end)) { + p+=2; + if ((int)(unsigned char)*(p-2) <= c && c <= (int)(unsigned char)*p) + return sig; + } + else if ((unsigned char)*p == c) return sig; + } + return !sig; +} + + + +int luaI_singlematch (int c, char *p, char *ep) { switch (*p) { case '.': /* matches any char */ - *ep = p+1; return 1; - case '\0': /* end of pattern; matches nothing */ - *ep = p; - return 0; case ESC: - if (*(++p) == '\0') - luaL_verror("incorrect pattern (ends with `%c')", ESC); - *ep = p+1; - return matchclass(c, (unsigned char)*p); - case '[': { - char *end = bracket_end(p+1); - int sig = *(p+1) == '^' ? (p++, 0) : 1; - if (end == NULL) lua_error("incorrect pattern (missing `]')"); - *ep = end+1; - while (++p < end) { - if (*p == ESC) { - if (((p+1) < end) && matchclass(c, (unsigned char)*++p)) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < end)) { - p+=2; - if ((unsigned char)*(p-2) <= c && c <= (unsigned char)*p) - return sig; - } - else if ((unsigned char)*p == c) return sig; - } - return !sig; - } + return matchclass(c, (unsigned char)*(p+1)); + case '[': + return matchbracketclass(c, p, ep-1); default: - *ep = p+1; return ((unsigned char)*p == c); } } -static char *matchbalance (char *s, int b, int e, struct Capture *cap) -{ - if (*s != b) return NULL; +static char *match (char *s, char *p, struct Capture *cap); + + +static char *matchbalance (char *s, char *p, struct Capture *cap) { + if (*p == 0 || *(p+1) == 0) + lua_error("unbalanced pattern"); + if (*s != *p) return NULL; else { + int b = *p; + int e = *(p+1); int cont = 1; while (++s < cap->src_end) { if (*s == e) { @@ -243,101 +261,120 @@ static char *matchbalance (char *s, int b, int e, struct Capture *cap) } -static char *matchitem (char *s, char *p, struct Capture *cap, char **ep) -{ - if (*p == ESC) { - p++; - if (isdigit((unsigned char)*p)) { /* capture */ - int l = check_cap(*p, cap); - int len = cap->capture[l].len; - *ep = p+1; - if (cap->src_end-s >= len && memcmp(cap->capture[l].init, s, len) == 0) - return s+len; - else return NULL; - } - else if (*p == 'b') { /* balanced string */ - p++; - if (*p == 0 || *(p+1) == 0) - lua_error("unbalanced pattern"); - *ep = p+2; - return matchbalance(s, *p, *(p+1), cap); - } - else p--; /* and go through */ +static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) { + int i = 0; /* counts maximum expand for item */ + while ((s+i)src_end && luaI_singlematch((unsigned char)*(s+i), p, ep)) + i++; + /* keeps trying to match mith the maximum repetitions */ + while (i>=0) { + char *res = match((s+i), ep+1, cap); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ } - /* "luaI_singlematch" sets "ep" (so must be called even when *s == 0) */ - return (luaI_singlematch((unsigned char)*s, p, ep) && ssrc_end) ? - s+1 : NULL; + return NULL; } -static char *match (char *s, char *p, struct Capture *cap) -{ +static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) { + for (;;) { + char *res = match(s, ep+1, cap); + if (res != NULL) + return res; + else if (ssrc_end && luaI_singlematch((unsigned char)*s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static char *start_capt (char *s, char *p, struct Capture *cap) { + char *res; + int level = cap->level; + if (level >= MAX_CAPT) lua_error("too many captures"); + cap->capture[level].init = s; + cap->capture[level].len = -1; + cap->level = level+1; + if ((res=match(s, p+1, cap)) == NULL) /* match failed? */ + cap->level--; /* undo capture */ + return res; +} + + +static char *end_capt (char *s, char *p, struct Capture *cap) { + int l = capture_to_close(cap); + char *res; + cap->capture[l].len = s - cap->capture[l].init; /* close capture */ + if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ + cap->capture[l].len = -1; /* undo capture */ + return res; +} + + +static char *match_capture (char *s, int level, struct Capture *cap) { + int l = check_cap(level, cap); + int len = cap->capture[l].len; + if (cap->src_end-s >= len && + memcmp(cap->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static char *match (char *s, char *p, struct Capture *cap) { init: /* using goto's to optimize tail recursion */ switch (*p) { - case '(': { /* start capture */ - char *res; - if (cap->level >= MAX_CAPT) lua_error("too many captures"); - cap->capture[cap->level].init = s; - cap->capture[cap->level].len = -1; - cap->level++; - if ((res=match(s, p+1, cap)) == NULL) /* match failed? */ - cap->level--; /* undo capture */ - return res; - } - case ')': { /* end capture */ - int l = capture_to_close(cap); - char *res; - cap->capture[l].len = s - cap->capture[l].init; /* close capture */ - if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ - cap->capture[l].len = -1; /* undo capture */ - return res; - } - case '\0': case '$': /* (possibly) end of pattern */ - if (*p == 0 || (*(p+1) == 0 && s == cap->src_end)) - return s; - /* else go through */ - default: { /* it is a pattern item */ - char *ep; /* get what is next */ - char *s1 = matchitem(s, p, cap, &ep); + case '(': /* start capture */ + return start_capt(s, p, cap); + case ')': /* end capture */ + return end_capt(s, p, cap); + case ESC: /* may be %[0-9] or %b */ + if (isdigit((unsigned char)(*(p+1)))) { /* capture? */ + s = match_capture(s, *(p+1), cap); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(p+2, s, cap) */ + } + else if (*(p+1) == 'b') { /* balanced string? */ + s = matchbalance(s, p+2, cap); + if (s == NULL) return NULL; + p+=4; goto init; /* else return match(p+4, s, cap); */ + } + else goto dflt; /* case default */ + case '\0': /* end of pattern */ + return s; /* match succeeded */ + case '$': + if (*(p+1) == '\0') /* is the '$' the last char in pattern? */ + return (s == cap->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + default: dflt: { /* it is a pattern item */ + char *ep = luaI_classend(p); /* points to what is next */ + int m = ssrc_end && luaI_singlematch((unsigned char)*s, p, ep); switch (*ep) { - case '*': { /* repetition */ - char *res; - if (s1 && s1>s && ((res=match(s1, p, cap)) != NULL)) - return res; - p=ep+1; goto init; /* else return match(s, ep+1, cap); */ - } case '?': { /* optional */ char *res; - if (s1 && ((res=match(s1, ep+1, cap)) != NULL)) + if (m && ((res=match(s+1, ep+1, cap)) != NULL)) return res; p=ep+1; goto init; /* else return match(s, ep+1, cap); */ } - case '-': { /* repetition */ - char *res; - if ((res = match(s, ep+1, cap)) != NULL) - return res; - else if (s1 && s1>s) { - s = s1; - goto init; /* return match(s1, p, cap); */ - } - else - return NULL; - } + case '*': /* 0 or more repetitions */ + return max_expand(s, p, ep, cap); + case '+': /* 1 or more repetitions */ + return (m ? max_expand(s+1, p, ep, cap) : NULL); + case '-': /* 0 or more repetitions (minimum) */ + return min_expand(s, p, ep, cap); default: - if (s1) { s=s1; p=ep; goto init; } /* return match(s1, ep, cap); */ - else return NULL; + if (!m) return NULL; + s++; p=ep; goto init; /* else return match(s+1, ep, cap); */ } } } } -static void str_find (void) -{ +static void str_find (void) { long l; char *s = luaL_check_lstr(1, &l); char *p = luaL_check_string(2); - long init = posrelat(luaL_opt_number(3, 1), l) - 1; + long init = posrelat(luaL_opt_long(3, 1), l) - 1; struct Capture cap; luaL_arg_check(0 <= init && init <= l, 3, "out of range"); if (lua_getparam(4) != LUA_NOOBJECT || @@ -368,8 +405,7 @@ static void str_find (void) } -static void add_s (lua_Object newp, struct Capture *cap) -{ +static void add_s (lua_Object newp, struct Capture *cap) { if (lua_isstring(newp)) { char *news = lua_getstring(newp); int l = lua_strlen(newp); @@ -411,13 +447,12 @@ static void add_s (lua_Object newp, struct Capture *cap) } -static void str_gsub (void) -{ +static void str_gsub (void) { long srcl; char *src = luaL_check_lstr(1, &srcl); char *p = luaL_check_string(2); lua_Object newp = lua_getparam(3); - int max_s = (int)luaL_opt_number(4, srcl+1); + int max_s = luaL_opt_int(4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; struct Capture cap; @@ -445,26 +480,33 @@ static void str_gsub (void) lua_pushnumber(n); /* number of substitutions */ } +/* }====================================================== */ -static void luaI_addquoted (char *s) -{ + +static void luaI_addquoted (int arg) { + long l; + char *s = luaL_check_lstr(arg, &l); luaL_addchar('"'); - for (; *s; s++) { - if (strchr("\"\\\n", *s)) - luaL_addchar('\\'); - luaL_addchar(*s); + while (l--) { + switch (*s) { + case '"': case '\\': case '\n': + luaL_addchar('\\'); + luaL_addchar(*s); + break; + case '\0': addnchar("\\000", 4); break; + default: luaL_addchar(*s); + } + s++; } luaL_addchar('"'); } -#define MAX_FORMAT 200 +/* maximum size of each format specification (such as '%-099.99d') */ +#define MAX_FORMAT 20 /* arbitrary limit */ -static void str_format (void) -{ +static void str_format (void) { int arg = 1; char *strfrmt = luaL_check_string(arg); - struct Capture cap; - cap.src_end = strfrmt+strlen(strfrmt)+1; luaL_resetbuffer(); while (*strfrmt) { if (*strfrmt != '%') @@ -472,34 +514,28 @@ static void str_format (void) else if (*++strfrmt == '%') luaL_addchar(*strfrmt++); /* %% */ else { /* format item */ - char form[MAX_FORMAT]; /* store the format ('%...') */ - char *buff; + struct Capture cap; + char form[MAX_FORMAT]; /* to store the format ('%...') */ + char *buff; /* to store the formatted item */ char *initf = strfrmt; form[0] = '%'; - cap.level = 0; - if (isdigit((unsigned char)initf[0]) && initf[1] == '$') { - arg = initf[0] - '0'; + if (isdigit((unsigned char)*initf) && *(initf+1) == '$') { + arg = *initf - '0'; initf += 2; /* skip the 'n$' */ } arg++; + cap.src_end = strfrmt+strlen(strfrmt)+1; + cap.level = 0; strfrmt = match(initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); - if (cap.capture[0].len > 2 || cap.capture[1].len > 2) /* < 100? */ + if (cap.capture[0].len > 2 || cap.capture[1].len > 2 || /* < 100? */ + strfrmt-initf > MAX_FORMAT-2) lua_error("invalid format (width or precision too long)"); strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */ form[strfrmt-initf+2] = 0; - buff = luaL_openspace(1000); /* to store the formatted value */ + buff = luaL_openspace(512); /* 512 > size of format('%99.99f', -1e308) */ switch (*strfrmt++) { - case 'q': - luaI_addquoted(luaL_check_string(arg)); - continue; - case 's': { - char *s = luaL_check_string(arg); - buff = luaL_openspace(strlen(s)); - sprintf(buff, form, s); - break; - } case 'c': case 'd': case 'i': - sprintf(buff, form, (int)luaL_check_number(arg)); + sprintf(buff, form, luaL_check_int(arg)); break; case 'o': case 'u': case 'x': case 'X': sprintf(buff, form, (unsigned int)luaL_check_number(arg)); @@ -507,6 +543,23 @@ static void str_format (void) case 'e': case 'E': case 'f': case 'g': case 'G': sprintf(buff, form, luaL_check_number(arg)); break; + case 'q': + luaI_addquoted(arg); + continue; /* skip the "addsize" at the end */ + case 's': { + long l; + char *s = luaL_check_lstr(arg, &l); + if (cap.capture[1].len == 0 && l >= 100) { + /* no precision and string is too big to be formatted; + keep original string */ + addnchar(s, l); + continue; /* skip the "addsize" at the end */ + } + else { + sprintf(buff, form, s); + break; + } + } default: /* also treat cases 'pnLlh' */ lua_error("invalid option in `format'"); } @@ -524,7 +577,7 @@ static struct luaL_reg strlib[] = { {"strupper", str_upper}, {"strchar", str_char}, {"strrep", str_rep}, -{"ascii", str_byte}, /* for compatibility */ +{"ascii", str_byte}, /* for compatibility with 3.0 and earlier */ {"strbyte", str_byte}, {"format", str_format}, {"strfind", str_find}, diff --git a/src/llex.c b/src/llex.c index ec1966cacc..2d607d996f 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,6 +1,6 @@ /* -** $Id: llex.c,v 1.23 1998/07/06 22:04:58 roberto Exp $ -** Lexical Analizer +** $Id: llex.c,v 1.36 1999/06/17 17:04:03 roberto Exp $ +** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -20,9 +20,6 @@ -int lua_debug=0; - - #define next(LS) (LS->current = zgetc(LS->lex_z)) @@ -35,8 +32,7 @@ char *reserved [] = {"and", "do", "else", "elseif", "end", "function", "until", "while"}; -void luaX_init (void) -{ +void luaX_init (void) { int i; for (i=0; i<(sizeof(reserved)/sizeof(reserved[0])); i++) { TaggedString *ts = luaS_new(reserved[i]); @@ -45,24 +41,28 @@ void luaX_init (void) } +#define MAXSRC 80 + void luaX_syntaxerror (LexState *ls, char *s, char *token) { - if (token[0] == 0) + char buff[MAXSRC]; + luaL_chunkid(buff, zname(ls->lex_z), sizeof(buff)); + if (token[0] == '\0') token = ""; - luaL_verror("%.100s;\n last token read: `%.50s' at line %d in chunk `%.50s'", - s, token, ls->linenumber, zname(ls->lex_z)); + luaL_verror("%.100s;\n last token read: `%.50s' at line %d in %.80s", + s, token, ls->linenumber, buff); } void luaX_error (LexState *ls, char *s) { - save(0); + save('\0'); luaX_syntaxerror(ls, s, luaL_buffer()); } -void luaX_token2str (LexState *ls, int token, char *s) { +void luaX_token2str (int token, char *s) { if (token < 255) { - s[0] = token; - s[1] = 0; + s[0] = (char)token; + s[1] = '\0'; } else strcpy(s, reserved[token-FIRST_RESERVED]); @@ -70,8 +70,8 @@ void luaX_token2str (LexState *ls, int token, char *s) { static void luaX_invalidchar (LexState *ls, int c) { - char buff[10]; - sprintf(buff, "0x%X", c); + char buff[8]; + sprintf(buff, "0x%02X", c); luaX_syntaxerror(ls, "invalid control char", buff); } @@ -106,17 +106,17 @@ void luaX_setinput (LexState *LS, ZIO *z) ** ======================================================= */ -#define PRAGMASIZE 20 +#ifndef PRAGMASIZE +#define PRAGMASIZE 80 /* arbitrary limit */ +#endif -static void skipspace (LexState *LS) -{ +static void skipspace (LexState *LS) { while (LS->current == ' ' || LS->current == '\t' || LS->current == '\r') next(LS); } -static int checkcond (LexState *LS, char *buff) -{ +static int checkcond (LexState *LS, char *buff) { static char *opts[] = {"nil", "1", NULL}; int i = luaL_findstring(buff, opts); if (i >= 0) return i; @@ -129,8 +129,7 @@ static int checkcond (LexState *LS, char *buff) } -static void readname (LexState *LS, char *buff) -{ +static void readname (LexState *LS, char *buff) { int i = 0; skipspace(LS); while (isalnum(LS->current) || LS->current == '_') { @@ -138,7 +137,7 @@ static void readname (LexState *LS, char *buff) buff[PRAGMASIZE] = 0; luaX_syntaxerror(LS, "pragma too long", buff); } - buff[i++] = LS->current; + buff[i++] = (char)LS->current; next(LS); } buff[i] = 0; @@ -148,8 +147,7 @@ static void readname (LexState *LS, char *buff) static void inclinenumber (LexState *LS); -static void ifskip (LexState *LS) -{ +static void ifskip (LexState *LS) { while (LS->ifstate[LS->iflevel].skip) { if (LS->current == '\n') inclinenumber(LS); @@ -160,8 +158,7 @@ static void ifskip (LexState *LS) } -static void inclinenumber (LexState *LS) -{ +static void inclinenumber (LexState *LS) { static char *pragmas [] = {"debug", "nodebug", "endinput", "end", "ifnot", "if", "else", NULL}; next(LS); /* skip '\n' */ @@ -174,10 +171,10 @@ static void inclinenumber (LexState *LS) readname(LS, buff); switch (luaL_findstring(buff, pragmas)) { case 0: /* debug */ - if (!skip) lua_debug = 1; + if (!skip) L->debug = 1; break; case 1: /* nodebug */ - if (!skip) lua_debug = 0; + if (!skip) L->debug = 0; break; case 2: /* endinput */ if (!skip) { @@ -221,6 +218,7 @@ static void inclinenumber (LexState *LS) } + /* ** ======================================================= ** LEXICAL ANALIZER @@ -229,12 +227,9 @@ static void inclinenumber (LexState *LS) - - -static int read_long_string (LexState *LS) -{ +static int read_long_string (LexState *LS) { int cont = 0; - while (1) { + for (;;) { switch (LS->current) { case EOZ: luaX_error(LS, "unfinished long string"); @@ -262,17 +257,16 @@ static int read_long_string (LexState *LS) save_and_next(LS); } } endloop: - save_and_next(LS); /* pass the second ']' */ - LS->seminfo.ts = luaS_newlstr(L->Mbuffbase+2, - L->Mbuffnext-(L->Mbuffbase-L->Mbuffer)-4); + save_and_next(LS); /* skip the second ']' */ + LS->seminfo.ts = luaS_newlstr(L->Mbuffer+(L->Mbuffbase+2), + L->Mbuffnext-L->Mbuffbase-4); return STRING; } int luaX_lex (LexState *LS) { - double a; luaL_resetbuffer(); - while (1) { + for (;;) { switch (LS->current) { case ' ': case '\t': case '\r': /* CR: to avoid problems with DOS */ @@ -347,7 +341,7 @@ int luaX_lex (LexState *LS) { c = 10*c + (LS->current-'0'); next(LS); } while (++i<3 && isdigit(LS->current)); - if (c >= 256) + if (c != (unsigned char)c) luaX_error(LS, "escape sequence too large"); save(c); } @@ -364,8 +358,8 @@ int luaX_lex (LexState *LS) { } } save_and_next(LS); /* skip delimiter */ - LS->seminfo.ts = luaS_newlstr(L->Mbuffbase+1, - L->Mbuffnext-(L->Mbuffbase-L->Mbuffer)-2); + LS->seminfo.ts = luaS_newlstr(L->Mbuffer+(L->Mbuffbase+1), + L->Mbuffnext-L->Mbuffbase-2); return STRING; } @@ -382,15 +376,11 @@ int luaX_lex (LexState *LS) { else return CONC; /* .. */ } else if (!isdigit(LS->current)) return '.'; - /* LS->current is a digit: goes through to number */ - a=0.0; - goto fraction; + goto fraction; /* LS->current is a digit: goes through to number */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - a=0.0; do { - a = 10.0*a + (LS->current-'0'); save_and_next(LS); } while (isdigit(LS->current)); if (LS->current == '.') { @@ -402,35 +392,19 @@ int luaX_lex (LexState *LS) { } } fraction: - { double da=0.1; - while (isdigit(LS->current)) - { - a += (LS->current-'0')*da; - da /= 10.0; - save_and_next(LS); - } - if (toupper(LS->current) == 'E') { - int e = 0; - int neg; - double ea; + while (isdigit(LS->current)) + save_and_next(LS); + if (toupper(LS->current) == 'E') { + save_and_next(LS); /* read 'E' */ + save_and_next(LS); /* read '+', '-' or first digit */ + while (isdigit(LS->current)) save_and_next(LS); - neg = (LS->current=='-'); - if (LS->current == '+' || LS->current == '-') save_and_next(LS); - if (!isdigit(LS->current)) - luaX_error(LS, "invalid numeral format"); - do { - e = 10*e + (LS->current-'0'); - save_and_next(LS); - } while (isdigit(LS->current)); - for (ea=neg?0.1:10.0; e>0; e>>=1) - { - if (e & 1) a *= ea; - ea *= ea; - } - } - LS->seminfo.r = a; - return NUMBER; } + save('\0'); + LS->seminfo.r = luaO_str2d(L->Mbuffer+L->Mbuffbase); + if (LS->seminfo.r < 0) + luaX_error(LS, "invalid numeric format"); + return NUMBER; case EOZ: if (LS->iflevel > 0) @@ -450,9 +424,9 @@ int luaX_lex (LexState *LS) { do { save_and_next(LS); } while (isalnum(LS->current) || LS->current == '_'); - save(0); - ts = luaS_new(L->Mbuffbase); - if (ts->head.marked >= 'A') + save('\0'); + ts = luaS_new(L->Mbuffer+L->Mbuffbase); + if (ts->head.marked >= FIRST_RESERVED) return ts->head.marked; /* reserved word */ LS->seminfo.ts = ts; return NAME; diff --git a/src/llex.h b/src/llex.h index ba8c52a30f..7c1a4be1f8 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,6 +1,6 @@ /* -** $Id: llex.h,v 1.9 1998/06/19 16:14:09 roberto Exp $ -** Lexical Analizer +** $Id: llex.h,v 1.12 1999/06/17 17:04:03 roberto Exp $ +** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -25,12 +25,14 @@ enum RESERVED { NAME, CONC, DOTS, EQ, GE, LE, NE, NUMBER, STRING, EOS}; -#define MAX_IFS 5 +#ifndef MAX_IFS +#define MAX_IFS 5 /* arbitrary limit */ +#endif /* "ifstate" keeps the state of each nested $if the lexical is dealing with. */ struct ifState { - int elsepart; /* true if its in the $else part */ + int elsepart; /* true if it's in the $else part */ int condition; /* true if $if condition is true */ int skip; /* true if part must be skipped */ }; @@ -56,7 +58,7 @@ void luaX_setinput (LexState *LS, ZIO *z); int luaX_lex (LexState *LS); void luaX_syntaxerror (LexState *ls, char *s, char *token); void luaX_error (LexState *ls, char *s); -void luaX_token2str (LexState *ls, int token, char *s); +void luaX_token2str (int token, char *s); #endif diff --git a/src/lmem.c b/src/lmem.c index bcb3c8e92e..5f840b005a 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.7 1998/06/29 22:03:06 roberto Exp $ +** $Id: lmem.c,v 1.17 1999/05/24 17:51:05 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -12,41 +12,54 @@ #include "lua.h" +/* +** real ANSI systems do not need these tests; +** but some systems (Sun OS) are not that ANSI... +*/ +#ifdef OLD_ANSI +#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s)) +#define free(b) if (b) (free)(b) +#endif + + +#define MINSIZE 8 /* minimum size for "growing" vectors */ + + -int luaM_growaux (void **block, unsigned long nelems, int size, - char *errormsg, unsigned long limit) -{ - if (nelems >= limit) - lua_error(errormsg); - nelems = (nelems == 0) ? 32 : nelems*2; - if (nelems > limit) - nelems = limit; - *block = luaM_realloc(*block, nelems*size); - return (int)nelems; + +static unsigned long power2 (unsigned long n) { + unsigned long p = MINSIZE; + while (p<=n) p<<=1; + return p; } +void *luaM_growaux (void *block, unsigned long nelems, int inc, int size, + char *errormsg, unsigned long limit) { + unsigned long newn = nelems+inc; + if (newn >= limit) lua_error(errormsg); + if ((newn ^ nelems) <= nelems || /* still the same power of 2 limit? */ + (nelems > 0 && newn < MINSIZE)) /* or block already is MINSIZE? */ + return block; /* do not need to reallocate */ + else /* it crossed a power of 2 boundary; grow to next power */ + return luaM_realloc(block, power2(newn)*size); +} + #ifndef DEBUG /* ** generic allocation routine. -** real ANSI systems do not need some of these tests, -** since realloc(NULL, s)==malloc(s) and realloc(b, 0)==free(b). -** But some systems (e.g. Sun OS) are not that ANSI... */ -void *luaM_realloc (void *block, unsigned long size) -{ +void *luaM_realloc (void *block, unsigned long size) { size_t s = (size_t)size; if (s != size) - lua_error("Allocation Error: Block too big"); + lua_error("memory allocation error: block too big"); if (size == 0) { - if (block) { - free(block); - } + free(block); /* block may be NULL, that is OK for free */ return NULL; } - block = block ? realloc(block, s) : malloc(s); + block = realloc(block, s); if (block == NULL) lua_error(memEM); return block; @@ -61,52 +74,66 @@ void *luaM_realloc (void *block, unsigned long size) #define HEADER (sizeof(double)) +#define MARKSIZE 16 #define MARK 55 + +#define blocksize(b) ((unsigned long *)((char *)(b) - HEADER)) + unsigned long numblocks = 0; unsigned long totalmem = 0; -static void *checkblock (void *block) -{ - unsigned long *b = (unsigned long *)((char *)block - HEADER); - unsigned long size = *b; - LUA_ASSERT(*(((char *)b)+size+HEADER) == MARK, - "corrupted block"); - numblocks--; - totalmem -= size; - return b; +static void *checkblock (void *block) { + if (block == NULL) + return NULL; + else { + unsigned long *b = blocksize(block); + unsigned long size = *b; + int i; + for (i=0;i size) oldsize = size; + memcpy(newblock+HEADER, block, oldsize); + freeblock(block); /* erase (and check) old copy */ + } + if (newblock == NULL) + lua_error(memEM); + totalmem += size; + numblocks++; + *(unsigned long *)newblock = size; + for (i=0;i /* memory error messages */ #define codeEM "code size overflow" @@ -19,18 +16,19 @@ #define refEM "reference table overflow" #define tableEM "table overflow" #define memEM "not enough memory" +#define arrEM "internal array bigger than `int' limit" void *luaM_realloc (void *oldblock, unsigned long size); -int luaM_growaux (void **block, unsigned long nelems, int size, +void *luaM_growaux (void *block, unsigned long nelems, int inc, int size, char *errormsg, unsigned long limit); #define luaM_free(b) luaM_realloc((b), 0) #define luaM_malloc(t) luaM_realloc(NULL, (t)) #define luaM_new(t) ((t *)luaM_malloc(sizeof(t))) #define luaM_newvector(n,t) ((t *)luaM_malloc((n)*sizeof(t))) -#define luaM_growvector(old,n,t,e,l) \ - (luaM_growaux((void**)old,n,sizeof(t),e,l)) -#define luaM_reallocvector(v,n,t) ((t *)luaM_realloc(v,(n)*sizeof(t))) +#define luaM_growvector(v,nelems,inc,t,e,l) \ + ((v)=(t *)luaM_growaux(v,nelems,inc,sizeof(t),e,l)) +#define luaM_reallocvector(v,n,t) ((v)=(t *)luaM_realloc(v,(n)*sizeof(t))) #ifdef DEBUG diff --git a/src/lobject.c b/src/lobject.c index 8d331ef97f..0225e2d8cc 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,9 +1,10 @@ /* -** $Id: lobject.c,v 1.13 1998/06/19 16:14:09 roberto Exp $ +** $Id: lobject.c,v 1.19 1999/04/13 19:28:49 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ +#include #include #include "lobject.h" @@ -34,14 +35,12 @@ int luaO_redimension (int oldsize) if (dimensions[i] > oldsize) return dimensions[i]; } - lua_error("table overflow"); + lua_error("tableEM"); return 0; /* to avoid warnings */ } -int luaO_equalObj (TObject *t1, TObject *t2) -{ - if (ttype(t1) != ttype(t2)) return 0; +int luaO_equalval (TObject *t1, TObject *t2) { switch (ttype(t1)) { case LUA_T_NIL: return 1; case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2); @@ -64,20 +63,67 @@ void luaO_insertlist (GCnode *root, GCnode *node) node->marked = 0; } + #ifdef OLD_ANSI -void luaO_memup (void *dest, void *src, int size) -{ - char *d = dest; - char *s = src; - while (size--) d[size]=s[size]; +void luaO_memup (void *dest, void *src, int size) { + while (size--) + ((char *)dest)[size]=((char *)src)[size]; } -void luaO_memdown (void *dest, void *src, int size) -{ - char *d = dest; - char *s = src; +void luaO_memdown (void *dest, void *src, int size) { int i; - for (i=0; i>=1) { + if (e & 1) res *= exp; + exp *= exp; + } + return res; +} + + +double luaO_str2d (char *s) { /* LUA_NUMBER */ + double a = 0.0; + int point = 0; + while (isdigit((unsigned char)*s)) { + a = 10.0*a + (*(s++)-'0'); + } + if (*s == '.') { + s++; + while (isdigit((unsigned char)*s)) { + a = 10.0*a + (*(s++)-'0'); + point++; + } + } + if (toupper((unsigned char)*s) == 'E') { + int e = 0; + int sig = 1; + s++; + if (*s == '-') { + s++; + sig = -1; + } + else if (*s == '+') s++; + if (!isdigit((unsigned char)*s)) return -1; /* no digit in the exponent? */ + do { + e = 10*e + (*(s++)-'0'); + } while (isdigit((unsigned char)*s)); + point -= sig*e; + } + while (isspace((unsigned char)*s)) s++; + if (*s != '\0') return -1; /* invalid trailing characters? */ + if (point > 0) + a /= expten(point); + else if (point < 0) + a *= expten(-point); + return a; +} + diff --git a/src/lobject.h b/src/lobject.h index fbd6070c92..f3b21477c4 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.21 1998/06/18 16:57:03 roberto Exp $ +** $Id: lobject.h,v 1.28 1999/03/16 16:43:27 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -32,10 +32,6 @@ #define LUA_NUM_TYPE double #endif -/* -** format to convert number to strings -*/ -#define NUMBER_FMT "%g" typedef LUA_NUM_TYPE real; @@ -45,13 +41,6 @@ typedef unsigned char Byte; /* unsigned 8 bits */ #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ -/* maximum value of a word of 2 bytes (-2 for safety); must fit in an "int" */ -#if MAX_INT < 65534 -#define MAX_WORD MAX_INT -#else -#define MAX_WORD 65534 -#endif - typedef unsigned int IntPoint; /* unsigned with same size as a pointer (for hashing) */ @@ -75,7 +64,6 @@ typedef enum { LUA_T_LINE = -11 } lua_Type; -#define NUM_TYPES 11 #define NUM_TAGS 7 @@ -139,7 +127,7 @@ typedef struct TProtoFunc { int nconsts; Byte *code; /* ends with opcode ENDCODE */ int lineDefined; - TaggedString *fileName; + TaggedString *source; struct LocVar *locvars; /* ends with line = -1 */ } TProtoFunc; @@ -192,11 +180,17 @@ typedef struct Hash { extern char *luaO_typenames[]; +#define luaO_typename(o) luaO_typenames[-ttype(o)] + + extern TObject luaO_nilobject; -int luaO_equalObj (TObject *t1, TObject *t2); +#define luaO_equalObj(t1,t2) ((ttype(t1) != ttype(t2)) ? 0 \ + : luaO_equalval(t1,t2)) +int luaO_equalval (TObject *t1, TObject *t2); int luaO_redimension (int oldsize); void luaO_insertlist (GCnode *root, GCnode *node); +double luaO_str2d (char *s); #ifdef OLD_ANSI void luaO_memup (void *dest, void *src, int size); diff --git a/src/lopcodes.h b/src/lopcodes.h index 27dded4730..6a59b39ef1 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.18 1998/06/25 14:37:00 roberto Exp $ +** $Id: lopcodes.h,v 1.33 1999/06/17 17:04:03 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -10,172 +10,129 @@ /* ** NOTICE: variants of the same opcode must be consecutive: First, those -** with byte parameter, then with built-in parameters, and last with -** word parameter. +** with word parameter, then with byte parameter. */ typedef enum { /* name parm before after side effect -----------------------------------------------------------------------------*/ -ENDCODE,/* - - - */ - -PUSHNIL,/* b - nil_0...nil_b */ -PUSHNIL0,/* - - nil */ - -PUSHNUMBER,/* b - (float)b */ -PUSHNUMBER0,/* - - 0.0 */ -PUSHNUMBER1,/* - - 1.0 */ -PUSHNUMBER2,/* - - 2.0 */ -PUSHNUMBERW,/* w - (float)w */ - -PUSHCONSTANT,/* b - CNST[b] */ -PUSHCONSTANT0,/*- - CNST[0] */ -PUSHCONSTANT1,/*- - CNST[1] */ -PUSHCONSTANT2,/*- - CNST[2] */ -PUSHCONSTANT3,/*- - CNST[3] */ -PUSHCONSTANT4,/*- - CNST[4] */ -PUSHCONSTANT5,/*- - CNST[5] */ -PUSHCONSTANT6,/*- - CNST[6] */ -PUSHCONSTANT7,/*- - CNST[7] */ -PUSHCONSTANTW,/*w - CNST[w] */ - -PUSHUPVALUE,/* b - Closure[b] */ -PUSHUPVALUE0,/* - - Closure[0] */ -PUSHUPVALUE1,/* - - Closure[1] */ - -PUSHLOCAL,/* b - LOC[b] */ -PUSHLOCAL0,/* - - LOC[0] */ -PUSHLOCAL1,/* - - LOC[1] */ -PUSHLOCAL2,/* - - LOC[2] */ -PUSHLOCAL3,/* - - LOC[3] */ -PUSHLOCAL4,/* - - LOC[4] */ -PUSHLOCAL5,/* - - LOC[5] */ -PUSHLOCAL6,/* - - LOC[6] */ -PUSHLOCAL7,/* - - LOC[7] */ - -GETGLOBAL,/* b - VAR[CNST[b]] */ -GETGLOBAL0,/* - - VAR[CNST[0]] */ -GETGLOBAL1,/* - - VAR[CNST[1]] */ -GETGLOBAL2,/* - - VAR[CNST[2]] */ -GETGLOBAL3,/* - - VAR[CNST[3]] */ -GETGLOBAL4,/* - - VAR[CNST[4]] */ -GETGLOBAL5,/* - - VAR[CNST[5]] */ -GETGLOBAL6,/* - - VAR[CNST[6]] */ -GETGLOBAL7,/* - - VAR[CNST[7]] */ -GETGLOBALW,/* w - VAR[CNST[w]] */ - -GETTABLE,/* - i t t[i] */ - -GETDOTTED,/* b t t[CNST[b]] */ -GETDOTTED0,/* - t t[CNST[0]] */ -GETDOTTED1,/* - t t[CNST[1]] */ -GETDOTTED2,/* - t t[CNST[2]] */ -GETDOTTED3,/* - t t[CNST[3]] */ -GETDOTTED4,/* - t t[CNST[4]] */ -GETDOTTED5,/* - t t[CNST[5]] */ -GETDOTTED6,/* - t t[CNST[6]] */ -GETDOTTED7,/* - t t[CNST[7]] */ -GETDOTTEDW,/* w t t[CNST[w]] */ - -PUSHSELF,/* b t t t[CNST[b]] */ -PUSHSELF0,/* - t t t[CNST[0]] */ -PUSHSELF1,/* - t t t[CNST[1]] */ -PUSHSELF2,/* - t t t[CNST[2]] */ -PUSHSELF3,/* - t t t[CNST[3]] */ -PUSHSELF4,/* - t t t[CNST[4]] */ -PUSHSELF5,/* - t t t[CNST[5]] */ -PUSHSELF6,/* - t t t[CNST[6]] */ -PUSHSELF7,/* - t t t[CNST[7]] */ -PUSHSELFW,/* w t t t[CNST[w]] */ - -CREATEARRAY,/* b - newarray(size = b) */ -CREATEARRAY0,/* - - newarray(size = 0) */ -CREATEARRAY1,/* - - newarray(size = 1) */ -CREATEARRAYW,/* w - newarray(size = w) */ - -SETLOCAL,/* b x - LOC[b]=x */ -SETLOCAL0,/* - x - LOC[0]=x */ -SETLOCAL1,/* - x - LOC[1]=x */ -SETLOCAL2,/* - x - LOC[2]=x */ -SETLOCAL3,/* - x - LOC[3]=x */ -SETLOCAL4,/* - x - LOC[4]=x */ -SETLOCAL5,/* - x - LOC[5]=x */ -SETLOCAL6,/* - x - LOC[6]=x */ -SETLOCAL7,/* - x - LOC[7]=x */ - -SETGLOBAL,/* b x - VAR[CNST[b]]=x */ -SETGLOBAL0,/* - x - VAR[CNST[0]]=x */ -SETGLOBAL1,/* - x - VAR[CNST[1]]=x */ -SETGLOBAL2,/* - x - VAR[CNST[2]]=x */ -SETGLOBAL3,/* - x - VAR[CNST[3]]=x */ -SETGLOBAL4,/* - x - VAR[CNST[4]]=x */ -SETGLOBAL5,/* - x - VAR[CNST[5]]=x */ -SETGLOBAL6,/* - x - VAR[CNST[6]]=x */ -SETGLOBAL7,/* - x - VAR[CNST[7]]=x */ -SETGLOBALW,/* w x - VAR[CNST[w]]=x */ - -SETTABLE0,/* - v i t - t[i]=v */ - -SETTABLE,/* b v a_b...a_1 i t a_b...a_1 i t t[i]=v */ - -SETLIST,/* b c v_c...v_1 t - t[i+b*FPF]=v_i */ -SETLIST0,/* b v_b...v_1 t - t[i]=v_i */ -SETLISTW,/* w c v_c...v_1 t - t[i+w*FPF]=v_i */ - -SETMAP,/* b v_b k_b ...v_0 k_0 t t t[k_i]=v_i */ -SETMAP0,/* - v_0 k_0 t t t[k_0]=v_0 */ - -EQOP,/* - y x (x==y)? 1 : nil */ -NEQOP,/* - y x (x~=y)? 1 : nil */ -LTOP,/* - y x (xy)? 1 : nil */ -GEOP,/* - y x (x>=y)? 1 : nil */ -ADDOP,/* - y x x+y */ -SUBOP,/* - y x x-y */ -MULTOP,/* - y x x*y */ -DIVOP,/* - y x x/y */ -POWOP,/* - y x x^y */ -CONCOP,/* - y x x..y */ -MINUSOP,/* - x -x */ -NOTOP,/* - x (x==nil)? 1 : nil */ - -ONTJMP,/* b x (x!=nil)? x : - (x!=nil)? PC+=b */ -ONTJMPW,/* w x (x!=nil)? x : - (x!=nil)? PC+=w */ -ONFJMP,/* b x (x==nil)? x : - (x==nil)? PC+=b */ -ONFJMPW,/* w x (x==nil)? x : - (x==nil)? PC+=w */ -JMP,/* b - - PC+=b */ -JMPW,/* w - - PC+=w */ -IFFJMP,/* b x - (x==nil)? PC+=b */ -IFFJMPW,/* w x - (x==nil)? PC+=w */ -IFTUPJMP,/* b x - (x!=nil)? PC-=b */ -IFTUPJMPW,/* w x - (x!=nil)? PC-=w */ -IFFUPJMP,/* b x - (x==nil)? PC-=b */ -IFFUPJMPW,/* w x - (x==nil)? PC-=w */ - -CLOSURE,/* b c v_c...v_1 closure(CNST[b], v_c...v_1) */ -CLOSUREW,/* w c v_b...v_1 closure(CNST[w], v_c...v_1) */ - -CALLFUNC,/* b c v_c...v_1 f r_b...r_1 f(v1,...,v_c) */ -CALLFUNC0,/* b v_b...v_1 f - f(v1,...,v_b) */ -CALLFUNC1,/* b v_b...v_1 f r_1 f(v1,...,v_b) */ - -RETCODE,/* b - - */ - -SETLINE,/* b - - LINE=b */ -SETLINEW,/* w - - LINE=w */ - -POP,/* b - - TOP-=(b+1) */ -POP0,/* - - - TOP-=1 */ -POP1/* - - - TOP-=2 */ +ENDCODE,/* - - (return) */ +RETCODE,/* b - (return) */ + +CALL,/* b c v_c...v_1 f r_b...r_1 f(v1,...,v_c) */ + +TAILCALL,/* b c v_c...v_1 f (return) f(v1,...,v_c) */ + +PUSHNIL,/* b - nil_0...nil_b */ +POP,/* b a_b...a_1 - */ + +PUSHNUMBERW,/* w - (float)w */ +PUSHNUMBER,/* b - (float)b */ + +PUSHNUMBERNEGW,/* w - (float)-w */ +PUSHNUMBERNEG,/* b - (float)-b */ + +PUSHCONSTANTW,/*w - CNST[w] */ +PUSHCONSTANT,/* b - CNST[b] */ + +PUSHUPVALUE,/* b - Closure[b] */ + +PUSHLOCAL,/* b - LOC[b] */ + +GETGLOBALW,/* w - VAR[CNST[w]] */ +GETGLOBAL,/* b - VAR[CNST[b]] */ + +GETTABLE,/* - i t t[i] */ + +GETDOTTEDW,/* w t t[CNST[w]] */ +GETDOTTED,/* b t t[CNST[b]] */ + +PUSHSELFW,/* w t t t[CNST[w]] */ +PUSHSELF,/* b t t t[CNST[b]] */ + +CREATEARRAYW,/* w - newarray(size = w) */ +CREATEARRAY,/* b - newarray(size = b) */ + +SETLOCAL,/* b x - LOC[b]=x */ + +SETGLOBALW,/* w x - VAR[CNST[w]]=x */ +SETGLOBAL,/* b x - VAR[CNST[b]]=x */ + +SETTABLEPOP,/* - v i t - t[i]=v */ + +SETTABLE,/* b v a_b...a_1 i t a_b...a_1 i t t[i]=v */ + +SETLISTW,/* w c v_c...v_1 t t t[i+w*FPF]=v_i */ +SETLIST,/* b c v_c...v_1 t t t[i+b*FPF]=v_i */ + +SETMAP,/* b v_b k_b ...v_0 k_0 t t t[k_i]=v_i */ + +NEQOP,/* - y x (x~=y)? 1 : nil */ +EQOP,/* - y x (x==y)? 1 : nil */ +LTOP,/* - y x (xy)? 1 : nil */ +GEOP,/* - y x (x>=y)? 1 : nil */ +ADDOP,/* - y x x+y */ +SUBOP,/* - y x x-y */ +MULTOP,/* - y x x*y */ +DIVOP,/* - y x x/y */ +POWOP,/* - y x x^y */ +CONCOP,/* - y x x..y */ +MINUSOP,/* - x -x */ +NOTOP,/* - x (x==nil)? 1 : nil */ + +ONTJMPW,/* w x (x!=nil)? x : - (x!=nil)? PC+=w */ +ONTJMP,/* b x (x!=nil)? x : - (x!=nil)? PC+=b */ +ONFJMPW,/* w x (x==nil)? x : - (x==nil)? PC+=w */ +ONFJMP,/* b x (x==nil)? x : - (x==nil)? PC+=b */ +JMPW,/* w - - PC+=w */ +JMP,/* b - - PC+=b */ +IFFJMPW,/* w x - (x==nil)? PC+=w */ +IFFJMP,/* b x - (x==nil)? PC+=b */ +IFTUPJMPW,/* w x - (x!=nil)? PC-=w */ +IFTUPJMP,/* b x - (x!=nil)? PC-=b */ +IFFUPJMPW,/* w x - (x==nil)? PC-=w */ +IFFUPJMP,/* b x - (x==nil)? PC-=b */ + +CLOSUREW,/* w c v_c...v_1 closure(CNST[w], v_c...v_1) */ +CLOSURE,/* b c v_c...v_1 closure(CNST[b], v_c...v_1) */ + +SETLINEW,/* w - - LINE=w */ +SETLINE,/* b - - LINE=b */ + +LONGARGW,/* w (add w*(1<<16) to arg of next instruction) */ +LONGARG,/* b (add b*(1<<16) to arg of next instruction) */ + +CHECKSTACK /* b (assert #temporaries == b; only for internal debuging!) */ } OpCode; #define RFIELDS_PER_FLUSH 32 /* records (SETMAP) */ -#define LFIELDS_PER_FLUSH 64 /* lists (SETLIST) */ +#define LFIELDS_PER_FLUSH 64 /* FPF - lists (SETLIST) */ + +#define ZEROVARARG 128 + + +/* maximum value of an arg of 3 bytes; must fit in an "int" */ +#if MAX_INT < (1<<24) +#define MAX_ARG MAX_INT +#else +#define MAX_ARG ((1<<24)-1) +#endif + +/* maximum value of a word of 2 bytes; cannot be bigger than MAX_ARG */ +#if MAX_ARG < (1<<16) +#define MAX_WORD MAX_ARG +#else +#define MAX_WORD ((1<<16)-1) +#endif + + +/* maximum value of a byte */ +#define MAX_BYTE ((1<<8)-1) -#define ZEROVARARG 64 #endif diff --git a/src/lparser.c b/src/lparser.c index 9b37d9df18..c18b75cc28 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,11 +1,12 @@ /* -** $Id: lparser.c,v 1.3 1998/07/06 22:07:51 roberto Exp $ +** $Id: lparser.c,v 1.37 1999/06/17 17:04:03 roberto Exp $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ #include +#include #include "lauxlib.h" #include "ldo.h" @@ -21,35 +22,48 @@ #include "lzio.h" -/* for limit numbers in error messages */ -#define MES_LIM(x) "(limit=" x ")" - /* size of a "normal" jump instruction: OpCode + 1 byte */ #define JMPSIZE 2 /* maximum number of local variables */ -#define MAXLOCALS 32 -#define SMAXLOCALS "32" +#ifndef MAXLOCALS +#define MAXLOCALS 200 /* arbitrary limit (<256) */ +#endif /* maximum number of upvalues */ -#define MAXUPVALUES 16 -#define SMAXUPVALUES "16" +#ifndef MAXUPVALUES +#define MAXUPVALUES 32 /* arbitrary limit (<256) */ +#endif + + +/* maximum number of variables in the left side of an assignment */ +#ifndef MAXVARSLH +#define MAXVARSLH 100 /* arbitrary limit (<255) */ +#endif + + +/* maximum number of parameters in a function */ +#ifndef MAXPARAMS +#define MAXPARAMS 100 /* arbitrary limit (locvars */ - int maxcode; /* size of f->code */ - int maxvars; /* size of f->locvars (-1 if no debug information) */ - int maxconsts; /* size of f->consts */ + int nvars; /* number of entries in f->locvars (-1 if no debug information) */ int lastsetline; /* line where last SETLINE was issued */ vardesc upvalues[MAXUPVALUES]; /* upvalues */ TaggedString *localvar[MAXLOCALS]; /* store local variable names */ } FuncState; +/* +** prototypes for non-terminal functions +*/ static int assignment (LexState *ls, vardesc *v, int nvars); static int cond (LexState *ls); static int funcname (LexState *ls, vardesc *v); @@ -117,22 +131,28 @@ static void exp1 (LexState *ls); static void exp2 (LexState *ls, vardesc *v); static void explist (LexState *ls, listdesc *e); static void explist1 (LexState *ls, listdesc *e); -static void ifpart (LexState *ls); +static void ifpart (LexState *ls, int line); static void parlist (LexState *ls); static void part (LexState *ls, constdesc *cd); static void recfield (LexState *ls); static void ret (LexState *ls); -static void simpleexp (LexState *ls, vardesc *v); static void statlist (LexState *ls); static void var_or_func (LexState *ls, vardesc *v); static void var_or_func_tail (LexState *ls, vardesc *v); +static void checklimit (LexState *ls, int val, int limit, char *msg) { + if (val > limit) { + char buff[100]; + sprintf(buff, "too many %s (limit=%d)", msg, limit); + luaX_error(ls, buff); + } +} + + static void check_pc (FuncState *fs, int n) { - if (fs->pc+n > fs->maxcode) - fs->maxcode = luaM_growvector(&fs->f->code, fs->maxcode, - Byte, codeEM, MAX_INT); + luaM_growvector(fs->f->code, fs->pc, n, Byte, codeEM, MAX_INT); } @@ -146,76 +166,79 @@ static void deltastack (LexState *ls, int delta) { FuncState *fs = ls->fs; fs->stacksize += delta; if (fs->stacksize > fs->maxstacksize) { - if (fs->stacksize > 255) + if (fs->stacksize > MAX_BYTE) luaX_error(ls, "function/expression too complex"); fs->maxstacksize = fs->stacksize; } } -static int code_oparg_at (LexState *ls, int pc, OpCode op, int builtin, - int arg, int delta) { +static void code_oparg_at (LexState *ls, int pc, OpCode op, + int arg, int delta) { Byte *code = ls->fs->f->code; deltastack(ls, delta); - if (arg < builtin) { - code[pc] = op+1+arg; - return 1; + if (arg <= MAX_BYTE) { + code[pc] = (Byte)op; + code[pc+1] = (Byte)arg; } - else if (arg <= 255) { - code[pc] = op; - code[pc+1] = arg; - return 2; - } - else if (arg <= MAX_WORD) { - code[pc] = op+1+builtin; - code[pc+1] = arg>>8; - code[pc+2] = arg&0xFF; - return 3; + else if (arg > MAX_ARG) + luaX_error(ls, "code too long"); + else { /* MAX_BYTE < arg < MAX_ARG */ + if (arg > MAX_WORD) { + code[pc] = (Byte)LONGARG; + code[pc+1] = (Byte)(arg>>16); + pc += 2; + } + code[pc] = (Byte)(op-1); /* opcode for word argument */ + code[pc+1] = (Byte)((arg&0xFFFF)>>8); + code[pc+2] = (Byte)(arg&0xFF); } - else luaX_error(ls, "code too long " MES_LIM("64K")); - return 0; /* to avoid warnings */ } -static int fix_opcode (LexState *ls, int pc, OpCode op, int builtin, int arg) { - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - if (arg < builtin) { /* close space */ - luaO_memdown(f->code+pc+1, f->code+pc+2, fs->pc-(pc+2)); - fs->pc--; - } - else if (arg > 255) { /* open space */ - check_pc(fs, 1); - luaO_memup(f->code+pc+1, f->code+pc, fs->pc-pc); - fs->pc++; +static int codesize (int arg) { + if (arg <= MAX_BYTE) return 2; /* opcode + 1 byte */ + else if (arg <= MAX_WORD) return 3; /* opcode + 1 word (2 bytes) */ + else return 5; /* LONGARG + 1 byte + opcode + 1 word (2 bytes) */ +} + + +static int fix_opcode (LexState *ls, int pc, OpCode op, int arg) { + int tomove = codesize(arg)-2; + if (tomove > 0) { /* need to open space? */ + FuncState *fs = ls->fs; + TProtoFunc *f = fs->f; + check_pc(fs, tomove); + luaO_memup(f->code+pc+tomove, f->code+pc, fs->pc-pc); + fs->pc += tomove; } - return code_oparg_at(ls, pc, op, builtin, arg, 0) - 2; + code_oparg_at(ls, pc, op, arg, 0); + return tomove; } -static void code_oparg (LexState *ls, OpCode op, int builtin, int arg, - int delta) { - check_pc(ls->fs, 3); /* maximum code size */ - ls->fs->pc += code_oparg_at(ls, ls->fs->pc, op, builtin, arg, delta); + +static void code_oparg (LexState *ls, OpCode op, int arg, int delta) { + int size = codesize(arg); + check_pc(ls->fs, size); + code_oparg_at(ls, ls->fs->pc, op, arg, delta); + ls->fs->pc += size; } static void code_opcode (LexState *ls, OpCode op, int delta) { deltastack(ls, delta); - code_byte(ls->fs, op); + code_byte(ls->fs, (Byte)op); } static void code_constant (LexState *ls, int c) { - code_oparg(ls, PUSHCONSTANT, 8, c, 1); + code_oparg(ls, PUSHCONSTANT, c, 1); } static int next_constant (FuncState *fs) { TProtoFunc *f = fs->f; - if (f->nconsts >= fs->maxconsts) { - fs->maxconsts = luaM_growvector(&f->consts, fs->maxconsts, TObject, - constantEM, MAX_WORD); - } + luaM_growvector(f->consts, f->nconsts, 1, TObject, constantEM, MAX_ARG); return f->nconsts++; } @@ -249,9 +272,9 @@ static int real_constant (FuncState *fs, real r) { if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) return c; } - /* not found; create a luaM_new entry */ + /* not found; create a new entry */ c = next_constant(fs); - cnt = fs->f->consts; /* 'next_constant' may reallocate this vector */ + cnt = fs->f->consts; /* 'next_constant' may have reallocated this vector */ ttype(&cnt[c]) = LUA_T_NUMBER; nvalue(&cnt[c]) = r; return c; @@ -259,9 +282,11 @@ static int real_constant (FuncState *fs, real r) { static void code_number (LexState *ls, real f) { - int i; - if (f >= 0 && f <= (real)MAX_WORD && (real)(i=(int)f) == f) - code_oparg(ls, PUSHNUMBER, 3, i, 1); /* f has a short integer value */ + real af = (f<0) ? -f : f; + if (0 <= af && af <= (real)MAX_WORD && (int)af == af) { + /* abs(f) has a short integer value */ + code_oparg(ls, (f<0) ? PUSHNUMBERNEG : PUSHNUMBER, (int)af, 1); + } else code_constant(ls, real_constant(ls->fs, f)); } @@ -269,24 +294,23 @@ static void code_number (LexState *ls, real f) { static void flush_record (LexState *ls, int n) { if (n > 0) - code_oparg(ls, SETMAP, 1, n-1, -2*n); + code_oparg(ls, SETMAP, n-1, -2*n); } static void flush_list (LexState *ls, int m, int n) { - if (n == 0) return; - code_oparg(ls, SETLIST, 1, m, -n); - code_byte(ls->fs, n); + if (n > 0) { + code_oparg(ls, SETLIST, m, -n); + code_byte(ls->fs, (Byte)n); + } } static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname, int line) { - if (fs->maxvars != -1) { /* debug information? */ + if (fs->nvars != -1) { /* debug information? */ TProtoFunc *f = fs->f; - if (fs->nvars >= fs->maxvars) - fs->maxvars = luaM_growvector(&f->locvars, fs->maxvars, - LocVar, "", MAX_WORD); + luaM_growvector(f->locvars, fs->nvars, 1, LocVar, "", MAX_INT); f->locvars[fs->nvars].varname = varname; f->locvars[fs->nvars].line = line; fs->nvars++; @@ -301,10 +325,8 @@ static void luaI_unregisterlocalvar (FuncState *fs, int line) { static void store_localvar (LexState *ls, TaggedString *name, int n) { FuncState *fs = ls->fs; - if (fs->nlocalvar+n < MAXLOCALS) - fs->localvar[fs->nlocalvar+n] = name; - else - luaX_error(ls, "too many local variables " MES_LIM(SMAXLOCALS)); + checklimit(ls, fs->nlocalvar+n+1, MAXLOCALS, "local variables"); + fs->localvar[fs->nlocalvar+n] = name; luaI_registerlocalvar(fs, name, ls->linenumber); } @@ -315,6 +337,16 @@ static void add_localvar (LexState *ls, TaggedString *name) { } +static void correctvarlines (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + if (fs->nvars != -1) { /* debug information? */ + for (; nvars; nvars--) { /* correct line information */ + fs->f->locvars[fs->nvars-nvars].line = fs->lastsetline; + } + } +} + + static int aux_localname (FuncState *fs, TaggedString *n) { int i; for (i=fs->nlocalvar-1; i >= 0; i--) @@ -326,13 +358,13 @@ static int aux_localname (FuncState *fs, TaggedString *n) { static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) { FuncState *fs = prev ? ls->fs->prev : ls->fs; int i = aux_localname(fs, n); - if (i >= 0) { /* local value */ + if (i >= 0) { /* local value? */ var->k = VLOCAL; var->info = i; } - else { /* check shadowing */ + else { FuncState *level = fs; - while ((level = level->prev) != NULL) + while ((level = level->prev) != NULL) /* check shadowing */ if (aux_localname(level, n) >= 0) luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); var->k = VGLOBAL; @@ -351,29 +383,26 @@ static int indexupvalue (LexState *ls, TaggedString *n) { return i; } /* new one */ - if (++(fs->nupvalues) > MAXUPVALUES) - luaX_error(ls, "too many upvalues in a single function " - MES_LIM(SMAXUPVALUES)); + ++(fs->nupvalues); + checklimit(ls, fs->nupvalues, MAXUPVALUES, "upvalues"); fs->upvalues[i] = v; /* i = fs->nupvalues - 1 */ return i; } static void pushupvalue (LexState *ls, TaggedString *n) { - int i; if (ls->fs->prev == NULL) luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); if (aux_localname(ls->fs, n) >= 0) luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str); - i = indexupvalue(ls, n); - code_oparg(ls, PUSHUPVALUE, 2, i, 1); + code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1); } static void check_debugline (LexState *ls) { - if (lua_debug && ls->linenumber != ls->fs->lastsetline) { - code_oparg(ls, SETLINE, 0, ls->linenumber, 0); + if (L->debug && ls->linenumber != ls->fs->lastsetline) { + code_oparg(ls, SETLINE, ls->linenumber, 0); ls->fs->lastsetline = ls->linenumber; } } @@ -381,22 +410,22 @@ static void check_debugline (LexState *ls) { static void adjuststack (LexState *ls, int n) { if (n > 0) - code_oparg(ls, POP, 2, n-1, -n); + code_oparg(ls, POP, n, -n); else if (n < 0) - code_oparg(ls, PUSHNIL, 1, (-n)-1, -n); + code_oparg(ls, PUSHNIL, (-n)-1, -n); } static void close_exp (LexState *ls, int pc, int nresults) { - if (pc > 0) { /* expression is an open function call */ + if (pc > 0) { /* expression is an open function call? */ Byte *code = ls->fs->f->code; - int nparams = code[pc]; /* save nparams */ - pc += fix_opcode(ls, pc-2, CALLFUNC, 2, nresults); - code[pc] = nparams; /* restore nparams */ - if (nresults != MULT_RET) - deltastack(ls, nresults); /* "push" results */ - deltastack(ls, -(nparams+1)); /* "pop" params and function */ + code[pc-1] = (Byte)nresults; /* set nresults */ + /* push results, pop params (at code[pc]) and function */ + deltastack(ls, nresults-(code[pc]+1)); } +#ifdef DEBUG + code_oparg(ls, CHECKSTACK, ls->fs->stacksize, 0); +#endif } @@ -408,7 +437,7 @@ static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { } else { /* must correct function call */ diff--; /* do not count function call itself */ - if (diff < 0) { /* more variables than values */ + if (diff <= 0) { /* more variables than values? */ /* function call must provide extra values */ close_exp(ls, d->pc, -diff); } @@ -423,29 +452,39 @@ static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { static void code_args (LexState *ls, int nparams, int dots) { FuncState *fs = ls->fs; fs->nlocalvar += nparams; /* "self" may already be there */ + checklimit(ls, fs->nlocalvar, MAXPARAMS, "parameters"); nparams = fs->nlocalvar; if (!dots) { - fs->f->code[1] = nparams; /* fill-in arg information */ + fs->f->code[1] = (Byte)nparams; /* fill-in arg information */ deltastack(ls, nparams); } else { - fs->f->code[1] = nparams+ZEROVARARG; + fs->f->code[1] = (Byte)(nparams+ZEROVARARG); deltastack(ls, nparams+1); add_localvar(ls, luaS_new("arg")); } } +static void unloaddot (LexState *ls, vardesc *v) { + /* dotted variables must be stored like regular indexed vars */ + if (v->k == VDOT) { + code_constant(ls, v->info); + v->k = VINDEXED; + } +} + + static void lua_pushvar (LexState *ls, vardesc *var) { switch (var->k) { case VLOCAL: - code_oparg(ls, PUSHLOCAL, 8, var->info, 1); + code_oparg(ls, PUSHLOCAL, var->info, 1); break; case VGLOBAL: - code_oparg(ls, GETGLOBAL, 8, var->info, 1); + code_oparg(ls, GETGLOBAL, var->info, 1); break; case VDOT: - code_oparg(ls, GETDOTTED, 8, var->info, 0); + code_oparg(ls, GETDOTTED, var->info, 0); break; case VINDEXED: code_opcode(ls, GETTABLE, -1); @@ -462,13 +501,13 @@ static void lua_pushvar (LexState *ls, vardesc *var) { static void storevar (LexState *ls, vardesc *var) { switch (var->k) { case VLOCAL: - code_oparg(ls, SETLOCAL, 8, var->info, -1); + code_oparg(ls, SETLOCAL, var->info, -1); break; case VGLOBAL: - code_oparg(ls, SETGLOBAL, 8, var->info, -1); + code_oparg(ls, SETGLOBAL, var->info, -1); break; case VINDEXED: - code_opcode(ls, SETTABLE0, -3); + code_opcode(ls, SETTABLEPOP, -3); break; default: LUA_INTERNALERROR("invalid var kind to store"); @@ -478,21 +517,20 @@ static void storevar (LexState *ls, vardesc *var) { static int fix_jump (LexState *ls, int pc, OpCode op, int n) { /* jump is relative to position following jump instruction */ - return fix_opcode(ls, pc, op, 0, n-(pc+JMPSIZE)); + return fix_opcode(ls, pc, op, n-(pc+JMPSIZE)); } static void fix_upjmp (LexState *ls, OpCode op, int pos) { int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */ - if (delta > 255) delta++; - code_oparg(ls, op, 0, delta, 0); + code_oparg(ls, op, delta+(codesize(delta)-2), 0); } static void codeIf (LexState *ls, int thenAdd, int elseAdd) { FuncState *fs = ls->fs; int elseinit = elseAdd+JMPSIZE; - if (fs->pc == elseinit) { /* no else part */ + if (fs->pc == elseinit) { /* no else part? */ fs->pc -= JMPSIZE; elseinit = fs->pc; } @@ -513,13 +551,14 @@ static void func_onstack (LexState *ls, FuncState *func) { else { for (i=0; inupvalues; i++) lua_pushvar(ls, &func->upvalues[i]); - code_oparg(ls, CLOSURE, 0, c, -func->nupvalues+1); - code_byte(fs, func->nupvalues); + deltastack(ls, 1); /* CLOSURE puts one extra element (before poping) */ + code_oparg(ls, CLOSURE, c, -func->nupvalues); + code_byte(fs, (Byte)func->nupvalues); } } -static void init_state (LexState *ls, FuncState *fs, TaggedString *filename) { +static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { TProtoFunc *f = luaF_newproto(); fs->prev = ls->fs; /* linked list of funcstates */ ls->fs = fs; @@ -529,17 +568,15 @@ static void init_state (LexState *ls, FuncState *fs, TaggedString *filename) { fs->nupvalues = 0; fs->lastsetline = 0; fs->f = f; - f->fileName = filename; + f->source = source; fs->pc = 0; - fs->maxcode = 0; f->code = NULL; - fs->maxconsts = 0; - if (lua_debug) - fs->nvars = fs->maxvars = 0; - else - fs->maxvars = -1; /* flag no debug information */ - code_byte(fs, 0); /* to be filled with stacksize */ + fs->nvars = (L->debug) ? 0 : -1; /* flag no debug information? */ + code_byte(fs, 0); /* to be filled with maxstacksize */ code_byte(fs, 0); /* to be filled with arg information */ + /* push function (to avoid GC) */ + tfvalue(L->stack.top) = f; ttype(L->stack.top) = LUA_T_PROTO; + incr_top; } @@ -547,14 +584,15 @@ static void close_func (LexState *ls) { FuncState *fs = ls->fs; TProtoFunc *f = fs->f; code_opcode(ls, ENDCODE, 0); - f->code[0] = fs->maxstacksize; - f->code = luaM_reallocvector(f->code, fs->pc, Byte); - f->consts = luaM_reallocvector(f->consts, f->nconsts, TObject); - if (fs->maxvars != -1) { /* debug information? */ + f->code[0] = (Byte)fs->maxstacksize; + luaM_reallocvector(f->code, fs->pc, Byte); + luaM_reallocvector(f->consts, f->nconsts, TObject); + if (fs->nvars != -1) { /* debug information? */ luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */ - f->locvars = luaM_reallocvector(f->locvars, fs->nvars, LocVar); + luaM_reallocvector(f->locvars, fs->nvars, LocVar); } ls->fs = fs->prev; + L->stack.top--; /* pop function */ } @@ -562,13 +600,11 @@ static void close_func (LexState *ls) { static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME, LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',', 0}; + static int is_in (int tok, int *toks) { - int *t = toks; - while (*t) { - if (*t == tok) - return t-toks; - t++; - } + int *t; + for (t=toks; *t; t++) + if (*t == tok) return t-toks; return -1; } @@ -580,19 +616,25 @@ static void next (LexState *ls) { static void error_expected (LexState *ls, int token) { char buff[100], t[TOKEN_LEN]; - luaX_token2str(ls, token, t); + luaX_token2str(token, t); sprintf(buff, "`%s' expected", t); luaX_error(ls, buff); } + +static void error_unexpected (LexState *ls) { + luaX_error(ls, "unexpected token"); +} + + static void error_unmatched (LexState *ls, int what, int who, int where) { if (where == ls->linenumber) error_expected(ls, what); else { char buff[100]; char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; - luaX_token2str(ls, what, t_what); - luaX_token2str(ls, who, t_who); + luaX_token2str(what, t_what); + luaX_token2str(who, t_who); sprintf(buff, "`%s' expected (to close `%s' at line %d)", t_what, t_who, where); luaX_error(ls, buff); @@ -612,13 +654,18 @@ static void check_match (LexState *ls, int what, int who, int where) { next(ls); } -static TaggedString *checkname (LexState *ls) { - TaggedString *ts; +static int checkname (LexState *ls) { + int sc; if (ls->token != NAME) luaX_error(ls, "`NAME' expected"); - ts = ls->seminfo.ts; + sc = string_constant(ls->fs, ls->seminfo.ts); next(ls); - return ts; + return sc; +} + + +static TaggedString *str_checkname (LexState *ls) { + return tsvalue(&ls->fs->f->consts[checkname(ls)]); } @@ -669,12 +716,9 @@ static int stat (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ FuncState *fs = ls->fs; switch (ls->token) { - case IF: { /* stat -> IF ifpart END */ - next(ls); - ifpart(ls); - check_match(ls, END, IF, line); + case IF: /* stat -> IF ifpart END */ + ifpart(ls, line); return 1; - } case WHILE: { /* stat -> WHILE cond DO block END */ TProtoFunc *f = fs->f; @@ -732,7 +776,8 @@ static int stat (LexState *ls) { next(ls); nvars = localnamelist(ls); decinit(ls, &d); - ls->fs->nlocalvar += nvars; + fs->nlocalvar += nvars; + correctvarlines(ls, nvars); /* vars will be alive only after decinit */ adjust_mult_assign(ls, nvars, &d); return 1; } @@ -746,8 +791,8 @@ static int stat (LexState *ls) { luaX_error(ls, "syntax error"); close_exp(ls, v.info, 0); } - else { - int left = assignment(ls, &v, 1); /* stat -> ['%'] NAME assignment */ + else { /* stat -> ['%'] NAME assignment */ + int left = assignment(ls, &v, 1); adjuststack(ls, left); /* remove eventual 'garbage' left on stack */ } return 1; @@ -758,7 +803,7 @@ static int stat (LexState *ls) { return 0; default: - luaX_error(ls, " expected"); + error_unexpected(ls); return 0; /* to avoid warnings */ } } @@ -788,18 +833,18 @@ static void block (LexState *ls) { chunk(ls); adjuststack(ls, fs->nlocalvar - nlocalvar); for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) - luaI_unregisterlocalvar(fs, ls->linenumber); + luaI_unregisterlocalvar(fs, fs->lastsetline); } static int funcname (LexState *ls, vardesc *v) { /* funcname -> NAME [':' NAME | '.' NAME] */ int needself = 0; - singlevar(ls, checkname(ls), v, 0); + singlevar(ls, str_checkname(ls), v, 0); if (ls->token == ':' || ls->token == '.') { needself = (ls->token == ':'); next(ls); lua_pushvar(ls, v); - code_string(ls, checkname(ls)); + code_constant(ls, checkname(ls)); v->k = VINDEXED; } return needself; @@ -808,7 +853,7 @@ static int funcname (LexState *ls, vardesc *v) { static void body (LexState *ls, int needself, int line) { /* body -> '(' parlist ')' chunk END */ FuncState newfs; - init_state(ls, &newfs, ls->fs->f->fileName); + init_state(ls, &newfs, ls->fs->f->source); newfs.f->lineDefined = line; check(ls, '('); if (needself) @@ -821,36 +866,40 @@ static void body (LexState *ls, int needself, int line) { func_onstack(ls, &newfs); } -static void ifpart (LexState *ls) { + +static void ifpart (LexState *ls, int line) { /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ - int c = cond(ls); + int c; int e; + next(ls); /* skip IF or ELSEIF */ + c = cond(ls); check(ls, THEN); block(ls); e = SaveWord(ls); - switch (ls->token) { - case ELSE: - next(ls); + if (ls->token == ELSEIF) + ifpart(ls, line); + else { + if (optional(ls, ELSE)) block(ls); - break; - - case ELSEIF: - next(ls); - ifpart(ls); - break; + check_match(ls, END, IF, line); } codeIf(ls, c, e); } + static void ret (LexState *ls) { /* ret -> [RETURN explist sc] */ - if (ls->token == RETURN) { + if (optional(ls, RETURN)) { listdesc e; check_debugline(ls); - next(ls); - explist(ls, &e); - close_exp(ls, e.pc, MULT_RET); - code_oparg(ls, RETCODE, 0, ls->fs->nlocalvar, 0); + explist(ls, &e); + if (e.pc > 0) { /* expression is an open function call? */ + Byte *code = ls->fs->f->code; + code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ + code[e.pc-1] = (Byte)ls->fs->nlocalvar; + } + else + code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ optional(ls, ';'); } @@ -863,6 +912,9 @@ static void ret (LexState *ls) { ** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. */ +#define INDNOT 0 +#define INDMINUS 1 + /* code of first binary operator */ #define FIRSTBIN 2 @@ -879,9 +931,9 @@ static int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; static OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, LTOP, LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP}; -#define MAXOPS 20 +#define MAXOPS 20 /* op's stack size (arbitrary limit) */ -typedef struct { +typedef struct stack_op { int ops[MAXOPS]; int top; } stack_op; @@ -892,39 +944,33 @@ static void exp1 (LexState *ls) { exp0(ls, &v); lua_pushvar(ls, &v); if (is_in(ls->token, expfollow) < 0) - luaX_error(ls, "ill formed expression"); + luaX_error(ls, "ill-formed expression"); } static void exp0 (LexState *ls, vardesc *v) { + /* exp0 -> exp2 {(AND | OR) exp2} */ exp2(ls, v); while (ls->token == AND || ls->token == OR) { - int is_and = (ls->token == AND); + int op = (ls->token == AND) ? ONFJMP : ONTJMP; int pc; lua_pushvar(ls, v); next(ls); pc = SaveWordPop(ls); exp2(ls, v); lua_pushvar(ls, v); - fix_jump(ls, pc, (is_and?ONFJMP:ONTJMP), ls->fs->pc); + fix_jump(ls, pc, op, ls->fs->pc); } } static void push (LexState *ls, stack_op *s, int op) { - if (s->top == MAXOPS) + if (s->top >= MAXOPS) luaX_error(ls, "expression too complex"); s->ops[s->top++] = op; } -static void prefix (LexState *ls, stack_op *s) { - while (ls->token == NOT || ls->token == '-') { - push(ls, s, ls->token==NOT?0:1); - next(ls); - } -} - static void pop_to (LexState *ls, stack_op *s, int prio) { int op; while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { @@ -933,92 +979,104 @@ static void pop_to (LexState *ls, stack_op *s, int prio) { } } -static void exp2 (LexState *ls, vardesc *v) { - stack_op s; - int op; - s.top = 0; - prefix(ls, &s); - simpleexp(ls, v); - while ((op = is_in(ls->token, binop)) >= 0) { - op += FIRSTBIN; - lua_pushvar(ls, v); - /* '^' is right associative, so must 'simulate' a higher priority */ - pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); - push(ls, &s, op); - next(ls); - prefix(ls, &s); - simpleexp(ls, v); - lua_pushvar(ls, v); - } - if (s.top > 0) { - lua_pushvar(ls, v); - pop_to(ls, &s, 0); - } -} - - -static void simpleexp (LexState *ls, vardesc *v) { +static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { check_debugline(ls); switch (ls->token) { - case '(': /* simpleexp -> '(' exp0 ')' */ - next(ls); - exp0(ls, v); - check(ls, ')'); - break; - - case NUMBER: /* simpleexp -> NUMBER */ - code_number(ls, ls->seminfo.r); + case NUMBER: { /* simpleexp -> NUMBER */ + real r = ls->seminfo.r; next(ls); - v->k = VEXP; v->info = 0; + /* dirty trick: check whether it is a -NUMBER not followed by '^' */ + /* (because the priority of '^' is closer than '-'...) */ + if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { + s->top--; /* remove '-' from stack */ + r = -r; + } + code_number(ls, r); break; + } case STRING: /* simpleexp -> STRING */ - code_string(ls, ls->seminfo.ts); + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ next(ls); - v->k = VEXP; v->info = 0; break; case NIL: /* simpleexp -> NIL */ adjuststack(ls, -1); next(ls); - v->k = VEXP; v->info = 0; break; case '{': /* simpleexp -> constructor */ constructor(ls); - v->k = VEXP; v->info = 0; break; - case FUNCTION: { /* simpleexp -> FUNCTION body */ - int line = ls->linenumber; + case FUNCTION: /* simpleexp -> FUNCTION body */ next(ls); - body(ls, 0, line); - v->k = VEXP; v->info = 0; + body(ls, 0, ls->linenumber); break; - } + + case '(': /* simpleexp -> '(' exp0 ')' */ + next(ls); + exp0(ls, v); + check(ls, ')'); + return; case NAME: case '%': var_or_func(ls, v); - break; + return; default: luaX_error(ls, " expected"); - break; + return; + } + v->k = VEXP; v->info = 0; +} + + +static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { + /* prefixexp -> {NOT | '-'} simpleexp */ + while (ls->token == NOT || ls->token == '-') { + push(ls, s, (ls->token==NOT)?INDNOT:INDMINUS); + next(ls); + } + simpleexp(ls, v, s); +} + + +static void exp2 (LexState *ls, vardesc *v) { + stack_op s; + int op; + s.top = 0; + prefixexp(ls, v, &s); + while ((op = is_in(ls->token, binop)) >= 0) { + op += FIRSTBIN; + lua_pushvar(ls, v); + /* '^' is right associative, so must 'simulate' a higher priority */ + pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); + push(ls, &s, op); + next(ls); + prefixexp(ls, v, &s); + lua_pushvar(ls, v); + } + if (s.top > 0) { + lua_pushvar(ls, v); + pop_to(ls, &s, 0); } } + static void var_or_func (LexState *ls, vardesc *v) { /* var_or_func -> ['%'] NAME var_or_func_tail */ if (optional(ls, '%')) { /* upvalue? */ - pushupvalue(ls, checkname(ls)); + pushupvalue(ls, str_checkname(ls)); v->k = VEXP; v->info = 0; /* closed expression */ } else /* variable name */ - singlevar(ls, checkname(ls), v, 0); + singlevar(ls, str_checkname(ls), v, 0); var_or_func_tail(ls, v); } + static void var_or_func_tail (LexState *ls, vardesc *v) { for (;;) { switch (ls->token) { @@ -1026,7 +1084,7 @@ static void var_or_func_tail (LexState *ls, vardesc *v) { next(ls); lua_pushvar(ls, v); /* 'v' must be on stack */ v->k = VDOT; - v->info = string_constant(ls->fs, checkname(ls)); + v->info = checkname(ls); break; case '[': /* var_or_func_tail -> '[' exp1 ']' */ @@ -1040,7 +1098,7 @@ static void var_or_func_tail (LexState *ls, vardesc *v) { case ':': /* var_or_func_tail -> ':' NAME funcparams */ next(ls); lua_pushvar(ls, v); /* 'v' must be on stack */ - code_oparg(ls, PUSHSELF, 8, string_constant(ls->fs, checkname(ls)), 1); + code_oparg(ls, PUSHSELF, checkname(ls), 1); v->k = VEXP; v->info = funcparams(ls, 1); break; @@ -1058,13 +1116,14 @@ static void var_or_func_tail (LexState *ls, vardesc *v) { static int funcparams (LexState *ls, int slf) { FuncState *fs = ls->fs; - int nparams = 1; /* default value */ + int nparams = 1; /* in cases STRING and constructor */ switch (ls->token) { case '(': { /* funcparams -> '(' explist ')' */ + int line = ls->linenumber; listdesc e; next(ls); explist(ls, &e); - check(ls, ')'); + check_match(ls, ')', '(', line); close_exp(ls, e.pc, 1); nparams = e.n; break; @@ -1075,7 +1134,7 @@ static int funcparams (LexState *ls, int slf) { break; case STRING: /* funcparams -> STRING */ - code_string(ls, ls->seminfo.ts); + code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ next(ls); break; @@ -1083,9 +1142,9 @@ static int funcparams (LexState *ls, int slf) { luaX_error(ls, "function arguments expected"); break; } - code_byte(fs, 0); /* save space for opcode */ - code_byte(fs, 0); /* and nresult */ - code_byte(fs, nparams+slf); + code_byte(fs, CALL); + code_byte(fs, 0); /* save space for nresult */ + code_byte(fs, (Byte)(nparams+slf)); return fs->pc-1; } @@ -1131,7 +1190,7 @@ static void parlist (LexState *ls) { case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ init: - store_localvar(ls, checkname(ls), nparams++); + store_localvar(ls, str_checkname(ls), nparams++); if (ls->token == ',') { next(ls); switch (ls->token) { @@ -1158,10 +1217,10 @@ static void parlist (LexState *ls) { static int localnamelist (LexState *ls) { /* localnamelist -> NAME {',' NAME} */ int i = 1; - store_localvar(ls, checkname(ls), 0); + store_localvar(ls, str_checkname(ls), 0); while (ls->token == ',') { next(ls); - store_localvar(ls, checkname(ls), i++); + store_localvar(ls, str_checkname(ls), i++); } return i; } @@ -1178,13 +1237,11 @@ static void decinit (LexState *ls, listdesc *d) { } } + static int assignment (LexState *ls, vardesc *v, int nvars) { int left = 0; - /* dotted variables must be stored like regular indexed vars */ - if (v->k == VDOT) { - code_constant(ls, v->info); - v->k = VINDEXED; - } + checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); + unloaddot(ls, v); if (ls->token == ',') { /* assignment -> ',' NAME assignment */ vardesc nv; next(ls); @@ -1204,12 +1261,13 @@ static int assignment (LexState *ls, vardesc *v, int nvars) { storevar(ls, v); } else { /* indexed var with values in between*/ - code_oparg(ls, SETTABLE, 0, left+(nvars-1), -1); - left += 2; /* table/index are not popped, because they aren't on top */ + code_oparg(ls, SETTABLE, left+(nvars-1), -1); + left += 2; /* table&index are not popped, because they aren't on top */ } return left; } + static void constructor (LexState *ls) { /* constructor -> '{' part [';' part] '}' */ int line = ls->linenumber; @@ -1229,7 +1287,7 @@ static void constructor (LexState *ls) { nelems += other_cd.n; } check_match(ls, '}', '{', line); - fix_opcode(ls, pc, CREATEARRAY, 2, nelems); + fix_opcode(ls, pc, CREATEARRAY, nelems); } static void part (LexState *ls, constdesc *cd) { @@ -1251,7 +1309,7 @@ static void part (LexState *ls, constdesc *cd) { code_string(ls, ls->fs->localvar[v.info]); break; default: - luaX_error(ls, "`=' unexpected"); + error_unexpected(ls); } next(ls); exp1(ls); @@ -1316,7 +1374,7 @@ static void recfield (LexState *ls) { /* recfield -> (NAME | '['exp1']') = exp1 */ switch (ls->token) { case NAME: - code_string(ls, checkname(ls)); + code_constant(ls, checkname(ls)); break; case '[': diff --git a/src/lparser.h b/src/lparser.h index b37fd815b3..9825ec57fc 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,6 +1,6 @@ /* -** $Id: lparser.h,v 1.2 1997/12/22 20:57:18 roberto Exp $ -** Syntax analizer and code generator +** $Id: lparser.h,v 1.3 1999/02/25 19:13:56 roberto Exp $ +** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ diff --git a/src/lstate.c b/src/lstate.c index 43015b97a8..3b98d72976 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.6 1998/06/02 20:37:04 roberto Exp $ +** $Id: lstate.c,v 1.12 1999/05/11 20:08:20 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -24,11 +24,19 @@ void lua_open (void) { if (lua_state) return; lua_state = luaM_new(lua_State); - L->numCblocks = 0; L->Cstack.base = 0; L->Cstack.lua2C = 0; L->Cstack.num = 0; L->errorJmp = NULL; + L->Mbuffer = NULL; + L->Mbuffbase = 0; + L->Mbuffsize = 0; + L->Mbuffnext = 0; + L->Cblocks = NULL; + L->numCblocks = 0; + L->debug = 0; + L->callhook = NULL; + L->linehook = NULL; L->rootproto.next = NULL; L->rootproto.marked = 0; L->rootcl.next = NULL; @@ -37,12 +45,9 @@ void lua_open (void) L->rootglobal.marked = 0; L->roottable.next = NULL; L->roottable.marked = 0; + L->IMtable = NULL; L->refArray = NULL; L->refSize = 0; - L->Mbuffsize = 0; - L->Mbuffnext = 0; - L->Mbuffbase = NULL; - L->Mbuffer = NULL; L->GCthreshold = GARBAGE_BLOCK; L->nblocks = 0; luaD_init(); @@ -69,6 +74,7 @@ void lua_close (void) luaM_free(L->IMtable); luaM_free(L->refArray); luaM_free(L->Mbuffer); + luaM_free(L->Cblocks); luaM_free(L); L = NULL; #ifdef DEBUG @@ -78,9 +84,3 @@ void lua_close (void) } -lua_State *lua_setstate (lua_State *st) { - lua_State *old = lua_state; - lua_state = st; - return old; -} - diff --git a/src/lstate.h b/src/lstate.h index 71d956fa89..168257dd6c 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.11 1998/06/24 13:33:00 roberto Exp $ +** $Id: lstate.h,v 1.19 1999/05/11 20:08:20 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -11,15 +11,24 @@ #include "lobject.h" #include "lua.h" +#include "luadebug.h" -#define MAX_C_BLOCKS 10 - #define GARBAGE_BLOCK 150 typedef int StkId; /* index to stack elements */ + +/* +** "jmp_buf" may be an array, so it is better to make sure it has an +** address (and not that it *is* an address...) +*/ +struct lua_longjmp { + jmp_buf b; +}; + + struct Stack { TObject *top; TObject *stack; @@ -34,7 +43,7 @@ struct C_Lua_Stack { }; -typedef struct { +typedef struct stringtable { int size; int nuse; /* number of elements (including EMPTYs) */ TaggedString **hash; @@ -53,22 +62,23 @@ struct lua_State { /* thread-specific state */ struct Stack stack; /* Lua stack */ struct C_Lua_Stack Cstack; /* C2lua struct */ - jmp_buf *errorJmp; /* current error recover point */ + struct lua_longjmp *errorJmp; /* current error recover point */ char *Mbuffer; /* global buffer */ - char *Mbuffbase; /* current first position of Mbuffer */ + int Mbuffbase; /* current first position of Mbuffer */ int Mbuffsize; /* size of Mbuffer */ int Mbuffnext; /* next position to fill in Mbuffer */ - struct C_Lua_Stack Cblocks[MAX_C_BLOCKS]; + struct C_Lua_Stack *Cblocks; int numCblocks; /* number of nested Cblocks */ + int debug; + lua_CHFunction callhook; + lua_LHFunction linehook; /* global state */ - TObject errorim; /* error tag method */ GCnode rootproto; /* list of all prototypes */ GCnode rootcl; /* list of all closures */ GCnode roottable; /* list of all tables */ GCnode rootglobal; /* list of strings with global values */ stringtable *string_root; /* array of hash tables for strings and udata */ struct IM *IMtable; /* table for tag methods */ - int IMtable_size; /* size of IMtable */ int last_tag; /* last used tag in IMtable */ struct ref *refArray; /* locked objects */ int refSize; /* size of refArray */ @@ -77,10 +87,8 @@ struct lua_State { }; -extern lua_State *lua_state; - - #define L lua_state #endif + diff --git a/src/lstring.c b/src/lstring.c index fd7cc580e0..fa974ae983 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.13 1998/06/19 16:14:09 roberto Exp $ +** $Id: lstring.c,v 1.19 1999/02/26 15:49:53 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -14,7 +14,9 @@ #include "lua.h" -#define NUM_HASHS 61 +#define NUM_HASHSTR 31 +#define NUM_HASHUDATA 31 +#define NUM_HASHS (NUM_HASHSTR+NUM_HASHUDATA) #define gcsizestring(l) (1+(l/64)) /* "weight" for a string with length 'l' */ @@ -25,8 +27,7 @@ static TaggedString EMPTY = {{NULL, 2}, 0L, 0, {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; -void luaS_init (void) -{ +void luaS_init (void) { int i; L->string_root = luaM_newvector(NUM_HASHS, stringtable); for (i=0; i>2)+(unsigned char)*(s++)); return h; } -static int newsize (stringtable *tb) -{ +static int newsize (stringtable *tb) { int size = tb->size; int realuse = 0; int i; @@ -54,16 +53,11 @@ static int newsize (stringtable *tb) for (i=0; ihash[i] != NULL && tb->hash[i] != &EMPTY) realuse++; - if (2*(realuse+1) <= size) /* +1 is the new element */ - return size; /* don't need to grow, just rehash to clear EMPTYs */ - else - return luaO_redimension(size); + return luaO_redimension((realuse+1)*2); /* +1 is the new element */ } -static void grow (stringtable *tb) -{ - +static void grow (stringtable *tb) { int ns = newsize(tb); TaggedString **newhash = luaM_newvector(ns, TaggedString *); int i; @@ -73,10 +67,13 @@ static void grow (stringtable *tb) tb->nuse = 0; for (i=0; isize; i++) { if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) { - int h = tb->hash[i]->hash%ns; - while (newhash[h]) - h = (h+1)%ns; - newhash[h] = tb->hash[i]; + unsigned long h = tb->hash[i]->hash; + int h1 = h%ns; + while (newhash[h1]) { + h1 += (h&(ns-2)) + 1; /* double hashing */ + if (h1 >= ns) h1 -= ns; + } + newhash[h1] = tb->hash[i]; tb->nuse++; } } @@ -86,8 +83,7 @@ static void grow (stringtable *tb) } -static TaggedString *newone_s (char *str, long l, unsigned long h) -{ +static TaggedString *newone_s (char *str, long l, unsigned long h) { TaggedString *ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l); memcpy(ts->str, str, l); ts->str[l] = 0; /* ending 0 */ @@ -101,8 +97,7 @@ static TaggedString *newone_s (char *str, long l, unsigned long h) return ts; } -static TaggedString *newone_u (char *buff, int tag, unsigned long h) -{ +static TaggedString *newone_u (char *buff, int tag, unsigned long h) { TaggedString *ts = luaM_new(TaggedString); ts->u.d.v = buff; ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; @@ -114,82 +109,79 @@ static TaggedString *newone_u (char *buff, int tag, unsigned long h) return ts; } -static TaggedString *insert_s (char *str, long l, stringtable *tb) -{ +static TaggedString *insert_s (char *str, long l, stringtable *tb) { TaggedString *ts; unsigned long h = hash_s(str, l); int size = tb->size; - int i; int j = -1; + int h1; if ((long)tb->nuse*3 >= (long)size*2) { grow(tb); size = tb->size; } - for (i = h%size; (ts = tb->hash[i]) != NULL; ) { + h1 = h%size; + while ((ts = tb->hash[h1]) != NULL) { if (ts == &EMPTY) - j = i; - else if (ts->constindex >= 0 && - ts->u.s.len == l && - (memcmp(str, ts->str, l) == 0)) + j = h1; + else if (ts->u.s.len == l && (memcmp(str, ts->str, l) == 0)) return ts; - if (++i == size) i=0; + h1 += (h&(size-2)) + 1; /* double hashing */ + if (h1 >= size) h1 -= size; } /* not found */ if (j != -1) /* is there an EMPTY space? */ - i = j; + h1 = j; else tb->nuse++; - ts = tb->hash[i] = newone_s(str, l, h); + ts = tb->hash[h1] = newone_s(str, l, h); return ts; } -static TaggedString *insert_u (void *buff, int tag, stringtable *tb) -{ + +static TaggedString *insert_u (void *buff, int tag, stringtable *tb) { TaggedString *ts; unsigned long h = (unsigned long)buff; int size = tb->size; - int i; int j = -1; + int h1; if ((long)tb->nuse*3 >= (long)size*2) { grow(tb); size = tb->size; } - for (i = h%size; (ts = tb->hash[i]) != NULL; ) { + h1 = h%size; + while ((ts = tb->hash[h1]) != NULL) { if (ts == &EMPTY) - j = i; - else if (ts->constindex < 0 && /* is a udata? */ - (tag == ts->u.d.tag || tag == LUA_ANYTAG) && - buff == ts->u.d.v) + j = h1; + else if ((tag == ts->u.d.tag || tag == LUA_ANYTAG) && buff == ts->u.d.v) return ts; - if (++i == size) i=0; + h1 += (h&(size-2)) + 1; /* double hashing */ + if (h1 >= size) h1 -= size; } /* not found */ if (j != -1) /* is there an EMPTY space? */ - i = j; + h1 = j; else tb->nuse++; - ts = tb->hash[i] = newone_u(buff, tag, h); + ts = tb->hash[h1] = newone_u(buff, tag, h); return ts; } -TaggedString *luaS_createudata (void *udata, int tag) -{ - return insert_u(udata, tag, &L->string_root[(unsigned)udata%NUM_HASHS]); + +TaggedString *luaS_createudata (void *udata, int tag) { + int t = ((unsigned)udata%NUM_HASHUDATA)+NUM_HASHSTR; + return insert_u(udata, tag, &L->string_root[t]); } -TaggedString *luaS_newlstr (char *str, long l) -{ - int i = (l==0)?0:(unsigned char)str[0]; - return insert_s(str, l, &L->string_root[i%NUM_HASHS]); +TaggedString *luaS_newlstr (char *str, long l) { + int t = (l==0) ? 0 : ((int)((unsigned char)str[0]*l))%NUM_HASHSTR; + return insert_s(str, l, &L->string_root[t]); } -TaggedString *luaS_new (char *str) -{ +TaggedString *luaS_new (char *str) { return luaS_newlstr(str, strlen(str)); } -TaggedString *luaS_newfixedstring (char *str) -{ +TaggedString *luaS_newfixedstring (char *str) { TaggedString *ts = luaS_new(str); if (ts->head.marked == 0) ts->head.marked = 2; /* avoid GC */ @@ -197,8 +189,7 @@ TaggedString *luaS_newfixedstring (char *str) } -void luaS_free (TaggedString *l) -{ +void luaS_free (TaggedString *l) { while (l) { TaggedString *next = (TaggedString *)l->head.next; L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len); @@ -212,8 +203,7 @@ void luaS_free (TaggedString *l) ** Garbage collection functions. */ -static void remove_from_list (GCnode *l) -{ +static void remove_from_list (GCnode *l) { while (l) { GCnode *next = l->next; while (next && !next->marked) @@ -223,8 +213,7 @@ static void remove_from_list (GCnode *l) } -TaggedString *luaS_collector (void) -{ +TaggedString *luaS_collector (void) { TaggedString *frees = NULL; int i; remove_from_list(&(L->rootglobal)); @@ -247,18 +236,18 @@ TaggedString *luaS_collector (void) } -TaggedString *luaS_collectudata (void) -{ +TaggedString *luaS_collectudata (void) { TaggedString *frees = NULL; int i; L->rootglobal.next = NULL; /* empty list of globals */ - for (i=0; istring_root[i]; int j; for (j=0; jsize; j++) { TaggedString *t = tb->hash[j]; - if (t == NULL || t == &EMPTY || t->constindex != -1) - continue; /* get only user data */ + if (t == NULL || t == &EMPTY) + continue; + LUA_ASSERT(t->constindex == -1, "must be userdata"); t->head.next = (GCnode *)frees; frees = t; tb->hash[j] = &EMPTY; @@ -268,8 +257,7 @@ TaggedString *luaS_collectudata (void) } -void luaS_freeall (void) -{ +void luaS_freeall (void) { int i; for (i=0; istring_root[i]; @@ -285,8 +273,7 @@ void luaS_freeall (void) } -void luaS_rawsetglobal (TaggedString *ts, TObject *newval) -{ +void luaS_rawsetglobal (TaggedString *ts, TObject *newval) { ts->u.s.globalval = *newval; if (ts->head.next == (GCnode *)ts) { /* is not in list? */ ts->head.next = L->rootglobal.next; @@ -295,8 +282,7 @@ void luaS_rawsetglobal (TaggedString *ts, TObject *newval) } -char *luaS_travsymbol (int (*fn)(TObject *)) -{ +char *luaS_travsymbol (int (*fn)(TObject *)) { TaggedString *g; for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next) if (fn(&g->u.s.globalval)) @@ -305,8 +291,7 @@ char *luaS_travsymbol (int (*fn)(TObject *)) } -int luaS_globaldefined (char *name) -{ +int luaS_globaldefined (char *name) { TaggedString *ts = luaS_new(name); return ts->u.s.globalval.ttype != LUA_T_NIL; } diff --git a/src/ltable.c b/src/ltable.c index 28cd2ed59c..d768ba0bbb 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 1.12 1998/01/28 16:50:33 roberto Exp $ +** $Id: ltable.c,v 1.22 1999/05/21 19:41:49 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -20,14 +20,11 @@ #define nodevector(t) ((t)->node) -#define REHASH_LIMIT 0.70 /* avoid more than this % full */ - #define TagDefault LUA_T_ARRAY; -static long int hashindex (TObject *ref) -{ +static long int hashindex (TObject *ref) { long int h; switch (ttype(ref)) { case LUA_T_NUMBER: @@ -56,61 +53,45 @@ static long int hashindex (TObject *ref) } -static int present (Hash *t, TObject *key) -{ +Node *luaH_present (Hash *t, TObject *key) { int tsize = nhash(t); long int h = hashindex(key); int h1 = h%tsize; - TObject *rf = ref(node(t, h1)); - if (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf)) { - int h2 = h%(tsize-2) + 1; - do { - h1 += h2; - if (h1 >= tsize) h1 -= tsize; - rf = ref(node(t, h1)); - } while (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf)); + Node *n = node(t, h1); + /* keep looking until an entry with "ref" equal to key or nil */ + while ((ttype(ref(n)) == ttype(key)) ? !luaO_equalval(key, ref(n)) + : ttype(ref(n)) != LUA_T_NIL) { + h1 += (h&(tsize-2)) + 1; /* double hashing */ + if (h1 >= tsize) h1 -= tsize; + n = node(t, h1); } - return h1; + return n; } -/* -** Alloc a vector node -*/ -static Node *hashnodecreate (int nhash) -{ - Node *v = luaM_newvector(nhash, Node); - int i; - for (i=0; ihead.next; L->nblocks -= gcsize(frees->nhash); - hashdelete(frees); + luaM_free(nodevector(frees)); + luaM_free(frees); frees = next; } } -Hash *luaH_new (int nhash) -{ +static Node *hashnodecreate (int nhash) { + Node *v = luaM_newvector(nhash, Node); + int i; + for (i=0; inode; int size = nhash(t); int realuse = 0; int i; for (i=0; inblocks += gcsize(nnew)-gcsize(nold); luaM_free(vold); } -/* -** If the hash node is present, return its pointer, otherwise return -** null. -*/ -TObject *luaH_get (Hash *t, TObject *ref) -{ - int h = present(t, ref); - if (ttype(ref(node(t, h))) != LUA_T_NIL) return val(node(t, h)); - else return NULL; -} - -/* -** If the hash node is present, return its pointer, otherwise create a luaM_new -** node for the given reference and also return its pointer. -*/ -TObject *luaH_set (Hash *t, TObject *ref) -{ - Node *n = node(t, present(t, ref)); - if (ttype(ref(n)) == LUA_T_NIL) { - nuse(t)++; - if ((float)nuse(t) > (float)nhash(t)*REHASH_LIMIT) { +void luaH_set (Hash *t, TObject *ref, TObject *val) { + Node *n = luaH_present(t, ref); + if (ttype(ref(n)) != LUA_T_NIL) + *val(n) = *val; + else { + TObject buff; + buff = *val; /* rehash may invalidate this address */ + if ((long)nuse(t)*3L > (long)nhash(t)*2L) { rehash(t); - n = node(t, present(t, ref)); + n = luaH_present(t, ref); } + nuse(t)++; *ref(n) = *ref; - ttype(val(n)) = LUA_T_NIL; + *val(n) = buff; } - return (val(n)); } -static Node *hashnext (Hash *t, int i) -{ - Node *n; - int tsize = nhash(t); - if (i >= tsize) - return NULL; - n = node(t, i); - while (ttype(ref(n)) == LUA_T_NIL || ttype(val(n)) == LUA_T_NIL) { - if (++i >= tsize) - return NULL; - n = node(t, i); - } - return node(t, i); +int luaH_pos (Hash *t, TObject *r) { + Node *n = luaH_present(t, r); + luaL_arg_check(ttype(val(n)) != LUA_T_NIL, 2, "key not found"); + return n-(t->node); } -Node *luaH_next (TObject *o, TObject *r) -{ - Hash *t = avalue(o); - if (ttype(r) == LUA_T_NIL) - return hashnext(t, 0); - else { - int i = present(t, r); - Node *n = node(t, i); - luaL_arg_check(ttype(ref(n))!=LUA_T_NIL && ttype(val(n))!=LUA_T_NIL, - 2, "key not found"); - return hashnext(t, i+1); - } + +void luaH_setint (Hash *t, int ref, TObject *val) { + TObject index; + ttype(&index) = LUA_T_NUMBER; + nvalue(&index) = ref; + luaH_set(t, &index, val); } + + +TObject *luaH_getint (Hash *t, int ref) { + TObject index; + ttype(&index) = LUA_T_NUMBER; + nvalue(&index) = ref; + return luaH_get(t, &index); +} + diff --git a/src/ltable.h b/src/ltable.h index 92b03167d3..49b485f2d3 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 1.5 1997/11/26 18:53:45 roberto Exp $ +** $Id: ltable.h,v 1.11 1999/02/23 14:57:28 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,10 +15,16 @@ #define val(n) (&(n)->val) #define nhash(t) ((t)->nhash) +#define luaH_get(t,ref) (val(luaH_present((t), (ref)))) +#define luaH_move(t,from,to) (luaH_setint(t, to, luaH_getint(t, from))) + Hash *luaH_new (int nhash); void luaH_free (Hash *frees); -TObject *luaH_get (Hash *t, TObject *ref); -TObject *luaH_set (Hash *t, TObject *ref); -Node *luaH_next (TObject *o, TObject *r); +Node *luaH_present (Hash *t, TObject *key); +void luaH_set (Hash *t, TObject *ref, TObject *val); +int luaH_pos (Hash *t, TObject *r); +void luaH_setint (Hash *t, int ref, TObject *val); +TObject *luaH_getint (Hash *t, int ref); + #endif diff --git a/src/ltm.c b/src/ltm.c index 0bbee22c19..709d5e5f25 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 1.16 1998/06/18 16:57:03 roberto Exp $ +** $Id: ltm.c,v 1.25 1999/05/21 19:41:49 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -22,8 +22,7 @@ char *luaT_eventname[] = { /* ORDER IM */ }; -static int luaI_checkevent (char *name, char *list[]) -{ +static int luaI_checkevent (char *name, char *list[]) { int e = luaL_findstring(name, list); if (e < 0) luaL_verror("`%.50s' is not a valid event name", name); @@ -35,7 +34,7 @@ static int luaI_checkevent (char *name, char *list[]) /* events in LUA_T_NIL are all allowed, since this is used as a * 'placeholder' for "default" fallbacks */ -static char validevents[NUM_TAGS][IM_N] = { /* ORDER LUA_T, ORDER IM */ +static char luaT_validevents[NUM_TAGS][IM_N] = { /* ORDER LUA_T, ORDER IM */ {1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_T_USERDATA */ {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_NUMBER */ {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_STRING */ @@ -45,71 +44,59 @@ static char validevents[NUM_TAGS][IM_N] = { /* ORDER LUA_T, ORDER IM */ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} /* LUA_T_NIL */ }; - -static int validevent (int t, int e) -{ /* ORDER LUA_T */ - return (t < LUA_T_NIL) ? 1 : validevents[-t][e]; +static int luaT_validevent (int t, int e) { /* ORDER LUA_T */ + return (t < LUA_T_NIL) ? 1 : luaT_validevents[-t][e]; } -static void init_entry (int tag) -{ +static void init_entry (int tag) { int i; for (i=0; iIMtable_size = NUM_TAGS*2; L->last_tag = -(NUM_TAGS-1); - L->IMtable = luaM_newvector(L->IMtable_size, struct IM); + luaM_growvector(L->IMtable, 0, NUM_TAGS, struct IM, arrEM, MAX_INT); for (t=L->last_tag; t<=0; t++) init_entry(t); } -int lua_newtag (void) -{ +int lua_newtag (void) { --L->last_tag; - if ((-L->last_tag) >= L->IMtable_size) - L->IMtable_size = luaM_growvector(&L->IMtable, L->IMtable_size, - struct IM, memEM, MAX_INT); + luaM_growvector(L->IMtable, -(L->last_tag), 1, struct IM, arrEM, MAX_INT); init_entry(L->last_tag); return L->last_tag; } -static void checktag (int tag) -{ +static void checktag (int tag) { if (!(L->last_tag <= tag && tag <= 0)) luaL_verror("%d is not a valid tag", tag); } -void luaT_realtag (int tag) -{ +void luaT_realtag (int tag) { if (!(L->last_tag <= tag && tag < LUA_T_NIL)) - luaL_verror("tag %d is not result of `newtag'", tag); + luaL_verror("tag %d was not created by `newtag'", tag); } -int lua_copytagmethods (int tagto, int tagfrom) -{ +int lua_copytagmethods (int tagto, int tagfrom) { int e; checktag(tagto); checktag(tagfrom); for (e=0; eerrorim)) - return "error"; - for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { /* ORDER IM */ + for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { int t; for (t=0; t>=L->last_tag; t--) if (fn(luaT_getim(t,e))) @@ -177,6 +162,7 @@ char *luaT_travtagmethods (int (*fn)(TObject *)) #ifdef LUA_COMPAT2_5 #include "lapi.h" +#include "lstring.h" static void errorFB (void) { @@ -191,23 +177,20 @@ static void errorFB (void) static void nilFB (void) { } -static void typeFB (void) -{ +static void typeFB (void) { lua_error("unexpected type"); } -static void fillvalids (IMS e, TObject *func) -{ +static void fillvalids (IMS e, TObject *func) { int t; for (t=LUA_T_NIL; t<=LUA_T_USERDATA; t++) - if (validevent(t, e)) + if (luaT_validevent(t, e)) *luaT_getim(t, e) = *func; } -void luaT_setfallback (void) -{ +void luaT_setfallback (void) { static char *oldnames [] = {"error", "getglobal", "arith", "order", NULL}; TObject oldfunc; lua_CFunction replace; @@ -215,11 +198,13 @@ void luaT_setfallback (void) lua_Object func = lua_getparam(2); luaL_arg_check(lua_isfunction(func), 2, "function expected"); switch (luaL_findstring(name, oldnames)) { - case 0: /* old error fallback */ - oldfunc = L->errorim; - L->errorim = *luaA_Address(func); + case 0: { /* old error fallback */ + TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval); + oldfunc = *em; + *em = *luaA_Address(func); replace = errorFB; break; + } case 1: /* old getglobal fallback */ oldfunc = *luaT_getim(LUA_T_NIL, IM_GETGLOBAL); *luaT_getim(LUA_T_NIL, IM_GETGLOBAL) = *luaA_Address(func); diff --git a/src/ltm.h b/src/ltm.h index b688d1e186..845ea15317 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 1.4 1997/11/26 18:53:45 roberto Exp $ +** $Id: ltm.h,v 1.5 1999/01/15 13:11:57 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -45,14 +45,14 @@ struct IM { #define luaT_getim(tag,event) (&L->IMtable[-(tag)].int_method[event]) -#define luaT_getimbyObj(o,e) (luaT_getim(luaT_efectivetag(o),(e))) +#define luaT_getimbyObj(o,e) (luaT_getim(luaT_effectivetag(o),(e))) extern char *luaT_eventname[]; void luaT_init (void); void luaT_realtag (int tag); -int luaT_efectivetag (TObject *o); +int luaT_effectivetag (TObject *o); void luaT_settagmethod (int t, char *event, TObject *func); TObject *luaT_gettagmethod (int t, char *event); char *luaT_travtagmethods (int (*fn)(TObject *)); diff --git a/src/lua/Makefile b/src/lua/Makefile index 1ec83706ab..cf5d31b64c 100644 --- a/src/lua/Makefile +++ b/src/lua/Makefile @@ -17,10 +17,10 @@ $T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib -lm $(LIB)/liblua.a: - cd ..; make + cd ..; $(MAKE) $(LIB)/liblualib.a: - cd ../lib; make + cd ../lib; $(MAKE) clean: rm -f $(OBJS) $T diff --git a/src/lua/README b/src/lua/README index 313404298e..db2eafb7e5 100644 --- a/src/lua/README +++ b/src/lua/README @@ -1,5 +1,6 @@ This client is a sample lua interpreter. -It can be used as a batch interpreter and interactively. +It can be used as a batch interpreter and also interactively. + Here are the options it understands: -v print version information @@ -11,10 +12,27 @@ Here are the options it understands: a=b sets global `a' with string `b' (no need to quote b) name dofile `name' -If no options are given, then it reads and executes lines from stdin. -In this case, each line must contain a complete statement. +If no options are given, then it reads lines from stdin and executes them +as they are read. So, each line must contain a complete statement. To span a statement across several lines, end each line with a backslash '\'. + To change the prompt, set the global variable _PROMPT to whatever you want. +You can do after calling the interpreter or on the command line with + _PROMPT="lua: " +for example. + +You must be careful when using quotes on the command line because they are +usually handled by the shell. This interpreter is good for using Lua as a standalone language. For a minimal interpreter, see etc/min.c. + +If your application simply exports new functions to Lua (which is common), +then you can use this interpreter unmodified: just define a function + + void lua_userinit (void) + +in your code. In this function, you should do whatever initializations are +need, typically exporting your functions to Lua. +If you use this scheme, you must explicily open any standard libraries you need. +See ../lib/linit.c diff --git a/src/lua/lua.c b/src/lua/lua.c index a6a92f71de..5acd61733d 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.14 1998/02/11 20:56:05 roberto Exp $ +** $Id: lua.c,v 1.21 1999/07/02 18:22:38 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -15,12 +15,6 @@ #include "lualib.h" -#ifndef OLD_ANSI -#include -#else -#define setlocale(a,b) 0 -#endif - #ifdef _POSIX_SOURCE #include #else @@ -32,27 +26,33 @@ typedef void (*handler)(int); /* type for signal actions */ static void laction (int i); -static handler lreset (void) -{ - lua_linehook = NULL; - lua_callhook = NULL; + +static lua_LHFunction old_linehook = NULL; +static lua_CHFunction old_callhook = NULL; + + +static handler lreset (void) { return signal(SIGINT, laction); } -static void lstop (void) -{ + +static void lstop (void) { + lua_setlinehook(old_linehook); + lua_setcallhook(old_callhook); lreset(); lua_error("interrupted!"); } -static void laction (int i) -{ - lua_linehook = (lua_LHFunction)lstop; - lua_callhook = (lua_CHFunction)lstop; + +static void laction (int i) { + signal(SIGINT, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + old_linehook = lua_setlinehook((lua_LHFunction)lstop); + old_callhook = lua_setcallhook((lua_CHFunction)lstop); } -static int ldo (int (*f)(char *), char *name) -{ + +static int ldo (int (*f)(char *), char *name) { int res; handler h = lreset(); res = f(name); /* dostring | dofile */ @@ -61,8 +61,7 @@ static int ldo (int (*f)(char *), char *name) } -static void print_message (void) -{ +static void print_message (void) { fprintf(stderr, "Lua: command line options:\n" " -v print version information\n" @@ -76,8 +75,7 @@ static void print_message (void) } -static void assign (char *arg) -{ +static void assign (char *arg) { if (strlen(arg) >= 500) fprintf(stderr, "lua: shell argument too long"); else { @@ -90,13 +88,11 @@ static void assign (char *arg) } } -#define BUF_SIZE 512 -static void manual_input (int prompt) -{ +static void manual_input (int prompt) { int cont = 1; while (cont) { - char buffer[BUF_SIZE]; + char buffer[BUFSIZ]; int i = 0; lua_beginblock(); if (prompt) @@ -112,13 +108,13 @@ static void manual_input (int prompt) buffer[i-1] = '\n'; else break; } - else if (i >= BUF_SIZE-1) { + else if (i >= BUFSIZ-1) { fprintf(stderr, "lua: argument line too long\n"); break; } - else buffer[i++] = c; + else buffer[i++] = (char)c; } - buffer[i] = 0; + buffer[i] = '\0'; ldo(lua_dostring, buffer); lua_endblock(); } @@ -129,11 +125,9 @@ static void manual_input (int prompt) int main (int argc, char *argv[]) { int i; - setlocale(LC_ALL, ""); - lua_iolibopen(); - lua_strlibopen(); - lua_mathlibopen(); + lua_open(); lua_pushstring("> "); lua_setglobal("_PROMPT"); + lua_userinit(); if (argc < 2) { /* no arguments? */ if (isatty(0)) { printf("%s %s\n", LUA_VERSION, LUA_COPYRIGHT); @@ -155,7 +149,7 @@ int main (int argc, char *argv[]) manual_input(0); break; case 'd': - lua_debug = 1; + lua_setdebug(1); break; case 'v': printf("%s %s\n(written by %s)\n\n", diff --git a/src/luac/Makefile b/src/luac/Makefile index 195b5cc4da..e2950e6087 100644 --- a/src/luac/Makefile +++ b/src/luac/Makefile @@ -5,8 +5,8 @@ LUA= ../.. include $(LUA)/config INCS= -I$(INC) $(EXTRA_INCS) -I.. -OBJS= dump.o luac.o opcode.o opt.o print.o stubs.o -SRCS= dump.c luac.c opcode.c opt.c print.c stubs.c luac.h opcode.h +OBJS= dump.o luac.o opcode.o opt.o print.o stubs.o test.o +SRCS= dump.c luac.c opcode.c opt.c print.c stubs.c test.c luac.h opcode.h T= $(BIN)/luac @@ -16,7 +16,7 @@ $T: $(OBJS) $(LIB)/liblua.a $(CC) -o $@ $(OBJS) -L$(LIB) -llua $(LIB)/liblua.a: - cd ..; make + cd ..; $(MAKE) clean: rm -f $(OBJS) $T diff --git a/src/luac/README b/src/luac/README index 1fd49cc233..9fba74bbe2 100644 --- a/src/luac/README +++ b/src/luac/README @@ -2,24 +2,27 @@ luac translates Lua programs into binary files that can be loaded and executed with lua_dofile in C or with dofile in Lua. The main advantages of pre-compiling chunks are: faster loading, protecting source code from user changes, off-line syntax error detection. - luac can also be used to learn about the Lua virtual machine. -Here are the options it understands: +Here are the options that luac understands: - -c compile (default) - -u undump - -d generate debugging information - -D predefine symbol for conditional compilation - -l list (default for -u) - -o output file for -c (default is "luac.out") - -O optimize - -p parse only - -q quiet (default for -c) - -v show version information - -V verbose - - compile "stdin" + -c compile (default) + -d generate debugging information + -D name predefine 'name' for conditional compilation + -l list (default for -u) + -n save numbers in native format (file may not be portable) + -o file output file for -c (default is "luac.out") + -O optimize + -p parse only + -q quiet (default for -c) + -t test code integrity + -u undump + -U name undefine 'name' for conditional compilation + -v show version information + -V verbose + - compile "stdin" Finally, luac is an example of how to use the internals of Lua (politely). Also, luac does not need the runtime code and stubs.c makes sure it is not linked into luac. This file also shows how to avoid linking the parser. + diff --git a/src/luac/dump.c b/src/luac/dump.c index ce9551e689..479ce5d416 100644 --- a/src/luac/dump.c +++ b/src/luac/dump.c @@ -1,16 +1,20 @@ /* -** $Id: dump.c,v 1.11 1998/07/12 00:17:37 lhf Exp $ +** $Id: dump.c,v 1.20 1999/07/02 19:34:26 lhf Exp $ ** save bytecodes to file ** See Copyright Notice in lua.h */ +#include #include #include #include "luac.h" -#define NotWord(x) ((unsigned short)x!=x) +#ifdef OLD_ANSI +#define strerror(e) "(no error message provided by operating system)" +#endif + #define DumpBlock(b,size,D) fwrite(b,size,1,D) -#define DumpNative(t,D) DumpBlock(&t,sizeof(t),D) +#define DumpInt DumpLong static void DumpWord(int i, FILE* D) { @@ -28,43 +32,24 @@ static void DumpLong(long i, FILE* D) DumpWord(lo,D); } -#if ID_NUMBER==ID_REAL4 -/* LUA_NUMBER */ -/* assumes sizeof(long)==4 and sizeof(float)==4 (IEEE) */ -static void DumpFloat(float f, FILE* D) +static void DumpNumber(real x, FILE* D, int native, TProtoFunc* tf) { - long l=*(long*)&f; - DumpLong(l,D); -} -#endif - -#if ID_NUMBER==ID_REAL8 -/* LUA_NUMBER */ -/* assumes sizeof(long)==4 and sizeof(double)==8 (IEEE) */ -static void DumpDouble(double f, FILE* D) -{ - long* l=(long*)&f; - int x=1; - if (*(char*)&x==1) /* little-endian */ - { - DumpLong(l[1],D); - DumpLong(l[0],D); - } - else /* big-endian */ + if (native) + DumpBlock(&x,sizeof(x),D); + else { - DumpLong(l[0],D); - DumpLong(l[1],D); + char b[256]; + int n; + sprintf(b,NUMBER_FMT"%n",x,&n); + luaU_str2d(b,tf->source->str); /* help lundump not to fail */ + fputc(n,D); + DumpBlock(b,n,D); } } -#endif static void DumpCode(TProtoFunc* tf, FILE* D) { - int size=CodeSize(tf); - if (NotWord(size)) - fprintf(stderr,"luac: warning: " - "\"%s\":%d code too long for 16-bit machines (%d bytes)\n", - fileName(tf),tf->lineDefined,size); + int size=luaU_codesize(tf); DumpLong(size,D); DumpBlock(tf->code,size,D); } @@ -72,87 +57,98 @@ static void DumpCode(TProtoFunc* tf, FILE* D) static void DumpString(char* s, int size, FILE* D) { if (s==NULL) - DumpWord(0,D); + DumpLong(0,D); else { - if (NotWord(size)) - luaL_verror("string too long (%d bytes): \"%.32s...\"",size,s); - DumpWord(size,D); + DumpLong(size,D); DumpBlock(s,size,D); } } static void DumpTString(TaggedString* s, FILE* D) { - if (s==NULL) DumpString(NULL,0,D); else DumpString(s->str,s->u.s.len+1,D); + if (s==NULL) + DumpString(NULL,0,D); + else + DumpString(s->str,s->u.s.len+1,D); } static void DumpLocals(TProtoFunc* tf, FILE* D) { - int n; - LocVar* lv; - for (n=0,lv=tf->locvars; lv && lv->line>=0; lv++) ++n; - DumpWord(n,D); - for (lv=tf->locvars; lv && lv->line>=0; lv++) + if (tf->locvars==NULL) + DumpInt(0,D); + else { - DumpWord(lv->line,D); - DumpTString(lv->varname,D); + LocVar* v; + int n=0; + for (v=tf->locvars; v->line>=0; v++) + ++n; + DumpInt(n,D); + for (v=tf->locvars; v->line>=0; v++) + { + DumpInt(v->line,D); + DumpTString(v->varname,D); + } } } -static void DumpFunction(TProtoFunc* tf, FILE* D); +static void DumpFunction(TProtoFunc* tf, FILE* D, int native); -static void DumpConstants(TProtoFunc* tf, FILE* D) +static void DumpConstants(TProtoFunc* tf, FILE* D, int native) { int i,n=tf->nconsts; - DumpWord(n,D); + DumpInt(n,D); for (i=0; iconsts+i; - fputc(-ttype(o),D); + fputc(-ttype(o),D); /* ttype(o) is negative - ORDER LUA_T */ switch (ttype(o)) { case LUA_T_NUMBER: - DumpNumber(nvalue(o),D); + DumpNumber(nvalue(o),D,native,tf); break; case LUA_T_STRING: DumpTString(tsvalue(o),D); break; case LUA_T_PROTO: - DumpFunction(tfvalue(o),D); + DumpFunction(tfvalue(o),D,native); break; case LUA_T_NIL: break; default: /* cannot happen */ - luaL_verror("cannot dump constant #%d: type=%d [%s]", - i,ttype(o),luaO_typename(o)); + luaU_badconstant("dump",i,o,tf); break; } } } -static void DumpFunction(TProtoFunc* tf, FILE* D) +static void DumpFunction(TProtoFunc* tf, FILE* D, int native) { - DumpWord(tf->lineDefined,D); - DumpTString(tf->fileName,D); + DumpInt(tf->lineDefined,D); + DumpTString(tf->source,D); DumpCode(tf,D); DumpLocals(tf,D); - DumpConstants(tf,D); + DumpConstants(tf,D,native); + if (ferror(D)) + luaL_verror("write error" IN ": %s (errno=%d)",INLOC,strerror(errno),errno); } -static void DumpHeader(TProtoFunc* Main, FILE* D) +static void DumpHeader(TProtoFunc* Main, FILE* D, int native) { - real t=TEST_NUMBER; fputc(ID_CHUNK,D); fputs(SIGNATURE,D); fputc(VERSION,D); - fputc(ID_NUMBER,D); - fputc(sizeof(t),D); - DumpNumber(t,D); + if (native) + { + fputc(sizeof(real),D); + DumpNumber(TEST_NUMBER,D,native,Main); + } + else + fputc(0,D); } -void DumpChunk(TProtoFunc* Main, FILE* D) +void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native) { - DumpHeader(Main,D); - DumpFunction(Main,D); + DumpHeader(Main,D,native); + DumpFunction(Main,D,native); } diff --git a/src/luac/luac.c b/src/luac/luac.c index c4619153e3..68af1c7628 100644 --- a/src/luac/luac.c +++ b/src/luac/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.10 1998/07/12 00:38:30 lhf Exp $ +** $Id: luac.c,v 1.17 1999/07/02 19:34:26 lhf Exp $ ** lua compiler (saves bytecodes to files; also list binary files) ** See Copyright Notice in lua.h */ @@ -9,43 +9,45 @@ #include #include "luac.h" #include "lparser.h" +#include "lstate.h" #include "lzio.h" -#include "luadebug.h" #define OUTPUT "luac.out" /* default output file */ -extern void DumpChunk(TProtoFunc* Main, FILE* D); -extern void PrintChunk(TProtoFunc* Main); -extern void OptChunk(TProtoFunc* Main); - static FILE* efopen(char* name, char* mode); static void doit(int undump, char* filename); static int listing=0; /* list bytecodes? */ -static int debugging=0; /* debug? */ +static int debugging=0; /* emit debug information? */ static int dumping=1; /* dump bytecodes? */ static int undumping=0; /* undump bytecodes? */ static int optimizing=0; /* optimize? */ static int parsing=0; /* parse only? */ +static int testing=0; /* test integrity? */ static int verbose=0; /* tell user what is done */ +static int native=0; /* save numbers in native format? */ static FILE* D; /* output file */ -static void usage(void) +static void usage(char* op) { - fprintf(stderr,"usage: " - "luac [-c | -u] [-D name] [-d] [-l] [-o output] [-O] [-p] [-q] [-v] [-V] [files]\n" - " -c\tcompile (default)\n" - " -u\tundump\n" - " -d\tgenerate debugging information\n" - " -D\tpredefine symbol for conditional compilation\n" - " -l\tlist (default for -u)\n" - " -o\toutput file for -c (default is \"" OUTPUT "\")\n" - " -O\toptimize\n" - " -p\tparse only\n" - " -q\tquiet (default for -c)\n" - " -v\tshow version information\n" - " -V\tverbose\n" - " -\tcompile \"stdin\"\n" + if (op) fprintf(stderr,"luac: unrecognized option '%s'\n",op); + fprintf(stderr, + "usage: luac [options] [filenames]. Available options are:\n" + " -c\t\tcompile (default)\n" + " -d\t\tgenerate debugging information\n" + " -D name\tpredefine 'name' for conditional compilation\n" + " -l\t\tlist (default for -u)\n" + " -n\t\tsave numbers in native format (file may not be portable)\n" + " -o file\toutput file for -c (default is \"" OUTPUT "\")\n" + " -O\t\toptimize\n" + " -p\t\tparse only\n" + " -q\t\tquiet (default for -c)\n" + " -t\t\ttest code integrity\n" + " -u\t\tundump\n" + " -U name\tundefine 'name' for conditional compilation\n" + " -v\t\tshow version information\n" + " -V\t\tverbose\n" + " -\t\tcompile \"stdin\"\n" ); exit(1); } @@ -61,7 +63,7 @@ int main(int argc, char* argv[]) { if (argv[i][0]!='-') /* end of options */ break; - else if (IS("-")) /* use stdin */ + else if (IS("-")) /* end of options; use stdin */ break; else if (IS("-c")) /* compile (and dump) */ { @@ -78,6 +80,8 @@ int main(int argc, char* argv[]) debugging=1; else if (IS("-l")) /* list */ listing=1; + else if (IS("-n")) /* native */ + native=1; else if (IS("-o")) /* output file */ d=argv[++i]; else if (IS("-O")) /* optimize */ @@ -89,34 +93,37 @@ int main(int argc, char* argv[]) } else if (IS("-q")) /* quiet */ listing=0; + else if (IS("-t")) /* test */ + testing=1; else if (IS("-u")) /* undump */ { dumping=0; undumping=1; listing=1; } + else if (IS("-U")) /* undefine */ + { + TaggedString* s=luaS_new(argv[++i]); + s->u.s.globalval.ttype=LUA_T_NIL; + } else if (IS("-v")) /* show version */ printf("%s %s\n(written by %s)\n\n",LUA_VERSION,LUA_COPYRIGHT,LUA_AUTHORS); else if (IS("-V")) /* verbose */ verbose=1; else /* unknown option */ - usage(); + usage(argv[i]); } --i; /* fake new argv[0] */ argc-=i; argv+=i; if (dumping || parsing) { - if (argc<2) usage(); + if (argc<2) usage(NULL); if (dumping) { for (i=1; idebug=0; + if (debugging) L->debug=1; Main=luaY_parser(z); - if (optimizing) OptChunk(Main); - if (listing) PrintChunk(Main); - if (dumping) DumpChunk(Main,D); + if (optimizing) luaU_optchunk(Main); + if (listing) luaU_printchunk(Main); + if (testing) luaU_testchunk(Main); + if (dumping) luaU_dumpchunk(Main,D,native); } static void do_undump(ZIO* z) { - while (1) + for (;;) { TProtoFunc* Main=luaU_undump1(z); if (Main==NULL) break; - if (optimizing) OptChunk(Main); - if (listing) PrintChunk(Main); + if (optimizing) luaU_optchunk(Main); + if (listing) luaU_printchunk(Main); + if (testing) luaU_testchunk(Main); } } static void doit(int undump, char* filename) { - FILE* f; + FILE* f= (filename==NULL) ? stdin : efopen(filename, undump ? "rb" : "r"); ZIO z; - if (filename==NULL) - { - f=stdin; filename="(stdin)"; - } - else - { - f=efopen(filename, undump ? "rb" : "r"); - } - zFopen(&z,f,filename); - if (verbose) fprintf(stderr,"%s\n",filename); + char source[255+2]; /* +2 for '@' and '\0' */ + luaL_filesource(source,filename,sizeof(source)); + zFopen(&z,f,source); + if (verbose) fprintf(stderr,"%s\n",source+1); if (undump) do_undump(&z); else do_compile(&z); if (f!=stdin) fclose(f); } diff --git a/src/luac/luac.h b/src/luac/luac.h index c3d8d73ae9..1ae5267bfe 100644 --- a/src/luac/luac.h +++ b/src/luac/luac.h @@ -1,11 +1,12 @@ /* -** $Id: luac.h,v 1.6 1998/07/12 00:17:37 lhf Exp $ +** $Id: luac.h,v 1.11 1999/07/02 19:34:26 lhf Exp $ ** definitions for luac ** See Copyright Notice in lua.h */ #include "lauxlib.h" #include "lfunc.h" +#include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lstring.h" @@ -13,21 +14,35 @@ typedef struct { - char* name; - int size; - int op; - int class; - int arg; - int arg2; + char* name; /* name of opcode */ + int op; /* value of opcode */ + int class; /* class of opcode (byte variant) */ + int args; /* types of arguments (operands) */ + int arg; /* arg #1 */ + int arg2; /* arg #2 */ } Opcode; -int OpcodeInfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE); -int CodeSize(TProtoFunc* tf); +/* from dump.c */ +void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native); -#define INFO(tf,p,I) OpcodeInfo(tf,p,I,__FILE__,__LINE__) -#define fileName(tf) ( (tf->fileName)==NULL ? NULL : tf->fileName->str ) +/* from opcode.c */ +int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE); +int luaU_codesize(TProtoFunc* tf); +/* from opt.c */ +void luaU_optchunk(TProtoFunc* Main); + +/* from print.c */ +void luaU_printchunk(TProtoFunc* Main); + +/* from test.c */ +void luaU_testchunk(TProtoFunc* Main); +TObject* luaU_getconstant(TProtoFunc* tf, int i, int at); + +#define INFO(tf,p,I) luaU_opcodeinfo(tf,p,I,__FILE__,__LINE__) + +/* fake (but convenient) opcodes */ #define NOP 255 -#define STACK -1 -#define ARGS -2 -#define VARARGS -3 +#define STACK (-1) +#define ARGS (-2) +#define VARARGS (-3) diff --git a/src/luac/opcode.c b/src/luac/opcode.c index c97e46a513..c2d4ae7dfc 100644 --- a/src/luac/opcode.c +++ b/src/luac/opcode.c @@ -1,83 +1,98 @@ /* -** $Id: opcode.c,v 1.4 1998/07/12 00:17:37 lhf Exp $ +** $Id: opcode.c,v 1.9 1999/05/25 19:58:55 lhf Exp $ ** opcode information ** See Copyright Notice in lua.h */ #include "luac.h" +enum { /* for Opcode.args */ + ARGS_NONE, + ARGS_B, + ARGS_W, + ARGS_BB, + ARGS_WB +}; + static Opcode Info[]= /* ORDER lopcodes.h */ { #include "opcode.h" }; +static Opcode Fake[]= /* ORDER luac.h */ +{ +{ "NOP", NOP, NOP, ARGS_NONE, -1, -1 }, +{ "STACK", STACK, STACK, ARGS_B, -1, -1 }, +{ "ARGS", ARGS, ARGS, ARGS_B, -1, -1 }, +{ "VARARGS", VARARGS, VARARGS, ARGS_B, -1, -1 }, +}; + #define NOPCODES (sizeof(Info)/sizeof(Info[0])) -int OpcodeInfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE) +int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE) { Opcode OP; Byte* code=tf->code; int op=*p; - if (p==code) + int size=1; + if (p==code) /* first byte is STACK */ { - OP.name="STACK"; - OP.size=1; - OP.op=STACK; - OP.class=STACK; + OP=Fake[-STACK]; OP.arg=op; } - else if (p==code+1) + else if (p==code+1) /* second byte is ARGS or VARARGS */ { - OP.size=1; - if (op>=ZEROVARARG) + if (op=NOPCODES) /* cannot happen */ { - luaL_verror("internal error at %s:%d: bad opcode %d at %d in tf=%p", - xFILE, xLINE,op,(int)(p-code),tf); + luaL_verror("[%s:%d] bad opcode %d at pc=%d" IN, + xFILE,xLINE,op,(int)(p-code),INLOC); return 0; } - else + else /* ordinary opcode */ { OP=Info[op]; - if (op==SETLIST || op==CLOSURE || op==CALLFUNC) + switch (OP.args) { - OP.arg=p[1]; - OP.arg2=p[2]; + case ARGS_NONE: size=1; + break; + case ARGS_B: size=2; OP.arg=p[1]; + break; + case ARGS_W: size=3; OP.arg=(p[1]<<8)+p[2]; + break; + case ARGS_BB: size=3; OP.arg=p[1]; OP.arg2=p[2]; + break; + case ARGS_WB: size=4; OP.arg=(p[1]<<8)+p[2]; OP.arg2=p[3]; + break; + default: /* cannot happen */ + luaL_verror("[%s:%d] bad args %d for %s at pc=%d" IN, + __FILE__,__LINE__,OP.args,OP.name,(int)(p-code),INLOC); + break; } - else if (OP.size==2) OP.arg=p[1]; - else if (OP.size>=3) OP.arg=(p[1]<<8)+p[2]; - if (op==SETLISTW || op==CLOSUREW) OP.arg2=p[3]; } *I=OP; - return OP.size; + return size; } -int CodeSize(TProtoFunc* tf) +int luaU_codesize(TProtoFunc* tf) { Byte* code=tf->code; Byte* p=code; - while (1) + for (;;) { Opcode OP; p+=INFO(tf,p,&OP); diff --git a/src/luac/opcode.h b/src/luac/opcode.h index 805933c73e..4ae910f5c8 100644 --- a/src/luac/opcode.h +++ b/src/luac/opcode.h @@ -1,134 +1,70 @@ /* -** $Id: opcode.h,v 1.3 1998/06/25 15:50:09 lhf Exp $ +** $Id: opcode.h,v 1.1 1999/03/25 13:43:05 lhf Exp $ ** opcode info to be #included into opcode.c -** extracted automatically from lopcodes.h by mkopcodeh +** extracted automatically from lopcodes.h by mkopcodeh -- DO NOT EDIT ** See Copyright Notice in lua.h */ -{ "ENDCODE", 1, ENDCODE, ENDCODE, ENDCODE-ENDCODE-1, 0 }, -{ "PUSHNIL", 2, PUSHNIL, PUSHNIL, PUSHNIL-PUSHNIL-1, 0 }, -{ "PUSHNIL0", 1, PUSHNIL0, PUSHNIL, PUSHNIL0-PUSHNIL-1, 0 }, -{ "PUSHNUMBER", 2, PUSHNUMBER, PUSHNUMBER, PUSHNUMBER-PUSHNUMBER-1, 0 }, -{ "PUSHNUMBER0", 1, PUSHNUMBER0, PUSHNUMBER, PUSHNUMBER0-PUSHNUMBER-1, 0 }, -{ "PUSHNUMBER1", 1, PUSHNUMBER1, PUSHNUMBER, PUSHNUMBER1-PUSHNUMBER-1, 0 }, -{ "PUSHNUMBER2", 1, PUSHNUMBER2, PUSHNUMBER, PUSHNUMBER2-PUSHNUMBER-1, 0 }, -{ "PUSHNUMBERW", 3, PUSHNUMBERW, PUSHNUMBER, PUSHNUMBERW-PUSHNUMBER-1, 0 }, -{ "PUSHCONSTANT", 2, PUSHCONSTANT, PUSHCONSTANT, PUSHCONSTANT-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT0", 1, PUSHCONSTANT0, PUSHCONSTANT, PUSHCONSTANT0-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT1", 1, PUSHCONSTANT1, PUSHCONSTANT, PUSHCONSTANT1-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT2", 1, PUSHCONSTANT2, PUSHCONSTANT, PUSHCONSTANT2-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT3", 1, PUSHCONSTANT3, PUSHCONSTANT, PUSHCONSTANT3-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT4", 1, PUSHCONSTANT4, PUSHCONSTANT, PUSHCONSTANT4-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT5", 1, PUSHCONSTANT5, PUSHCONSTANT, PUSHCONSTANT5-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT6", 1, PUSHCONSTANT6, PUSHCONSTANT, PUSHCONSTANT6-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANT7", 1, PUSHCONSTANT7, PUSHCONSTANT, PUSHCONSTANT7-PUSHCONSTANT-1, 0 }, -{ "PUSHCONSTANTW", 3, PUSHCONSTANTW, PUSHCONSTANT, PUSHCONSTANTW-PUSHCONSTANT-1, 0 }, -{ "PUSHUPVALUE", 2, PUSHUPVALUE, PUSHUPVALUE, PUSHUPVALUE-PUSHUPVALUE-1, 0 }, -{ "PUSHUPVALUE0", 1, PUSHUPVALUE0, PUSHUPVALUE, PUSHUPVALUE0-PUSHUPVALUE-1, 0 }, -{ "PUSHUPVALUE1", 1, PUSHUPVALUE1, PUSHUPVALUE, PUSHUPVALUE1-PUSHUPVALUE-1, 0 }, -{ "PUSHLOCAL", 2, PUSHLOCAL, PUSHLOCAL, PUSHLOCAL-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL0", 1, PUSHLOCAL0, PUSHLOCAL, PUSHLOCAL0-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL1", 1, PUSHLOCAL1, PUSHLOCAL, PUSHLOCAL1-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL2", 1, PUSHLOCAL2, PUSHLOCAL, PUSHLOCAL2-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL3", 1, PUSHLOCAL3, PUSHLOCAL, PUSHLOCAL3-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL4", 1, PUSHLOCAL4, PUSHLOCAL, PUSHLOCAL4-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL5", 1, PUSHLOCAL5, PUSHLOCAL, PUSHLOCAL5-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL6", 1, PUSHLOCAL6, PUSHLOCAL, PUSHLOCAL6-PUSHLOCAL-1, 0 }, -{ "PUSHLOCAL7", 1, PUSHLOCAL7, PUSHLOCAL, PUSHLOCAL7-PUSHLOCAL-1, 0 }, -{ "GETGLOBAL", 2, GETGLOBAL, GETGLOBAL, GETGLOBAL-GETGLOBAL-1, 0 }, -{ "GETGLOBAL0", 1, GETGLOBAL0, GETGLOBAL, GETGLOBAL0-GETGLOBAL-1, 0 }, -{ "GETGLOBAL1", 1, GETGLOBAL1, GETGLOBAL, GETGLOBAL1-GETGLOBAL-1, 0 }, -{ "GETGLOBAL2", 1, GETGLOBAL2, GETGLOBAL, GETGLOBAL2-GETGLOBAL-1, 0 }, -{ "GETGLOBAL3", 1, GETGLOBAL3, GETGLOBAL, GETGLOBAL3-GETGLOBAL-1, 0 }, -{ "GETGLOBAL4", 1, GETGLOBAL4, GETGLOBAL, GETGLOBAL4-GETGLOBAL-1, 0 }, -{ "GETGLOBAL5", 1, GETGLOBAL5, GETGLOBAL, GETGLOBAL5-GETGLOBAL-1, 0 }, -{ "GETGLOBAL6", 1, GETGLOBAL6, GETGLOBAL, GETGLOBAL6-GETGLOBAL-1, 0 }, -{ "GETGLOBAL7", 1, GETGLOBAL7, GETGLOBAL, GETGLOBAL7-GETGLOBAL-1, 0 }, -{ "GETGLOBALW", 3, GETGLOBALW, GETGLOBAL, GETGLOBALW-GETGLOBAL-1, 0 }, -{ "GETTABLE", 1, GETTABLE, GETTABLE, GETTABLE-GETTABLE-1, 0 }, -{ "GETDOTTED", 2, GETDOTTED, GETDOTTED, GETDOTTED-GETDOTTED-1, 0 }, -{ "GETDOTTED0", 1, GETDOTTED0, GETDOTTED, GETDOTTED0-GETDOTTED-1, 0 }, -{ "GETDOTTED1", 1, GETDOTTED1, GETDOTTED, GETDOTTED1-GETDOTTED-1, 0 }, -{ "GETDOTTED2", 1, GETDOTTED2, GETDOTTED, GETDOTTED2-GETDOTTED-1, 0 }, -{ "GETDOTTED3", 1, GETDOTTED3, GETDOTTED, GETDOTTED3-GETDOTTED-1, 0 }, -{ "GETDOTTED4", 1, GETDOTTED4, GETDOTTED, GETDOTTED4-GETDOTTED-1, 0 }, -{ "GETDOTTED5", 1, GETDOTTED5, GETDOTTED, GETDOTTED5-GETDOTTED-1, 0 }, -{ "GETDOTTED6", 1, GETDOTTED6, GETDOTTED, GETDOTTED6-GETDOTTED-1, 0 }, -{ "GETDOTTED7", 1, GETDOTTED7, GETDOTTED, GETDOTTED7-GETDOTTED-1, 0 }, -{ "GETDOTTEDW", 3, GETDOTTEDW, GETDOTTED, GETDOTTEDW-GETDOTTED-1, 0 }, -{ "PUSHSELF", 2, PUSHSELF, PUSHSELF, PUSHSELF-PUSHSELF-1, 0 }, -{ "PUSHSELF0", 1, PUSHSELF0, PUSHSELF, PUSHSELF0-PUSHSELF-1, 0 }, -{ "PUSHSELF1", 1, PUSHSELF1, PUSHSELF, PUSHSELF1-PUSHSELF-1, 0 }, -{ "PUSHSELF2", 1, PUSHSELF2, PUSHSELF, PUSHSELF2-PUSHSELF-1, 0 }, -{ "PUSHSELF3", 1, PUSHSELF3, PUSHSELF, PUSHSELF3-PUSHSELF-1, 0 }, -{ "PUSHSELF4", 1, PUSHSELF4, PUSHSELF, PUSHSELF4-PUSHSELF-1, 0 }, -{ "PUSHSELF5", 1, PUSHSELF5, PUSHSELF, PUSHSELF5-PUSHSELF-1, 0 }, -{ "PUSHSELF6", 1, PUSHSELF6, PUSHSELF, PUSHSELF6-PUSHSELF-1, 0 }, -{ "PUSHSELF7", 1, PUSHSELF7, PUSHSELF, PUSHSELF7-PUSHSELF-1, 0 }, -{ "PUSHSELFW", 3, PUSHSELFW, PUSHSELF, PUSHSELFW-PUSHSELF-1, 0 }, -{ "CREATEARRAY", 2, CREATEARRAY, CREATEARRAY, CREATEARRAY-CREATEARRAY-1, 0 }, -{ "CREATEARRAY0", 1, CREATEARRAY0, CREATEARRAY, CREATEARRAY0-CREATEARRAY-1, 0 }, -{ "CREATEARRAY1", 1, CREATEARRAY1, CREATEARRAY, CREATEARRAY1-CREATEARRAY-1, 0 }, -{ "CREATEARRAYW", 3, CREATEARRAYW, CREATEARRAY, CREATEARRAYW-CREATEARRAY-1, 0 }, -{ "SETLOCAL", 2, SETLOCAL, SETLOCAL, SETLOCAL-SETLOCAL-1, 0 }, -{ "SETLOCAL0", 1, SETLOCAL0, SETLOCAL, SETLOCAL0-SETLOCAL-1, 0 }, -{ "SETLOCAL1", 1, SETLOCAL1, SETLOCAL, SETLOCAL1-SETLOCAL-1, 0 }, -{ "SETLOCAL2", 1, SETLOCAL2, SETLOCAL, SETLOCAL2-SETLOCAL-1, 0 }, -{ "SETLOCAL3", 1, SETLOCAL3, SETLOCAL, SETLOCAL3-SETLOCAL-1, 0 }, -{ "SETLOCAL4", 1, SETLOCAL4, SETLOCAL, SETLOCAL4-SETLOCAL-1, 0 }, -{ "SETLOCAL5", 1, SETLOCAL5, SETLOCAL, SETLOCAL5-SETLOCAL-1, 0 }, -{ "SETLOCAL6", 1, SETLOCAL6, SETLOCAL, SETLOCAL6-SETLOCAL-1, 0 }, -{ "SETLOCAL7", 1, SETLOCAL7, SETLOCAL, SETLOCAL7-SETLOCAL-1, 0 }, -{ "SETGLOBAL", 2, SETGLOBAL, SETGLOBAL, SETGLOBAL-SETGLOBAL-1, 0 }, -{ "SETGLOBAL0", 1, SETGLOBAL0, SETGLOBAL, SETGLOBAL0-SETGLOBAL-1, 0 }, -{ "SETGLOBAL1", 1, SETGLOBAL1, SETGLOBAL, SETGLOBAL1-SETGLOBAL-1, 0 }, -{ "SETGLOBAL2", 1, SETGLOBAL2, SETGLOBAL, SETGLOBAL2-SETGLOBAL-1, 0 }, -{ "SETGLOBAL3", 1, SETGLOBAL3, SETGLOBAL, SETGLOBAL3-SETGLOBAL-1, 0 }, -{ "SETGLOBAL4", 1, SETGLOBAL4, SETGLOBAL, SETGLOBAL4-SETGLOBAL-1, 0 }, -{ "SETGLOBAL5", 1, SETGLOBAL5, SETGLOBAL, SETGLOBAL5-SETGLOBAL-1, 0 }, -{ "SETGLOBAL6", 1, SETGLOBAL6, SETGLOBAL, SETGLOBAL6-SETGLOBAL-1, 0 }, -{ "SETGLOBAL7", 1, SETGLOBAL7, SETGLOBAL, SETGLOBAL7-SETGLOBAL-1, 0 }, -{ "SETGLOBALW", 3, SETGLOBALW, SETGLOBAL, SETGLOBALW-SETGLOBAL-1, 0 }, -{ "SETTABLE0", 1, SETTABLE0, SETTABLE0, SETTABLE0-SETTABLE0-1, 0 }, -{ "SETTABLE", 2, SETTABLE, SETTABLE, SETTABLE-SETTABLE-1, 0 }, -{ "SETLIST", 3, SETLIST, SETLIST, SETLIST-SETLIST-1, 0 }, -{ "SETLIST0", 2, SETLIST0, SETLIST, SETLIST0-SETLIST-1, 0 }, -{ "SETLISTW", 4, SETLISTW, SETLIST, SETLISTW-SETLIST-1, 0 }, -{ "SETMAP", 2, SETMAP, SETMAP, SETMAP-SETMAP-1, 0 }, -{ "SETMAP0", 1, SETMAP0, SETMAP, SETMAP0-SETMAP-1, 0 }, -{ "EQOP", 1, EQOP, EQOP, EQOP-EQOP-1, 0 }, -{ "NEQOP", 1, NEQOP, NEQOP, NEQOP-NEQOP-1, 0 }, -{ "LTOP", 1, LTOP, LTOP, LTOP-LTOP-1, 0 }, -{ "LEOP", 1, LEOP, LEOP, LEOP-LEOP-1, 0 }, -{ "GTOP", 1, GTOP, GTOP, GTOP-GTOP-1, 0 }, -{ "GEOP", 1, GEOP, GEOP, GEOP-GEOP-1, 0 }, -{ "ADDOP", 1, ADDOP, ADDOP, ADDOP-ADDOP-1, 0 }, -{ "SUBOP", 1, SUBOP, SUBOP, SUBOP-SUBOP-1, 0 }, -{ "MULTOP", 1, MULTOP, MULTOP, MULTOP-MULTOP-1, 0 }, -{ "DIVOP", 1, DIVOP, DIVOP, DIVOP-DIVOP-1, 0 }, -{ "POWOP", 1, POWOP, POWOP, POWOP-POWOP-1, 0 }, -{ "CONCOP", 1, CONCOP, CONCOP, CONCOP-CONCOP-1, 0 }, -{ "MINUSOP", 1, MINUSOP, MINUSOP, MINUSOP-MINUSOP-1, 0 }, -{ "NOTOP", 1, NOTOP, NOTOP, NOTOP-NOTOP-1, 0 }, -{ "ONTJMP", 2, ONTJMP, ONTJMP, ONTJMP-ONTJMP-1, 0 }, -{ "ONTJMPW", 3, ONTJMPW, ONTJMP, ONTJMPW-ONTJMP-1, 0 }, -{ "ONFJMP", 2, ONFJMP, ONFJMP, ONFJMP-ONFJMP-1, 0 }, -{ "ONFJMPW", 3, ONFJMPW, ONFJMP, ONFJMPW-ONFJMP-1, 0 }, -{ "JMP", 2, JMP, JMP, JMP-JMP-1, 0 }, -{ "JMPW", 3, JMPW, JMP, JMPW-JMP-1, 0 }, -{ "IFFJMP", 2, IFFJMP, IFFJMP, IFFJMP-IFFJMP-1, 0 }, -{ "IFFJMPW", 3, IFFJMPW, IFFJMP, IFFJMPW-IFFJMP-1, 0 }, -{ "IFTUPJMP", 2, IFTUPJMP, IFTUPJMP, IFTUPJMP-IFTUPJMP-1, 0 }, -{ "IFTUPJMPW", 3, IFTUPJMPW, IFTUPJMP, IFTUPJMPW-IFTUPJMP-1, 0 }, -{ "IFFUPJMP", 2, IFFUPJMP, IFFUPJMP, IFFUPJMP-IFFUPJMP-1, 0 }, -{ "IFFUPJMPW", 3, IFFUPJMPW, IFFUPJMP, IFFUPJMPW-IFFUPJMP-1, 0 }, -{ "CLOSURE", 3, CLOSURE, CLOSURE, CLOSURE-CLOSURE-1, 0 }, -{ "CLOSUREW", 4, CLOSUREW, CLOSURE, CLOSUREW-CLOSURE-1, 0 }, -{ "CALLFUNC", 3, CALLFUNC, CALLFUNC, CALLFUNC-CALLFUNC-1, 0 }, -{ "CALLFUNC0", 2, CALLFUNC0, CALLFUNC, CALLFUNC0-CALLFUNC-1, 0 }, -{ "CALLFUNC1", 2, CALLFUNC1, CALLFUNC, CALLFUNC1-CALLFUNC-1, 0 }, -{ "RETCODE", 2, RETCODE, RETCODE, RETCODE-RETCODE-1, 0 }, -{ "SETLINE", 2, SETLINE, SETLINE, SETLINE-SETLINE-1, 0 }, -{ "SETLINEW", 3, SETLINEW, SETLINE, SETLINEW-SETLINE-1, 0 }, -{ "POP", 2, POP, POP, POP-POP-1, 0 }, -{ "POP0", 1, POP0, POP, POP0-POP-1, 0 }, -{ "POP1", 1, POP1, POP, POP1-POP-1, 0 }, +{ "ENDCODE", ENDCODE, ENDCODE, ARGS_NONE, -1, -1 }, +{ "RETCODE", RETCODE, RETCODE, ARGS_B, -1, -1 }, +{ "CALL", CALL, CALL, ARGS_BB, -1, -1 }, +{ "TAILCALL", TAILCALL, TAILCALL, ARGS_BB, -1, -1 }, +{ "PUSHNIL", PUSHNIL, PUSHNIL, ARGS_B, -1, -1 }, +{ "POP", POP, POP, ARGS_B, -1, -1 }, +{ "PUSHNUMBERW", PUSHNUMBERW, PUSHNUMBER, ARGS_W, -1, -1 }, +{ "PUSHNUMBER", PUSHNUMBER, PUSHNUMBER, ARGS_B, -1, -1 }, +{ "PUSHNUMBERNEGW", PUSHNUMBERNEGW, PUSHNUMBERNEG, ARGS_W, -1, -1 }, +{ "PUSHNUMBERNEG", PUSHNUMBERNEG, PUSHNUMBERNEG, ARGS_B, -1, -1 }, +{ "PUSHCONSTANTW", PUSHCONSTANTW, PUSHCONSTANT, ARGS_W, -1, -1 }, +{ "PUSHCONSTANT", PUSHCONSTANT, PUSHCONSTANT, ARGS_B, -1, -1 }, +{ "PUSHUPVALUE", PUSHUPVALUE, PUSHUPVALUE, ARGS_B, -1, -1 }, +{ "PUSHLOCAL", PUSHLOCAL, PUSHLOCAL, ARGS_B, -1, -1 }, +{ "GETGLOBALW", GETGLOBALW, GETGLOBAL, ARGS_W, -1, -1 }, +{ "GETGLOBAL", GETGLOBAL, GETGLOBAL, ARGS_B, -1, -1 }, +{ "GETTABLE", GETTABLE, GETTABLE, ARGS_NONE, -1, -1 }, +{ "GETDOTTEDW", GETDOTTEDW, GETDOTTED, ARGS_W, -1, -1 }, +{ "GETDOTTED", GETDOTTED, GETDOTTED, ARGS_B, -1, -1 }, +{ "PUSHSELFW", PUSHSELFW, PUSHSELF, ARGS_W, -1, -1 }, +{ "PUSHSELF", PUSHSELF, PUSHSELF, ARGS_B, -1, -1 }, +{ "CREATEARRAYW", CREATEARRAYW, CREATEARRAY, ARGS_W, -1, -1 }, +{ "CREATEARRAY", CREATEARRAY, CREATEARRAY, ARGS_B, -1, -1 }, +{ "SETLOCAL", SETLOCAL, SETLOCAL, ARGS_B, -1, -1 }, +{ "SETGLOBALW", SETGLOBALW, SETGLOBAL, ARGS_W, -1, -1 }, +{ "SETGLOBAL", SETGLOBAL, SETGLOBAL, ARGS_B, -1, -1 }, +{ "SETTABLEPOP", SETTABLEPOP, SETTABLEPOP, ARGS_NONE, -1, -1 }, +{ "SETTABLE", SETTABLE, SETTABLE, ARGS_B, -1, -1 }, +{ "SETLISTW", SETLISTW, SETLIST, ARGS_WB, -1, -1 }, +{ "SETLIST", SETLIST, SETLIST, ARGS_BB, -1, -1 }, +{ "SETMAP", SETMAP, SETMAP, ARGS_B, -1, -1 }, +{ "NEQOP", NEQOP, NEQOP, ARGS_NONE, -1, -1 }, +{ "EQOP", EQOP, EQOP, ARGS_NONE, -1, -1 }, +{ "LTOP", LTOP, LTOP, ARGS_NONE, -1, -1 }, +{ "LEOP", LEOP, LEOP, ARGS_NONE, -1, -1 }, +{ "GTOP", GTOP, GTOP, ARGS_NONE, -1, -1 }, +{ "GEOP", GEOP, GEOP, ARGS_NONE, -1, -1 }, +{ "ADDOP", ADDOP, ADDOP, ARGS_NONE, -1, -1 }, +{ "SUBOP", SUBOP, SUBOP, ARGS_NONE, -1, -1 }, +{ "MULTOP", MULTOP, MULTOP, ARGS_NONE, -1, -1 }, +{ "DIVOP", DIVOP, DIVOP, ARGS_NONE, -1, -1 }, +{ "POWOP", POWOP, POWOP, ARGS_NONE, -1, -1 }, +{ "CONCOP", CONCOP, CONCOP, ARGS_NONE, -1, -1 }, +{ "MINUSOP", MINUSOP, MINUSOP, ARGS_NONE, -1, -1 }, +{ "NOTOP", NOTOP, NOTOP, ARGS_NONE, -1, -1 }, +{ "ONTJMPW", ONTJMPW, ONTJMP, ARGS_W, -1, -1 }, +{ "ONTJMP", ONTJMP, ONTJMP, ARGS_B, -1, -1 }, +{ "ONFJMPW", ONFJMPW, ONFJMP, ARGS_W, -1, -1 }, +{ "ONFJMP", ONFJMP, ONFJMP, ARGS_B, -1, -1 }, +{ "JMPW", JMPW, JMP, ARGS_W, -1, -1 }, +{ "JMP", JMP, JMP, ARGS_B, -1, -1 }, +{ "IFFJMPW", IFFJMPW, IFFJMP, ARGS_W, -1, -1 }, +{ "IFFJMP", IFFJMP, IFFJMP, ARGS_B, -1, -1 }, +{ "IFTUPJMPW", IFTUPJMPW, IFTUPJMP, ARGS_W, -1, -1 }, +{ "IFTUPJMP", IFTUPJMP, IFTUPJMP, ARGS_B, -1, -1 }, +{ "IFFUPJMPW", IFFUPJMPW, IFFUPJMP, ARGS_W, -1, -1 }, +{ "IFFUPJMP", IFFUPJMP, IFFUPJMP, ARGS_B, -1, -1 }, +{ "CLOSUREW", CLOSUREW, CLOSURE, ARGS_WB, -1, -1 }, +{ "CLOSURE", CLOSURE, CLOSURE, ARGS_BB, -1, -1 }, +{ "SETLINEW", SETLINEW, SETLINE, ARGS_W, -1, -1 }, +{ "SETLINE", SETLINE, SETLINE, ARGS_B, -1, -1 }, +{ "LONGARGW", LONGARGW, LONGARG, ARGS_W, -1, -1 }, +{ "LONGARG", LONGARG, LONGARG, ARGS_B, -1, -1 }, +{ "CHECKSTACK", CHECKSTACK, CHECKSTACK, ARGS_B, -1, -1 }, diff --git a/src/luac/opt.c b/src/luac/opt.c index 5084ddeec2..e2becc2ab8 100644 --- a/src/luac/opt.c +++ b/src/luac/opt.c @@ -1,70 +1,126 @@ /* -** $Id: opt.c,v 1.4 1998/04/02 20:44:08 lhf Exp $ +** $Id: opt.c,v 1.12 1999/07/02 19:34:26 lhf Exp $ ** optimize bytecodes ** See Copyright Notice in lua.h */ #include #include +#include #include "luac.h" -#include "lmem.h" + +static void FixArg(Byte* p, int i, int j, int isconst) +{ + if (j==i) + ; + else if (i<=MAX_BYTE) /* j>8; + p[2]=j; + } + } + else /* previous instruction must've been LONGARG */ + { + if (isconst && j<=MAX_WORD) p[-2]=p[-1]=NOP; else p[-1]=j>>16; + p[1]=j>>8; + p[2]=j; + } +} static void FixConstants(TProtoFunc* tf, int* C) { Byte* code=tf->code; Byte* p=code; - while (1) + int longarg=0; + for (;;) { Opcode OP; int n=INFO(tf,p,&OP); int op=OP.class; - int i=OP.arg; - if (op==ENDCODE) break; - if ( op==PUSHCONSTANT || op==GETDOTTED || op==PUSHSELF || - op==GETGLOBAL || op==SETGLOBAL) + int i=OP.arg+longarg; + longarg=0; + if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED || + op==PUSHSELF || op==SETGLOBAL || op==CLOSURE) + FixArg(p,i,C[i],1); + else if (op==LONGARG) longarg=i<<16; + else if (op==ENDCODE) break; + p+=n; + } +} + +#define UNREF 1 /* "type" of unused constants */ +#define BIAS 128 /* mark for used constants */ + +static void NoUnrefs(TProtoFunc* tf) +{ + int i,n=tf->nconsts; + Byte* code=tf->code; + Byte* p=code; + int longarg=0; + for (;;) /* mark all used constants */ + { + Opcode OP; + int n=INFO(tf,p,&OP); + int op=OP.class; + int i=OP.arg+longarg; + longarg=0; + if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED || + op==PUSHSELF || op==SETGLOBAL || op==CLOSURE) { - int j=C[i]; - if (j==i) - ; - else if (n==1) - { - p[0]=op+j+1; - } - else if (n==2) - { - if (j<8) { p[0]=op+j+1; p[1]=NOP; } else p[1]=j; - } - else - { - if (j<=255) - { - p[0]=op; - p[1]=j; - p[2]=NOP; - } - else - { - p[1]= 0x0000FF & (j>>8); - p[2]= 0x0000FF & j; - } - } + TObject* o=tf->consts+i; + if (ttype(o)<=0) ttype(o)+=BIAS; /* mark as used */ } + else if (op==LONGARG) longarg=i<<16; + else if (op==ENDCODE) break; p+=n; } + for (i=0; iconsts+i; + if (ttype(o)<=0) + ttype(o)=UNREF; /* mark as unused */ + else + ttype(o)-=BIAS; /* unmark used constant */ + } } -static TProtoFunc* TF; +#define CMP(oa,ob,f) memcmp(&f(oa),&f(ob),sizeof(f(oa))) -static int compare(const void* a, const void *b) +static int compare(TProtoFunc* tf, int ia, int ib) +{ + TObject* oa=tf->consts+ia; + TObject* ob=tf->consts+ib; + int t=ttype(oa)-ttype(ob); + if (t) return t; + switch (ttype(oa)) + { + case LUA_T_NUMBER: return CMP(oa,ob,nvalue); + case LUA_T_STRING: return CMP(oa,ob,tsvalue); + case LUA_T_PROTO: return CMP(oa,ob,tfvalue); + case LUA_T_NIL: return 0; + case UNREF: return 0; + default: return ia-ib; /* cannot happen */ + } +} + +static TProtoFunc* TF; /* for sort */ + +static int compare1(const void* a, const void* b) { int ia=*(int*)a; int ib=*(int*)b; - int t; - TObject* oa=TF->consts+ia; - TObject* ob=TF->consts+ib; - t=ttype(oa)-ttype(ob); if (t) return t; - t=oa->value.i-ob->value.i; if (t) return t; - return ia-ib; + int t=compare(TF,ia,ib); + return (t) ? t : ia-ib; } static void OptConstants(TProtoFunc* tf) @@ -74,43 +130,60 @@ static void OptConstants(TProtoFunc* tf) int i,k; int n=tf->nconsts; if (n==0) return; - C=luaM_reallocvector(C,n,int); - D=luaM_reallocvector(D,n,int); + luaM_reallocvector(C,n,int); + luaM_reallocvector(D,n,int); + NoUnrefs(tf); for (i=0; iconsts+k; - TObject* ob=tf->consts+j; - if (ttype(oa)==ttype(ob) && oa->value.i==ob->value.i) D[j]=k; else k=j; + if (compare(tf,k,j)==0) D[j]=k; else k=j; } k=0; /* build rename map & pack constants */ for (i=0; iconsts[k]=tf->consts[i]; C[i]=k++; } else C[i]=C[D[i]]; + if (D[i]==i) /* new value */ + { + TObject* o=tf->consts+i; + if (ttype(o)!=UNREF) + { + tf->consts[k]=tf->consts[i]; + C[i]=k++; + } + } + else C[i]=C[D[i]]; + } + if (ksource->str,tf->lineDefined,n,k); + FixConstants(tf,C); + tf->nconsts=k; } - if (k>=n) return; -printf("\t\"%s\":%d reduced constants from %d to %d\n", - tf->fileName->str,tf->lineDefined,n,k); - tf->nconsts=k; - FixConstants(tf,C); } static int NoDebug(TProtoFunc* tf) { Byte* code=tf->code; Byte* p=code; + int lop=NOP; /* last opcode */ int nop=0; - while (1) /* change SETLINE to NOP */ + for (;;) /* change SETLINE to NOP */ { Opcode OP; int n=INFO(tf,p,&OP); int op=OP.class; - if (op==ENDCODE) break; if (op==NOP) ++nop; - if (op==SETLINE) { nop+=n; memset(p,NOP,n); } + else if (op==SETLINE) + { + int m; + if (lop==LONGARG) m=2; else if (lop==LONGARGW) m=3; else m=0; + nop+=n+m; memset(p-m,NOP,n+m); + } + else if (op==ENDCODE) break; + lop=OP.op; p+=n; } return nop; @@ -125,8 +198,8 @@ static int FixJump(TProtoFunc* tf, Byte* a, Byte* b) Opcode OP; int n=INFO(tf,p,&OP); int op=OP.class; - if (op==ENDCODE) break; if (op==NOP) ++nop; + else if (op==ENDCODE) break; p+=n; } return nop; @@ -136,42 +209,22 @@ static void FixJumps(TProtoFunc* tf) { Byte* code=tf->code; Byte* p=code; - while (1) + int longarg=0; + for (;;) { Opcode OP; int n=INFO(tf,p,&OP); int op=OP.class; - int i=OP.arg; - int nop; + int i=OP.arg+longarg; + int nop=0; + longarg=0; if (op==ENDCODE) break; - nop=0; - if (op==IFTUPJMP || op==IFFUPJMP) nop=FixJump(tf,p-i+n,p); else - if (op==ONTJMP || op==ONFJMP || op==JMP || op==IFFJMP) nop=FixJump(tf,p,p+i+n); - if (nop>0) - { - int j=i-nop; - if (n==2) - p[1]=j; - else -#if 0 - { - if (j<=255) /* does NOT work for nested loops */ - { - if (op==IFTUPJMP || op==IFFUPJMP) --j; - p[0]=OP.op-1; /* *JMP and *JMPW are consecutive */ - p[1]=j; - p[2]=NOP; - } - else -#endif - { - p[1]= 0x0000FF & (j>>8); - p[2]= 0x0000FF & j; - } -#if 0 - } -#endif - } + else if (op==IFTUPJMP || op==IFFUPJMP) + nop=FixJump(tf,p-i+n,p); + else if (op==ONTJMP || op==ONFJMP || op==JMP || op==IFFJMP) + nop=FixJump(tf,p,p+i+n); + else if (op==LONGARG) longarg=i<<16; + if (nop>0) FixArg(p,i,i-nop,0); p+=n; } } @@ -181,7 +234,7 @@ static void PackCode(TProtoFunc* tf) Byte* code=tf->code; Byte* p=code; Byte* q=code; - while (1) + for (;;) { Opcode OP; int n=INFO(tf,p,&OP); @@ -190,14 +243,13 @@ static void PackCode(TProtoFunc* tf) p+=n; if (op==ENDCODE) break; } -printf("\t\"%s\":%d reduced code from %d to %d\n", - tf->fileName->str,tf->lineDefined,(int)(p-code),(int)(q-code)); +printf("\t" SOURCE " reduced code from %d to %d\n", + tf->source->str,tf->lineDefined,(int)(p-code),(int)(q-code)); } static void OptCode(TProtoFunc* tf) { - int nop=NoDebug(tf); - if (nop==0) return; /* cannot improve code */ + if (NoDebug(tf)==0) return; /* cannot improve code */ FixJumps(tf); PackCode(tf); } @@ -216,13 +268,14 @@ static void OptFunctions(TProtoFunc* tf) static void OptFunction(TProtoFunc* tf) { - tf->locvars=NULL; /* remove local variables table */ OptConstants(tf); OptCode(tf); OptFunctions(tf); + tf->source=luaS_new(""); + tf->locvars=NULL; } -void OptChunk(TProtoFunc* Main) +void luaU_optchunk(TProtoFunc* Main) { OptFunction(Main); } diff --git a/src/luac/print.c b/src/luac/print.c index ce98539015..b1ee8934b9 100644 --- a/src/luac/print.c +++ b/src/luac/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.13 1998/07/12 00:17:37 lhf Exp $ +** $Id: print.c,v 1.21 1999/05/25 19:58:55 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -9,88 +9,81 @@ #include "luac.h" #ifdef DEBUG -void PrintConstant1(TProtoFunc* tf, int i) -{ - TObject* o=tf->consts+i; - printf("%6d ",i); - if (i<0 || i>=tf->nconsts) - printf("(bad constant #%d: max=%d)",i,tf->nconsts); - else - switch (ttype(o)) - { - case LUA_T_NUMBER: - printf("N " NUMBER_FMT "\n",nvalue(o)); /* LUA_NUMBER */ - break; - case LUA_T_STRING: - printf("S %p\t\"%s\"\n",(void*)tsvalue(o),svalue(o)); - break; - case LUA_T_PROTO: - printf("F %p\n",(void*)tfvalue(o)); - break; - default: /* cannot happen */ - printf("? %d\n",ttype(o)); - break; - } -} - static void PrintConstants(TProtoFunc* tf) { int i,n=tf->nconsts; - printf("constants (%d):\n",n); - for (i=0; i=tf->nconsts) - printf("(bad constant #%d: max=%d)",i,tf->nconsts); - else + printf("constants (%d) for %p:\n",n,tf); + for (i=0; iconsts+i; + printf("%6d ",i); switch (ttype(o)) { case LUA_T_NUMBER: - printf(NUMBER_FMT,nvalue(o)); /* LUA_NUMBER */ + printf("N " NUMBER_FMT "\n",(double)nvalue(o)); break; case LUA_T_STRING: - printf("\"%s\"",svalue(o)); + printf("S %p\t\"%s\"\n",tsvalue(o),svalue(o)); break; case LUA_T_PROTO: - printf("function at %p",(void*)tfvalue(o)); + printf("F %p\n",tfvalue(o)); break; case LUA_T_NIL: - printf("(nil)"); + printf("nil\n"); break; default: /* cannot happen */ - printf("(bad constant #%d: type=%d [%s])\n",i,ttype(o),luaO_typename(o)); + printf("? type=%d\n",ttype(o)); break; } } } +#endif -#define VarStr(i) svalue(tf->consts+i) +static void PrintConstant(TProtoFunc* tf, int i, int at) +{ + TObject* o=luaU_getconstant(tf,i,at); + switch (ttype(o)) + { + case LUA_T_NUMBER: + printf(NUMBER_FMT,(double)nvalue(o)); + break; + case LUA_T_STRING: + printf("\"%s\"",svalue(o)); + break; + case LUA_T_PROTO: + printf("function at %p",(void*)tfvalue(o)); + break; + case LUA_T_NIL: + printf("(nil)"); + break; + default: /* cannot happen */ + luaU_badconstant("print",i,o,tf); + break; + } +} static void PrintCode(TProtoFunc* tf) { Byte* code=tf->code; Byte* p=code; int line=0; - while (1) + int longarg=0; + for (;;) { Opcode OP; int n=INFO(tf,p,&OP); - int op=OP.op; - int i=OP.arg; - printf("%6d ",(int)(p-code)); + int i=OP.arg+longarg; + int at=p-code; + longarg=0; + printf("%6d ",at); { Byte* q=p; int j=n; while (j--) printf("%02X",*q++); } - printf("%*s%-13s",2*(5-n),"",OP.name); - - if (n!=1 || op<0) printf("\t%d",i); else if (i>=0) printf("\t"); + printf("%*s%-14s ",2*(5-n),"",OP.name); + if (OP.arg >=0) printf("%d",i); + if (OP.arg2>=0) printf(" %d",OP.arg2); switch (OP.class) { @@ -99,13 +92,14 @@ static void PrintCode(TProtoFunc* tf) printf("\n"); return; - case CLOSURE: - printf(" %d",OP.arg2); case PUSHCONSTANT: + case GETGLOBAL: + case SETGLOBAL: case GETDOTTED: case PUSHSELF: + case CLOSURE: printf("\t; "); - PrintConstant(tf,i); + PrintConstant(tf,i,at); break; case PUSHLOCAL: @@ -116,29 +110,24 @@ static void PrintCode(TProtoFunc* tf) break; } - case GETGLOBAL: - case SETGLOBAL: - printf("\t; %s",VarStr(i)); - break; - - case SETLIST: - case CALLFUNC: - if (n>=3) printf(" %d",OP.arg2); + case SETLINE: + printf("\t; " SOURCE,tf->source->str,line=i); break; - case SETLINE: - printf("\t; \"%s\":%d",fileName(tf),line=i); + case LONGARG: + longarg=i<<16; break; /* suggested by Norman Ramsey */ - case IFTUPJMP: - case IFFUPJMP: - i=-i; case ONTJMP: case ONFJMP: case JMP: case IFFJMP: - printf("\t; to %d",(int)(p-code)+i+n); + printf("\t; to %d",at+i+n); + break; + case IFTUPJMP: + case IFFUPJMP: + printf("\t; to %d",at-i+n); break; } @@ -150,47 +139,44 @@ static void PrintCode(TProtoFunc* tf) static void PrintLocals(TProtoFunc* tf) { LocVar* v=tf->locvars; - int n,i=0; - if (v==NULL || v->varname==NULL) return; + int n,i; + if (v==NULL || v->line<0) return; n=tf->code[1]; if (n>=ZEROVARARG) n-=ZEROVARARG; - printf("locals:"); - if (n>0) - { - for (i=0; ivarname->str); - } - if (v->varname!=NULL) + for (i=0; ivarname->str); + for (; v->line>=0; v++) { - for (; v->line>=0; v++) + if (v->varname==NULL) { - if (v->varname==NULL) - { - printf(")"); --i; - } - else - { - printf(" (%s",v->varname->str); i++; - } + --i; if (i<0) luaL_verror("bad locvars[%d]",v-tf->locvars); else printf(")"); + } + else + { + ++i; printf(" (%s",v->varname->str); } - i-=n; - while (i--) printf(")"); } + i-=n; + while (i--) printf(")"); printf("\n"); } +#define IsMain(tf) (tf->lineDefined==0) + static void PrintHeader(TProtoFunc* tf, TProtoFunc* Main, int at) { - int size=CodeSize(tf); + int size=luaU_codesize(tf); if (IsMain(tf)) - printf("\nmain of \"%s\" (%d bytes at %p)\n",fileName(tf),size,(void*)tf); - else if (Main) + printf("\nmain " SOURCE " (%d bytes at %p)\n", + tf->source->str,tf->lineDefined,size,tf); + else { - printf("\nfunction defined at \"%s\":%d (%d bytes at %p); used at ", - fileName(tf),tf->lineDefined,size,(void*)tf); - if (IsMain(Main)) + printf("\nfunction " SOURCE " (%d bytes at %p); used at ", + tf->source->str,tf->lineDefined,size,tf); + if (Main && IsMain(Main)) printf("main"); else - printf("%p",(void*)Main); + printf("%p",Main); printf("+%d\n",at); } } @@ -201,17 +187,21 @@ static void PrintFunctions(TProtoFunc* Main) { Byte* code=Main->code; Byte* p=code; - while (1) + int longarg=0; + for (;;) { Opcode OP; int n=INFO(Main,p,&OP); - if (OP.class==ENDCODE) break; - if (OP.class==PUSHCONSTANT || OP.class==CLOSURE) + int op=OP.class; + int i=OP.arg+longarg; + longarg=0; + if (op==PUSHCONSTANT || op==CLOSURE) { - int i=OP.arg; TObject* o=Main->consts+i; if (ttype(o)==LUA_T_PROTO) PrintFunction(tfvalue(o),Main,(int)(p-code)); } + else if (op==LONGARG) longarg=i<<16; + else if (op==ENDCODE) break; p+=n; } } @@ -227,7 +217,7 @@ static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at) PrintFunctions(tf); } -void PrintChunk(TProtoFunc* Main) +void luaU_printchunk(TProtoFunc* Main) { PrintFunction(Main,0,0); } diff --git a/src/luac/stubs.c b/src/luac/stubs.c index d42bec2555..5f38940ed8 100644 --- a/src/luac/stubs.c +++ b/src/luac/stubs.c @@ -1,9 +1,17 @@ /* -** $Id: stubs.c,v 1.8 1998/07/12 00:17:37 lhf Exp $ +** $Id: stubs.c,v 1.11 1999/03/11 17:09:10 lhf Exp $ ** avoid runtime modules in luac ** See Copyright Notice in lua.h */ +#ifdef NOSTUBS + +/* according to gcc, ANSI C forbids an empty source file */ +void luaU_dummy(void); +void luaU_dummy(void){} + +#else + #include #include #include @@ -22,32 +30,34 @@ void lua_error(char* s) } /* copied from lauxlib.c */ -void luaL_verror(char* fmt, ...) +void luaL_verror (char *fmt, ...) { - char buff[500]; - va_list argp; - va_start(argp,fmt); - vsprintf(buff,fmt,argp); - va_end(argp); - lua_error(buff); + char buff[500]; + va_list argp; + va_start(argp, fmt); + vsprintf(buff, fmt, argp); + va_end(argp); + lua_error(buff); } /* copied from lauxlib.c */ -int luaL_findstring (char* name, char* list[]) -{ - int i; - for (i=0; list[i]; i++) - if (strcmp(list[i], name) == 0) - return i; - return -1; +void luaL_filesource (char *out, char *filename, int len) { + if (filename == NULL) filename = "(stdin)"; + sprintf(out, "@%.*s", len-2, filename); /* -2 for '@' and '\0' */ } /* avoid runtime modules in lstate.c */ + +#include "lbuiltin.h" +#include "ldo.h" +#include "lgc.h" +#include "ltable.h" +#include "ltm.h" + void luaB_predefine(void){} void luaC_hashcallIM(Hash *l){} void luaC_strcallIM(TaggedString *l){} void luaD_gcIM(TObject *o){} -void luaD_init(void){} void luaH_free(Hash *frees){} void luaT_init(void){} @@ -59,10 +69,53 @@ void luaT_init(void){} #ifdef NOPARSER -int lua_debug=0; +#include "llex.h" +#include "lparser.h" void luaX_init(void){} -void luaY_init(void){} -void luaY_parser(void) { lua_error("parser not loaded"); } +void luaD_init(void){} + +TProtoFunc* luaY_parser(ZIO *z) { + lua_error("parser not loaded"); + return NULL; +} + +#else +/* copied from lauxlib.c */ +int luaL_findstring (char *name, char *list[]) { + int i; + for (i=0; list[i]; i++) + if (strcmp(list[i], name) == 0) + return i; + return -1; /* name not found */ +} + +/* copied from lauxlib.c */ +void luaL_chunkid (char *out, char *source, int len) { + len -= 13; /* 13 = strlen("string ''...\0") */ + if (*source == '@') + sprintf(out, "file `%.*s'", len, source+1); + else if (*source == '(') + strcpy(out, "(C code)"); + else { + char *b = strchr(source , '\n'); /* stop string at first new line */ + int lim = (b && (b-source)stack.stack = luaM_newvector(STACK_UNIT, TObject); + L->stack.top = L->stack.stack; + L->stack.last = L->stack.stack+(STACK_UNIT-1); +} + +#endif #endif diff --git a/src/luac/test.c b/src/luac/test.c new file mode 100644 index 0000000000..78ba4556d7 --- /dev/null +++ b/src/luac/test.c @@ -0,0 +1,253 @@ +/* +** $Id: test.c,v 1.10 1999/07/02 19:34:26 lhf Exp $ +** test integrity +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include "luac.h" + +#define AT "pc=%d" +#define ATLOC 0) +#define UNSAFE(s) \ + luaL_verror("unsafe code at " AT IN "\n " s,at,INLOC + +TObject* luaU_getconstant(TProtoFunc* tf, int i, int at) +{ + if (i>=tf->nconsts) UNSAFE("bad constant #%d (max=%d)"),i,tf->nconsts-1,ATLOC; + return tf->consts+i; +} + +static int check(int n, TProtoFunc* tf, int at, int sp, int ss) +{ + if (n==0) return sp; + sp+=n; + if (sp<00) UNSAFE("stack underflow (sp=%d)"),sp,ATLOC; + if (sp>ss) UNSAFE("stack overflow (sp=%d ss=%d)"),sp,ss,ATLOC; + return sp; +} + +#define CHECK(before,after) \ + sp=check(-(before),tf,at,sp,ss), sp=check(after,tf,at,sp,ss) + +static int jmpok(TProtoFunc* tf, int size, int at, int d) +{ + int to=at+d; + if (to<2 || to>=size) + UNSAFE("invalid jump to %d (valid range is 2..%d)"),to,size-1,ATLOC; + return to; +} + +static void TestStack(TProtoFunc* tf, int size, int* SP, int* JP) +{ + Byte* code=tf->code; + Byte* p=code; + int longarg=0; + int ss=0; + int sp=0; + for (;;) + { + Opcode OP; + int n=INFO(tf,p,&OP); + int op=OP.class; + int i=OP.arg+longarg; + int at=p-code; + longarg=0; + switch (op) /* test sanity of operands */ + { + case PUSHCONSTANT: + case GETGLOBAL: + case GETDOTTED: + case PUSHSELF: + case SETGLOBAL: + case CLOSURE: + { + TObject* o=luaU_getconstant(tf,i,at); + if ((op==CLOSURE && ttype(o)!=LUA_T_PROTO) + || (op==GETGLOBAL && ttype(o)!=LUA_T_STRING) + || (op==SETGLOBAL && ttype(o)!=LUA_T_STRING)) + UNSAFE("bad operand to %s"),OP.name,ATLOC; + break; + } + case PUSHLOCAL: + if (i>=sp) UNSAFE("bad local #%d (max=%d)"),i,sp-1,ATLOC; + break; + case SETLOCAL: + if (i>=(sp-1)) UNSAFE("bad local #%d (max=%d)"),i,sp-2,ATLOC; + break; + case ONTJMP: + case ONFJMP: /* negate to remember ON?JMP */ + JP[at]=-jmpok(tf,size,at,i+n); + break; + case JMP: /* remember JMP targets */ + case IFFJMP: + JP[at]= jmpok(tf,size,at,i+n); + break; + case IFTUPJMP: + case IFFUPJMP: + JP[at]= jmpok(tf,size,at,-i+n); + break; + } + + SP[at]=sp; /* remember depth before instruction */ + + switch (op) + { + case STACK: ss=i; break; + case ARGS: CHECK(0,i); break; + case VARARGS: break; + case ENDCODE: return; + case RETCODE: CHECK(i,0); sp=i; break; + case CALL: CHECK(OP.arg2+1,i); break; + case TAILCALL: CHECK(OP.arg2,0); sp=i; break; + case PUSHNIL: CHECK(0,i+1); break; + case POP: CHECK(0,-i); break; + case PUSHNUMBER: + case PUSHNUMBERNEG: + case PUSHCONSTANT: + case PUSHUPVALUE: + case PUSHLOCAL: + case GETGLOBAL: CHECK(0,1); break; + case GETTABLE: CHECK(2,1); break; + case GETDOTTED: CHECK(1,1); break; + case PUSHSELF: CHECK(1,2); break; + case CREATEARRAY: CHECK(0,1); break; + case SETLOCAL: CHECK(1,0); break; + case SETGLOBAL: CHECK(1,0); break; + case SETTABLEPOP: CHECK(3,0); break; + case SETTABLE: CHECK(i+3,i+2); break; + case SETLIST: CHECK(OP.arg2+1,1); break; + case SETMAP: CHECK(2*(i+1)+1,1); break; + case NEQOP: + case EQOP: + case LTOP: + case LEOP: + case GTOP: + case GEOP: + case ADDOP: + case SUBOP: + case MULTOP: + case DIVOP: + case POWOP: + case CONCOP: CHECK(2,1); break; + case MINUSOP: + case NOTOP: CHECK(1,1); break; + case ONTJMP: + case ONFJMP: + case IFFJMP: + case IFTUPJMP: + case IFFUPJMP: CHECK(1,0); break; + case JMP: break; + case CLOSURE: CHECK(OP.arg2,1); break; + case SETLINE: break; + case LONGARG: + longarg=i<<16; + if (longarg<0) UNSAFE("longarg overflow"),ATLOC; + break; + case CHECKSTACK: break; + default: /* cannot happen */ + UNSAFE("cannot test opcode %d [%s]"),OP.op,OP.name,ATLOC; + break; + } + p+=n; + } +} + +static void TestJumps(TProtoFunc* tf, int size, int* SP, int* JP) +{ + int i; + for (i=0; ilocvars==NULL) return; + for (v=tf->locvars; v->line>=0; v++) + { + int at=v-tf->locvars; /* for ATLOC */ + if (l>v->line) + UNSAFE("bad line number %d; expected at least %d"),v->line,l,ATLOC; + l=v->line; + if (v->varname==NULL) + { + if (--d<0) UNSAFE("no scope to close"),ATLOC; + } + else + ++d; + } +} + +static void TestFunction(TProtoFunc* tf); + +static void TestConstants(TProtoFunc* tf) +{ + int i,n=tf->nconsts; + for (i=0; iconsts+i; + switch (ttype(o)) + { + case LUA_T_NUMBER: + break; + case LUA_T_STRING: + break; + case LUA_T_PROTO: + TestFunction(tfvalue(o)); + break; + case LUA_T_NIL: + break; + default: /* cannot happen */ + luaU_badconstant("print",i,o,tf); + break; + } + } +} + +static void TestFunction(TProtoFunc* tf) +{ + TestCode(tf); + TestLocals(tf); + TestConstants(tf); +} + +void luaU_testchunk(TProtoFunc* Main) +{ + TestFunction(Main); +} diff --git a/src/lundump.c b/src/lundump.c index 4fe2b0d721..0c3b5fd711 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.12 1998/07/12 01:46:59 lhf Exp $ +** $Id: lundump.c,v 1.21 1999/07/02 19:34:26 lhf Exp $ ** load bytecodes from files ** See Copyright Notice in lua.h */ @@ -9,99 +9,96 @@ #include "lauxlib.h" #include "lfunc.h" #include "lmem.h" +#include "lopcodes.h" #include "lstring.h" #include "lundump.h" #define LoadBlock(b,size,Z) ezread(Z,b,size) -#define LoadNative(t,Z) LoadBlock(&t,sizeof(t),Z) -#if ID_NUMBER==ID_NATIVE - #define doLoadNumber(f,Z) LoadNative(f,Z) -#else - #define doLoadNumber(f,Z) f=LoadNumber(Z) -#endif - -static void unexpectedEOZ(ZIO* Z) +static void unexpectedEOZ (ZIO* Z) { luaL_verror("unexpected end of file in %s",zname(Z)); } -static int ezgetc(ZIO* Z) +static int ezgetc (ZIO* Z) { int c=zgetc(Z); if (c==EOZ) unexpectedEOZ(Z); return c; } -static void ezread(ZIO* Z, void* b, int n) +static void ezread (ZIO* Z, void* b, int n) { int r=zread(Z,b,n); if (r!=0) unexpectedEOZ(Z); } -static unsigned int LoadWord(ZIO* Z) +static unsigned int LoadWord (ZIO* Z) { unsigned int hi=ezgetc(Z); unsigned int lo=ezgetc(Z); return (hi<<8)|lo; } -static unsigned long LoadLong(ZIO* Z) +static unsigned long LoadLong (ZIO* Z) { unsigned long hi=LoadWord(Z); unsigned long lo=LoadWord(Z); return (hi<<16)|lo; } -#if ID_NUMBER==ID_REAL4 -/* LUA_NUMBER */ -/* assumes sizeof(long)==4 and sizeof(float)==4 (IEEE) */ -static float LoadFloat(ZIO* Z) +/* +* convert number from text +*/ +double luaU_str2d (char* b, char* where) { - unsigned long l=LoadLong(Z); - float f; - memcpy(&f,&l,sizeof(f)); - return f; + int negative=(b[0]=='-'); + double x=luaO_str2d(b+negative); + if (x<0) luaL_verror("cannot convert number '%s' in %s",b,where); + return negative ? -x : x; } -#endif -#if ID_NUMBER==ID_REAL8 -/* LUA_NUMBER */ -/* assumes sizeof(long)==4 and sizeof(double)==8 (IEEE) */ -static double LoadDouble(ZIO* Z) +static real LoadNumber (ZIO* Z, int native) { - unsigned long l[2]; - double f; - int x=1; - if (*(char*)&x==1) /* little-endian */ + real x; + if (native) { - l[1]=LoadLong(Z); - l[0]=LoadLong(Z); + LoadBlock(&x,sizeof(x),Z); + return x; } - else /* big-endian */ + else { - l[0]=LoadLong(Z); - l[1]=LoadLong(Z); + char b[256]; + int size=ezgetc(Z); + LoadBlock(b,size,Z); + b[size]=0; + return luaU_str2d(b,zname(Z)); } - memcpy(&f,l,sizeof(f)); - return f; } -#endif -static Byte* LoadCode(ZIO* Z) +static int LoadInt (ZIO* Z, char* message) { - unsigned long size=LoadLong(Z); - unsigned int s=size; - void* b; - if (s!=size) luaL_verror("code too long (%ld bytes) in %s",size,zname(Z)); - b=luaM_malloc(size); + unsigned long l=LoadLong(Z); + unsigned int i=l; + if (i!=l) luaL_verror(message,l,zname(Z)); + return i; +} + +#define PAD 5 /* two word operands plus opcode */ + +static Byte* LoadCode (ZIO* Z) +{ + int size=LoadInt(Z,"code too long (%ld bytes) in %s"); + Byte* b=luaM_malloc(size+PAD); LoadBlock(b,size,Z); + if (b[size-1]!=ENDCODE) luaL_verror("bad code in %s",zname(Z)); + memset(b+size,ENDCODE,PAD); /* pad code for safety */ return b; } -static TaggedString* LoadTString(ZIO* Z) +static TaggedString* LoadTString (ZIO* Z) { - int size=LoadWord(Z); + long size=LoadLong(Z); if (size==0) return NULL; else @@ -112,65 +109,65 @@ static TaggedString* LoadTString(ZIO* Z) } } -static void LoadLocals(TProtoFunc* tf, ZIO* Z) +static void LoadLocals (TProtoFunc* tf, ZIO* Z) { - int i,n=LoadWord(Z); + int i,n=LoadInt(Z,"too many locals (%ld) in %s"); if (n==0) return; tf->locvars=luaM_newvector(n+1,LocVar); for (i=0; ilocvars[i].line=LoadWord(Z); + tf->locvars[i].line=LoadInt(Z,"too many lines (%ld) in %s"); tf->locvars[i].varname=LoadTString(Z); } tf->locvars[i].line=-1; /* flag end of vector */ tf->locvars[i].varname=NULL; } -static TProtoFunc* LoadFunction(ZIO* Z); +static TProtoFunc* LoadFunction (ZIO* Z, int native); -static void LoadConstants(TProtoFunc* tf, ZIO* Z) +static void LoadConstants (TProtoFunc* tf, ZIO* Z, int native) { - int i,n=LoadWord(Z); + int i,n=LoadInt(Z,"too many constants (%ld) in %s"); tf->nconsts=n; if (n==0) return; tf->consts=luaM_newvector(n,TObject); for (i=0; iconsts+i; - ttype(o)=-ezgetc(Z); + ttype(o)=-ezgetc(Z); /* ttype(o) is negative - ORDER LUA_T */ switch (ttype(o)) { case LUA_T_NUMBER: - doLoadNumber(nvalue(o),Z); + nvalue(o)=LoadNumber(Z,native); break; case LUA_T_STRING: tsvalue(o)=LoadTString(Z); break; case LUA_T_PROTO: - tfvalue(o)=LoadFunction(Z); + tfvalue(o)=LoadFunction(Z,native); break; case LUA_T_NIL: break; - default: - luaL_verror("bad constant #%d in %s: type=%d [%s]", - i,zname(Z),ttype(o),luaO_typename(o)); + default: /* cannot happen */ + luaU_badconstant("load",i,o,tf); break; } } } -static TProtoFunc* LoadFunction(ZIO* Z) +static TProtoFunc* LoadFunction (ZIO* Z, int native) { TProtoFunc* tf=luaF_newproto(); - tf->lineDefined=LoadWord(Z); - tf->fileName=LoadTString(Z); + tf->lineDefined=LoadInt(Z,"lineDefined too large (%ld) in %s"); + tf->source=LoadTString(Z); + if (tf->source==NULL) tf->source=luaS_new(zname(Z)); tf->code=LoadCode(Z); LoadLocals(tf,Z); - LoadConstants(tf,Z); + LoadConstants(tf,Z,native); return tf; } -static void LoadSignature(ZIO* Z) +static void LoadSignature (ZIO* Z) { char* s=SIGNATURE; while (*s!=0 && ezgetc(Z)==*s) @@ -178,10 +175,10 @@ static void LoadSignature(ZIO* Z) if (*s!=0) luaL_verror("bad signature in %s",zname(Z)); } -static void LoadHeader(ZIO* Z) +static int LoadHeader (ZIO* Z) { - int version,id,sizeofR; - real f=-TEST_NUMBER,tf=TEST_NUMBER; + int version,sizeofR; + int native; LoadSignature(Z); version=ezgetc(Z); if (version>VERSION) @@ -192,32 +189,36 @@ static void LoadHeader(ZIO* Z) luaL_verror( "%s too old: version=0x%02x; expected at least 0x%02x", zname(Z),version,VERSION0); - id=ezgetc(Z); /* test number representation */ sizeofR=ezgetc(Z); - if (id!=ID_NUMBER || sizeofR!=sizeof(real)) + native=(sizeofR!=0); + if (native) /* test number representation */ { - luaL_verror("unknown number signature in %s: " - "read 0x%02x%02x; expected 0x%02x%02x", - zname(Z),id,sizeofR,ID_NUMBER,sizeof(real)); + if (sizeofR!=sizeof(real)) + luaL_verror("unknown number size in %s: read %d; expected %d", + zname(Z),sizeofR,sizeof(real)); + else + { + real tf=TEST_NUMBER; + real f=LoadNumber(Z,native); + if ((long)f!=(long)tf) + luaL_verror("unknown number format in %s: " + "read " NUMBER_FMT "; expected " NUMBER_FMT, + zname(Z),f,tf); + } } - doLoadNumber(f,Z); - if (f!=tf) - luaL_verror("unknown number representation in %s: " - "read " NUMBER_FMT "; expected " NUMBER_FMT, /* LUA_NUMBER */ - zname(Z),f,tf); + return native; } -static TProtoFunc* LoadChunk(ZIO* Z) +static TProtoFunc* LoadChunk (ZIO* Z) { - LoadHeader(Z); - return LoadFunction(Z); + return LoadFunction(Z,LoadHeader(Z)); } /* ** load one chunk from a file or buffer ** return main if ok and NULL at EOF */ -TProtoFunc* luaU_undump1(ZIO* Z) +TProtoFunc* luaU_undump1 (ZIO* Z) { int c=zgetc(Z); if (c==ID_CHUNK) @@ -226,3 +227,13 @@ TProtoFunc* luaU_undump1(ZIO* Z) luaL_verror("%s is not a Lua binary file",zname(Z)); return NULL; } + +/* +* handle constants that cannot happen +*/ +void luaU_badconstant (char* s, int i, TObject* o, TProtoFunc* tf) +{ + int t=ttype(o); + char* name= (t>0 || tlineDefined==0) -#define luaO_typename(o) luaO_typenames[-ttype(o)] - -/* number representation */ -#define ID_INT4 'l' /* 4-byte integers */ -#define ID_REAL4 'f' /* 4-byte reals */ -#define ID_REAL8 'd' /* 8-byte reals */ -#define ID_NATIVE '?' /* whatever your machine uses */ - -/* -* use a multiple of PI for testing number representation. -* multiplying by 1E8 gives notrivial integer values. -*/ -#define TEST_NUMBER 3.14159265358979323846E8 - -/* LUA_NUMBER -* choose one below for the number representation in precompiled chunks. -* the default is ID_REAL8 because the default for LUA_NUM_TYPE is double. -* if your machine does not use IEEE 754, use ID_NATIVE. -* the next version will support conversion to/from IEEE 754. -* -* if you change LUA_NUM_TYPE, make sure you set ID_NUMBER accordingly, -* specially if sizeof(long)!=4. -* for types other than the ones listed below, you'll have to write your own -* dump and undump routines. -*/ - -#ifndef ID_NUMBER -#define ID_NUMBER ID_REAL8 +TProtoFunc* luaU_undump1 (ZIO* Z); /* load one chunk */ +void luaU_badconstant (char* s, int i, TObject* o, TProtoFunc* tf); + /* handle cases that cannot happen */ +double luaU_str2d (char* b, char* where); + /* convert number from text */ + +/* definitions for headers of binary files */ +#define VERSION 0x32 /* last format change was in 3.2 */ +#define VERSION0 0x32 /* last major change was in 3.2 */ +#define ID_CHUNK 27 /* binary files start with ESC... */ +#define SIGNATURE "Lua" /* ...followed by this signature */ + +/* formats for error messages */ +#define SOURCE "<%s:%d>" +#define IN " in %p " SOURCE +#define INLOC tf,tf->source->str,tf->lineDefined + +/* format for numbers in listings and error messages */ +#ifndef NUMBER_FMT +#define NUMBER_FMT "%.16g" /* LUA_NUMBER */ #endif -#if 0 -#define ID_NUMBER ID_INT4 -#define ID_NUMBER ID_REAL4 -#define ID_NUMBER ID_REAL8 -#define ID_NUMBER ID_NATIVE -#endif - -#endif +/* a multiple of PI for testing native format */ +/* multiplying by 1E8 gives non-trivial integer values */ +#define TEST_NUMBER 3.14159265358979323846E8 -#if ID_NUMBER==ID_REAL4 - #define DumpNumber DumpFloat - #define LoadNumber LoadFloat - #define SIZEOF_NUMBER 4 -#elif ID_NUMBER==ID_REAL8 - #define DumpNumber DumpDouble - #define LoadNumber LoadDouble - #define SIZEOF_NUMBER 8 -#elif ID_NUMBER==ID_INT4 - #define DumpNumber DumpLong - #define LoadNumber LoadLong - #define SIZEOF_NUMBER 4 -#elif ID_NUMBER==ID_NATIVE - #define DumpNumber DumpNative - #define LoadNumber LoadNative - #define SIZEOF_NUMBER sizeof(real) -#else - #error bad ID_NUMBER #endif diff --git a/src/lvm.c b/src/lvm.c index 72c26c1caa..670642b9cf 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,11 +1,14 @@ /* -** $Id: lvm.c,v 1.30 1998/06/11 18:21:37 roberto Exp $ +** $Id: lvm.c,v 1.58 1999/06/22 20:37:23 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ +#include +#include #include +#include #include #include "lauxlib.h" @@ -13,6 +16,7 @@ #include "lfunc.h" #include "lgc.h" #include "lmem.h" +#include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" @@ -27,9 +31,7 @@ #endif -#define skip_word(pc) (pc+=2) -#define get_word(pc) ((*(pc)<<8)+(*((pc)+1))) -#define next_word(pc) (pc+=2, get_word(pc-2)) +#define highbyte(x) ((x)<<8) /* Extra stack size to run a function: LUA_T_LINE(1), TM calls(2), ... */ @@ -37,45 +39,47 @@ -static TaggedString *strconc (TaggedString *l, TaggedString *r) -{ - size_t nl = l->u.s.len; - size_t nr = r->u.s.len; - char *buffer = luaL_openspace(nl+nr+1); +static TaggedString *strconc (TaggedString *l, TaggedString *r) { + long nl = l->u.s.len; + long nr = r->u.s.len; + char *buffer = luaL_openspace(nl+nr); memcpy(buffer, l->str, nl); memcpy(buffer+nl, r->str, nr); return luaS_newlstr(buffer, nl+nr); } -int luaV_tonumber (TObject *obj) -{ /* LUA_NUMBER */ - double t; - char c; +int luaV_tonumber (TObject *obj) { /* LUA_NUMBER */ if (ttype(obj) != LUA_T_STRING) return 1; - else if (sscanf(svalue(obj), "%lf %c",&t, &c) == 1) { - nvalue(obj) = (real)t; + else { + double t; + char *e = svalue(obj); + int sig = 1; + while (isspace((unsigned char)*e)) e++; + if (*e == '-') { + e++; + sig = -1; + } + else if (*e == '+') e++; + /* no digit before or after decimal point? */ + if (!isdigit((unsigned char)*e) && !isdigit((unsigned char)*(e+1))) + return 2; + t = luaO_str2d(e); + if (t<0) return 2; + nvalue(obj) = (real)t*sig; ttype(obj) = LUA_T_NUMBER; return 0; } - else - return 2; } -int luaV_tostring (TObject *obj) -{ /* LUA_NUMBER */ +int luaV_tostring (TObject *obj) { /* LUA_NUMBER */ if (ttype(obj) != LUA_T_NUMBER) return 1; else { - char s[60]; - real f = nvalue(obj); - int i; - if ((real)(-MAX_INT) <= f && f <= (real)MAX_INT && (real)(i=(int)f) == f) - sprintf (s, "%d", i); - else - sprintf (s, NUMBER_FMT, nvalue(obj)); + char s[32]; /* 16 digits, signal, point and \0 (+ some extra...) */ + sprintf(s, "%.16g", (double)nvalue(obj)); tsvalue(obj) = luaS_new(s); ttype(obj) = LUA_T_STRING; return 0; @@ -83,8 +87,15 @@ int luaV_tostring (TObject *obj) } -void luaV_closure (int nelems) -{ +void luaV_setn (Hash *t, int val) { + TObject index, value; + ttype(&index) = LUA_T_STRING; tsvalue(&index) = luaS_new("n"); + ttype(&value) = LUA_T_NUMBER; nvalue(&value) = val; + luaH_set(t, &index, &value); +} + + +void luaV_closure (int nelems) { if (nelems > 0) { struct Stack *S = &L->stack; Closure *c = luaF_newclosure(nelems); @@ -101,99 +112,110 @@ void luaV_closure (int nelems) ** Function to index a table. ** Receives the table at top-2 and the index at top-1. */ -void luaV_gettable (void) -{ - struct Stack *S = &L->stack; +void luaV_gettable (void) { + TObject *table = L->stack.top-2; TObject *im; - if (ttype(S->top-2) != LUA_T_ARRAY) /* not a table, get "gettable" method */ - im = luaT_getimbyObj(S->top-2, IM_GETTABLE); + if (ttype(table) != LUA_T_ARRAY) { /* not a table, get gettable method */ + im = luaT_getimbyObj(table, IM_GETTABLE); + if (ttype(im) == LUA_T_NIL) + lua_error("indexed expression not a table"); + } else { /* object is a table... */ - int tg = (S->top-2)->value.a->htag; + int tg = table->value.a->htag; im = luaT_getim(tg, IM_GETTABLE); if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */ - TObject *h = luaH_get(avalue(S->top-2), S->top-1); - if (h != NULL && ttype(h) != LUA_T_NIL) { - --S->top; - *(S->top-1) = *h; + TObject *h = luaH_get(avalue(table), table+1); + if (ttype(h) == LUA_T_NIL && + (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL)) { + /* result is nil and there is an "index" tag method */ + luaD_callTM(im, 2, 1); /* calls it */ } - else if (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL) - luaD_callTM(im, 2, 1); else { - --S->top; - ttype(S->top-1) = LUA_T_NIL; + L->stack.top--; + *table = *h; /* "push" result into table position */ } return; } /* else it has a "gettable" method, go through to next command */ } /* object is not a table, or it has a "gettable" method */ - if (ttype(im) != LUA_T_NIL) - luaD_callTM(im, 2, 1); - else - lua_error("indexed expression not a table"); + luaD_callTM(im, 2, 1); } /* -** Function to store indexed based on values at the stack.top -** mode = 0: raw store (without tag methods) -** mode = 1: normal store (with tag methods) -** mode = 2: "deep L->stack.stack" store (with tag methods) +** Receives table at *t, index at *(t+1) and value at top. */ -void luaV_settable (TObject *t, int mode) -{ +void luaV_settable (TObject *t) { struct Stack *S = &L->stack; - TObject *im = (mode == 0) ? NULL : luaT_getimbyObj(t, IM_SETTABLE); - if (ttype(t) == LUA_T_ARRAY && (im == NULL || ttype(im) == LUA_T_NIL)) { - TObject *h = luaH_set(avalue(t), t+1); - *h = *(S->top-1); - S->top -= (mode == 2) ? 1 : 3; + TObject *im; + if (ttype(t) != LUA_T_ARRAY) { /* not a table, get "settable" method */ + im = luaT_getimbyObj(t, IM_SETTABLE); + if (ttype(im) == LUA_T_NIL) + lua_error("indexed expression not a table"); } - else { /* object is not a table, and/or has a specific "settable" method */ - if (im && ttype(im) != LUA_T_NIL) { - if (mode == 2) { - *(S->top+1) = *(L->stack.top-1); - *(S->top) = *(t+1); - *(S->top-1) = *t; - S->top += 2; /* WARNING: caller must assure stack space */ - } - luaD_callTM(im, 3, 0); + else { /* object is a table... */ + im = luaT_getim(avalue(t)->htag, IM_SETTABLE); + if (ttype(im) == LUA_T_NIL) { /* and does not have a "settable" method */ + luaH_set(avalue(t), t+1, S->top-1); + S->top--; /* pop value */ + return; } - else - lua_error("indexed expression not a table"); + /* else it has a "settable" method, go through to next command */ } + /* object is not a table, or it has a "settable" method */ + /* prepare arguments and call the tag method */ + *(S->top+1) = *(L->stack.top-1); + *(S->top) = *(t+1); + *(S->top-1) = *t; + S->top += 2; /* WARNING: caller must assure stack space */ + luaD_callTM(im, 3, 0); } -void luaV_getglobal (TaggedString *ts) -{ - /* WARNING: caller must assure stack space */ - TObject *value = &ts->u.s.globalval; - TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL); - if (ttype(im) == LUA_T_NIL) { /* default behavior */ - *L->stack.top++ = *value; - } +void luaV_rawsettable (TObject *t) { + if (ttype(t) != LUA_T_ARRAY) + lua_error("indexed expression not a table"); else { struct Stack *S = &L->stack; - ttype(S->top) = LUA_T_STRING; - tsvalue(S->top) = ts; - S->top++; - *S->top++ = *value; - luaD_callTM(im, 2, 1); + luaH_set(avalue(t), t+1, S->top-1); + S->top -= 3; } } -void luaV_setglobal (TaggedString *ts) -{ +void luaV_getglobal (TaggedString *ts) { + /* WARNING: caller must assure stack space */ + /* only userdata, tables and nil can have getglobal tag methods */ + static char valid_getglobals[] = {1, 0, 0, 1, 0, 0, 1, 0}; /* ORDER LUA_T */ + TObject *value = &ts->u.s.globalval; + if (valid_getglobals[-ttype(value)]) { + TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL); + if (ttype(im) != LUA_T_NIL) { /* is there a tag method? */ + struct Stack *S = &L->stack; + ttype(S->top) = LUA_T_STRING; + tsvalue(S->top) = ts; + S->top++; + *S->top++ = *value; + luaD_callTM(im, 2, 1); + return; + } + /* else no tag method: go through to default behavior */ + } + *L->stack.top++ = *value; /* default behavior */ +} + + +void luaV_setglobal (TaggedString *ts) { TObject *oldvalue = &ts->u.s.globalval; TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL); - if (ttype(im) == LUA_T_NIL) /* default behavior */ + if (ttype(im) == LUA_T_NIL) /* is there a tag method? */ luaS_rawsetglobal(ts, --L->stack.top); else { /* WARNING: caller must assure stack space */ struct Stack *S = &L->stack; - TObject newvalue = *(S->top-1); + TObject newvalue; + newvalue = *(S->top-1); ttype(S->top-1) = LUA_T_STRING; tsvalue(S->top-1) = ts; *S->top++ = *oldvalue; @@ -225,7 +247,7 @@ static void call_arith (IMS event) } -static int strcomp (char *l, long ll, char *r, long lr) +static int luaV_strcomp (char *l, long ll, char *r, long lr) { for (;;) { long temp = strcoll(l, r); @@ -242,18 +264,17 @@ static int strcomp (char *l, long ll, char *r, long lr) } } -static void comparison (lua_Type ttype_less, lua_Type ttype_equal, - lua_Type ttype_great, IMS op) -{ +void luaV_comparison (lua_Type ttype_less, lua_Type ttype_equal, + lua_Type ttype_great, IMS op) { struct Stack *S = &L->stack; TObject *l = S->top-2; TObject *r = S->top-1; - int result; + real result; if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER) - result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1; + result = nvalue(l)-nvalue(r); else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING) - result = strcomp(svalue(l), tsvalue(l)->u.s.len, - svalue(r), tsvalue(r)->u.s.len); + result = luaV_strcomp(svalue(l), tsvalue(l)->u.s.len, + svalue(r), tsvalue(r)->u.s.len); else { call_binTM(op, "unexpected type in comparison"); return; @@ -265,27 +286,16 @@ static void comparison (lua_Type ttype_less, lua_Type ttype_equal, } -void luaV_pack (StkId firstel, int nvararg, TObject *tab) -{ +void luaV_pack (StkId firstel, int nvararg, TObject *tab) { TObject *firstelem = L->stack.stack+firstel; int i; + Hash *htab; if (nvararg < 0) nvararg = 0; - avalue(tab) = luaH_new(nvararg+1); /* +1 for field 'n' */ + htab = avalue(tab) = luaH_new(nvararg+1); /* +1 for field 'n' */ ttype(tab) = LUA_T_ARRAY; - for (i=0; istack; /* to optimize */ - Byte *pc = tf->code; + register Byte *pc = tf->code; TObject *consts = tf->consts; - if (lua_callhook) + if (L->callhook) luaD_callHook(base, tf, 0); luaD_checkstack((*pc++)+EXTRA_STACK); if (*pc < ZEROVARARG) @@ -319,228 +328,159 @@ StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base) luaC_checkGC(); adjust_varargs(base+(*pc++)-ZEROVARARG); } - while (1) { - int aux; - switch ((OpCode)(aux = *pc++)) { + for (;;) { + register int aux = 0; + switchentry: + switch ((OpCode)*pc++) { + + case ENDCODE: + S->top = S->stack + base; + goto ret; + + case RETCODE: + base += *pc++; + goto ret; - case PUSHNIL0: - ttype(S->top++) = LUA_T_NIL; + case CALL: aux = *pc++; + luaD_calln(*pc++, aux); break; - case PUSHNIL: - aux = *pc++; + case TAILCALL: aux = *pc++; + luaD_calln(*pc++, MULT_RET); + base += aux; + goto ret; + + case PUSHNIL: aux = *pc++; do { ttype(S->top++) = LUA_T_NIL; } while (aux--); break; - case PUSHNUMBER: - aux = *pc++; goto pushnumber; - - case PUSHNUMBERW: - aux = next_word(pc); goto pushnumber; + case POP: aux = *pc++; + S->top -= aux; + break; - case PUSHNUMBER0: case PUSHNUMBER1: case PUSHNUMBER2: - aux -= PUSHNUMBER0; - pushnumber: + case PUSHNUMBERW: aux += highbyte(*pc++); + case PUSHNUMBER: aux += *pc++; ttype(S->top) = LUA_T_NUMBER; nvalue(S->top) = aux; S->top++; break; - case PUSHLOCAL: - aux = *pc++; goto pushlocal; + case PUSHNUMBERNEGW: aux += highbyte(*pc++); + case PUSHNUMBERNEG: aux += *pc++; + ttype(S->top) = LUA_T_NUMBER; + nvalue(S->top) = -aux; + S->top++; + break; - case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: - case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: - aux -= PUSHLOCAL0; - pushlocal: - *S->top++ = *((S->stack+base) + aux); + case PUSHCONSTANTW: aux += highbyte(*pc++); + case PUSHCONSTANT: aux += *pc++; + *S->top++ = consts[aux]; break; - case GETGLOBALW: - aux = next_word(pc); goto getglobal; + case PUSHUPVALUE: aux = *pc++; + *S->top++ = cl->consts[aux+1]; + break; - case GETGLOBAL: - aux = *pc++; goto getglobal; + case PUSHLOCAL: aux = *pc++; + *S->top++ = *((S->stack+base) + aux); + break; - case GETGLOBAL0: case GETGLOBAL1: case GETGLOBAL2: case GETGLOBAL3: - case GETGLOBAL4: case GETGLOBAL5: case GETGLOBAL6: case GETGLOBAL7: - aux -= GETGLOBAL0; - getglobal: + case GETGLOBALW: aux += highbyte(*pc++); + case GETGLOBAL: aux += *pc++; luaV_getglobal(tsvalue(&consts[aux])); break; case GETTABLE: - luaV_gettable(); - break; - - case GETDOTTEDW: - aux = next_word(pc); goto getdotted; - - case GETDOTTED: - aux = *pc++; goto getdotted; + luaV_gettable(); + break; - case GETDOTTED0: case GETDOTTED1: case GETDOTTED2: case GETDOTTED3: - case GETDOTTED4: case GETDOTTED5: case GETDOTTED6: case GETDOTTED7: - aux -= GETDOTTED0; - getdotted: + case GETDOTTEDW: aux += highbyte(*pc++); + case GETDOTTED: aux += *pc++; *S->top++ = consts[aux]; luaV_gettable(); break; - case PUSHSELFW: - aux = next_word(pc); goto pushself; - - case PUSHSELF: - aux = *pc++; goto pushself; - - case PUSHSELF0: case PUSHSELF1: case PUSHSELF2: case PUSHSELF3: - case PUSHSELF4: case PUSHSELF5: case PUSHSELF6: case PUSHSELF7: - aux -= PUSHSELF0; - pushself: { - TObject receiver = *(S->top-1); + case PUSHSELFW: aux += highbyte(*pc++); + case PUSHSELF: aux += *pc++; { + TObject receiver; + receiver = *(S->top-1); *S->top++ = consts[aux]; luaV_gettable(); *S->top++ = receiver; break; } - case PUSHCONSTANTW: - aux = next_word(pc); goto pushconstant; - - case PUSHCONSTANT: - aux = *pc++; goto pushconstant; - - case PUSHCONSTANT0: case PUSHCONSTANT1: case PUSHCONSTANT2: - case PUSHCONSTANT3: case PUSHCONSTANT4: case PUSHCONSTANT5: - case PUSHCONSTANT6: case PUSHCONSTANT7: - aux -= PUSHCONSTANT0; - pushconstant: - *S->top++ = consts[aux]; - break; - - case PUSHUPVALUE: - aux = *pc++; goto pushupvalue; - - case PUSHUPVALUE0: case PUSHUPVALUE1: - aux -= PUSHUPVALUE0; - pushupvalue: - *S->top++ = cl->consts[aux+1]; + case CREATEARRAYW: aux += highbyte(*pc++); + case CREATEARRAY: aux += *pc++; + luaC_checkGC(); + avalue(S->top) = luaH_new(aux); + ttype(S->top) = LUA_T_ARRAY; + S->top++; break; - case SETLOCAL: - aux = *pc++; goto setlocal; - - case SETLOCAL0: case SETLOCAL1: case SETLOCAL2: case SETLOCAL3: - case SETLOCAL4: case SETLOCAL5: case SETLOCAL6: case SETLOCAL7: - aux -= SETLOCAL0; - setlocal: + case SETLOCAL: aux = *pc++; *((S->stack+base) + aux) = *(--S->top); break; - case SETGLOBALW: - aux = next_word(pc); goto setglobal; - - case SETGLOBAL: - aux = *pc++; goto setglobal; - - case SETGLOBAL0: case SETGLOBAL1: case SETGLOBAL2: case SETGLOBAL3: - case SETGLOBAL4: case SETGLOBAL5: case SETGLOBAL6: case SETGLOBAL7: - aux -= SETGLOBAL0; - setglobal: + case SETGLOBALW: aux += highbyte(*pc++); + case SETGLOBAL: aux += *pc++; luaV_setglobal(tsvalue(&consts[aux])); break; - case SETTABLE0: - luaV_settable(S->top-3, 1); - break; + case SETTABLEPOP: + luaV_settable(S->top-3); + S->top -= 2; /* pop table and index */ + break; case SETTABLE: - luaV_settable(S->top-3-(*pc++), 2); + luaV_settable(S->top-3-(*pc++)); break; - case SETLISTW: - aux = next_word(pc); aux *= LFIELDS_PER_FLUSH; goto setlist; - - case SETLIST: - aux = *(pc++) * LFIELDS_PER_FLUSH; goto setlist; - - case SETLIST0: - aux = 0; - setlist: { + case SETLISTW: aux += highbyte(*pc++); + case SETLIST: aux += *pc++; { int n = *(pc++); - TObject *arr = S->top-n-1; - for (; n; n--) { - ttype(S->top) = LUA_T_NUMBER; - nvalue(S->top) = n+aux; - *(luaH_set(avalue(arr), S->top)) = *(S->top-1); - S->top--; - } + Hash *arr = avalue(S->top-n-1); + aux *= LFIELDS_PER_FLUSH; + for (; n; n--) + luaH_setint(arr, n+aux, --S->top); break; } - case SETMAP0: - aux = 0; goto setmap; - - case SETMAP: - aux = *pc++; - setmap: { - TObject *arr = S->top-(2*aux)-3; + case SETMAP: aux = *pc++; { + Hash *arr = avalue(S->top-(2*aux)-3); do { - *(luaH_set(avalue(arr), S->top-2)) = *(S->top-1); + luaH_set(arr, S->top-2, S->top-1); S->top-=2; } while (aux--); break; } - case POP: - aux = *pc++; goto pop; - - case POP0: case POP1: - aux -= POP0; - pop: - S->top -= (aux+1); - break; - - case CREATEARRAYW: - aux = next_word(pc); goto createarray; - - case CREATEARRAY0: case CREATEARRAY1: - aux -= CREATEARRAY0; goto createarray; - - case CREATEARRAY: - aux = *pc++; - createarray: - luaC_checkGC(); - avalue(S->top) = luaH_new(aux); - ttype(S->top) = LUA_T_ARRAY; - S->top++; - break; - - case EQOP: case NEQOP: { + case NEQOP: aux = 1; + case EQOP: { int res = luaO_equalObj(S->top-2, S->top-1); + if (aux) res = !res; S->top--; - if (aux == NEQOP) res = !res; ttype(S->top-1) = res ? LUA_T_NUMBER : LUA_T_NIL; nvalue(S->top-1) = 1; break; } case LTOP: - comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); + luaV_comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); break; case LEOP: - comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); + luaV_comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); break; case GTOP: - comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); + luaV_comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); break; case GEOP: - comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); + luaV_comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); break; case ADDOP: { @@ -624,98 +564,47 @@ StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base) nvalue(S->top-1) = 1; break; - case ONTJMPW: - aux = next_word(pc); goto ontjmp; - - case ONTJMP: - aux = *pc++; - ontjmp: + case ONTJMPW: aux += highbyte(*pc++); + case ONTJMP: aux += *pc++; if (ttype(S->top-1) != LUA_T_NIL) pc += aux; else S->top--; break; - case ONFJMPW: - aux = next_word(pc); goto onfjmp; - - case ONFJMP: - aux = *pc++; - onfjmp: + case ONFJMPW: aux += highbyte(*pc++); + case ONFJMP: aux += *pc++; if (ttype(S->top-1) == LUA_T_NIL) pc += aux; else S->top--; break; - case JMPW: - aux = next_word(pc); goto jmp; - - case JMP: - aux = *pc++; - jmp: + case JMPW: aux += highbyte(*pc++); + case JMP: aux += *pc++; pc += aux; break; - case IFFJMPW: - aux = next_word(pc); goto iffjmp; - - case IFFJMP: - aux = *pc++; - iffjmp: + case IFFJMPW: aux += highbyte(*pc++); + case IFFJMP: aux += *pc++; if (ttype(--S->top) == LUA_T_NIL) pc += aux; break; - case IFTUPJMPW: - aux = next_word(pc); goto iftupjmp; - - case IFTUPJMP: - aux = *pc++; - iftupjmp: + case IFTUPJMPW: aux += highbyte(*pc++); + case IFTUPJMP: aux += *pc++; if (ttype(--S->top) != LUA_T_NIL) pc -= aux; break; - case IFFUPJMPW: - aux = next_word(pc); goto iffupjmp; - - case IFFUPJMP: - aux = *pc++; - iffupjmp: + case IFFUPJMPW: aux += highbyte(*pc++); + case IFFUPJMP: aux += *pc++; if (ttype(--S->top) == LUA_T_NIL) pc -= aux; break; - case CLOSUREW: - aux = next_word(pc); goto closure; - - case CLOSURE: - aux = *pc++; - closure: + case CLOSUREW: aux += highbyte(*pc++); + case CLOSURE: aux += *pc++; *S->top++ = consts[aux]; luaV_closure(*pc++); luaC_checkGC(); break; - case CALLFUNC: - aux = *pc++; goto callfunc; - - case CALLFUNC0: case CALLFUNC1: - aux -= CALLFUNC0; - callfunc: { - StkId newBase = (S->top-S->stack)-(*pc++); - luaD_call(newBase, aux); - break; - } - - case ENDCODE: - S->top = S->stack + base; - /* goes through */ - case RETCODE: - if (lua_callhook) - luaD_callHook(base, NULL, 1); - return (base + ((aux==RETCODE) ? *pc : 0)); - - case SETLINEW: - aux = next_word(pc); goto setline; - - case SETLINE: - aux = *pc++; - setline: + case SETLINEW: aux += highbyte(*pc++); + case SETLINE: aux += *pc++; if ((S->stack+base-1)->ttype != LUA_T_LINE) { /* open space for LINE value */ luaD_openstack((S->top-S->stack)-base); @@ -723,15 +612,24 @@ StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base) (S->stack+base-1)->ttype = LUA_T_LINE; } (S->stack+base-1)->value.i = aux; - if (lua_linehook) + if (L->linehook) luaD_lineHook(aux); break; -#ifdef DEBUG - default: - LUA_INTERNALERROR("opcode doesn't match"); -#endif + case LONGARGW: aux += highbyte(*pc++); + case LONGARG: aux += *pc++; + aux = highbyte(highbyte(aux)); + goto switchentry; /* do not reset "aux" */ + + case CHECKSTACK: aux = *pc++; + LUA_ASSERT((S->top-S->stack)-base == aux && S->last >= S->top, + "wrong stack size"); + break; + } - } + } ret: + if (L->callhook) + luaD_callHook(0, NULL, 1); + return base; } diff --git a/src/lvm.h b/src/lvm.h index 9b3f900913..d6a639e2c9 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 1.4 1997/12/15 16:17:20 roberto Exp $ +** $Id: lvm.h,v 1.8 1999/02/08 17:07:59 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include "ldo.h" #include "lobject.h" +#include "ltm.h" #define tonumber(o) ((ttype(o) != LUA_T_NUMBER) && (luaV_tonumber(o) != 0)) @@ -19,11 +20,15 @@ void luaV_pack (StkId firstel, int nvararg, TObject *tab); int luaV_tonumber (TObject *obj); int luaV_tostring (TObject *obj); +void luaV_setn (Hash *t, int val); void luaV_gettable (void); -void luaV_settable (TObject *t, int mode); +void luaV_settable (TObject *t); +void luaV_rawsettable (TObject *t); void luaV_getglobal (TaggedString *ts); void luaV_setglobal (TaggedString *ts); StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base); void luaV_closure (int nelems); +void luaV_comparison (lua_Type ttype_less, lua_Type ttype_equal, + lua_Type ttype_great, IMS op); #endif diff --git a/src/lzio.c b/src/lzio.c index 0ab1adf41d..865d9c5eb6 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.3 1997/12/22 20:57:18 roberto Exp $ +** $Id: lzio.c,v 1.7 1999/03/05 13:15:50 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -15,11 +15,11 @@ /* ----------------------------------------------------- memory buffers --- */ -static int zmfilbuf (ZIO* z) -{ +static int zmfilbuf (ZIO* z) { return EOZ; } + ZIO* zmopen (ZIO* z, char* b, int size, char *name) { if (b==NULL) return NULL; @@ -41,9 +41,10 @@ ZIO* zsopen (ZIO* z, char* s, char *name) /* -------------------------------------------------------------- FILEs --- */ -static int zffilbuf (ZIO* z) -{ - int n=fread(z->buffer,1,ZBSIZE,z->u); +static int zffilbuf (ZIO* z) { + int n; + if (feof((FILE *)z->u)) return EOZ; + n=fread(z->buffer,1,ZBSIZE,z->u); if (n==0) return EOZ; z->n=n-1; z->p=z->buffer; @@ -64,16 +65,15 @@ ZIO* zFopen (ZIO* z, FILE* f, char *name) /* --------------------------------------------------------------- read --- */ -int zread (ZIO *z, void *b, int n) -{ +int zread (ZIO *z, void *b, int n) { while (n) { int m; if (z->n == 0) { if (z->filbuf(z) == EOZ) - return n; /* retorna quantos faltaram ler */ - zungetc(z); /* poe o resultado de filbuf no buffer */ + return n; /* return number of missing bytes */ + zungetc(z); /* put result from 'filbuf' in the buffer */ } - m = (n <= z->n) ? n : z->n; /* minimo de n e z->n */ + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; z->p += m; From e7eacfb8851d87e681e6f5a1fbead87565b4aa46 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Thu, 25 Nov 1999 12:00:00 +0000 Subject: [PATCH 10/97] Lua 3.2.1 --- include/lua.h | 4 ++-- src/lparser.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/lua.h b/include/lua.h index f46b2e1d6b..5635a550bf 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.32 1999/05/11 20:29:19 roberto Exp $ +** $Id: lua.h,v 1.32a 1999/05/11 20:29:19 roberto Exp $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -11,7 +11,7 @@ #ifndef lua_h #define lua_h -#define LUA_VERSION "Lua 3.2" +#define LUA_VERSION "Lua 3.2.1" #define LUA_COPYRIGHT "Copyright (C) 1994-1999 TeCGraf, PUC-Rio" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" diff --git a/src/lparser.c b/src/lparser.c index c18b75cc28..b0aa13f5ac 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.37 1999/06/17 17:04:03 roberto Exp $ +** $Id: lparser.c,v 1.37a 1999/06/17 17:04:03 roberto Exp $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -665,7 +665,8 @@ static int checkname (LexState *ls) { static TaggedString *str_checkname (LexState *ls) { - return tsvalue(&ls->fs->f->consts[checkname(ls)]); + int i = checkname(ls); /* this call may realloc `f->consts' */ + return tsvalue(&ls->fs->f->consts[i]); } From b7610da5fed99f59ac73ae452da8839a0f2c1bda Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 22 Feb 2000 12:00:00 +0000 Subject: [PATCH 11/97] Lua 3.2.2 --- include/lua.h | 4 ++-- src/lapi.c | 3 ++- src/ldo.c | 8 +++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/lua.h b/include/lua.h index 5635a550bf..03ebe7d036 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.32a 1999/05/11 20:29:19 roberto Exp $ +** $Id: lua.h,v 1.32b 1999/05/11 20:29:19 roberto Exp $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -11,7 +11,7 @@ #ifndef lua_h #define lua_h -#define LUA_VERSION "Lua 3.2.1" +#define LUA_VERSION "Lua 3.2.2" #define LUA_COPYRIGHT "Copyright (C) 1994-1999 TeCGraf, PUC-Rio" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" diff --git a/src/lapi.c b/src/lapi.c index 0a5b99db52..16bd9ff936 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.47 1999/06/22 20:37:23 roberto Exp $ +** $Id: lapi.c,v 1.47b 1999/06/22 20:37:23 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -179,6 +179,7 @@ lua_Object lua_rawgettable (void) { void lua_settable (void) { checkCparams(3); + luaD_checkstack(3); /* may need that to call T.M. */ luaV_settable(L->stack.top-3); L->stack.top -= 2; /* pop table and index */ } diff --git a/src/ldo.c b/src/ldo.c index bf840bf4b7..281a4ec4da 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.45 1999/06/22 20:37:23 roberto Exp $ +** $Id: ldo.c,v 1.45b 1999/06/22 20:37:23 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -357,12 +357,14 @@ int lua_dofile (char *filename) { FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); if (f == NULL) return 2; + luaL_filesource(source, filename, sizeof(source)); c = fgetc(f); ungetc(c, f); bin = (c == ID_CHUNK); - if (bin) + if (bin && f != stdin) { f = freopen(filename, "rb", f); /* set binary mode */ - luaL_filesource(source, filename, sizeof(source)); + if (f == NULL) return 2; + } luaZ_Fopen(&z, f, source); status = do_main(&z, bin); if (f != stdin) From 8cb71cb5548e3138e5d4e4744f52c79d9fafb116 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Mon, 6 Nov 2000 12:00:00 +0000 Subject: [PATCH 12/97] Lua 4.0 --- COPYRIGHT | 29 +- HISTORY | 32 +- INSTALL | 57 +- MANIFEST | 41 +- Makefile | 36 +- README | 60 +- config | 70 +- doc/idx.html | 577 +++-- doc/index.html | 74 +- doc/logo.gif | Bin 0 -> 2750 bytes doc/lua.1 | 143 ++ doc/lua.html | 151 ++ doc/luac.1 | 139 ++ doc/luac.html | 149 +- doc/luac.man | 188 -- doc/manual.html | 4237 +++++++++++++++++++--------------- doc/readme.html | 23 +- etc/Makefile | 32 +- etc/README | 41 +- etc/bin2c.c | 6 +- etc/def.lua | 9 + etc/lua.ico | Bin 0 -> 1078 bytes etc/lua.magic | 10 + etc/lua.xpm | 44 + etc/min.c | 25 +- etc/stdcall.lua | 10 + etc/trace.c | 35 +- include/Makefile | 2 +- include/lauxlib.h | 115 +- include/lua.h | 247 +- include/luadebug.h | 40 +- include/lualib.h | 26 +- src/Makefile | 18 +- src/lapi.c | 796 +++---- src/lapi.h | 11 +- src/lauxlib.c | 133 -- src/lbuffer.c | 75 - src/lbuiltin.c | 736 ------ src/lbuiltin.h | 14 - src/lcode.c | 701 ++++++ src/lcode.h | 70 + src/ldebug.c | 466 ++++ src/ldebug.h | 21 + src/ldo.c | 544 +++-- src/ldo.h | 33 +- src/lfunc.c | 121 +- src/lfunc.h | 15 +- src/lgc.c | 442 ++-- src/lgc.h | 9 +- src/lib/Makefile | 6 +- src/lib/README | 6 +- src/lib/lauxlib.c | 216 ++ src/lib/lbaselib.c | 651 ++++++ src/lib/ldblib.c | 277 +-- src/lib/linit.c | 17 - src/lib/liolib.c | 729 +++--- src/lib/lmathlib.c | 193 +- src/lib/lstrlib.c | 503 ++-- src/llex.c | 495 ++-- src/llex.h | 70 +- src/llimits.h | 204 ++ src/lmem.c | 178 +- src/lmem.h | 45 +- src/lobject.c | 170 +- src/lobject.h | 250 +- src/lopcodes.h | 210 +- src/lparser.c | 1912 +++++++-------- src/lparser.h | 50 +- src/lstate.c | 153 +- src/lstate.h | 87 +- src/lstring.c | 335 +-- src/lstring.h | 35 +- src/ltable.c | 336 ++- src/ltable.h | 34 +- src/ltests.c | 543 +++++ src/ltm.c | 271 +-- src/ltm.h | 71 +- src/lua/Makefile | 4 +- src/lua/README | 50 +- src/lua/lua.c | 314 ++- src/luac/Makefile | 6 +- src/luac/README | 34 +- src/luac/dump.c | 173 +- src/luac/luac.c | 252 +- src/luac/luac.h | 37 +- src/luac/opcode.c | 102 - src/luac/opcode.h | 70 - src/luac/opt.c | 326 +-- src/luac/print.c | 252 +- src/luac/print.h | 55 + src/luac/stubs.c | 176 +- src/luac/test.c | 253 -- src/lundump.c | 303 +-- src/lundump.h | 28 +- src/lvm.c | 1023 ++++---- src/lvm.h | 28 +- src/lzio.c | 68 +- src/lzio.h | 27 +- test/array.lua | 13 - test/bisect.lua | 3 + test/cf-for.lua | 19 + test/examples/ps/hilbert.lua | 2 - test/examples/www/staff.lua | 8 +- test/fib.lua | 30 +- test/globals.lua | 13 +- test/life.lua | 121 + test/lisp.lua | 22 + test/old.lua | 42 + test/qp.lua | 6 + test/save.lua | 13 +- test/sort.lua | 5 +- test/table.lua | 7 + test/trace-calls.lua | 23 + test/trace-globals.lua | 75 + test/trace.lua | 33 - test/undefined.lua | 20 + test/webform.lua | 8 + 117 files changed, 12839 insertions(+), 10105 deletions(-) create mode 100644 doc/logo.gif create mode 100644 doc/lua.1 create mode 100644 doc/lua.html create mode 100644 doc/luac.1 delete mode 100644 doc/luac.man create mode 100644 etc/def.lua create mode 100644 etc/lua.ico create mode 100644 etc/lua.magic create mode 100644 etc/lua.xpm create mode 100644 etc/stdcall.lua delete mode 100644 src/lauxlib.c delete mode 100644 src/lbuffer.c delete mode 100644 src/lbuiltin.c delete mode 100644 src/lbuiltin.h create mode 100644 src/lcode.c create mode 100644 src/lcode.h create mode 100644 src/ldebug.c create mode 100644 src/ldebug.h create mode 100644 src/lib/lauxlib.c create mode 100644 src/lib/lbaselib.c delete mode 100644 src/lib/linit.c create mode 100644 src/llimits.h create mode 100644 src/ltests.c delete mode 100644 src/luac/opcode.c delete mode 100644 src/luac/opcode.h create mode 100644 src/luac/print.h delete mode 100644 src/luac/test.c delete mode 100644 test/array.lua create mode 100644 test/cf-for.lua create mode 100644 test/life.lua create mode 100644 test/lisp.lua create mode 100644 test/old.lua create mode 100644 test/qp.lua create mode 100644 test/table.lua create mode 100644 test/trace-calls.lua create mode 100644 test/trace-globals.lua delete mode 100644 test/trace.lua create mode 100644 test/undefined.lua create mode 100644 test/webform.lua diff --git a/COPYRIGHT b/COPYRIGHT index 65c64ac3be..eef88b050c 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,4 +1,4 @@ -Lua COPYRIGHT NOTICE +Lua Copyright Notice -------------------- Lua is free and non-proprietary. @@ -8,44 +8,47 @@ Lua (probably) qualifies as Open Source software. Nevertheless, Lua is not in the public domain and TeCGraf keeps its copyright. If you use Lua, please give us credit (a nice way to do this is to include a -logo in a web page for your product), but we would appreciate *not* receiving -lengthy legal documents to sign. +Lua logo in a web page for your product), but we would appreciate *not* +receiving lengthy legal documents to sign. The legal details are below. =============================================================================== -Copyright (c) 1994-1999 TeCGraf, PUC-Rio. All rights reserved. +Copyright (C) 1994-2000 TeCGraf, PUC-Rio. All rights reserved. Permission is hereby granted, without written agreement and without license -or royalty fees, to use, copy, modify, and distribute this software and its -documentation for any purpose, including commercial applications, subject to +or royalty fees, to use, copy, modify, translate, and distribute +this software and its documentation (hereby called the "package") +for any purpose, including commercial applications, subject to the following conditions: * The above copyright notice and this permission notice shall appear in all - copies or substantial portions of this software. + copies or substantial portions of this package. - * The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a + * The origin of this package must not be misrepresented; you must not + claim that you wrote the original package. If you use this package in a product, an acknowledgment in the product documentation would be greatly appreciated (but it is not required). * Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. + misrepresented as being the original package. The authors specifically disclaim any warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular -purpose. The software provided hereunder is on an "as is" basis, and the +purpose. The package provided hereunder is on an "as is" basis, and the authors have no obligation to provide maintenance, support, updates, enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the authors be held liable to any party for direct, indirect, special, -incidental, or consequential damages arising out of the use of this software +incidental, or consequential damages arising out of the use of this package and its documentation. The Lua language and this implementation have been entirely designed and written by Waldemar Celes, Roberto Ierusalimschy, and Luiz Henrique de Figueiredo -at TeCGraf, PUC-Rio. +at TeCGraf, PUC-Rio in Brazil. This implementation contains no third-party code. =============================================================================== + +(end of COPYRIGHT) diff --git a/HISTORY b/HISTORY index b01a4c41c3..10b033ae3d 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,32 @@ -This is Lua 3.2 +This is Lua 4.0. + +* Changes from version 3.2 to 4.0 + ------------------------------- + Language: + + new "break" and "for" statements (both numerical and for tables). + + uniform treatment of globals: globals are now stored in a Lua table. + + improved error messages. + + no more '$debug': full speed *and* full debug information. + + new read form: read(N) for next N bytes. + + general read patterns now deprecated. + (still available with -DCOMPAT_READPATTERNS.) + + all return values are passed as arguments for the last function + (old semantics still available with -DLUA_COMPAT_ARGRET) + + garbage collection tag methods for tables now deprecated. + + there is now only one tag method for order. + API: + + New API: fully re-entrant, simpler, and more efficient. + + New debug API. + Implementation: + + cleaner virtual machine -- at least 20% faster. + + non-recursive garbage-collector algorithm. + + reduced memory usage for programs with many strings. + + improved treatment for memory allocation errors. + + improved support for 16-bit machines (we hope). + + code now compiles unmodified as both ANSI C and C++. + + numbers in bases other than 10 are converted using strtoul. + + new -f option in Lua to support #! scripts. + + luac can now combine text and binaries. * Changes from version 3.1 to 3.2 ------------------------------- @@ -79,3 +107,5 @@ This is Lua 3.2 + fallbacks + simplified syntax for tables + many internal improvements + +(end of HISTORY) diff --git a/INSTALL b/INSTALL index 1c5b924229..e31eefad29 100644 --- a/INSTALL +++ b/INSTALL @@ -1,11 +1,14 @@ -This is Lua 3.2 +This is Lua 4.0. * Installation ------------ Building Lua on a Unix system should be very easy: 1. Edit "config" to suit your platform, if at all necessary. - 2. Then, type "make". + 2. Do "make". + 3. If you want to install Lua in an "official" place in your system, + then do "make install". The official place and the way to install + files are defined in "config". You may have to be root to do this. See below for instructions for Windows and Macintosh. @@ -17,55 +20,53 @@ This is Lua 3.2 * include files in ./include. These are the only directories you need for development. - There is a reference manual in html in ./doc, some sample code in ./test, - and some useful stuff in ./etc. - You don't need these directories for development. + There man pages for lua and luac in both nroff and html, and a reference + manual in html in ./doc, some sample code in ./test, and some useful stuff + in ./etc. You don't need these directories for development. See also the README files in the various subdirectories. - A convenient staring point is ./doc/readme.html. + A convenient starting point is ./doc/readme.html. * If you have problems (and solutions!) ------------------------------------- If "make" fails, please let us know (lua@tecgraf.puc-rio.br). - If you make changes to "config", please send them to us. + If you make changes to "config" or to the Makefiles, please send them to us. * Shared libraries ---------------- - If you are running SunOs 4.x, type the following after "make" succeeds: - ld -o lib/liblua.so.3.2 src/*.o - ld -o lib/liblualib.so.3.2 src/lib/*.o + If you are running Linux, do "make so" after "make" succeeds. + This will create shared libraries in ./lib. It's probably better to + build shared libraries before "make install". - If you are running Linux, type the following after "make" succeeds: - ld -o lib/liblua.so.3.2 -shared src/*.o - ld -o lib/liblualib.so.3.2 -shared src/lib/*.o - cd lib - ln -s liblua.so.3.2 liblua.so - ln -s liblualib.so.3.2 liblualib.so.3.2 + If you want the interpreter and the compiler to use shared libraries, + then do "make sobin" too. - If you want the interpreter to use shared libraries, then do this too: - rm bin/lua - cd src/lua; make - You may need to include lib/ in the LD_LIBRAY_PATH environment variable. + You may need to include lib/ in the LD_LIBRAY_PATH environment variable + to link programs that use the shared libraries if you don't put them in + the "official" places with "make install". - Building shared libraries in other systems is similar but details differ. + Building shared libraries in other systems is similar but details differ; + you may need to fix a few details in the top-level Makefile. * Installation on Windows or Macintosh ------------------------------------ The instructions for building Lua on a Mac or Windows machine depend on the particular compiler you are using. The simplest way is to create a folder with all .c and .h files. - Then create projects for the basic library, the standard library, - the interpreter and the compiler, as follows: + Then create projects for the core library, the standard library, + the interpreter, and the compiler, as follows: - basic lib: lapi.c lauxlib.c lbuffer.c lbuiltin.c ldo.c lfunc.c lgc.c - llex.c lmem.c lobject.c lparser.c lstate.c lstring.c ltable.c + core lib: lapi.c lcode.c ldebug.c ldo.c lfunc.c lgc.c llex.c lmem.c + lobject.c lparser.c lstate.c lstring.c ltable.c ltests.c ltm.c lundump.c lvm.c lzio.c - standard lib: linit.c ldblib.c liolib.c lmathlib.c lstrlib.c + standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c - interpreter: basic lib, standard lib, lua.c + interpreter: core lib, standard lib, lua.c - compiler: basic lib, dump.c luac.c opcode.c opt.c print.c stubs.c test.c + compiler: core lib, dump.c luac.c opt.c print.c stubs.c Of course, to use Lua as a library, you'll have to know how to create and use libraries with your compiler. + +(end of INSTALL) diff --git a/MANIFEST b/MANIFEST index 3b2aec5645..d7dfbc5473 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,4 +1,4 @@ -MANIFEST contents of Lua 3.2 distribution on Thu Jul 8 10:34:45 EST 1999 +MANIFEST contents of Lua 4.0 distribution on Mon Nov 6 19:15:16 EDT 2000 lua lua/COPYRIGHT lua/HISTORY @@ -11,16 +11,24 @@ lua/config lua/doc lua/doc/idx.html lua/doc/index.html +lua/doc/logo.gif +lua/doc/lua.1 +lua/doc/lua.html +lua/doc/luac.1 lua/doc/luac.html -lua/doc/luac.man lua/doc/manual.html lua/doc/readme.html lua/etc lua/etc/Makefile lua/etc/README lua/etc/bin2c.c +lua/etc/def.lua +lua/etc/lua.ico +lua/etc/lua.magic +lua/etc/lua.xpm lua/etc/min.c lua/etc/setfallback.lua +lua/etc/stdcall.lua lua/etc/trace.c lua/include lua/include/Makefile @@ -33,10 +41,10 @@ lua/src lua/src/Makefile lua/src/lapi.c lua/src/lapi.h -lua/src/lauxlib.c -lua/src/lbuffer.c -lua/src/lbuiltin.c -lua/src/lbuiltin.h +lua/src/lcode.c +lua/src/lcode.h +lua/src/ldebug.c +lua/src/ldebug.h lua/src/ldo.c lua/src/ldo.h lua/src/lfunc.c @@ -46,13 +54,15 @@ lua/src/lgc.h lua/src/lib lua/src/lib/Makefile lua/src/lib/README +lua/src/lib/lauxlib.c +lua/src/lib/lbaselib.c lua/src/lib/ldblib.c -lua/src/lib/linit.c lua/src/lib/liolib.c lua/src/lib/lmathlib.c lua/src/lib/lstrlib.c lua/src/llex.c lua/src/llex.h +lua/src/llimits.h lua/src/lmem.c lua/src/lmem.h lua/src/lobject.c @@ -66,6 +76,7 @@ lua/src/lstring.c lua/src/lstring.h lua/src/ltable.c lua/src/ltable.h +lua/src/ltests.c lua/src/ltm.c lua/src/ltm.h lua/src/lua @@ -78,12 +89,10 @@ lua/src/luac/README lua/src/luac/dump.c lua/src/luac/luac.c lua/src/luac/luac.h -lua/src/luac/opcode.c -lua/src/luac/opcode.h lua/src/luac/opt.c lua/src/luac/print.c +lua/src/luac/print.h lua/src/luac/stubs.c -lua/src/luac/test.c lua/src/lundump.c lua/src/lundump.h lua/src/lvm.c @@ -92,8 +101,8 @@ lua/src/lzio.c lua/src/lzio.h lua/test lua/test/README -lua/test/array.lua lua/test/bisect.lua +lua/test/cf-for.lua lua/test/cf.lua lua/test/examples lua/test/examples/ps @@ -108,9 +117,17 @@ lua/test/factorial.lua lua/test/fib.lua lua/test/globals.lua lua/test/hello.lua +lua/test/life.lua +lua/test/lisp.lua lua/test/lua lua/test/luac +lua/test/old.lua +lua/test/qp.lua lua/test/save.lua lua/test/sort.lua -lua/test/trace.lua +lua/test/table.lua +lua/test/trace-calls.lua +lua/test/trace-globals.lua +lua/test/undefined.lua +lua/test/webform.lua END OF MANIFEST diff --git a/Makefile b/Makefile index bd67221b0e..adf018f2cb 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,41 @@ -# makefile for lua hierarchy +# makefile for Lua hierarchy +# see INSTALL for installation instructions +# see file "config" for customization instructions -all co clean klean: +LUA= . + +include $(LUA)/config + +# primary targets (only "all" and "clean" are useful after distribution) +all clean co klean: cd include; $(MAKE) $@ cd src; $(MAKE) $@ cd src/luac; $(MAKE) $@ cd src/lib; $(MAKE) $@ cd src/lua; $(MAKE) $@ +# remove debug information from binaries strip: - strip bin/lua* + strip bin/lua bin/luac + +# official installation +install: all strip + mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) + $(INSTALL_EXEC) bin/* $(INSTALL_BIN) + $(INSTALL_DATA) include/*.h $(INSTALL_INC) + $(INSTALL_DATA) lib/lib* $(INSTALL_LIB) + $(INSTALL_DATA) doc/*.1 $(INSTALL_MAN) + +# shared libraries (for Linux) +so: + ld -o lib/liblua.so.$V -shared src/*.o + ld -o lib/liblualib.so.$V -shared src/lib/*.o + cd lib; ln -s liblua.so.$V liblua.so; ln -s liblualib.so.$V liblualib.so + +# binaries using shared libraries +sobin: + rm -f bin/lua bin/luac + cd src/lua; $(MAKE) + cd src/luac; $(MAKE) + +# (end of Makefile) diff --git a/README b/README index 07896c24a9..81f767aee8 100644 --- a/README +++ b/README @@ -1,37 +1,53 @@ -This is Lua 3.2 +This is Lua 4.0. +See HISTORY for a summary of changes since the last version. * What is Lua? ------------ - Lua is a programming language originally designed for extending applications, - but also frequently used as a general-purpose, stand-alone language. + Lua is a powerful, light-weight programming language designed for extending + applications. Lua is also frequently used as a general-purpose, stand-alone + language. + Lua combines simple procedural syntax (similar to Pascal) with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, interpreted from bytecodes, and has automatic memory management, making it ideal for configuration, scripting, and rapid prototyping. + Lua is a language engine that you can embed into your application. + This means that, besides syntax and semantics, Lua has an API that + allows the application to exchange data with Lua programs and also to + extend Lua with C functions. In this sense, Lua can be regarded as a + language framework for building domain-specific languages. + Lua is implemented as a small library of C functions, written in ANSI C, and compiles unmodified in all known platforms. The implementation goals are simplicity, efficiency, portability, and low embedding cost. + The result is a fast language engine with small footprint, making it + ideal in embedded systems too. - Lua was awarded the first prize (technological category) in the Second Compaq - Award for Research and Development in Computer Science in 1997. This award - is a joint venture of Compaq Computer in Brazil, the Brazilian Ministry of - Science and Technology, and the Brazilian Academy of Sciences. + Lua was awarded the first prize (technological category) in the + Second Compaq Award for Research and Development in Computer Science in 1997. + This award was a joint venture of Compaq Computer in Brazil, the Brazilian + Ministry of Science and Technology, and the Brazilian Academy of Sciences. + + Lua has been used in many different projects around the world. + For a short list, see http://www.tecgraf.puc-rio.br/lua/uses.html . * Availability ------------ Lua is freely available for both academic and commercial purposes and can be downloaded from the sites below. See COPYRIGHT for details. - Home page: http://www.tecgraf.puc-rio.br/lua/ - http://csg.uwaterloo.ca/~lhf/lua/ - In Brazil: ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz - In Canada: ftp://csg.uwaterloo.ca/pub/lhf/lua/lua.tar.gz - In the US: ftp://ftp.cdrom.com/pub/languages/lua/lua.tar.gz - In Germany: ftp://ftp.uni-trier.de/pub/languages/lua/lua.tar.gz - In Germany: ftp://ftp.gwdg.de/pub/languages/lua/lua.tar.gz - In Greece: ftp://ftp.ntua.gr/pub/lang/lua/lua.tar.gz + Home page: http://www.tecgraf.puc-rio.br/lua/ + http://csg.uwaterloo.ca/~lhf/lua/ + In Brazil: ftp://ftp.tecgraf.puc-rio.br/pub/lua/ + In Canada: ftp://csg.uwaterloo.ca/pub/lhf/lua/ + In the US: ftp://ftp.freesoftware.com/pub/languages/lua/ + In Germany: ftp://ftp.uni-trier.de/pub/languages/lua/ + In Germany: ftp://ftp.gwdg.de/pub/languages/lua/ + In Greece: ftp://ftp.ntua.gr/pub/lang/lua/ + In Japan: ftp://ftp.u-aizu.ac.jp/pub/lang/lua/ + In Denmark: ftp://ftp.ucore.com/lua/dist * Installation ------------ @@ -39,16 +55,18 @@ This is Lua 3.2 * Contacting the authors ---------------------- - Lua has been designed and implemented by Waldemar Celes, - Roberto Ierusalimschy and Luiz Henrique de Figueiredo. + Lua was designed and implemented by Waldemar Celes, Roberto Ierusalimschy + and Luiz Henrique de Figueiredo. They can be contacted by email at lua@tecgraf.puc-rio.br. - Send your comments, bug reports and anything else to lua@tecgraf.puc-rio.br. + Send your comments, questions, and bug reports to lua@tecgraf.puc-rio.br. For reporting bugs, try also the mailing list: lua-l@tecgraf.puc-rio.br. - To subscribe to this list, send "subscribe lua-l YOUR-NAME" to - listproc@tecgraf.puc-rio.br in the body of the message (not in the subject). + For more information about this list, including instructions on how to + subscribe, see http://www.tecgraf.puc-rio.br/lua/lua-l.html . - Lua has been developed at TeCGraf, the Computer Graphics Technology Group + Lua is developed at TeCGraf, the Computer Graphics Technology Group of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). TeCGraf is a laboratory of the Department of Computer Science. Dozens of industrial products developed by TeCGraf use Lua. + +(end of README) diff --git a/config b/config index fe62a51e9f..6a271eaf87 100644 --- a/config +++ b/config @@ -1,68 +1,100 @@ # configuration file for making Lua +# see INSTALL for installation instructions # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= # ------------------------------------------------------------------ Lua -# if you need compatibility with version 2.5 or older, uncomment the line below. -#COMPAT= -DLUA_COMPAT2_5 - # Lua uses double for numbers. To change this, uncomment one of the lines below. #NUMBER= -DLUA_NUM_TYPE=double #NUMBER= -DLUA_NUM_TYPE=float #NUMBER= -DLUA_NUM_TYPE=long +# Optionally, you may also want change how numbers are converted to strings, +# and vice-versa. Look for LUA_NUMBER in llimits.h and in the rest of the code. -# if you want support for pipes, uncomment the following line. +# If you want support for pipes, uncomment the following line. +# You need popen in your C library. #POPEN= -DPOPEN +# If you need compatibility with previous versions, edit and uncomment the +# definition of COMPAT below. +# Use -DLUA_COMPAT_READPATTERN if you need complex read patterns. +# Use -DLUA_COMPAT_ARGRET if you need the old semantics that used only the +# first value returned by a function when it is called as the last parameter. +# Use -DLUA_DEPRECATEDFUNCS if you need the obsolete functions in the standard +# Lua library (not recommended). +#COMPAT= -DLUA_COMPAT_READPATTERN -DLUA_COMPAT_ARGRET -DLUA_DEPRECATEDFUNCS + # ------------------------------------------------------------------ C compiler -# you need an ANSI C compiler. gcc is a popular one. +# You need an ANSI C compiler. gcc is a popular one. CC= gcc -WARN= -ansi -Wall +WARN= -ansi -pedantic -Wall -# on IRIX, cc is a good ANSI compiler. +# On IRIX, cc is a good ANSI compiler. #CC= cc #WARN= -ansi -fullwarn -# on Solaris, cc is optional. you may have to add -Dsparc if you use -Xc. +# On Solaris, cc is optional. You may have to add -Dsparc if you use -Xc. #CC= cc #WARN= -Xc # -Dsparc # ------------------------------------------------------------------ C library -# if your C library is not POSIX compliant, comment the following line. +# If your C library is not POSIX compliant, comment the following line. POSIX= -D_POSIX_SOURCE -# if your C library does not have the newer ANSI functions memmove, strerror, +# If your C library does not have the newer ANSI functions strerror, strcoll, # and locale support, uncomment the following line. SunOs 4.1.x is one example. #OLD_ANSI= -DOLD_ANSI -# in SunOs 4.1.x, standard headers in /usr/include are not ANSI, +# In SunOs 4.1.x, standard headers in /usr/include are not ANSI, # so uncomment the following line to avoid prototypes warnings. -#EXTRA_INCS= -I/usr/5include +#EXTRA_INCS= -I/usr/5include + +# The stand-alone Lua interpreter needs the math functions, which are usually +# in libm.a (-lm). If your C library already includes the math functions, +# or if you are using a modified interpreter that does not need them, +# then comment the following line. +EXTRA_LIBS= -lm # ------------------------------------------------------------------ librarian -# this should work in all unix systems. +# This should work in all Unix systems. AR= ar rcu -# if your system doesn't have (or need) ranlib, use RANLIB=true. -# on some systems, "ar s" does what ranlib would do. +# If your system doesn't have (or need) ranlib, use RANLIB=true. +# On some systems, "ar s" does what ranlib would do. RANLIB= ranlib #RANLIB= ar s #RANLIB= true -# == END OF USER SETTINGS. DO NOT CHANGE ANYTHING BELOW THIS LINE ============= +# ------------------------------------------------------------------ install + +# Locations for "make install". You may need to be root do "make install". +INSTALL_ROOT= /usr/local +INSTALL_BIN= $(INSTALL_ROOT)/bin +INSTALL_INC= $(INSTALL_ROOT)/include +INSTALL_LIB= $(INSTALL_ROOT)/lib +INSTALL_MAN= $(INSTALL_ROOT)/man/man1 -VERSION= 3.2 +# You might prefer to use "install" if you have it. +INSTALL_EXEC= cp +INSTALL_DATA= cp +#INSTALL_EXEC= install -m 0755 +#INSTALL_DATA= install -m 0644 +# == END OF USER SETTINGS. DO NOT CHANGE ANYTHING BELOW THIS LINE ============= + +BIN= $(LUA)/bin INC= $(LUA)/include LIB= $(LUA)/lib -BIN= $(LUA)/bin INCS= -I$(INC) $(EXTRA_INCS) -DEFS= $(COMPAT) $(NUMBER) $(OLD_ANSI) $(EXTRALIB) $(EXTRA_DEFS) +DEFS= $(COMPAT) $(NUMBER) $(OLD_ANSI) $(EXTRA_DEFS) CFLAGS= -O2 $(WARN) $(INCS) $(DEFS) +V=4.0 + +# (end of config) diff --git a/doc/idx.html b/doc/idx.html index 65b0e78a52..74693a564c 100644 --- a/doc/idx.html +++ b/doc/idx.html @@ -1,282 +1,409 @@ -Lua 3.2 Reference Manual - Word Index +Lua 4.0 Reference Manual - Word Index -

    Index

    +
    +

    +Lua +Reference manual +- word index +

    -..
    -Adjustment
    -Assignment
    -Basic Expressions
    -C pointers
    -C2lua
    -Coercion
    -Comments
    -Expressions
    -Function Definitions
    -Global variables
    -Identifiers
    -LUA_ANYTAG
    -LUA_NOOBJECT
    -Literal strings
    -Local variables
    -Lua Stand-alone
    -Numerical constants
    -Operator precedence
    -PI
    -Pre-processor
    -Types and Tags
    -Upvalues
    -Visibility
    -_ERRORMESSAGE
    -_INPUT
    -_OUTPUT
    -_STDERR
    -_STDIN
    -_STDOUT
    -abs
    -acos
    -add event
    -alert
    +..
    +_ALERT
    +_ERRORMESSAGE
    +_INPUT
    +_OUTPUT
    +_PROMPT
    +_STDERR
    +_STDIN
    +_STDOUT
    + +

    + +abs
    +acceptable index
    +acos
    +``add'' event
    +adjustment
    +alert
    and
    -appendto
    +appendto
    +arg
    arguments
    -arg
    arithmetic operators
    arrays
    -asin
    -assert
    +asin
    +assert
    +assignment
    associative arrays
    -atan2
    -atan
    +atan
    +atan2
    + +

    + +basic expressions
    basic types
    block
    -call
    +break statement
    + +

    + +C API
    +....... LUA_ANYTAG
    +....... lua_baselibopen
    +....... lua_call
    +....... lua_CFunction
    +....... lua_close
    +....... lua_concat
    +....... lua_copytagmethods
    +....... lua_dblibopen
    +....... lua_Debug
    +....... lua_dobuffer
    +....... lua_dofile
    +....... lua_dostring
    +....... lua_equal
    +....... LUA_ERRERR
    +....... LUA_ERRFILE
    +....... LUA_ERRMEM
    +....... lua_error
    +....... LUA_ERRRUN
    +....... LUA_ERRSYNTAX
    +....... lua_getgccount
    +....... lua_getgcthreshold
    +....... lua_getglobal
    +....... lua_getglobals
    +....... lua_getinfo
    +....... lua_getlocal
    +....... lua_getn
    +....... lua_getref
    +....... lua_getregistry
    +....... lua_getstack
    +....... lua_gettable
    +....... lua_gettagmethod
    +....... lua_gettop
    +....... lua_Hook
    +....... lua_insert
    +....... lua_iolibopen
    +....... lua_iscfunction
    +....... lua_isfunction
    +....... lua_isnil
    +....... lua_isnumber
    +....... lua_isstring
    +....... lua_istable
    +....... lua_isuserdata
    +....... lua_lessthan
    +....... lua_mathlibopen
    +....... LUA_MINSTACK
    +....... LUA_MULTRET
    +....... lua_newtable
    +....... lua_newtag
    +....... lua_next
    +....... LUA_NOREF
    +....... lua_open
    +....... lua_pushcclosure
    +....... lua_pushcfunction
    +....... lua_pushlstring
    +....... lua_pushnil
    +....... lua_pushnumber
    +....... lua_pushstring
    +....... lua_pushuserdata
    +....... lua_pushusertag
    +....... lua_pushvalue
    +....... lua_rawcall
    +....... lua_rawget
    +....... lua_rawgeti
    +....... lua_rawset
    +....... lua_rawseti
    +....... lua_ref
    +....... LUA_REFNIL
    +....... LUA_REFREGISTRY
    +....... lua_register
    +....... lua_remove
    +....... lua_setcallhook
    +....... lua_setgcthreshold
    +....... lua_setglobal
    +....... lua_setglobals
    +....... lua_setlinehook
    +....... lua_setlocal
    +....... lua_settable
    +....... lua_settag
    +....... lua_settagmethod
    +....... lua_settop
    +....... lua_stackspace
    +....... lua_State
    +....... lua_strlen
    +....... lua_strlibopen
    +....... lua_tag
    +....... lua_tocfunction
    +....... lua_tonumber
    +....... lua_tostring
    +....... lua_touserdata
    +....... lua_type
    +....... lua_typename
    +....... lua_unref
    +C closure
    +C pointers
    +call
    captures
    -ceil
    +ceil
    character class
    chunk
    -clock
    -closefile
    +clock
    +closefile
    closing a file
    -collectgarbage
    -concatenation event
    +coercion
    +collectgarbage
    +comments
    concatenation
    +``concatenation'' event
    condition expression
    constructors
    -copytagmethods
    -cos
    -date
    -debug pragma
    -deg
    -div event
    -dofile
    -dostring
    +copytagmethods
    +cos
    + +

    + +date
    +def
    +``div'' event
    +dofile
    +dostring
    + +

    + eight-bit clean
    -error
    +error
    event
    -execute
    -exit
    +execute
    +exit
    +exp
    exponentiation
    +expressions
    + +

    + file handles
    -floor
    -flush
    -foreachi
    -foreachvar
    -foreach
    -format
    -frexp
    -funcinfo
    -function call
    -function event
    +floor
    +flush
    +for statement
    +foreach
    +foreachi
    +format
    +frexp
    function
    -gc event
    -ge event
    -getenv
    -getglobal event
    -getglobal
    -getlocal
    -getn
    -getstack
    -gettable event
    -gettagmethod
    -gettagmethod
    +function call
    +function definitions
    +``function'' event
    + +

    + +``gc'' event
    +getargs
    +getenv
    +getglobal
    +``getglobal'' event
    +getinfo
    +getlocal
    +getn
    +``gettable'' event
    +gettagmethod
    global environment
    -gsub
    -gt event
    -if-then-else
    -index event
    -ldexp
    -le event
    -log10
    +global variables
    +globals
    +grammar
    +....... args
    +....... binop
    +....... block
    +....... chunk
    +....... declist
    +....... exp
    +....... exp1
    +....... explist1
    +....... ffield
    +....... ffieldlist
    +....... ffieldlist1
    +....... fieldlist
    +....... funcname
    +....... function
    +....... functioncall
    +....... init
    +....... lfieldlist
    +....... lfieldlist1
    +....... parlist1
    +....... stat
    +....... tableconstructor
    +....... unop
    +....... upvalue
    +....... var
    +....... varlist1
    +....... varorfunc
    +gsub
    + +

    + +identifiers
    +if-then-else statement
    +``index'' event
    + +

    + +ldexp
    +literal strings
    +local variables
    +log
    +log10
    logical operators
    -log
    -lt event
    -lua2C
    -lua_CFunction
    -lua_Object
    -lua_callfunction
    -lua_close
    -lua_collectgarbage
    -lua_copytagmethods
    -lua_createtable
    -lua_dobuffer
    -lua_dofile
    -lua_dostring
    -lua_error
    -lua_getcfunction
    -lua_getglobal
    -lua_getnumber
    -lua_getparam
    -lua_getref
    -lua_getresult
    -lua_getstring
    -lua_gettable
    -lua_gettagmethod
    -lua_getuserdata
    -lua_iolibopen
    -lua_iscfunction
    -lua_isfunction
    -lua_isnil
    -lua_isnumber
    -lua_isstring
    -lua_istable
    -lua_isuserdata
    -lua_lua2C
    -lua_mathlibopen
    -lua_newtag
    -lua_open
    -lua_pop
    -lua_pushcclosure
    -lua_pushcfunction
    -lua_pushlstring
    -lua_pushnil
    -lua_pushnumber
    -lua_pushobject
    -lua_pushstring
    -lua_pushuserdata
    -lua_pushusertag
    -lua_rawgetglobal
    -lua_rawgetglobal
    -lua_rawgetglobal
    -lua_rawsettable
    -lua_ref
    -lua_register
    -lua_setglobal
    -lua_setstate
    -lua_settable
    -lua_settagmethod
    -lua_settag
    -lua_state
    -lua_strlen
    -lua_strlibopen
    -lua_tag
    -lua_unref
    -luac
    -luac
    -max
    +``lt'' event
    +Lua stand-alone
    +luac
    + +

    + +max
    methods
    -min
    -mod
    -mul event
    +min
    +mod
    +``mul'' event
    multiple assignment
    -newtag
    -nextvar
    -next
    + +

    + +newtag
    +next
    nil
    not
    number
    -openfile
    +numerical constants
    + +

    + +openfile
    +operator precedence
    or
    -packed results
    -pattern item
    + +

    + pattern
    +pattern item
    +PI
    piped input
    -piped output
    -popen
    -popen
    -pow event
    +popen
    +``pow'' event
    pre-compilation
    -predefined functions
    -print
    +print
    protected calls
    -rad
    -randomseed
    -random
    -rawgetglobal
    -rawgettable
    -rawsetglobal
    -rawsettable
    -read pattern
    -readfrom
    -read
    + +

    + +rad
    +random
    +randomseed
    +rawget
    +rawset
    +read
    +readfrom
    records
    reference
    -reflexivity
    relational operators
    -remove
    -rename
    -repeat-until
    +remove
    +rename
    +repeat-until statement
    reserved words
    return statement
    -return
    -seek
    -self
    -setcallhook
    -setglobal event
    -setglobal
    -setlinehook
    -setlocale
    -setlocal
    -settable event
    -settagmethod
    -settagmethod
    -settag
    + +

    + +seek
    +self
    +setcallhook
    +setglobal
    +``setglobal'' event
    +setlinehook
    +setlocal
    +setlocale
    +``settable'' event
    +settag
    +settagmethod
    short-cut evaluation
    -sin
    -skips
    -sort
    -sqrt
    +sin
    +sort
    +sqrt
    +stack index
    +state
    statements
    -stderr
    -strbyte
    -strchar
    -strfind
    +stderr
    +strbyte
    +strchar
    +strfind
    string
    -strlen
    -strlower
    -strrep
    -strsub
    -strupper
    -sub event
    +strlen
    +strlower
    +strrep
    +strsub
    +strupper
    +``sub'' event
    + +

    + table
    -tag methods
    tag
    -tag
    -tan
    -tinsert
    -tmpname
    +tag
    +tag method
    +....... add
    +....... concatenation
    +....... div
    +....... function
    +....... gc
    +....... getglobal
    +....... gettable
    +....... index
    +....... lt
    +....... mul
    +....... pow
    +....... setglobal
    +....... settable
    +....... sub
    +....... unm
    +tan
    +tinsert
    +tmpname
    tokens
    -tonumber
    -tostring
    -tremove
    -type
    -unm event
    +tonumber
    +tostring
    +tremove
    +type
    +types and tags
    + +

    + +``unm'' event
    +upvalues
    userdata
    -vararg
    -version 3.0
    -version 3.1
    -while-do
    -writeto
    -write
    + +

    + +valid index
    +vararg function
    +version 3.2
    +visibility
    + +

    + +while-do statement
    +write
    +writeto
    + +

    +


    Last update: -Wed Jul 7 13:36:24 EST 1999 +Mon Nov 6 17:35:51 EDT 2000 by lhf. diff --git a/doc/index.html b/doc/index.html index e6ff5faffd..b7603a30a1 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,30 +1,23 @@ -Lua 3.2 Reference Manual - Contents +Lua: reference manual - contents
    -

    Reference Manual of the Programming Language -Lua -3.2

    -

    -Roberto Ierusalimschy, -Luiz Henrique de Figueiredo, -Waldemar Celes -
    -lua@tecgraf.puc-rio.br
    -TeCGraf, -Computer Science Department, -PUC-Rio -

    +

    +Lua +Reference manual +

    + +Reference Manual of the Programming Language +Lua +4.0 [ top | -contents -| index | ps @@ -33,7 +26,7 @@

    Reference Manual of the Programming Language | old versions ] -
    +


    Last update: -Wed Jul 7 13:36:24 EST 1999 +Mon Nov 6 17:36:08 EDT 2000 by lhf. diff --git a/doc/logo.gif b/doc/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..f3e68936b2dfa279f75f700f9756eb0849a69cc9 GIT binary patch literal 2750 zcmeH``#;kQ1INFcY2Vq#+~%$gtGN|D>Col0ea$`0r060H54l7wp>(zxx#f&z$Osu> z!$cPyr!SF0j*3b}C|yYC;i%K2J)QsJ`Qdzi`Mh4ApFXem>-Bc?aCLMFV<3;^`@3v7`_radHyb+vnNai^$|WeSHCeAOJxD0GtN? z$v*`CKM24uO#X^O0Duy(`TNn|PSC&~QeceTTPnNKL2au;_gbp%oFkZfO57FIy}7!0 z0!V^^yIDq<fHXf{28|*LNag9GL zi!nc*Hc(8>ZsDlBIN6XC$E#7RO1kpmx`JJV#iO{6To@ww>gAfeEK&@sv3JxA+KKs0 z9NXl~;lPkB45SKiLqdZA@UF39Kc8rAND(O1>^^$m50O2-gt6YQ!{kn7+)~$fEb-~= zSScb~2wg~_jBMOvgAnDuAo8Xl(16Jj=I@g}%y4fvjGAa!ef^E;^rjcwG0n$+xjEB? z)FfY9@1hFY!S3ka!(m|1ff@>}0|~SU9E-zsRYB2S2}qgL=`6FM;wgZtMdR|&@VY7h z6_@-FY1mf80*NFyGrC6i4K@S+vd(;uQQDVbq=}vGq^CtJEd;{ubnW(1+djfA^hzD& zoremBVY+rQR|*<4NJoHm8qgUTvG9yGF&ZMv+ zOQD$0V^6`ekEFEJ;0M{mXJRbHF9J-$`)AIVCQX(z%@dgPWOXLDtJY`D(I~DM8nyDg zg;0hZ@h4{;kRWbd*05-)H?dxxN1ot!y|`@aP{H9K(v{NR+$r7 zRtP$qT8x#et1)e>pKlX)Im>xQ)ri-~`-q0%(Z3>G(43k%Mxi{pnP%H?YvDG4wpoNx zda;XL;Ds-fq3Xop&^D|Cci!I?Z(|N?)H?ClzM1;0ZdLr#l683K{V`{JlwBg*EXwYf zGw}1~eAZjbuRm_KOg0a+D!AfXA{* z^stHHCzV%(+G#z__$^C0frHh=>-Ty$r7q=$;4bTHumIhvEV`=&4Z#o8EZs>$+P$oH zwXxuuv);IvDZ=Plm54eaEd?>Bmo@G0l5yz1wK=V-sqhAa;PeqX#d_uMUTeJz85?nI z$w-Ur(KE3`$tP_AjL`eK-94g2xM;5GPOe8?7OX;C40ZM#)1`ezpV0K+svbyLulXj6 zd^#0JZRdMct}MkH-gv${>Z=and#=FLh7RhCbsuQTNW^;p%hjbY*`(E)aYA@b*5egl z!9cajg8Uf-`q%eMWdb9_y1|V^Rd;|#S=1t?yDA-9+8%7R!o17Rso$V&_{n$PBij}m zc0Y5Zfc!M|&>M9$t-svARHb0b&G;^%PcvUd#~~LfsJ_Rqq%w9ok3WUBi`5&#OTKwp z&IWc|uYx(Y8UgnjOx=Aic5o>AYv)`kg``Y(RuoBEA4s5CXA+hvVgCt{K{?#odd9yo zQ&GXPqr<|6x0e0~uu`3A+6i%`3c3i3vY8bnokf*_^>00C1QRrEHj-S)of^JV+-)I9 z!ST$X{!*>S1%JqbH4&ezMmz49U9(MJRp+?{;&&BS^<)v9oRL5KcdZ4DTDdNg@%Ez?rlZeQ$I{(8{VtH|SLu@O`g#J0(mThBM6IfRO@NE}LrY z8u@I4ioF^LeaH>^KU&mamBmbWwZ_|#s&t>yNrGDs?%NLZ|Q zjrKOih9_7UePIfB>&Cc!4wWu>`7qrPI=b1E8yYi}h) RM~qN3KA4Y>u_pmL{s-EGoeKZ} literal 0 HcmV?d00001 diff --git a/doc/lua.1 b/doc/lua.1 new file mode 100644 index 0000000000..b156181852 --- /dev/null +++ b/doc/lua.1 @@ -0,0 +1,143 @@ +.\" lua.man,v 1.3 2000/09/04 21:41:28 lhf Exp +.TH LUA 1 "2000/09/04 21:41:28" +.SH NAME +lua \- Lua interpreter +.SH SYNOPSIS +.B lua +[ +.I arguments +] +.SH DESCRIPTION +.B lua +is the stand-alone Lua interpreter. +It loads and executes Lua programs, +either in textual source form or +in precompiled binary form, +as output by +.BR luac , +the Lua compiler. +.B lua +can be used as a batch interpreter and also interactively. +.LP +The +.I arguments +can be options, assignments, or filenames, +and are processed in order, +from left to right. +.LP +Options start with +.B \- +and are described below. +.LP +An assignment is an argument of the form +.BR a=b , +which assigns the string +.RB ` b ' +to the global variable +.BR a . +Note that no quotes are needed around the string if it does not contain spaces +or other characters special to the shell. +This is for convenience only. +(In general, +you should be careful when using quotes and spaces on the command line +because they are usually handled by the shell.) +.LP +If the argument is neither an option nor an assignment, +then it is assumed to be a filename, +which is then loaded and executed. +.LP +If no arguments are given, +then +.B "\-v \-i" +is assumed when the standard input is a terminal; +otherwise, +.B \- +is assumed. +.SH OPTIONS +.TP +.B \- +load the standard input as a file, +that is, +not interactively, +even when the standard input is a terminal. +.TP +.B \-c +close Lua before exiting. +.TP +.BI \-e " stat" +execute statement +.IR stat . +You will need to quote +.I stat +if it contains spaces or quotes. +.TP +.BI \-f " file" +collect all remaining arguments as strings into a global table named +.B arg +and then execute +.IR file . +The arguments in +.B arg +start at 0, +which contains the string +.RI ` file '. +The index of the last argument is stored in +.BR "arg.n" . +.TP +.B \-i +enter interactive mode, +displaying a prompt. +In this mode, +.B lua +reads lines from the standard input and executes them as they are read. +Each line must contain a complete statement. +To span a statement across several lines, end each line with a backslash +.BR `\e' . +The prompt shown is the value of the global variable +.BR _PROMPT , +if this value is a string. +So, +to change the prompt, +set +.B _PROMPT +to a string of your choice. +You can do that after calling the interpreter +or on the command line with +.BR "_PROMPT=\'lua: \'" , +for example. +(Note the need for quotes, because the string contains a space.) +The default prompt is ``> ''. +.TP +.B \-q +enter interactive mode, +but without displaying a prompt. +.TP +.BI \-s n +set the stack size to +.IB n . +If present, +this must be the first option. +Note that +.I n +is in the same argument as +.BR -s . +For example, +to specify a stack size of 2000, +use +.BR -s2000 . +.TP +.B \-v +print version information. +.SH "SEE ALSO" +.BR luac (1) +.br +http://www.tecgraf.puc-rio.br/lua/ +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +R. Ierusalimschy, +L. H. de Figueiredo, +and +W. Celes +(lua@tecgraf.puc-rio.br) +.\" EOF diff --git a/doc/lua.html b/doc/lua.html new file mode 100644 index 0000000000..ef861bb54b --- /dev/null +++ b/doc/lua.html @@ -0,0 +1,151 @@ + + + +LUA man page + + + + +

    NAME

    +lua - Lua interpreter +

    SYNOPSIS

    +lua +[ +arguments +] +

    DESCRIPTION

    +lua +is the stand-alone Lua interpreter. +It loads and executes Lua programs, +either in textual source form or +in precompiled binary form, +as output by +luac, +the Lua compiler. +lua +can be used as a batch interpreter and also interactively. +

    +The +arguments +can be options, assignments, or filenames, +and are processed in order, +from left to right. +

    +Options start with +- +and are described below. +

    +An assignment is an argument of the form +a=b, +which assigns the string +.RB ` b ' +to the global variable +a. +Note that no quotes are needed around the string if it does not contain spaces +or other characters special to the shell. +This is for convenience only. +(In general, +you should be careful when using quotes and spaces on the command line +because they are usually handled by the shell.) +

    +If the argument is neither an option nor an assignment, +then it is assumed to be a filename, +which is then loaded and executed. +

    +If no arguments are given, +then +"-v -i" +is assumed when the standard input is a terminal; +otherwise, +- +is assumed. +

    OPTIONS

    +

    +- +load the standard input as a file, +that is, +not interactively, +even when the standard input is a terminal. +

    +-c +close Lua before exiting. +

    +-e "stat" +execute statement +stat. +You will need to quote +stat +if it contains spaces or quotes. +

    +-f "file" +collect all remaining arguments as strings into a global table named +arg +and then execute +file. +The arguments in +arg +start at 0, +which contains the string +.RI ` file '. +The index of the last argument is stored in +"arg.n". +

    +-i +enter interactive mode, +displaying a prompt. +In this mode, +lua +reads lines from the standard input and executes them as they are read. +Each line must contain a complete statement. +To span a statement across several lines, end each line with a backslash +`\e'. +The prompt shown is the value of the global variable +_PROMPT, +if this value is a string. +So, +to change the prompt, +set +_PROMPT +to a string of your choice. +You can do that after calling the interpreter +or on the command line with +"_PROMPT=\'lua: \'", +for example. +(Note the need for quotes, because the string contains a space.) +The default prompt is ``> ''. +

    +-q +enter interactive mode, +but without displaying a prompt. +

    +-sn +set the stack size to +.IB n . +If present, +this must be the first option. +Note that +n +is in the same argument as +-s. +For example, +to specify a stack size of 2000, +use +-s2000. +

    +-v +print version information. +

    SEE ALSO

    +luac(1) +
    +http://www.tecgraf.puc-rio.br/lua/ +

    DIAGNOSTICS

    +Error messages should be self explanatory. +

    AUTHORS

    +R. Ierusalimschy, +L. H. de Figueiredo, +and +W. Celes +(lua@tecgraf.puc-rio.br) + + + diff --git a/doc/luac.1 b/doc/luac.1 new file mode 100644 index 0000000000..212f9b61c6 --- /dev/null +++ b/doc/luac.1 @@ -0,0 +1,139 @@ +.\" luac.man,v 1.20 2000/10/06 15:11:21 lhf Exp +.TH LUAC 1 "2000/10/06 15:11:21" +.SH NAME +luac \- Lua compiler +.SH SYNOPSIS +.B luac +[ +.I options +] [ +.I filenames +] +.SH DESCRIPTION +.B luac +is the Lua compiler. +It translates programs written in the Lua programming language +into binary files that can be loaded and executed with +.B lua_dofile +in C or with +.B dofile +in Lua. +.LP +The main advantages of precompiling chunks are: +faster loading, +protecting source code from user changes, +and +off-line syntax error detection. +.LP +Pre-compiling does not imply faster execution +because in Lua chunks are always compiled into bytecodes before being executed. +.B luac +simply allows those bytecodes to be saved in a file for later execution. +.LP +.B luac +produces a single output file containing the bytecodes +for all source files given. +By default, +the output file is named +.BR luac.out , +but you can change this with the +.B \-o +option. +.LP +The binary files created by +.B luac +are portable to all architectures with the same word size. +This means that +binary files created on a 32-bit platform (such as Intel) +can be read without change in another 32-bit platform (such as Sparc), +even if the byte order (``endianess'') is different. +On the other hand, +binary files created on a 16-bit platform cannot be read in a 32-bit platform. +.LP +In the command line, +you can mix +text files containing Lua source and +binary files containing precompiled chunks. +This is useful to combine several precompiled chunks, +even from different (but compatible) platforms, +into a single precompiled chunk. +.LP +You can use +.B "\-" +to indicate +.I stdin +as a source file. +.LP +The internal format of the binary files produced by +.B luac +may change when a new version of Lua is released. +We try to maintain compatibility even for binary files, +but it is not always possible. +So, +save the source files of all Lua programs that you precompile. +.LP +.SH OPTIONS +Options must be separate. +.TP +.B \-l +produce a listing of the compiled bytecode for Lua's virtual machine. +Listing bytecodes is useful to learn about Lua's virtual machine. +If no files are given, then +.B luac +loads +.B luac.out +and lists its contents. +.TP +.BI \-o " file" +output to +.IR file , +instead of the default +.BR luac.out . +The output file can be a source file because +all files are loaded before the output file is written. +.TP +.B \-p +load files but do not generate any output file. +Used mainly for syntax checking or testing precompiled chunks: +corrupted files will probably generate errors when loaded. +For a thourough integrity test, +use +.BR \-t . +.TP +.B \-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running these chunks, +then the error messages might not contain the full information they usually do. +.TP +.B \-t +perform a thourough integrity test of precompiled chunks. +Code that passes this test is completely safe, +in the sense that it will not break the interpreter. +However, +there is no guarantee that such code does anything sensible. +(None can be given, because the halting problem is unsolvable.) +If no files are given, then +.B luac +loads +.B luac.out +and tests its contents. +.TP +.B \-v +print version information. +.SH FILES +.TP 15 +.B luac.out +default output file +.SH "SEE ALSO" +.BR lua (1) +.br +http://www.tecgraf.puc-rio.br/lua/ +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +L. H. de Figueiredo, +R. Ierusalimschy and +W. Celes +(lua@tecgraf.puc-rio.br) +.\" EOF diff --git a/doc/luac.html b/doc/luac.html index 92d9ddf1e8..e083c2b39a 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -1,4 +1,4 @@ - + LUAC man page @@ -25,14 +25,11 @@

    DESCRIPTION

    dofile in Lua.

    -The main advantages of pre-compiling chunks are: +The main advantages of precompiling chunks are: faster loading, protecting source code from user changes, and off-line syntax error detection. -The binary files created by -luac -are portable to all architectures.

    Pre-compiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. @@ -49,126 +46,87 @@

    DESCRIPTION

    -o option.

    +The binary files created by +luac +are portable to all architectures with the same word size. +This means that +binary files created on a 32-bit platform (such as Intel) +can be read without change in another 32-bit platform (such as Sparc), +even if the byte order (``endianess'') is different. +On the other hand, +binary files created on a 16-bit platform cannot be read in a 32-bit platform. +

    +In the command line, +you can mix +text files containing Lua source and +binary files containing precompiled chunks. +This is useful to combine several precompiled chunks, +even from different (but compatible) platforms, +into a single precompiled chunk. +

    You can use "-" to indicate stdin as a source file.

    -luac -can also load and list binary files with the --u -option. -

    -Binary files produced by differents runs of -luac -(even in different machines) -can be combined into one large file, -using -cat(1). -The result is still a valid binary file -and can be loaded with a single call to -lua_dofile -or -dofile. -

    The internal format of the binary files produced by luac may change when a new version of Lua is released. We try to maintain compatibility even for binary files, -but sometimes it cannot be done. +but it is not always possible. So, save the source files of all Lua programs that you precompile.

    OPTIONS

    Options must be separate.

    --c -compile (this is the default). -

    --u -undump, i.e., load and list the given binary files. -If no files are given, then luac undumps -luac.out. -Listing a binary file is useful to learn Lua's virtual machine. -Listing is also useful to test the integrity of binary files: -corrupted files will probably generate errors when undumped. -To test without listing, use --q. -For a thourough integrity test, -use --t. -

    --d -turn debugging on. -Individual chunks may -still control the generation of debug information with -$debug and $nodebug. -If debugging is on, then listings show the names of the local variables. -

    --D "name" -predefine symbol -name -for conditional compilation. -By default, -luac -does -not -predefine any symbols, -not even the built-in functions. -

    -l produce a listing of the compiled bytecode for Lua's virtual machine. -This is the default when undumping. -

    --n -Save numbers in native format. -By default, -numbers are saved in text form, -for maximum portability. -Binary files with numbers in native format are slightly faster to load, -but are not completely portable. +Listing bytecodes is useful to learn about Lua's virtual machine. +If no files are given, then +luac +loads +luac.out +and lists its contents.

    --o "filename" +-o "file" output to -filename, +file, instead of the default luac.out. -The output file cannot be a source file. -

    --O -optimize. -Debug information is removed -and -duplicate constants are coalesced. +The output file can be a source file because +all files are loaded before the output file is written.

    -p -parse sources files but do not generate any output file. -Used mainly for syntax checking. +load files but do not generate any output file. +Used mainly for syntax checking or testing precompiled chunks: +corrupted files will probably generate errors when loaded. +For a thourough integrity test, +use +-t.

    --q -quiet; produces no listing. -This is the default when compiling. +-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running these chunks, +then the error messages might not contain the full information they usually do.

    -t -perform a thourough integrity test when undumping. +perform a thourough integrity test of precompiled chunks. Code that passes this test is completely safe, in the sense that it will not break the interpreter. However, there is no guarantee that such code does anything sensible. (None can be given, because the halting problem is unsolvable.) -

    --U "name" -undefine symbol -name -for conditional compilation. +If no files are given, then +luac +loads +luac.out +and tests its contents.

    -v print version information. -

    --V -verbose; -print the names of the source files as they are processed.

    FILES

    luac.out @@ -176,19 +134,14 @@

    FILES

    SEE ALSO

    lua(1)
    -"Reference Manual of the Programming Language Lua" -
    http://www.tecgraf.puc-rio.br/lua/ -
    -"Lua: an extensible extension language", -Software: Practice & Experience -26 -#6 (1996) 635-652.

    DIAGNOSTICS

    Error messages should be self explanatory.

    AUTHORS

    L. H. de Figueiredo, R. Ierusalimschy and W. Celes -(lua@tecgraf.puc-rio.br) +(lua@tecgraf.puc-rio.br) + + diff --git a/doc/luac.man b/doc/luac.man deleted file mode 100644 index 818448b8f5..0000000000 --- a/doc/luac.man +++ /dev/null @@ -1,188 +0,0 @@ -.\" luac.man,v 1.17 1999/07/07 16:02:07 lhf Exp -.TH LUAC 1 "1999/07/07 16:02:07" -.SH NAME -luac \- Lua compiler -.SH SYNOPSIS -.B luac -[ -.I options -] [ -.I filenames -] -.SH DESCRIPTION -.B luac -is the Lua compiler. -It translates programs written in the Lua programming language -into binary files that can be loaded and executed with -.B lua_dofile -in C or with -.B dofile -in Lua. -.LP -The main advantages of pre-compiling chunks are: -faster loading, -protecting source code from user changes, -and -off-line syntax error detection. -The binary files created by -.B luac -are portable to all architectures. -.LP -Pre-compiling does not imply faster execution -because in Lua chunks are always compiled into bytecodes before being executed. -.B luac -simply allows those bytecodes to be saved in a file for later execution. -.LP -.B luac -produces a single output file containing the bytecodes -for all source files given. -By default, -the output file is named -.BR luac.out , -but you can change this with the -.B \-o -option. -.LP -You can use -.B "\-" -to indicate -.I stdin -as a source file. -.LP -.B luac -can also load and list binary files with the -.B \-u -option. -.LP -Binary files produced by differents runs of -.B luac -(even in different machines) -can be combined into one large file, -using -.BR cat (1). -The result is still a valid binary file -and can be loaded with a single call to -.B lua_dofile -or -.BR dofile . -.LP -The internal format of the binary files produced by -.B luac -may change when a new version of Lua is released. -We try to maintain compatibility even for binary files, -but sometimes it cannot be done. -So, -save the source files of all Lua programs that you precompile. -.LP -.SH OPTIONS -Options must be separate. -.TP -.B \-c -compile (this is the default). -.TP -.B \-u -undump, i.e., load and list the given binary files. -If no files are given, then luac undumps -.BR luac.out . -Listing a binary file is useful to learn Lua's virtual machine. -Listing is also useful to test the integrity of binary files: -corrupted files will probably generate errors when undumped. -To test without listing, use -.BR \-q . -For a thourough integrity test, -use -.BR \-t . -.TP -.B \-d -turn debugging on. -Individual chunks may -still control the generation of debug information with -$debug and $nodebug. -If debugging is on, then listings show the names of the local variables. -.TP -.BI \-D " name" -predefine symbol -.I name -for conditional compilation. -By default, -.B luac -does -.I not -predefine any symbols, -not even the built-in functions. -.TP -.B \-l -produce a listing of the compiled bytecode for Lua's virtual machine. -This is the default when undumping. -.TP -.B \-n -Save numbers in native format. -By default, -numbers are saved in text form, -for maximum portability. -Binary files with numbers in native format are slightly faster to load, -but are not completely portable. -.TP -.BI \-o " filename" -output to -.IR filename , -instead of the default -.BR luac.out . -The output file cannot be a source file. -.TP -.B \-O -optimize. -Debug information is removed -and -duplicate constants are coalesced. -.TP -.B \-p -parse sources files but do not generate any output file. -Used mainly for syntax checking. -.TP -.B \-q -quiet; produces no listing. -This is the default when compiling. -.TP -.B \-t -perform a thourough integrity test when undumping. -Code that passes this test is completely safe, -in the sense that it will not break the interpreter. -However, -there is no guarantee that such code does anything sensible. -(None can be given, because the halting problem is unsolvable.) -.TP -.BI \-U " name" -undefine symbol -.I name -for conditional compilation. -.TP -.B \-v -print version information. -.TP -.B \-V -verbose; -print the names of the source files as they are processed. -.SH FILES -.TP 15 -.B luac.out -default output file -.SH "SEE ALSO" -.BR lua (1) -.br -.I "Reference Manual of the Programming Language Lua" -.br -http://www.tecgraf.puc-rio.br/lua/ -.br -"Lua: an extensible extension language", -.I Software: Practice & Experience -.B 26 -#6 (1996) 635-652. -.SH DIAGNOSTICS -Error messages should be self explanatory. -.SH AUTHORS -L. H. de Figueiredo, -R. Ierusalimschy and -W. Celes -.I (lua@tecgraf.puc-rio.br) -.\" EOF diff --git a/doc/manual.html b/doc/manual.html index 8c157c2b53..703bd16557 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,10 +1,19 @@ + -Lua 3.2 Reference Manual +Lua: reference manual 4.0 + -

    Lua 3.2 Reference Manual

    - +
    +

    +Lua +Reference Manual of the Programming Language +Lua +4.0 +

    + +

    @@ -15,7 +24,7 @@

    1 - Introduction

    Lua is an extension programming language designed to support general procedural programming with data description facilities. -Lua is intended to be used as a light-weight, but powerful, +Lua is intended to be used as a powerful, light-weight configuration language for any program that needs one.

    Lua is implemented as a library, written in C. @@ -24,21 +33,40 @@

    1 - Introduction

    called the embedding program. This host program can invoke functions to execute a piece of code in Lua, can write and read Lua variables, -and can register C functions to be called by Lua code. -Through the use of C functions, Lua can be augmented to cope with +and can register C functions to be called by Lua code. +Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework.

    Lua is free-distribution software, -and provided as usual with no guarantees, -as stated in the copyright notice. +and is provided as usual with no guarantees, +as stated in its copyright notice. The implementation described in this manual is available at the following URL's:

    -   http://www.tecgraf.puc-rio.br/lua/
    -   ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz
    +       http://www.tecgraf.puc-rio.br/lua/
    +       ftp://ftp.tecgraf.puc-rio.br/pub/lua/
     

    +Like any other reference manual, +this document is dry in places. +For a discussion of the decisions behind the design of Lua, +see the papers below, +which are available at the web site above. +

      +
    • +R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. +Lua-an extensible extension language. +Software: Practice & Experience 26 #6 (1996) 635--652. +
    • +L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. +The design and implementation of a language for extending applications. +Proceedings of XXI Brazilian Seminar on Software and Hardware (1994) 273--283. +
    • +L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. +Lua: an extensible embedded language. +Dr. Dobb's Journal 21 #12 (Dec 1996) 26--33. +


    @@ -46,43 +74,50 @@

    1 - Introduction

    2 - Environment and Chunks

    All statements in Lua are executed in a global environment. -This environment, which keeps all global variables, -is initialized with a call from the embedding program to +This environment is initialized with a call from the embedding program to lua_open and persists until a call to lua_close, or the end of the embedding program. -Optionally, a user can create multiple independent global -environments (see Section 5.1). +If necessary, +the host programmer can create multiple independent global +environments, and freely switch between them (see Section 5.1).

    The global environment can be manipulated by Lua code or by the embedding program, which can read and write global variables using API functions from the library that implements Lua.

    -Global variables do not need declaration. +Global variables in Lua do not need to be declared. Any variable is assumed to be global unless explicitly declared local -(see Section 4.5.5). -Before the first assignment, the value of a global variable is nil; -this default can be changed (see Section 4.8). +(see Section 4.4.6). +Before the first assignment, the value of a global variable is nil +(this default can be changed; see Section 4.8). +A table is used to keep all global names and values +(tables are explained in Section 3).

    The unit of execution of Lua is called a chunk. -A chunk is simply a sequence of statements: -

    -chunk ::= {stat} [ret]
    -
    -Statements are described in Section 4.5. -(As usual, {a} means 0 or more a's, -[a] means an optional a and ('a)+ means -one or more a's.) -

    -A chunk may be in a file or in a string inside the host program. -A chunk may optionally end with a return statement (see Section 4.5.3). -When a chunk is executed, first all its code is pre-compiled, -then the statements are executed in sequential order. +A chunk is simply a sequence of statements, +which are executed sequentially. +Each statement can be optionally followed by a semicolon: +

    +       chunk ::= {stat [`;']}
    +
    +Statements are described in Section 4.4. +(The notation above is the usual extended BNF, +in which +{a} means 0 or more a's, +[a] means an optional a, and +(a)+ means one or more a's. +The complete syntax of Lua is given in BNF). +

    +A chunk may be stored in a file or in a string inside the host program. +When a chunk is executed, first it is pre-compiled into bytecodes for +a virtual machine, and then the statements are executed in sequential order, +by simulating the virtual machine. All modifications a chunk effects on the global environment persist -after the chunk end. +after the chunk ends.

    -Chunks may also be pre-compiled into binary form; +Chunks may also be pre-compiled into binary form and stored in files; see program luac for details. Text files with chunks and their binary pre-compiled forms are interchangeable. @@ -95,11 +130,12 @@

    2 - Environment and Chunks

    3 - Types and Tags

    -Lua is a dynamically typed language. -Variables do not have types; only values do. +Lua is a dynamically typed language. +This means that +variables do not have types; only values do. Therefore, there are no type definitions in the language. All values carry their own type. -Besides a type, all values also have a tag. +Besides a type, all values also have a tag.

    There are six basic types in Lua: nil, number, string, function, userdata, and table. @@ -107,26 +143,30 @@

    3 - Types and Tags

    whose main property is to be different from any other value. Number represents real (double-precision floating-point) numbers, while string has the usual meaning. -Lua is eight-bit clean, + +Lua is 8-bit clean, and so strings may contain any 8-bit character, -including embedded zeros ('\0'). -The function type returns a string describing the type +including embedded zeros ('\0') (see Section 4.1). +The type function returns a string describing the type of a given value (see Section 6.1).

    -Functions are considered first-class values in Lua. +Functions are considered first-class values in Lua. This means that functions can be stored in variables, passed as arguments to other functions, and returned as results. Lua can call (and manipulate) functions written in Lua and functions written in C. -They can be distinguished by their tags: +The two kinds of functions can be distinguished by their tags: all Lua functions have the same tag, -and all C functions have the same tag, +and all C functions have the same tag, which is different from the tag of Lua functions. +The tag function returns the tag +of a given value (see Section 6.1).

    The type userdata is provided to allow -arbitrary C pointers to be stored in Lua variables. -It corresponds to a void* and has no pre-defined operations in Lua, -besides assignment and equality test. +arbitrary C pointers to be stored in Lua variables. +This type corresponds to a void* +and has no pre-defined operations in Lua, +except assignment and equality test. However, by using tag methods, the programmer can define operations for userdata values (see Section 4.8). @@ -135,100 +175,109 @@

    3 - Types and Tags

    that is, arrays that can be indexed not only with numbers, but with any value (except nil). Therefore, this type may be used not only to represent ordinary arrays, -but also symbol tables, sets, records, etc. +but also symbol tables, sets, records, graphs, trees, etc. Tables are the main data structuring mechanism in Lua. To represent records, Lua uses the field name as an index. The language supports this representation by providing a.name as syntactic sugar for a["name"]. -Tables may also carry methods. +Tables may also carry methods: Because functions are first class values, table fields may contain functions. The form t:f(x) is syntactic sugar for t.f(t,x), which calls the method f from the table t passing -itself as the first parameter (see Section 4.6.9). +the table itself as the first parameter (see Section 4.5.9).

    Note that tables are objects, and not values. -Variables cannot contain tables, only references to them. +Variables do not contain tables, only references to them. Assignment, parameter passing, and returns always manipulate references to tables, and do not imply any kind of copy. Moreover, tables must be explicitly created before used -(see Section 4.6.7). +(see Section 4.5.7).

    -Tags are mainly used to select tag methods when +Each of the types nil, number, and string has a different tag. +All values of each of these types have the same pre-defined tag. +As explained above, +values of type function can have two different tags, +depending on whether they are Lua functions or C functions. +Finally, +values of type userdata and table can have variable tags, +assigned by the programmer (see Section 4.8). +The tag function returns the tag of a given value. +User tags are created with the function newtag. +The settag function +is used to change the tag of a table (see Section 6.1). +The tag of userdata values can only be set from C (see Section 5.7). +Tags are mainly used to select tag methods when some events occur. Tag methods are the main mechanism for extending the semantics of Lua (see Section 4.8). -Each of the types nil, number and string has a different tag. -All values of each of these types have this same pre-defined tag. -Values of type function can have two different tags, -depending on whether they are Lua functions or C functions. -Finally, -values of type userdata and table can have -as many different tags as needed (see Section 4.8). -Tags are created with the function newtag, -and the function tag returns the tag of a given value. -To change the tag of a given table, -there is the function settag (see Section 6.1). -


    4 - The Language

    -This section describes the lexis, the syntax and the semantics of Lua. +This section describes the lexis, the syntax, and the semantics of Lua.

    4.1 - Lexical Conventions

    -Identifiers in Lua can be any string of letters, +Identifiers in Lua can be any string of letters, digits, and underscores, not beginning with a digit. -The definition of letter depends on the current locale: +This coincides with the definition of identifiers in most languages, +except that +the definition of letter depends on the current locale: Any character considered alphabetic by the current locale can be used in an identifier. -The following words are reserved, and cannot be used as identifiers: +The following words are reserved, and cannot be used as identifiers:

    -      and       do        else      elseif
    -      end       function  if        local
    -      nil       not       or        repeat
    -      return    then      until     while
    +       and       break     do        else      elseif
    +       end       for       function  if        in
    +       local     nil       not       or        repeat
    +       return    then      until     while
     
    +

    Lua is a case-sensitive language: -and is a reserved word, but And and \'and -(if the locale permits) are two other different identifiers. +and is a reserved word, but And and ánd +(if the locale permits) are two different, valid identifiers. As a convention, identifiers starting with underscore followed by -uppercase letters are reserved for internal variables. +uppercase letters (such as _INPUT) +are reserved for internal variables.

    The following strings denote other tokens:

    -         ~=  <=  >=  <   >   ==  =   +   -   *   /   
    -         (   )   {   }   [   ]   ;   ,   .   ..  ...
    +       ~=    <=    >=    <     >     ==    =     +     -     *     /     
    +       (     )     {     }     [     ]     ;     ,     .     ..    ...
     

    -Literal strings can be delimited by matching single or double quotes, +Literal strings +can be delimited by matching single or double quotes, and can contain the C-like escape sequences -'\a' (bell), -'\b' (backspace), -'\f' (form feed), -'\n' (new line), -'\r' (carriage return), -'\t' (horizontal tab), -'\v' (vertical tab), -'\\', (backslash), -'\"', (double quote), -and '\'' (single quote). +`\a' (bell), +`\b' (backspace), +`\f' (form feed), +`\n' (newline), +`\r' (carriage return), +`\t' (horizontal tab), +`\v' (vertical tab), +`\\' (backslash), +`\"' (double quote), +`\'' (single quote), +and `\newline' (that is, a backslash followed by a real newline, +which results in a newline in the string). A character in a string may also be specified by its numerical value, -through the escape sequence '\ddd', -where ddd is a sequence of up to three decimal digits. -Strings in Lua may contain any 8-bit value, including embedded 0. +through the escape sequence `\ddd', +where ddd is a sequence of up to three decimal digits. +Strings in Lua may contain any 8-bit value, including embedded zeros, +which can be specified as `\000'.

    -Literal strings can also be delimited by matching [[ ... ]]. +Literal strings can also be delimited by matching [[ ... ]]. Literals in this bracketed form may run for several lines, -may contain nested [[ ... ]] pairs, +may contain nested [[ ... ]] pairs, and do not interpret escape sequences. This form is specially convenient for writing strings that contain program pieces or @@ -236,268 +285,363 @@

    4.1 - Lexical Conventions

    As an example, in a system using ASCII, the following three literals are equivalent:
    -1) "alo\n123\""
    -2) '\97lo\10\04923"'
    -3) [[alo
    -   123"]]
    +       1)   "alo\n123\""
    +       2)   '\97lo\10\04923"'
    +       3)   [[alo
    +            123"]]
     

    -

    -Comments start anywhere outside a string with a +Comments start anywhere outside a string with a double hyphen (--) and run until the end of the line. Moreover, the first line of a chunk is skipped if it starts with #. This facility allows the use of Lua as a script interpreter in Unix systems (see Section 8).

    -Numerical constants may be written with an optional decimal part, +Numerical constants may be written with an optional decimal part and an optional decimal exponent. Examples of valid numerical constants are

            3     3.0     3.1416  314.16e-2   0.31416E1
     

    - - -

    4.2 - The Pre-processor

    -

    -All lines that start with a $ sign are handled by a pre-processor. -The $ sign must be immediately -followed by one of the following directives: -

    -
    debug
    - turn on debugging facilities (see Section 4.9). -
    nodebug
    - turn off debugging facilities (see Section 4.9). -
    if cond
    - starts a conditional part. -If cond is false, then this part is skipped by the lexical analyzer. -
    ifnot cond
    - starts a conditional part. -If cond is true, then this part is skipped by the lexical analyzer. -
    end
    - ends a conditional part. -
    else
    - starts an ``else'' conditional part, -flipping the ``skip'' status. -
    endinput
    - ends the lexical parse of the file. -
    -

    -Directives may be freely nested. -Particularly, a $endinput may occur inside a $if; -in that case, even the matching $end is not parsed. -

    -A cond part may be -

    -
    nil
    - always false. -
    1
    - always true. -
    name
    - true if the value of the -global variable name is different from nil. -Note that name is evaluated before the chunk starts its execution. -Therefore, actions in a chunk do not affect its own conditional directives. -
    -

    - -

    4.3 - Coercion

    + +

    4.2 - Coercion

    Lua provides some automatic conversions between values at run time. Any arithmetic operation applied to a string tries to convert that string to a number, following the usual rules. Conversely, whenever a number is used when a string is expected, that number is converted to a string, in a reasonable format. -For complete control on how numbers are converted to strings, +The format is chosen so that +a conversion from number to string then back to number +reproduces the original number exactly. +Thus, +the conversion does not necessarily produces nice-looking text for some numbers. +For complete control of how numbers are converted to strings, use the format function (see Section 6.2).

    - -

    4.4 - Adjustment

    + +

    4.3 - Adjustment

    Functions in Lua can return many values. Because there are no type declarations, when a function is called -the system does not know how many values a function will return, +the system does not know how many values the function will return, or how many parameters it needs. Therefore, sometimes, a list of values must be adjusted, at run time, to a given length. If there are more values than are needed, then the excess values are thrown away. -If there are more needs than values, +If there are less values than are needed, then the list is extended with as many nil's as needed. -Adjustment occurs in multiple assignment (see Section 4.5.2) -and function calls (see Section 4.6.8). +This adjustment occurs in multiple assignments (see Section 4.4.2) +and in function calls (see Section 4.5.8).

    - -

    4.5 - Statements

    + +

    4.4 - Statements

    Lua supports an almost conventional set of statements, similar to those in Pascal or C. The conventional commands include -assignment, control structures and procedure calls. +assignment, control structures, and procedure calls. Non-conventional commands include table constructors -(see Section 4.6.7), -and local variable declarations (see Section 4.5.5). +(see Section 4.5.7) +and local variable declarations (see Section 4.4.6).

    -

    4.5.1 - Blocks

    -A block is a list of statements, which are executed sequentially. -A statement may be optionally followed by a semicolon: +

    4.4.1 - Blocks

    +A block is a list of statements; +syntactically, a block is equal to a chunk:
    -block ::= {stat sc} [ret]
    -sc ::= [';']
    +       block ::= chunk
     
    -For syntactic reasons, a return statement can only be written -as the last statement of a block. -This restriction also avoids some ``statement not reached'' conditions.

    A block may be explicitly delimited:

    -stat ::= do block end
    +       stat ::= do block end
     
    -This is useful to control the scope of local variables (see Section 4.5.5). +Explicit blocks are useful +to control the scope of local variables (see Section 4.4.6). +Explicit blocks are also sometimes used to +add a return or break statement in the middle +of another block (see Section 4.4.3).

    -

    4.5.2 - Assignment

    -The language allows multiple assignment. +

    4.4.2 - Assignment

    +Lua allows multiple assignment. Therefore, the syntax for assignment -defines a list of variables on the left side, +defines a list of variables on the left side and a list of expressions on the right side. -Both lists have their elements separated by commas: +The elements in both lists are separated by commas:
    -stat ::= varlist1 '=' explist1
    -varlist1 ::= var {',' var}
    +       stat ::= varlist1 `=' explist1
    +       varlist1 ::= var {`,' var}
     
    This statement first evaluates all values on the right side and eventual indices on the left side, and then makes the assignments. -Therefore, it can be used to exchange two values, as in +So, the code +
    +       i = 3
    +       i, a[i] = 4, 20
    +
    +sets a[3] to 20, but does not affect a[4] +because the i in a[i] is evaluated +before it is assigned 4. +

    +Multiple assignment can be used to exchange two values, as in

    -   x, y = y, x
    +       x, y = y, x
     
    -The two lists may have different lengths. -Before the assignment, the list of values is adjusted to -the length of the list of variables (see Section 4.4). +

    +The two lists in a multiple assignment may have different lengths. +Before the assignment, the list of values is adjusted to +the length of the list of variables (see Section 4.3).

    A single name can denote a global variable, a local variable, or a formal parameter:

    -var ::= name
    +       var ::= name
     
    +

    Square brackets are used to index a table:

    -var ::= simpleexp '[' exp1 ']'
    +       var ::= varorfunc `[' exp1 `]'
    +       varorfunc ::= var | functioncall
     
    -The simpleexp should result in a table value, -from where the field indexed by the expression +The varorfunc should result in a table value, +from where the field indexed by the expression exp1 value gets the assigned value.

    The syntax var.NAME is just syntactic sugar for var["NAME"]:

    -var ::= simpleexp '.' name
    +       var ::= varorfunc `.' name
     

    The meaning of assignments and evaluations of global variables and indexed variables can be changed by tag methods (see Section 4.8). Actually, an assignment x = val, where x is a global variable, -is equivalent to a call setglobal('x', val); +is equivalent to a call setglobal("x", val) and an assignment t[i] = val is equivalent to -settable_event(t, i, val). -See Section 4.8 for a complete description of these functions. -(Function setglobal is pre-defined in Lua. -Function settable_event is used only for explanatory purposes.) -

    -

    4.5.3 - Control Structures

    -The condition expression of a control structure may return any value. +settable_event(t,i,val). +See Section 4.8 for a complete description of these functions +(setglobal is in the basic library; +settable_event is used for explanatory purposes only). +

    + +

    4.4.3 - Control Structures

    +The control structures +if, while, and repeat have the usual meaning and +familiar syntax + + + +
    +       stat ::= while exp1 do block end
    +       stat ::= repeat block until exp1
    +       stat ::= if exp1 then block {elseif exp1 then block} [else block] end
    +
    +The condition expression exp1 of a control structure may return any value. All values different from nil are considered true; only nil is considered false. -if's, while's and repeat's have the usual meaning. -

    - -

    -stat ::= while exp1 do block end 
    | repeat block until exp1
    | if exp1 then block {elseif exp1 then block} [else block] end -

    -A return is used to return values from a function or from a chunk. +The return statement is used to return values +from a function or from a chunk. -Because they may return more than one value, -the syntax for a return statement is -

    -ret ::= return [explist1] [sc]
    -
    + +Because functions or chunks may return more than one value, +the syntax for the return statement is +
    +       stat ::= return [explist1]
    +
    +

    +The break statement can be used to terminate the execution of a loop, +skipping to the next statement after the loop: + +

    +       stat ::= break
    +
    +A break ends the innermost enclosing loop +(while, repeat, or for). +

    +For syntactic reasons, return and break +statements can only be written as the last statements of a block. +If it is really necessary to return or break in the +middle of a block, +an explicit inner block can used, +as in the idiom `do return end', +because now return is last statement in the inner block. +

    + +

    4.4.4 - For Statement

    +

    +The for statement has two forms, +one for numbers and one for tables. +The numerical for loop has the following syntax: +

    +       stat ::= for name `=' exp1 `,' exp1 [`,' exp1] do block end
    +
    +A for statement like +
    +       for var = e1 ,e2, e3 do block end
    +
    +is equivalent to the code: +
    +       do
    +         local var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
    +         if not (var and _limit and _step) then error() end
    +         while (_step>0 and var<=_limit) or (_step<=0 and var>=_limit) do
    +           block
    +           var = var+_step
    +         end
    +       end
    +
    +Note the following: +
    • sep=0pt +
    • _limit and _step are invisible variables. +The names are here for explanatory purposes only. +
    • The behavior is undefined if you assign to var inside +the block. +
    • If the third expression (the step) is absent, then a step of 1 is used. +
    • Both the limit and the step are evaluated only once, +before the loop starts. +
    • The variable var is local to the statement; +you cannot use its value after the for ends. +
    • You can use break to exit a for. +If you need the value of the index, +assign it to another variable before breaking. +
    +

    +The table for statement traverses all pairs +(index,value) of a given table. +It has the following syntax: +

    +       stat ::= for name `,' name in exp1 do block end
    +
    +A for statement like +
    +       for index, value in exp do block end
    +
    +is equivalent to the code: +
    +       do
    +         local _t = exp
    +         local index, value = next(t, nil)
    +         while index do
    +           block
    +           index, value = next(t, index)
    +         end
    +       end
    +
    +Note the following: +
    • sep=0pt +
    • _t is an invisible variable. +The name is here for explanatory purposes only. +
    • The behavior is undefined if you assign to index inside +the block. +
    • The behavior is undefined if you change +the table _t during the traversal. +
    • The variables index and value are local to the statement; +you cannot use their values after the for ends. +
    • You can use break to exit a for. +If you need the value of index or value, +assign them to other variables before breaking. +
    • The order that table elements are traversed is undefined, +even for numerical indices. +If you want to traverse indices in numerical order, +use a numerical for. +
    +

    -

    4.5.4 - Function Calls as Statements

    +

    4.4.5 - Function Calls as Statements

    Because of possible side-effects, function calls can be executed as statements:
    -stat ::= functioncall
    +       stat ::= functioncall
     
    In this case, all returned values are thrown away. -Function calls are explained in Section 4.6.8. +Function calls are explained in Section 4.5.8.

    -

    4.5.5 - Local Declarations

    +

    4.4.6 - Local Declarations

    Local variables may be declared anywhere inside a block. -Their scope begins after the declaration and lasts until the -end of the block. The declaration may include an initial assignment:
    -stat ::= local declist [init]
    -declist ::= name {',' name}
    -init ::= '=' explist1
    +       stat ::= local declist [init]
    +       declist ::= name {`,' name}
    +       init ::= `=' explist1
     
    If present, an initial assignment has the same semantics of a multiple assignment. Otherwise, all variables are initialized with nil.

    +A chunk is also a block, +and so local variables can be declared outside any explicit block.

    - -

    4.6 - Expressions

    +The scope of local variables begins after +the declaration and lasts until the end of the block. +Thus, the code +local print=print +creates a local variable called print whose +initial value is that of the global variable of the same name.

    -

    4.6.1 - Basic Expressions

    -Basic expressions are -
    -exp ::= '(' exp ')'
    -exp ::= nil
    -exp ::= 'number'
    -exp ::= 'literal'
    -exp ::= function
    -exp ::= simpleexp
    -
    +

    + +

    4.5 - Expressions

    +

    +

    4.5.1 - Basic Expressions

    +The basic expressions in Lua are
    -simpleexp ::= var
    -simpleexp ::= upvalue
    -simpleexp ::= functioncall
    +       exp ::= `(' exp `)'
    +       exp ::= nil
    +       exp ::= number
    +       exp ::= literal
    +       exp ::= var
    +       exp ::= upvalue
    +       exp ::= function
    +       exp ::= functioncall
    +       exp ::= tableconstructor
     

    Numbers (numerical constants) and -string literals are explained in Section 4.1; -variables are explained in Section 4.5.2; -upvalues are explained in Section 4.7; -function definitions (function) are explained in Section 4.6.9; -function calls are explained in Section 4.6.8. +literal strings are explained in Section 4.1; +variables are explained in Section 4.4.2; +upvalues are explained in Section 4.6; +function definitions are explained in Section 4.5.9; +function calls are explained in Section 4.5.8. +Table constructors are explained in Section 4.5.7.

    An access to a global variable x is equivalent to a -call getglobal('x'); +call getglobal("x") and an access to an indexed variable t[i] is equivalent to -a call gettable_event(t, i). -See Section 4.8 for a description of these functions. -(Function getglobal is pre-defined in Lua. -Function gettable_event is used only for explanatory purposes.) +a call gettable_event(t,i). +See Section 4.8 for a description of these functions +(getglobal is in the basic library; +gettable_event is used for explanatory purposes only).

    The non-terminal exp1 is used to indicate that the values returned by an expression must be adjusted to one single value:

    -exp1 ::= exp
    +       exp1 ::= exp
     

    -

    4.6.2 - Arithmetic Operators

    +

    4.5.2 - Arithmetic Operators

    Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), -/ (division) and ^ (exponentiation), +/ (division), and ^ (exponentiation); and unary - (negation). If the operands are numbers, or strings that can be converted to -numbers (according to the rules given in Section 4.3), +numbers (according to the rules given in Section 4.2), then all operations except exponentiation have the usual meaning. Otherwise, an appropriate tag method is called (see Section 4.8). An exponentiation always calls a tag method. @@ -505,196 +649,216 @@

    4.6.2 - Arithmetic Operators

    giving the expected meaning to exponentiation (see Section 6.3).

    -

    4.6.3 - Relational Operators

    -Lua provides the following relational operators: +

    4.5.3 - Relational Operators

    +The relational operators in Lua are
    -       <   >   <=  >=  ~=  ==
    +       ==    ~=    <     >     <=    >=
     
    -All these return nil as false and a value different from nil as true. +These operators return nil as false and a value different from nil as true.

    -Equality first compares the tags of its operands. +Equality (==) first compares the tags of its operands. If they are different, then the result is nil. Otherwise, their values are compared. Numbers and strings are compared in the usual way. -Tables, userdata and functions are compared by reference, -that is, two tables are considered equal only if they are the same table. +Tables, userdata, and functions are compared by reference, +that is, two tables are considered equal only if they are the same table. The operator ~= is exactly the negation of equality (==). -Note that the conversion rules of Section 4.3 +

    +The conversion rules of Section 4.2 do not apply to equality comparisons. -Thus, "0"==0 evaluates to false, +Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table.

    -The other operators work as follows. +The order operators work as follows. If both arguments are numbers, then they are compared as such. Otherwise, if both arguments are strings, then their values are compared using lexicographical order. -Otherwise, the ``order'' tag method is called (see Section 4.8). +Otherwise, the ``lt'' tag method is called (see Section 4.8).

    -

    4.6.4 - Logical Operators

    -The logical operators are +

    4.5.4 - Logical Operators

    +The logical operators in Lua are
    -             and   or   not
    +       and   or    not
     
    -Like control structures, all logical operators +Like the control structures, all logical operators consider nil as false and anything else as true. -The operator and returns nil if its first argument is nil; +

    +The conjunction operator and returns nil if its first argument is nil; otherwise, it returns its second argument. -The operator or returns its first argument +The disjunction operator or returns its first argument if it is different from nil; otherwise, it returns its second argument. Both and and or use short-cut evaluation, that is, -the second operand is evaluated only when necessary. +the second operand is evaluated only if necessary.

    -A useful Lua idiom is x = x or v, +There are two useful Lua idioms that use logical operators. +The first idiom is +

    +       x = x or v
    +
    which is equivalent to
    -      if x == nil then x = v end
    +       if x == nil then x = v end
     
    -i.e., it sets x to a default value v when -x is not set. +This idiom sets x to a default value v when x is not set.

    -

    4.6.5 - Concatenation

    +The second idiom is +
    +       x = a and b or c
    +
    +which should be read as x = (a and b) or c. +This idiom is equivalent to +
    +       if a then x = b else x = c end
    +
    +provided that b is not nil. +

    + +

    4.5.5 - Concatenation

    The string concatenation operator in Lua is -denoted by ``..''. -If both operands are strings or numbers, they are converted to -strings according to the rules in Section 4.3. +denoted by two dots (`..'). +If both operands are strings or numbers, then they are converted to +strings according to the rules in Section 4.2. Otherwise, the ``concat'' tag method is called (see Section 4.8).

    -

    4.6.6 - Precedence

    -Operator precedence follows the table below, +

    4.5.6 - Precedence

    +Operator precedence in Lua follows the table below, from the lower to the higher priority:
    -             and   or
    -             <   >   <=  >=  ~=  ==
    -             ..
    -             +   -
    -             *   /
    -             not  - (unary)
    -             ^
    +       and   or
    +       <     >     <=    >=    ~=    ==
    +       ..
    +       +     -
    +       *     /
    +       not   - (unary)
    +       ^
     
    All binary operators are left associative, except for ^ (exponentiation), which is right associative. +The pre-compiler may rearrange the order of evaluation of +associative operators (such as .. or +), +as long as these optimizations do not change normal results. +However, these optimizations may change some results +if you define non-associative +tag methods for these operators.

    -

    4.6.7 - Table Constructors

    +

    4.5.7 - Table Constructors

    Table constructors are expressions that create tables; every time a constructor is evaluated, a new table is created. Constructors can be used to create empty tables, -or to create a table and initialize some fields. -

    +or to create a table and initialize some of its fields. The general syntax for constructors is

    -tableconstructor ::= '{' fieldlist '}'
    -fieldlist ::= lfieldlist | ffieldlist | lfieldlist ';' ffieldlist | ffieldlist ';' lfieldlist
    -lfieldlist ::= [lfieldlist1]
    -ffieldlist ::= [ffieldlist1]
    +       tableconstructor ::= `{' fieldlist `}'
    +       fieldlist ::= lfieldlist | ffieldlist | lfieldlist `;' ffieldlist | ffieldlist `;' lfieldlist
    +       lfieldlist ::= [lfieldlist1]
    +       ffieldlist ::= [ffieldlist1]
     

    The form lfieldlist1 is used to initialize lists:

    -lfieldlist1 ::= exp {',' exp} [',']
    +       lfieldlist1 ::= exp {`,' exp} [`,']
     
    The expressions in the list are assigned to consecutive numerical indices, -starting with 1. +starting with 1. For example,
    -   a = {"v1", "v2", 34}
    +       a = {"v1", "v2", 34}
     
    is equivalent to
    -  do
    -    local temp = {}
    -    temp[1] = "v1"
    -    temp[2] = "v2"
    -    temp[3] = 34
    -    a = temp
    -  end
    +       do
    +         local temp = {}
    +         temp[1] = "v1"
    +         temp[2] = "v2"
    +         temp[3] = 34
    +         a = temp
    +       end
     

    The form ffieldlist1 initializes other fields in a table:

    -ffieldlist1 ::= ffield {',' ffield} [',']
    -ffield ::= '[' exp ']' '=' exp | name '=' exp
    +       ffieldlist1 ::= ffield {`,' ffield} [`,']
    +       ffield ::= `[' exp `]' `=' exp | name `=' exp
     
    For example,
    -   a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
    +       a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
     
    is equivalent to
    -  do
    -    local temp = {}
    -    temp[f(k)] = g(y)
    -    temp.x = 1    -- or temp["x"] = 1
    -    temp.y = 3    -- or temp["y"] = 3
    -    temp[0] = b+c
    -    a = temp
    -  end
    +       do
    +         local temp = {}
    +         temp[f(k)] = g(y)
    +         temp.x = 1    -- or temp["x"] = 1
    +         temp.y = 3    -- or temp["y"] = 3
    +         temp[0] = b+c
    +         a = temp
    +       end
     
    An expression like {x = 1, y = 4} is in fact syntactic sugar for {["x"] = 1, ["y"] = 4}.

    Both forms may have an optional trailing comma, and can be used in the same constructor separated by -a semi-collon. -For example, all forms below are correct: +a semi-colon. +For example, all forms below are correct.

    -   x = {;}
    -   x = {'a', 'b',}
    -   x = {type='list'; 'a', 'b'}
    -   x = {f(0), f(1), f(2),; n=3,}
    +       x = {;}
    +       x = {"a", "b",}
    +       x = {type="list"; "a", "b"}
    +       x = {f(0), f(1), f(2),; n=3,}
     

    -

    4.6.8 - Function Calls

    -A function call has the following syntax: +

    4.5.8 - Function Calls

    +A function call in Lua has the following syntax:
    -functioncall ::= simpleexp args
    +       functioncall ::= varorfunc args
     
    -First, simpleexp is evaluated. +First, varorfunc is evaluated. If its value has type function, then this function is called, with the given arguments. Otherwise, the ``function'' tag method is called, -having as first parameter the value of simpleexp, -and then the original call parameters. +having as first parameter the value of varorfunc, +and then the original call arguments +(see Section 4.8).

    -The form: +The form

    -functioncall ::= simpleexp ':' name args
    +       functioncall ::= varorfunc `:' name args
     
    can be used to call ``methods''. -A call simpleexp:name(...) -is syntactic sugar for -
    -  simpleexp.name(simpleexp, ...)
    -
    -except that simpleexp is evaluated only once. +A call v:name(...) +is syntactic sugar for v.name(v, ...), +except that v is evaluated only once.

    Arguments have the following syntax:

    -args ::= '(' [explist1] ')'
    -args ::= tableconstructor
    -args ::= 'literal'
    -explist1 ::= exp1 {',' exp1}
    +       args ::= `(' [explist1] `)'
    +       args ::= tableconstructor
    +       args ::= literal
    +       explist1 ::= {exp1 `,'} exp
     
    All argument expressions are evaluated before the call. A call of the form f{...} is syntactic sugar for f({...}), that is, -the parameter list is a single new table. +the argument list is a single new table. A call of the form f'...' (or f"..." or f[[...]]) is syntactic sugar for f('...'), that is, -the parameter list is a single literal string. +the argument list is a single literal string.

    Because a function can return any number of results -(see Section 4.5.3), -the number of results must be adjusted before used. -If the function is called as a statement (see Section 4.5.4), +(see Section 4.4.3), +the number of results must be adjusted before they are used (see Section 4.3). +If the function is called as a statement (see Section 4.4.5), then its return list is adjusted to 0, thus discarding all returned values. If the function is called in a place that needs a single value @@ -704,166 +868,230 @@

    4.6.8 - Function Calls

    If the function is called in a place that can hold many values (syntactically denoted by the non-terminal exp), then no adjustment is made. -Note that the only place that can hold many values -is the last (or the only) expression in an assignment -or in a return statement; see examples below. +The only places that can hold many values +is the last (or the only) expression in an assignment, +in an argument list, or in the return statement. +Here are some examples:
    -      f();               -- adjusted to 0
    -      g(x, f());         -- f() is adjusted to 1
    -      a,b,c = f(), x;    -- f() is adjusted to 1 result (and c gets nil)
    -      a,b,c = x, f();    -- f() is adjusted to 2
    -      a,b,c = f();       -- f() is adjusted to 3
    -      return f();        -- returns all values returned by f()
    +       f()                -- adjusted to 0 results
    +       g(f(), x)          -- f() is adjusted to 1 result
    +       g(x, f())          -- g gets x plus all values returned by f()
    +       a,b,c = f(), x     -- f() is adjusted to 1 result (and c gets nil)
    +       a,b,c = x, f()     -- f() is adjusted to 2
    +       a,b,c = f()        -- f() is adjusted to 3
    +       return f()         -- returns all values returned by f()
    +       return x,y,f()     -- returns a, b, and all values returned by f()
     

    -

    4.6.9 - Function Definitions

    +

    4.5.9 - Function Definitions

    The syntax for function definition is

    -function ::= function '(' [parlist1] ')' block end
    -stat ::= function funcname '(' [parlist1] ')' block end
    -funcname ::= name | name '.' name
    +       function ::= function `(' [parlist1] `)' block end
    +       stat ::= function funcname `(' [parlist1] `)' block end
    +       funcname ::= name | name `.' name | name `:' name
     
    The statement
    -      function f (...)
    -        ...
    -      end
    +       function f () ... end
     
    is just syntactic sugar for
    -      f = function (...)
    -            ...
    -          end
    +       f = function () ... end
    +
    +and the statement +
    +       function v.f () ... end
    +
    +is syntactic sugar for +
    +       v.f = function () ... end
     

    A function definition is an executable expression, whose value has type function. When Lua pre-compiles a chunk, -all its function bodies are pre-compiled, too. +all its function bodies are pre-compiled too. Then, whenever Lua executes the function definition, -its upvalues are fixed (see Section 4.7), -and the function is instantiated (or ``closed''). -This function instance (or ``closure'') +its upvalues are fixed (see Section 4.6), +and the function is instantiated (or closed). +This function instance (or closure) is the final value of the expression. -Different instances of a same function +Different instances of the same function may have different upvalues.

    Parameters act as local variables, initialized with the argument values:

    -parlist1 ::= '...'
    -parlist1 ::= name {',' name} [',' '...']
    +       parlist1 ::= `...'
    +       parlist1 ::= name {`,' name} [`,' `...']
     
    When a function is called, the list of arguments is adjusted to -the length of the list of parameters (see Section 4.4), -unless the function is a vararg function, -indicated by the dots (...) at the end of its parameter list. +the length of the list of parameters (see Section 4.3), +unless the function is a vararg function, +which is +indicated by three dots (`...') at the end of its parameter list. A vararg function does not adjust its argument list; -instead, it collects any extra arguments into an implicit parameter, +instead, it collects all extra arguments into an implicit parameter, called arg. -This parameter is always initialized as a table, -with a field n whose value is the number of extra arguments, -and the extra arguments at positions 1, 2, ... +The value of arg is a table, +with a field n whose value is the number of extra arguments, +and the extra arguments at positions 1, 2, ..., n.

    -As an example, suppose definitions like: +As an example, consider the following definitions:

    -      function f(a, b) end
    -      function g(a, b, ...) end
    +       function f(a, b) end
    +       function g(a, b, ...) end
    +       function r() return 1,2,3 end
     
    Then, we have the following mapping from arguments to parameters:
    -      CALL            PARAMETERS
    +       CALL            PARAMETERS
     

    - f(3) a=3, b=nil - f(3, 4) a=3, b=4 - f(3, 4, 5) a=3, b=4 + f(3) a=3, b=nil + f(3, 4) a=3, b=4 + f(3, 4, 5) a=3, b=4 + f(r(), 10) a=1, b=10 + f(r()) a=1, b=2

    - g(3) a=3, b=nil, arg={n=0} - g(3, 4) a=3, b=4, arg={n=0} - g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2} + g(3) a=3, b=nil, arg={n=0} + g(3, 4) a=3, b=4, arg={n=0} + g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2} + g(5, r()) a=5, b=1, arg={2, 3; n=2}

    -Results are returned using the return statement (see Section 4.5.3). -If control reaches the end of a function without a return instruction, +Results are returned using the return statement (see Section 4.4.3). +If control reaches the end of a function +without encountering a return statement, then the function returns with no results.

    -There is a special syntax for defining methods, -that is, functions that have an implicit extra parameter self: +The syntax

    -function ::= function name ':' name '(' [parlist1] ')' block end
    +       funcname ::= name `:' name
     
    -Thus, a declaration like +is used for defining methods, +that is, functions that have an implicit extra parameter self. +

    +The statement

    -      function v:f (...)
    -        ...
    -      end
    +       function v:f (...) ... end
     
    -is equivalent to +is just syntactic sugar for
    -      v.f = function (self, ...)
    -        ...
    -      end
    +       v.f = function (self, ...) ... end
     
    -that is, the function gets an extra formal parameter called self. -Note that the variable v must have been -previously initialized with a table value. +Note that the function gets an extra formal parameter called self.

    - -

    4.7 - Visibility and Upvalues

    - + +

    4.6 - Visibility and Upvalues

    +

    A function body may refer to its own local variables -(which includes its parameters) and to global variables, -as long as they are not shadowed by local -variables from enclosing functions. +(which include its parameters) and to global variables, +as long as they are not shadowed by local +variables with the same name from enclosing functions. A function cannot access a local variable from an enclosing function, since such variables may no longer exist when the function is called. However, a function may access the value of a local variable -from an enclosing function, using upvalues. -

    +from an enclosing function, using upvalues, +whose syntax is

    -upvalue ::= '%' name
    +       upvalue ::= `%' name
     
    +

    An upvalue is somewhat similar to a variable expression, -but whose value is frozen when the function wherein it +but whose value is frozen when the function wherein it appears is instantiated. The name used in an upvalue may be the name of any variable visible -at the point where the function is defined. +at the point where the function is defined, +that is, +global variables and local variables +from the immediately enclosing function. +Note that when the upvalue is a table, +only the reference to that table +(which is the value of the upvalue) is frozen; +the table contents can be changed at will. +Using table values as upvalues is a technique for having +writable but private state attached to functions.

    Here are some examples:

    -      a,b,c = 1,2,3   -- global variables
    -      function f (x)
    -        local b       -- x and b are local to f
    -        local g = function (a)
    -          local y     -- a and y are local to g
    -          p = a       -- OK, access local 'a'
    -          p = c       -- OK, access global 'c'
    -          p = b       -- ERROR: cannot access a variable in outer scope
    -          p = %b      -- OK, access frozen value of 'b' (local to 'f')
    -          p = %c      -- OK, access frozen value of global 'c'
    -          p = %y      -- ERROR: 'y' is not visible where 'g' is defined
    -        end           -- g
    -      end             -- f
    +       a,b,c = 1,2,3   -- global variables
    +       local d
    +       function f (x)
    +         local b = {}  -- x and b are local to f; b shadows the global b
    +         local g = function (a)
    +           local y     -- a and y are local to g
    +           p = a       -- OK, access local `a'
    +           p = c       -- OK, access global `c'
    +           p = b       -- ERROR: cannot access a variable in outer scope
    +           p = %b      -- OK, access frozen value of `b' (local to `f')
    +           %b = 3      -- ERROR: cannot change an upvalue
    +           %b.x = 3    -- OK, change the table contents
    +           p = %c      -- OK, access frozen value of global `c'
    +           p = %y      -- ERROR: `y' is not visible where `g' is defined
    +           p = %d      -- ERROR: `d' is not visible where `g' is defined
    +         end           -- g
    +       end             -- f
     

    + + +

    4.7 - Error Handling

    +

    +Because Lua is an extension language, +all Lua actions start from C code in the host program +calling a function from the Lua library. +Whenever an error occurs during Lua compilation or execution, +the function _ERRORMESSAGE is called +(provided it is different from nil), +and then the corresponding function from the library +(lua_dofile, lua_dostring, +lua_dobuffer, or lua_call) +is terminated, returning an error condition. +

    +Memory allocation errors are an exception to the previous rule. +When memory allocation fails, Lua may not be able to execute the +_ERRORMESSAGE function. +So, for this kind of error, Lua does not call +the _ERRORMESSAGE function; +instead, the corresponding function from the library +returns immediately with a special error code (LUA_ERRMEM). +This and other error codes are defined in lua.h; +Section 5.8. +

    +The only argument to _ERRORMESSAGE is a string +describing the error. +The default definition for +this function calls _ALERT, +which prints the message to stderr (see Section 6.1). +The standard I/O library redefines _ERRORMESSAGE +and uses the debug facilities (see Section 7) +to print some extra information, +such as a call stack traceback. +

    +Lua code can explicitly generate an error by calling the +function error (see Section 6.1). +Lua code can ``catch'' an error using the function +call (see Section 6.1). +

    +

    4.8 - Tag Methods

    Lua provides a powerful mechanism to extend its semantics, -called tag methods. +called tag methods. A tag method is a programmer-defined function -that is called at specific key points during the evaluation of a program, +that is called at specific key points during the execution of a Lua program, allowing the programmer to change the standard Lua behavior at these points. Each of these points is called an event.

    @@ -876,8 +1104,8 @@

    4.8 - Tag Methods

    (a string; see below), and the third parameter is the new method (a function), or nil to restore the default behavior for the pair. -The function returns the previous tag method for that pair. -Another function, gettagmethod, +The settagmethod function returns the previous tag method for that pair. +A companion function gettagmethod receives a tag and an event name and returns the current method associated with the pair.

    @@ -885,573 +1113,640 @@

    4.8 - Tag Methods

    identified by the given names. The semantics of tag methods is better explained by a Lua function describing the behavior of the interpreter at each event. -The function not only shows when a tag method is called, -but also its arguments, its results and the default behavior. -Please notice that the code shown here is only illustrative; +This function not only shows when a tag method is called, +but also its arguments, its results, and the default behavior. +The code shown here is only illustrative; the real behavior is hard coded in the interpreter, and it is much more efficient than this simulation. All functions used in these descriptions -(rawgetglobal, tonumber, call, etc.) +(rawget, tonumber, call, etc.) are described in Section 6.1.

    ``add'':
    -called when a + operation is applied to non numerical operands. +called when a + operation is applied to non-numerical operands.

    -The function getbinmethod defines how Lua chooses a tag method +The function getbinmethod below defines how Lua chooses a tag method for a binary operation. First, Lua tries the first operand. If its tag does not define a tag method for the operation, then Lua tries the second operand. -If it also fails, then it gets a tag method from tag 0: -

    -      function getbinmethod (op1, op2, event)
    -        return gettagmethod(tag(op1), event) or
    -               gettagmethod(tag(op2), event) or
    -               gettagmethod(0, event)
    -      end
    -
    -
    -      function add_event (op1, op2)
    -        local o1, o2 = tonumber(op1), tonumber(op2)
    -        if o1 and o2 then  -- both operands are numeric
    -          return o1+o2  -- '+' here is the primitive 'add'
    -        else  -- at least one of the operands is not numeric
    -          local tm = getbinmethod(op1, op2, "add")
    -          if tm then
    -            -- call the method with both operands and an extra
    -            -- argument with the event name
    -            return tm(op1, op2, "add")
    -          else  -- no tag method available: default behavior
    -            error("unexpected type at arithmetic operation")
    -          end
    -        end
    -      end
    +If it also fails, then it gets a tag method from tag 0.
    +
    +       function getbinmethod (op1, op2, event)
    +         return gettagmethod(tag(op1), event) or
    +                gettagmethod(tag(op2), event) or
    +                gettagmethod(0, event)
    +       end
    +
    +Using this function, +the tag method for the ``add'' event is +
    +       function add_event (op1, op2)
    +         local o1, o2 = tonumber(op1), tonumber(op2)
    +         if o1 and o2 then  -- both operands are numeric
    +           return o1+o2  -- '+' here is the primitive 'add'
    +         else  -- at least one of the operands is not numeric
    +           local tm = getbinmethod(op1, op2, "add")
    +           if tm then
    +             -- call the method with both operands and an extra
    +             -- argument with the event name
    +             return tm(op1, op2, "add")
    +           else  -- no tag method available: default behavior
    +             error("unexpected type at arithmetic operation")
    +           end
    +         end
    +       end
     

    ``sub'':
    -called when a - operation is applied to non numerical operands. -Behavior similar to the "add" event. +called when a - operation is applied to non-numerical operands. +Behavior similar to the ``add'' event.

    ``mul'':
    -called when a * operation is applied to non numerical operands. -Behavior similar to the "add" event. +called when a * operation is applied to non-numerical operands. +Behavior similar to the ``add'' event.

    ``div'':
    -called when a / operation is applied to non numerical operands. -Behavior similar to the "add" event. +called when a / operation is applied to non-numerical operands. +Behavior similar to the ``add'' event.

    ``pow'':
    -called when a ^ operation is applied. +called when a ^ operation (exponentiation) is applied, +even for numerical operands.
    -      function pow_event (op1, op2)
    -        local tm = getbinmethod(op1, op2, "pow")
    -        if tm then
    -          -- call the method with both operands and an extra
    -          -- argument with the event name
    -          return tm(op1, op2, "pow")
    -        else  -- no tag method available: default behavior
    -          error("unexpected type at arithmetic operation")
    -        end
    -      end
    +       function pow_event (op1, op2)
    +         local tm = getbinmethod(op1, op2, "pow")
    +         if tm then
    +           -- call the method with both operands and an extra
    +           -- argument with the event name
    +           return tm(op1, op2, "pow")
    +         else  -- no tag method available: default behavior
    +           error("unexpected type at arithmetic operation")
    +         end
    +       end
     

    ``unm'':
    -called when an unary - operation is applied to a non numerical operand. -
    -      function unm_event (op)
    -        local o = tonumber(op)
    -        if o then  -- operand is numeric
    -          return -o  -- '-' here is the primitive 'unm'
    -        else  -- the operand is not numeric.
    -          -- Try to get a tag method from the operand;
    -          --  if it does not have one, try a "global" one (tag 0)
    -          local tm = gettagmethod(tag(op), "unm") or
    -                     gettagmethod(0, "unm")
    -          if tm then
    -            -- call the method with the operand, nil, and an extra
    -            -- argument with the event name
    -            return tm(op, nil, "unm")
    -          else  -- no tag method available: default behavior
    -            error("unexpected type at arithmetic operation")
    -          end
    -        end
    -      end
    +called when a unary - operation is applied to a non-numerical operand.
    +
    +       function unm_event (op)
    +         local o = tonumber(op)
    +         if o then  -- operand is numeric
    +           return -o  -- '-' here is the primitive 'unm'
    +         else  -- the operand is not numeric.
    +           -- Try to get a tag method from the operand;
    +           --  if it does not have one, try a "global" one (tag 0)
    +           local tm = gettagmethod(tag(op), "unm") or
    +                      gettagmethod(0, "unm")
    +           if tm then
    +             -- call the method with the operand, nil, and an extra
    +             -- argument with the event name
    +             return tm(op, nil, "unm")
    +           else  -- no tag method available: default behavior
    +             error("unexpected type at arithmetic operation")
    +           end
    +         end
    +       end
     

    ``lt'':
    -called when a < operation is applied to non numerical -or non string operands. -
    -      function lt_event (op1, op2)
    -        if type(op1) == "number" and type(op2) == "number" then
    -          return op1 < op2   -- numeric comparison
    -        elseif type(op1) == "string" and type(op2) == "string" then
    -          return op1 < op2   -- lexicographic comparison
    -        else
    -          local tm = getbinmethod(op1, op2, "lt")
    -          if tm then
    -            return tm(op1, op2, "lt")
    -          else
    -            error("unexpected type at comparison");
    -          end
    -        end
    -      end
    -
    -

    -

    ``gt'':
    -called when a > operation is applied to non numerical -or non string operands. -Behavior similar to the "lt" event. -

    -

    ``le'':
    -called when a <= operation is applied to non numerical -or non string operands. -Behavior similar to the "lt" event. -

    -

    ``ge'':
    -called when a >= operation is applied to non numerical -or non string operands. -Behavior similar to the "lt" event. +called when an order operation is applied to non-numerical +or non-string operands. +It corresponds to the < operator. +
    +       function lt_event (op1, op2)
    +         if type(op1) == "number" and type(op2) == "number" then
    +           return op1 < op2   -- numeric comparison
    +         elseif type(op1) == "string" and type(op2) == "string" then
    +           return op1 < op2   -- lexicographic comparison
    +         else
    +           local tm = getbinmethod(op1, op2, "lt")
    +           if tm then
    +             return tm(op1, op2, "lt")
    +           else
    +             error("unexpected type at comparison");
    +           end
    +         end
    +       end
    +
    +The other order operators use this tag method according to the +usual equivalences: +
    +       a>b    <=>  b<a
    +       a<=b   <=>  not (b<a)
    +       a>=b   <=>  not (a<b)
    +

    ``concat'':
    -called when a concatenation is applied to non string operands. -
    -      function concat_event (op1, op2)
    -        if (type(op1) == "string" or type(op1) == "number") and
    -           (type(op2) == "string" or type(op2) == "number") then
    -          return op1..op2  -- primitive string concatenation
    -        else
    -          local tm = getbinmethod(op1, op2, "concat")
    -          if tm then
    -            return tm(op1, op2, "concat")
    -          else
    -            error("unexpected type for concatenation")
    -          end
    -        end
    -      end
    +called when a concatenation is applied to non-string operands.
    +
    +       function concat_event (op1, op2)
    +         if (type(op1) == "string" or type(op1) == "number") and
    +            (type(op2) == "string" or type(op2) == "number") then
    +           return op1..op2  -- primitive string concatenation
    +         else
    +           local tm = getbinmethod(op1, op2, "concat")
    +           if tm then
    +             return tm(op1, op2, "concat")
    +           else
    +             error("unexpected type for concatenation")
    +           end
    +         end
    +       end
     

    ``index'':
    called when Lua tries to retrieve the value of an index not present in a table. -See event "gettable" for its semantics. +See the ``gettable'' event for its semantics.

    ``getglobal'':
    called whenever Lua needs the value of a global variable. This method can only be set for nil and for tags created by newtag. -
    -      function getglobal (varname)
    -        local value = rawgetglobal(varname)
    -        local tm = gettagmethod(tag(value), "getglobal")
    -        if not tm then
    -          return value
    -        else
    -          return tm(varname, value)
    -        end
    -      end
    -
    -The function getglobal is pre-defined in Lua (see Section 6.1). +Note that +the tag is that of the current value of the global variable. +
    +       function getglobal (varname)
    +         -- access the table of globals
    +         local value = rawget(globals(), varname)
    +         local tm = gettagmethod(tag(value), "getglobal")
    +         if not tm then
    +           return value
    +         else
    +           return tm(varname, value)
    +         end
    +       end
    +
    +The function getglobal is defined in the basic library (see Section 6.1).

    ``setglobal'':
    called whenever Lua assigns to a global variable. This method cannot be set for numbers, strings, and tables and -userdata with default tags. +userdata with the default tag.
    -      function setglobal (varname, newvalue)
    -        local oldvalue = rawgetglobal(varname)
    -        local tm = gettagmethod(tag(oldvalue), "setglobal")
    -        if not tm then
    -          return rawsetglobal(varname, newvalue)
    -        else
    -          return tm(varname, oldvalue, newvalue)
    -        end
    -      end
    +       function setglobal (varname, newvalue)
    +         local oldvalue = rawget(globals(), varname)
    +         local tm = gettagmethod(tag(oldvalue), "setglobal")
    +         if not tm then
    +           rawset(globals(), varname, newvalue)
    +         else
    +           tm(varname, oldvalue, newvalue)
    +         end
    +       end
     
    -Notice: the function setglobal is pre-defined in Lua (see Section 6.1). +The function setglobal is defined in the basic library (see Section 6.1).

    ``gettable'':
    called whenever Lua accesses an indexed variable. -This method cannot be set for tables with default tag. -
    -      function gettable_event (table, index)
    -        local tm = gettagmethod(tag(table), "gettable")
    -        if tm then
    -          return tm(table, index)
    -        elseif type(table) ~= "table" then
    -          error("indexed expression not a table");
    -        else
    -          local v = rawgettable(table, index)
    -          tm = gettagmethod(tag(table), "index")
    -          if v == nil and tm then
    -            return tm(table, index)
    -          else
    -            return v
    -          end
    -        end
    -      end
    +This method cannot be set for tables with the default tag.
    +
    +       function gettable_event (table, index)
    +         local tm = gettagmethod(tag(table), "gettable")
    +         if tm then
    +           return tm(table, index)
    +         elseif type(table) ~= "table" then
    +           error("indexed expression not a table");
    +         else
    +           local v = rawget(table, index)
    +           tm = gettagmethod(tag(table), "index")
    +           if v == nil and tm then
    +             return tm(table, index)
    +           else
    +             return v
    +           end
    +         end
    +       end
     

    ``settable'':
    called when Lua assigns to an indexed variable. -This method cannot be set for tables with default tag. +This method cannot be set for tables with the default tag.
    -      function settable_event (table, index, value)
    -        local tm = gettagmethod(tag(table), "settable")
    -        if tm then
    -          tm(table, index, value)
    -        elseif type(table) ~= "table" then
    -          error("indexed expression not a table")
    -        else
    -          rawsettable(table, index, value)
    -        end
    -      end
    +       function settable_event (table, index, value)
    +         local tm = gettagmethod(tag(table), "settable")
    +         if tm then
    +           tm(table, index, value)
    +         elseif type(table) ~= "table" then
    +           error("indexed expression not a table")
    +         else
    +           rawset(table, index, value)
    +         end
    +       end
     

    ``function'':
    -called when Lua tries to call a non function value. -
    -      function function_event (func, ...)
    -        if type(func) == "function" then
    -          return call(func, arg)
    -        else
    -          local tm = gettagmethod(tag(func), "function")
    -          if tm then
    -            local i = arg.n
    -            while i > 0 do
    -              arg[i+1] = arg[i]
    -              i = i-1
    -            end
    -            arg.n = arg.n+1
    -            arg[1] = func
    -            return call(tm, arg)
    -          else
    -            error("call expression not a function")
    -          end
    -        end
    -      end
    +called when Lua tries to call a non-function value.
    +
    +       function function_event (func, ...)
    +         if type(func) == "function" then
    +           return call(func, arg)
    +         else
    +           local tm = gettagmethod(tag(func), "function")
    +           if tm then
    +             for i=arg.n,1,-1 do
    +               arg[i+1] = arg[i]
    +             end
    +             arg.n = arg.n+1
    +             arg[1] = func
    +             return call(tm, arg)
    +           else
    +             error("call expression not a function")
    +           end
    +         end
    +       end
     

    ``gc'':
    -called when Lua is ``garbage collecting'' an object. -This method cannot be set for strings, numbers, functions, -and userdata with default tag. -For each object to be collected, +called when Lua is ``garbage collecting'' a userdata. +This tag method can be set only from C, +and cannot be set for a userdata with the default tag. +For each userdata to be collected, Lua does the equivalent of the following function:
    -      function gc_event (obj)
    -        local tm = gettagmethod(tag(obj), "gc")
    -        if tm then
    -          tm(obj)
    -        end
    -      end
    -
    -Moreover, at the end of a garbage collection cycle, + function gc_event (obj) + local tm = gettagmethod(tag(obj), "gc") + if tm then + tm(obj) + end + end +
    +In a garbage-collection cycle, +the tag methods for userdata are called in reverse order of tag creation, +that is, the first tag methods to be called are those associated +with the last tag created in the program. +Moreover, at the end of the cycle, Lua does the equivalent of the call gc_event(nil).

    - - -

    4.9 - Error Handling

    -

    -Because Lua is an extension language, -all Lua actions start from C code in the host program -calling a function from the Lua library. -Whenever an error occurs during Lua compilation or execution, -function _ERRORMESSAGE is called -(provided it is different from nil), -and then the corresponding function from the library -(lua_dofile, lua_dostring, -lua_dobuffer, or lua_callfunction) -is terminated, returning an error condition. -

    -The only argument to _ERRORMESSAGE is a string -describing the error. -The default definition for this function calls _ALERT, -which prints the message to stderr (see Section 6.1). -The standard I/O library redefines _ERRORMESSAGE, -and uses the debug facilities (see Section 7) -to print some extra information, -such as the call stack. -

    -To provide more information about errors, -Lua programs should include the compilation pragma $debug. - - -When an error occurs in a chunk compiled with this option, -the I/O error routine is able to print the number of the -lines where the calls (and the error) were made. -

    -Lua code can explicitly generate an error by calling the built-in -function error (see Section 6.1). -Lua code can ``catch'' an error using the built-in function -call (see Section 6.1). -

    -


    5 - The Application Program Interface

    -

    + This section describes the API for Lua, that is, -the set of C functions available to the host program to communicate -with the Lua library. -The API functions can be classified in the following categories: -

      -
    1. managing states; -
    2. exchanging values between C and Lua; -
    3. executing Lua code; -
    4. manipulating (reading and writing) Lua objects; -
    5. calling Lua functions; -
    6. C functions to be called by Lua; -
    7. manipulating references to Lua Objects. -
    +the set of C functions available to the host program to communicate +with Lua. All API functions and related types and constants are declared in the header file lua.h.

    +Even when we use the term ``function'', +any facility in the API may be provided as a macro instead. +All such macros use each of its arguments exactly once, +and so do not generate hidden side-effects. +

    +

    -

    5.1 - Managing States

    +

    5.1 - States

    +

    +The Lua library is fully reentrant: +it does not have any global variables. + The whole state of the Lua interpreter -(global variables, stack, tag methods, etc) -is stored in a dynamic structure pointed by -

    -typedef struct lua_State lua_State;
    -extern lua_State *lua_state;
    -
    -The variable lua_state is the only C global variable in -the Lua library. +(global variables, stack, tag methods, etc.) +is stored in a dynamically allocated structure of type lua_State; +this state must be passed as the first argument to +every function in the library (except lua_open below).

    Before calling any API function, -this state must be initialized. -This is done by calling +you must create a state by calling +

    -void lua_open (void);
    +       lua_State *lua_open (int stacksize);
     
    -This function allocates and initializes some internal structures, -and defines all pre-defined functions of Lua. -If lua_state is already different from NULL, -lua_open has no effect; -therefore, it is safe to call this function multiple times. -All standard libraries call lua_open when they are opened. +The sole argument to this function is the stack size for the interpreter. +(Each function call needs one stack position for each argument, local variable, +and temporary value, plus one position for book-keeping. +The stack must also have some 20 extra positions available. +For very small implementations, without recursive functions, +a stack size of 100 should be enough.) +If stacksize is zero, +then a default size of 1024 is used.

    -Function lua_setstate is used to change the current state -of Lua: +To release a state created with lua_open, call +

    -lua_State *lua_setstate (lua_State *st);
    +       void lua_close (lua_State *L);
     
    -It sets lua_state to st and returns the old state. +This function destroys all objects in the given Lua environment +(calling the corresponding garbage-collection tag methods, if any) +and frees all dynamic memory used by that state. +Usually, you do not need to call this function, +because all resources are naturally released when your program ends. +On the other hand, +long-running programs - +like a daemon or a web server - +might need to release states as soon as they are not needed, +to avoid growing too big. +

    +With the exception of lua_open, +all functions in the Lua API need a state as their first argument.

    -Multiple, independent states may be created. -For that, you must set lua_state back to NULL before -calling lua_open. -An easy way to do that is defining an auxiliary function: -

    -      lua_State *lua_newstate (void) {
    -        lua_State *old = lua_setstate(NULL);
    -        lua_open();
    -        return lua_setstate(old);
    -      }
    -
    -This function creates a new state without changing the current state -of the interpreter. -Note that any new state is created with all predefined functions, -but any additional library (such as the standard libraries) must be -explicitly open in the new state, if needed. -

    -If necessary, a state may be released by calling -

    -void lua_close (void);
    -
    -This function destroys all objects in the current Lua environment -(calling the correspondent garbage collector tag methods), -frees all dynamic memory used by the state, -and then sets lua_state to NULL. -Usually, there is no need to call this function, -since these resources are naturally released when the program ends. -If lua_state is already NULL, -lua_close has no effect. -

    -If you are using multiple states, -you may find useful to define the following function, -which releases a given state: -

    -      void lua_freestate (lua_State *st) {
    -        lua_State *old = lua_setstate(st);
    -        lua_close();
    -        if (old != st) lua_setstate(old);
    -      }
    -

    - -

    5.2 - Exchanging Values between C and Lua

    -Because Lua has no static type system, -all values passed between Lua and C have type -lua_Object, -which works like an abstract type in C that can hold any Lua value. -Values of type lua_Object have no meaning outside Lua; -for instance, -the comparison of two lua_Object's is undefined. -

    -To check the type of a lua_Object, +

    5.2 - The Stack and Indices

    +

    +Lua uses a stack to pass values to and from C. +Each element in this stack represents a Lua value +(nil, number, string, etc.). +

    +For convenience, +most query operations in the API do not follow a strict stack discipline. +Instead, they can refer to any element in the stack by using an index: +A positive index represents an absolute stack position +(starting at 1, not 0 as in C); +a negative index represents an offset from the top of the stack. +More specifically, if the stack has n elements, +index 1 represents the first element +(that is, the first element pushed onto the stack), +and +index n represents the last element; +index -1 also represents the last element +(that is, the element at the top), +and index -n represents the first element. +We say that an index is valid +if it lays between 1 and the stack top +(that is, if 1 <= abs(index) <= top). + +

    +At any time, you can get the index of the top element by calling + +

    +       int lua_gettop (lua_State *L);
    +
    +Because indices start at 1, +the result of lua_gettop is equal to the number of elements in the stack +(and so 0 means an empty stack). +

    +When you interact with Lua API, +you are responsible for controlling stack overflow. +The function +

    +       int lua_stackspace (lua_State *L);
    +
    +returns the number of stack positions still available. +Whenever Lua calls C, +it ensures that +at least LUA_MINSTACK positions are still available. +LUA_MINSTACK is defined in lua.h and is at least 16, +and so you have to worry about stack space only +when your code has loops pushing elements onto the stack. +

    +Most query functions accept as indices any value inside the +available stack space. +Such indices are called acceptable indices. +More formally, we can define an acceptable index +as +

    +     (index < 0 && abs(index) <= top) || (index > 0 && index <= top + stackspace)
    +
    +Note that 0 is not an acceptable index. +

    + +

    5.3 - Stack Manipulation

    +The API offers the following functions for basic stack manipulation: + + +
    +       void lua_settop    (lua_State *L, int index);
    +       void lua_pushvalue (lua_State *L, int index);
    +       void lua_remove    (lua_State *L, int index);
    +       void lua_insert    (lua_State *L, int index);
    +
    +

    +lua_settop accepts any acceptable index, +or 0, +and sets the stack top to that index. +If the new top is larger than the old one, +then the new elements are filled with nil. +If index is 0, then all stack elements are removed. +A useful macro defined in the API is +

    +       #define lua_pop(L,n) lua_settop(L, -(n)-1)
    +
    +which pops n elements from the stack. +

    +lua_pushvalue pushes onto the stack a copy of the element +at the given index. +lua_remove removes the element at the given position, +shifting down the elements on top of that position to fill in the gap. +lua_insert moves the top element into the given position, +shifting up the elements on top of that position to open space. +These functions accept only valid indices. +As an example, if the stack starts as 10 20 30 40 50 +(from bottom to top), +then +

    +       lua_pushvalue(L, 3)    --> 10 20 30 40 50 30
    +       lua_pushvalue(L, -1)   --> 10 20 30 40 50 30 30
    +       lua_remove(L, -3)      --> 10 20 30 40 30 30
    +       lua_remove(L,  6)      --> 10 20 30 40 30
    +       lua_insert(L,  1)      --> 30 10 20 30 40
    +       lua_insert(L, -1)      --> 30 10 20 30 40  (no effect)
    +       lua_settop(L, -3)      --> 30 10 20
    +       lua_settop(L, 6)       --> 30 10 20 nil nil nil
    +
    +

    +

    + +

    5.4 - Querying the Stack

    +

    +To check the type of a stack element, the following functions are available: + - - -

    -int lua_isnil       (lua_Object object);
    -int lua_isnumber    (lua_Object object);
    -int lua_isstring    (lua_Object object);
    -int lua_istable     (lua_Object object);
    -int lua_isfunction  (lua_Object object);
    -int lua_iscfunction (lua_Object object);
    -int lua_isuserdata  (lua_Object object);
    -
    -These functions return 1 if the object is compatible with the given type, -and 0 otherwise. -The function lua_isnumber accepts numbers and numerical strings, -whereas -lua_isstring accepts strings and numbers (see Section 4.3), -and lua_isfunction accepts Lua functions and C functions. -

    -To get the tag of a lua_Object, -the following function is available: - -

    -int lua_tag (lua_Object object);
    -
    -

    -To translate a value from type lua_Object to a specific C type, -the programmer can use: - - -

    -double         lua_getnumber    (lua_Object object);
    -char          *lua_getstring    (lua_Object object);
    -long           lua_strlen       (lua_Object object);
    -lua_CFunction  lua_getcfunction (lua_Object object);
    -void          *lua_getuserdata  (lua_Object object);
    -
    -

    -lua_getnumber converts a lua_Object to a floating-point number. -This lua_Object must be a number or a string convertible to number -(see Section 4.3); otherwise, lua_getnumber returns 0. -

    -lua_getstring converts a lua_Object to a string (char*). -This lua_Object must be a string or a number; -otherwise, the function returns 0 (the NULL pointer). -This function does not create a new string, -but returns a pointer to a string inside the Lua environment. -Those strings always have a 0 after their last character (like in C), + + +

    +       int         lua_type        (lua_State *L, int index);
    +       int         lua_tag         (lua_State *L, int index);
    +       int         lua_isnil       (lua_State *L, int index);
    +       int         lua_isnumber    (lua_State *L, int index);
    +       int         lua_isstring    (lua_State *L, int index);
    +       int         lua_istable     (lua_State *L, int index);
    +       int         lua_isfunction  (lua_State *L, int index);
    +       int         lua_iscfunction (lua_State *L, int index);
    +       int         lua_isuserdata  (lua_State *L, int index);
    +
    +These functions can be called with any acceptable index. +

    +lua_type returns one of the following constants, +according to the type of the given object: +LUA_TNIL, +LUA_TNUMBER, +LUA_TSTRING, +LUA_TTABLE, +LUA_TFUNCTION, +LUA_TUSERDATA. +If the index is non-valid +(that is, if that stack position is ``empty''), +then lua_type returns LUA_TNONE. +These constants can be converted to strings with + +

    +       const char *lua_typename (lua_State *L, int t);
    +
    +where t is a type returned by lua_type. +The strings returned by lua_typename are +"nil", "number", "string", "table", +"function", "userdata", and "no value", +

    +lua_tag returns the tag of a value, +or LUA_NOTAG for a non-valid index. +

    +The lua_is* functions return 1 if the object is compatible +with the given type, and 0 otherwise. +They always return 0 for a non-valid index. +lua_isnumber accepts numbers and numerical strings, +lua_isstring accepts strings and numbers (see Section 4.2), +and lua_isfunction accepts both Lua functions and C functions. +To distinguish between Lua functions and C functions, +you should use lua_iscfunction. +To distinguish between numbers and numerical strings, +you can use lua_type. +

    +The API also has functions to compare two values in the stack: + + +

    +       int lua_equal    (lua_State *L, int index1, int index2);
    +       int lua_lessthan (lua_State *L, int index1, int index2);
    +
    +These functions are equivalent to their counterparts in Lua. +Specifically, lua_lessthan is equivalent to the lt_event +described in Section 4.8. +Both functions return 0 if any of the indices are non-valid. +

    +To translate a value in the stack to a specific C type, +you can use the following conversion functions: + + +

    +       double         lua_tonumber    (lua_State *L, int index);
    +       const char    *lua_tostring    (lua_State *L, int index);
    +       size_t         lua_strlen      (lua_State *L, int index);
    +       lua_CFunction  lua_tocfunction (lua_State *L, int index);
    +       void          *lua_touserdata  (lua_State *L, int index);
    +
    +These functions can be called with any acceptable index. +When called with a non-valid index, +they act as if the given value had an incorrect type. +

    +lua_tonumber converts the value at the given index +to a floating-point number. +This value must be a number or a string convertible to number +(see Section 4.2); otherwise, lua_tonumber returns 0. +

    +lua_tostring converts a Lua value to a string +(const char*). +This value must be a string or a number; +otherwise, the function returns NULL. +This function returns a pointer to a string inside the Lua environment. +Those strings always have a zero ('\0') after their last character (as in C), but may contain other zeros in their body. If you do not know whether a string may contain zeros, -you can use lua_strlen to get the actual length. +you should use lua_strlen to get its actual length. Because Lua has garbage collection, -there is no guarantee that the pointer returned by lua_getstring -will be valid after the block ends -(see Section 5.3). +there is no guarantee that the pointer returned by lua_tostring +will be valid after the respective value is removed from the stack.

    -lua_getcfunction converts a lua_Object to a C function. -This lua_Object must have type CFunction; -otherwise, lua_getcfunction returns 0 (the NULL pointer). -The type lua_CFunction is explained in Section 5.7. +lua_tocfunction converts a value in the stack to a C function. +This value must be a C function; +otherwise, lua_tocfunction returns NULL. +The type lua_CFunction is explained in Section 5.13.

    -lua_getuserdata converts a lua_Object to void*. -This lua_Object must have type userdata; -otherwise, lua_getuserdata returns 0 (the NULL pointer). +lua_touserdata converts a value to void*. +This value must have type userdata; +otherwise, lua_touserdata returns NULL.

    - - -

    5.3 - Garbage Collection

    -Because Lua has automatic memory management and garbage collection, -a lua_Object has a limited scope, -and is only valid inside the block where it has been created. -A C function called from Lua is a block, -and its parameters are valid only until its end. -It is good programming practice to convert Lua objects to C values -as soon as they are available, -and never to store lua_Objects in C global variables. -

    -A garbage collection cycle can be forced by: - -

    -long lua_collectgarbage (long limit);
    -
    -This function returns the number of objects collected. -The argument limit makes the next cycle occur only -after that number of new objects have been created. -If limit=0, then Lua uses an adaptive heuristics to set this limit. -

    -

    -All communication between Lua and C is done through two -abstract data types, called lua2C and C2lua. -The first one, as the name implies, is used to pass values -from Lua to C: -parameters when Lua calls C and results when C calls Lua. -The structure C2lua is used in the reverse direction: -parameters when C calls Lua and results when Lua calls C. -

    -The structure lua2C is an abstract array, -which can be indexed with the function: - -

    -lua_Object lua_lua2C (int number);
    -
    -where number starts with 1. -When called with a number larger than the array size, -this function returns LUA_NOOBJECT. -In this way, it is possible to write C functions that receive -a variable number of parameters, -and to call Lua functions that return a variable number of results. -Note that the structure lua2C cannot be directly modified by C code. -

    -The second structure, C2lua, is an abstract stack. -Pushing elements into this stack -is done with the following functions: +

    +

    + +

    5.5 - Pushing values onto the Stack

    +

    +The API has the following functions to +push C values onto the stack: - - -

    -void lua_pushnumber    (double n);
    -void lua_pushlstring   (char *s, long len);
    -void lua_pushstring    (char *s);
    -void lua_pushusertag   (void *u, int tag);
    -void lua_pushnil       (void);
    -void lua_pushobject    (lua_Object object);
    -void lua_pushcfunction (lua_CFunction f);  /* macro */
    -
    -All of them receive a C value, -convert it to a corresponding lua_Object, -and leave the result on the top of C2lua. -In particular, functions lua_pushlstring and lua_pushstring -make an internal copy of the given string. -Function lua_pushstring can only be used to push proper C strings -(that is, strings that do not contain zeros and end with a zero); -otherwise you should use the more generic lua_pushlstring. -The function - -
    -lua_Object lua_pop (void);
    -
    -returns a reference to the object at the top of the C2lua stack, -and pops it. -

    -As a general rule, all API functions pop from the stack -all elements they use. + +

    +       void lua_pushnumber    (lua_State *L, double n);
    +       void lua_pushlstring   (lua_State *L, const char *s, size_t len);
    +       void lua_pushstring    (lua_State *L, const char *s);
    +       void lua_pushusertag   (lua_State *L, void *u, int tag);
    +       void lua_pushnil       (lua_State *L);
    +       void lua_pushcfunction (lua_State *L, lua_CFunction f);
    +
    +These functions receive a C value, +convert it to a corresponding Lua value, +and push the result onto the stack. +In particular, lua_pushlstring and lua_pushstring +make an internal copy of the given string. +lua_pushstring can only be used to push proper C strings +(that is, strings that end with a zero and do not contain embedded zeros); +otherwise you should use the more general lua_pushlstring, +which accepts an explicit size. +

    +

    + + +

    5.6 - Garbage Collection

    +

    +Lua uses two numbers to control its garbage collection. +One number counts how many bytes of dynamic memory Lua is using, +and the other is a threshold. +(This internal byte counter kept by Lua is not completely acurate; +it is just a lower bound, usually within 10% of the correct value.) +When the number of bytes crosses the threshold, +Lua runs a garbage-collection cycle, +which reclaims the memory of all ``dead'' objects +(that is, objects no longer accessible from Lua). +The byte counter is corrected, +and then the threshold is reset to twice the value of the byte counter. +

    +You can access the current values of these two numbers through the +following functions: + +

    +       int  lua_getgccount (lua_State *L);
    +       int  lua_getgcthreshold (lua_State *L);
    +
    +Both return their respective values in Kbytes. +You can change the threshold value with + +
    +       void  lua_setgcthreshold (lua_State *L, int newthreshold);
    +
    +Again, the newthreshold value is given in Kbytes. +When you call this function, +Lua sets the new threshold and checks it against the byte counter. +If the new threshold is smaller than the byte counter, +then Lua immediately runs the garbage collector; +after the collection, +a new threshold is set according to the previous rule. +

    +If you want to change the adaptative behavior of the garbage collector, +you can use the garbage-collection tag method for nil +to set your own threshold +(the tag method is called after Lua resets the threshold). +

    +

    + + +

    5.7 - Userdata and Tags

    Because userdata are objects, the function lua_pushusertag may create a new userdata. If Lua has a userdata with the given value (void*) and tag, -that userdata is pushed. +then that userdata is pushed. Otherwise, a new userdata is created, with the given value and tag. If this function is called with tag equal to LUA_ANYTAG, @@ -1462,230 +1757,361 @@

    5.3 - Garbage Collection

    Userdata can have different tags, whose semantics are only known to the host program. -Tags are created with the function: +Tags are created with the function

    -int lua_newtag (void);
    +       int lua_newtag (lua_State *L);
     
    The function lua_settag changes the tag of -the object on the top of C2lua (and pops it); -the object must be a userdata or a table. +the object on top of the stack (without popping it):
    -void lua_settag (int tag);
    -
    -tag must be a value created with lua_newtag. -

    -When C code calls Lua repeatedly, as in a loop, -objects returned by these calls can accumulate, -and may cause a stack overflow. -To avoid this, -nested blocks can be defined with the functions: -

    -void lua_beginblock (void);
    -void lua_endblock   (void);
    +       void lua_settag (lua_State *L, int tag);
     
    -After the end of the block, -all lua_Object's created inside it are released. -The use of explicit nested blocks is good programming practice -and is strongly encouraged. +The object must be a userdata or a table; +the given tag must be a value created with lua_newtag.

    - -

    5.4 - Executing Lua Code

    + + +

    5.8 - Executing Lua Code

    A host program can execute Lua chunks written in a file or in a string -using the following functions: +by using the following functions:
    -int lua_dofile   (char *filename);
    -int lua_dostring (char *string);
    -int lua_dobuffer (char *buff, int size, char *name);
    +       int lua_dofile   (lua_State *L, const char *filename);
    +       int lua_dostring (lua_State *L, const char *string);
    +       int lua_dobuffer (lua_State *L, const char *buff,
    +                         size_t size, const char *name);
     
    -All these functions return an error code: -0, in case of success; non zero, in case of errors. -More specifically, lua_dofile returns 2 if for any reason -it could not open the file. +These functions return +0 in case of success, or one of the following error codes if they fail: +
      +
    • LUA_ERRRUN - +error while running the chunk. +
    • LUA_ERRSYNTAX - +syntax error during pre-compilation. +
    • LUA_ERRMEM - +memory allocation error. +For such errors, Lua does not call _ERRORMESSAGE (see Section 4.7). +
    • LUA_ERRERR - +error while running _ERRORMESSAGE. +For such errors, Lua does not call _ERRORMESSAGE again, to avoid loops. +
    • LUA_ERRFILE - +error opening the file (only for lua_dofile). +In this case, +you may want to +check errno, +call strerror, +or call perror to tell the user what went wrong. +
    +These constants are defined in lua.h. +

    When called with argument NULL, lua_dofile executes the stdin stream. -Functions lua_dofile and lua_dobuffer +lua_dofile and lua_dobuffer are both able to execute pre-compiled chunks. They automatically detect whether the chunk is text or binary, and load it accordingly (see program luac). -Function lua_dostring executes only source code. +lua_dostring executes only source code, +given in textual form.

    -The third parameter to lua_dobuffer (name) +The third parameter to lua_dobuffer is the ``name of the chunk'', -used in error messages and debug information. +which is used in error messages and debug information. If name is NULL, -Lua gives a default name to the chunk. +then Lua gives a default name to the chunk. +

    +These functions push onto the stack +any values eventually returned by the chunk. +A chunk may return any number of values; +Lua takes care that these values fit into the stack space, +but after the call the responsibility is back to you. +If you need to push other elements after calling any of these functions, +and you want to ``play safe'', +you must either check the stack space +with lua_stackspace +or remove the returned elements +from the stack (if you do not need them). +For instance, the following code +loads a chunk in a file and discards all results returned by this chunk, +leaving the stack as it was before the call: +

    +      {
    +       int oldtop = lua_gettop(L);
    +       lua_dofile(L, filename);
    +       lua_settop(L, oldtop);
    +      }
    +

    -These functions return, in structure lua2C, -any values eventually returned by the chunks. -They also empty the stack C2lua.

    + +

    5.9 - Manipulating Global Variables in Lua

    - -

    5.5 - Manipulating Lua Objects

    -To read the value of any global Lua variable, -one uses the function: +To read the value of a global Lua variable, +you call
    -lua_Object lua_getglobal (char *varname);
    +       void lua_getglobal (lua_State *L, const char *varname);
     
    -As in Lua, this function may trigger a tag method. -To read the real value of any global variable, +which pushes onto the stack the value of the given variable. +As in Lua, this function may trigger a tag method +for the ``getglobal'' event (see Section 4.8). +To read the real value of a global variable, without invoking any tag method, -use the raw version: - -
    -lua_Object lua_rawgetglobal (char *varname);
    -
    +use lua_rawget over the table of globals +(see below).

    -To store a value previously pushed onto C2lua in a global variable, -there is the function: +To store a value in a global variable, +you call

    -void lua_setglobal (char *varname);
    +       void lua_setglobal (lua_State *L, const char *varname);
     
    -As in Lua, this function may trigger a tag method. -To set the real value of any global variable, +which pops from the stack the value to be stored in the given variable. +As in Lua, this function may trigger a tag method +for the ``setglobal'' event (see Section 4.8). +To set the real value of a global variable, without invoking any tag method, -use the raw version: - +use lua_rawset over the table of globals +(see below). +

    +All global variables are kept in an ordinary Lua table. +You can get this table calling +

    -void lua_rawsetglobal (char *varname);
    +       void lua_getglobals (lua_State *L);
     
    +which pushes the current table of globals onto the stack. +To set another table as the table of globals, +you call + +
    +       void lua_setglobals (lua_State *L);
    +
    +The table to be used is popped from the stack.

    -Tables can also be manipulated via the API. -The function + +

    5.10 - Manipulating Tables in Lua

    +Lua tables can also be manipulated through the API. +

    +To read the value of in a table, +the table must reside somewhere in the stack. +With this set, +you call

    -lua_Object lua_gettable (void);
    +       void lua_gettable (lua_State *L, int index);
     
    -pops a table and an index from the stack C2lua, -and returns the contents of the table at that index. -As in Lua, this operation may trigger a tag method. -To get the real value of any table index, +where index refers to the table. +lua_gettable pops a key from the stack, +and returns (on the stack) the contents of the table at that key. +As in Lua, this operation may trigger a tag method +for the ``gettable'' event. +To get the real value of any table key, without invoking any tag method, use the raw version: - +
    -lua_Object lua_rawgettable (void);
    +       void lua_rawget (lua_State *L, int index);
     

    -To store a value in an index, -the program must push the table, the index, -and the value onto C2lua, -and then call the function +To store a value into a table that resides somewhere in the stack, +you push the key and the value onto the stack +(in this order), +and then call

    -void lua_settable (void);
    +       void lua_settable (lua_State *L, int index);
     
    -Again, the tag method for ``settable'' may be called. +where index refers to the table. +lua_settable pops from the stack both the key and the value. +As in Lua, this operation may trigger a tag method +for the ``settable'' event. To set the real value of any table index, without invoking any tag method, use the raw version: - +
    -void lua_rawsettable (void);
    +       void lua_rawset (lua_State *L, int index);
     

    Finally, the function - + +

    +       void lua_newtable (lua_State *L);
    +
    +creates a new, empty table and pushes it onto the stack. +

    + +

    5.11 - Using Tables as Arrays

    +The API has functions that help to use Lua tables as arrays, +that is, +tables indexed by numbers only: + + +
    -lua_Object lua_createtable (void);
    +       void lua_rawgeti (lua_State *L, int index, int n);
    +       void lua_rawseti (lua_State *L, int index, int n);
    +       int  lua_getn    (lua_State *L, int index);
     
    -creates and returns a new, empty table.

    +lua_rawgeti gets the value of the n-th element of the table +at stack position index.

    - -

    5.6 - Calling Lua Functions

    -Functions defined in Lua by a chunk +lua_rawseti sets the value of the n-th element of the table +at stack position index to the value at the top of the stack. +

    +lua_getn returns the number of elements in the table +at stack position index. +This number is the value of the table field n, +if it has a numeric value, +or +the largest numerical index with a non-nil value in the table. +

    + +

    5.12 - Calling Lua Functions

    +

    +Functions defined in Lua +(and C functions registered in Lua) can be called from the host program. This is done using the following protocol: -first, the arguments to the function are pushed onto C2lua -(see Section 5.3), in direct order, i.e., the first argument is pushed first. -Then, the function is called using - -

    -int lua_callfunction (lua_Object function);
    -
    -This function returns an error code: -0, in case of success; non zero, in case of errors. -Finally, the results (a Lua function may return many values) -are returned in structure lua2C, -and can be retrieved with the macro lua_getresult, - -which is just another name to function lua_lua2C. -Note that function lua_callfunction -pops all elements from the C2lua stack. -

    -The following example shows how a C program may do the +First, the function to be called is pushed onto the stack; +then, the arguments to the function are pushed +(see Section 5.5) in direct order, that is, the first argument is pushed first. +Finally, the function is called using + +

    +       int lua_call (lua_State *L, int nargs, int nresults);
    +
    +This function returns the same error codes as lua_dostring and +friends (see Section 5.8). +If you want to propagate the error, +instead of returning an error code, +use + +
    +       void lua_rawcall (lua_State *L, int nargs, int nresults);
    +
    +

    +In both functions, +nargs is the number of arguments that you pushed onto the stack. +All arguments and the function value are popped from the stack, +and the function results are pushed. +The number of results are adjusted (see Section 4.3) to nresults, +unless nresults is LUA_MULTRET. +In that case, all results from the function are pushed. +The function results are pushed in direct order +(the first result is pushed first), +so that after the call the last result is on the top. +

    +The following example shows how the host program may do the equivalent to the Lua code:

    -      a,b = f("how", t.x, 4)
    +       a,b = f("how", t.x, 4)
     
    +Here it is in C:
    -  lua_pushstring("how");                               /* 1st argument */
    -  lua_pushobject(lua_getglobal("t"));      /* push value of global 't' */
    -  lua_pushstring("x");                          /* push the string 'x' */
    -  lua_pushobject(lua_gettable());      /* push result of t.x (2nd arg) */
    -  lua_pushnumber(4);                                   /* 3rd argument */
    -  lua_callfunction(lua_getglobal("f"));           /* call Lua function */
    -  lua_pushobject(lua_getresult(1));   /* push first result of the call */
    -  lua_setglobal("a");                       /* set global variable 'a' */
    -  lua_pushobject(lua_getresult(2));  /* push second result of the call */
    -  lua_setglobal("b");                       /* set global variable 'b' */
    +    lua_getglobal(L, "t");                      /* global `t' (for later use) */
    +    lua_getglobal(L, "f");                           /* function to be called */
    +    lua_pushstring(L, "how");                                 /* 1st argument */
    +    lua_pushstring(L, "x");                            /* push the string `x' */
    +    lua_gettable(L, -4);                      /* push result of t.x (2nd arg) */
    +    lua_pushnumber(L, 4);                                     /* 3rd argument */
    +    lua_call(L, 3, 2);        /* call function with 3 arguments and 2 results */
    +    lua_setglobal(L, "b");                         /* set global variable `b' */
    +    lua_setglobal(L, "a");                         /* set global variable `a' */
    +    lua_pop(L, 1);                               /* remove `t' from the stack */
     
    +Notice that the code above is ``balanced'': +at its end ,the stack is back to its original configuration. +This is considered good programming practice. +

    -Some special Lua functions have exclusive interfaces. -A C function can generate a Lua error calling the function +

    +Some special Lua functions have their own C interfaces. +The host program can generate a Lua error calling the function

    -void lua_error (char *message);
    +       void lua_error (lua_State *L, const char *message);
     
    This function never returns. -If the C function has been called from Lua, +If lua_error is called from a C function that has been called from Lua, then the corresponding Lua execution terminates, as if an error had occurred inside Lua code. -Otherwise, the whole host program terminates with a call to exit(1). -The message is passed to the error handler function, -_ERRORMESSAGE. +Otherwise, the whole host program terminates with a call to +exit(EXIT_FAILURE). +Before terminating execution, +the message is passed to the error handler function, +_ERRORMESSAGE (see Section 4.7). If message is NULL, then _ERRORMESSAGE is not called.

    -Tag methods can be changed with: +

    +Tag methods can be changed with

    -lua_Object lua_settagmethod (int tag, char *event);
    +       void lua_settagmethod (lua_State *L, int tag, const char *event);
     
    -The first parameter is the tag, -and the second is the event name (see Section 4.8); -the new method is pushed from C2lua. -This function returns a lua_Object, -which is the old tag method value. -To get just the current value of a tag method, +The second parameter is the tag, +and the third is the event name (see Section 4.8); +the new method is popped from the stack. +To get the current value of a tag method, use the function
    -lua_Object lua_gettagmethod (int tag, char *event);
    +       void lua_gettagmethod (lua_State *L, int tag, const char *event);
     

    It is also possible to copy all tag methods from one tag to another:

    -int lua_copytagmethods (int tagto, int tagfrom);
    +       int lua_copytagmethods (lua_State *L, int tagto, int tagfrom);
     
    This function returns tagto.

    +You can traverse a table with the function +

    +       int lua_next (lua_State *L, int index);
    +
    +where index refers to the table to be traversed. +The function pops a key from the stack, +and pushes a key-value pair from the table +(the ``next'' pair after the given key). +If there are no more elements, then the function returns 0 +(and pushes nothing). +A typical traversal looks like this: +
    +       /* table is in the stack at index `t' */
    +       lua_pushnil(L);  /* first key */
    +       while (lua_next(L, t) != 0) {
    +         /* `key' is at index -2 and `value' at index -1 */
    +         printf("%s - %s\n",
    +           lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
    +         lua_pop(L, 1);  /* removes `value'; keeps `index' for next iteration */
    +       }
    +
    +

    +The function +

    +       void lua_concat (lua_State *L, int n);
    +
    +concatenates the n values at the top of the stack, +pops them, and leaves the result at the top; +n must be at least 2. +Concatenation is done following the usual semantics of Lua +(see Section 4.5.5). +

    +

    - -

    5.7 - C Functions

    -To register a C function to Lua, -there is the following macro: + +

    5.13 - Defining C Functions

    +To register a C function to Lua, +there is the following convenience macro:
    -#define lua_register(n,f)       (lua_pushcfunction(f), lua_setglobal(n))
    -/* char *n;         */
    -/* lua_CFunction f; */
    +     #define lua_register(L, n, f) (lua_pushcfunction(L, f), lua_setglobal(L, n))
    +     /* const char *n;   */
    +     /* lua_CFunction f; */
     
    which receives the name the function will have in Lua, and a pointer to the function. @@ -1693,110 +2119,185 @@

    5.7 - C Functions

    which is defined as
    -typedef void (*lua_CFunction) (void);
    +       typedef int (*lua_CFunction) (lua_State *L);
     
    -that is, a pointer to a function with no parameters and no results. +that is, a pointer to a function with integer result and a single argument, +a Lua environment.

    In order to communicate properly with Lua, -a C function must follow a protocol, -which defines the way parameters and results are passed. -

    -A C function receives its arguments in structure lua2C; -to access them, it uses the macro lua_getparam, -again just another name for lua_lua2C. -To return values, a C function just pushes them onto the stack C2lua, -in direct order (see Section 5.2). -Like a Lua function, a C function called by Lua can also return +a C function must follow the following protocol, +which defines the way parameters and results are passed: +A C function receives its arguments from Lua in the stack, +in direct order (the first argument is pushed first). +To return values to Lua, a C function just pushes them onto the stack, +in direct order (the first result is pushed first), +and returns the number of results. +Like a Lua function, a C function called by Lua can also return many results.

    -When a C function is created, -it is possible to associate some upvalues to it, -thus creating a C closure; -then these values are passed to the function whenever it is called, -as common arguments. -To associate upvalues to a function, -first these values must be pushed on C2lua. -Then the function - -

    -void lua_pushcclosure (lua_CFunction fn, int n);
    -
    -is used to put the C function on C2lua, -with the argument n telling how many upvalues must be -associated with the function; +As an example, the following function receives a variable number +of numerical arguments and returns their average and sum: +
    +       static int foo (lua_State *L) {
    +         int n = lua_gettop(L);    /* number of arguments */
    +         double sum = 0;
    +         int i;
    +         for (i = 1; i <= n; i++) {
    +           if (!lua_isnumber(L, i))
    +             lua_error(L, "incorrect argument to function `average'");
    +           sum += lua_tonumber(L, i);
    +         }
    +         lua_pushnumber(L, sum/n);        /* first result */
    +         lua_pushnumber(L, sum);         /* second result */
    +         return 2;                   /* number of results */
    +       }
    +
    +This function may be registered in Lua as `average' by calling +
    +       lua_register(L, "average", foo);
    +
    +

    +

    +When a C function is created, +it is possible to associate some upvalues to it +(see Section 4.6), +thus creating a C closure; +these values are passed to the function whenever it is called, +as ordinary arguments. +To associate upvalues to a C function, +first these values should be pushed onto the stack. +Then the function +

    +       void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
    +
    +is used to push the C function onto the stack, +with the argument n telling how many upvalues should be +associated with the function +(these upvalues are popped from the stack); in fact, the macro lua_pushcfunction is defined as lua_pushcclosure with n set to 0. -Then, any time the function is called, -these upvalues are inserted as the first arguments to the function, -before the actual arguments provided in the call. -

    -For some examples of C functions, see files lstrlib.c, -liolib.c and lmathlib.c in the official Lua distribution. -

    - -

    5.8 - References to Lua Objects

    -

    -As noted in Section 5.3, lua_Objects are volatile. -If the C code needs to keep a lua_Object -outside block boundaries, -then it must create a reference to the object. -The routines to manipulate references are the following: +Then, whenever the C function is called, +these upvalues are inserted as the last arguments to the function, +after the actual arguments provided in the call. +This makes it easy to get the upvalues without knowing how many arguments +the function received (recall that functions in Lua can receive any number of +arguments): The i-th upvalue is in the stack at index i-(n+1), +where n is the number of upvalues. +

    +For more examples of C functions and closures, see files +lbaselib.c, liolib.c, lmathlib.c, and lstrlib.c +in the official Lua distribution. +

    + +

    5.14 - References to Lua Objects

    +

    +If the C code needs to keep a Lua value +outside the life span of a C function, +then it must create a reference to the value. +The functions to manipulate references are the following:

    -int        lua_ref    (int lock);
    -lua_Object lua_getref (int ref);
    -void       lua_unref  (int ref);
    +       int   lua_ref    (lua_State *L, int lock);
    +       int   lua_getref (lua_State *L, int ref);
    +       void  lua_unref  (lua_State *L, int ref);
     
    -The function lua_ref creates a reference -to the object that is on the top of the stack, +

    +lua_ref pops a value from +the stack, creates a reference to it, and returns this reference. -If lock is true, the object is locked: +For a nil value, +the reference is always LUA_REFNIL. +(lua.h also defines a constant LUA_NOREF +that +is different from any valid reference.) +If lock is not zero, then the object is locked: this means the object will not be garbage collected. -Note that an unlocked reference may be garbage collected. -Whenever the referenced object is needed, +Unlocked references may be garbage collected. +

    +Whenever the referenced object is needed in C, a call to lua_getref -returns a handle to it; +pushes that object onto the stack; if the object has been collected, -lua_getref returns LUA_NOOBJECT. +lua_getref returns 0 (and does not push anything).

    When a reference is no longer needed, -it can be released with a call to lua_unref. +it should be released with a call to lua_unref. +

    +

    +

    Registry

    +When Lua starts, it registers a table at position +LUA_REFREGISTRY. +It can be accessed through the macro +

    +  #define lua_getregistry(L)      lua_getref(L, LUA_REFREGISTRY)
    +
    +This table can be used by C libraries as a general registry mechanism. +Any C library can store data into this table, +as long as it chooses a key different from other libraries.


    -

    6 - Predefined Functions and Libraries

    +

    6 - Standard Libraries

    -The set of predefined functions in Lua is small but powerful. -Most of them provide features that allow some degree of -reflexivity in the language. -Some of these features cannot be simulated with the rest of the -language nor with the standard Lua API. -Others are just convenient interfaces to common API functions. -

    -The libraries, on the other hand, provide useful routines +The standard libraries provide useful functions that are implemented directly through the standard API. Therefore, they are not necessary to the language, -and are provided as separate C modules. -Currently, there are three standard libraries: +and are provided as separate C modules. +Currently, Lua has the following standard libraries:

      +
    • basic library;
    • string manipulation;
    • mathematical functions (sin, log, etc);
    • input and output (plus some system facilities).
    To have access to these libraries, -the C host program must call the functions +the C host program must call the functions +lua_baselibopen, lua_strlibopen, lua_mathlibopen, -and lua_iolibopen, declared in lualib.h. - -

    +and lua_iolibopen, which are declared in lualib.h. + + + +

    -

    6.1 - Predefined Functions

    +

    6.1 - Basic Functions

    +

    +The basic library provides some core functions to Lua. +Therefore, if you do not include this library in your application, +you should check carefully whether you need to provide some alternative +implementation for some facilities. +(For instance, +without function _ERRORMESSAGE, +Lua is unable to show error messages.) +

    + +

    _ALERT (message)

    +Prints its only string argument to stderr. +All error messages in Lua are printed through the function stored +in the _ALERT global variable +(see Section 4.7). +Therefore, a program may assign another function to this variable +to change the way such messages are shown +(for instance, for systems without stderr). +

    +

    assert (v [, message])

    +Issues an ``assertion failed!'' error +when its argument v is nil. +This function is equivalent to the following Lua function: +
    +       function assert (v, m)
    +         if not v then
    +           m = m or ""
    +           error("assertion failed!  " .. m)
    +         end
    +       end
    +

    call (func, arg [, mode [, errhandler]])

    @@ -1805,29 +2306,13 @@

    call (func, arg [, mode [, errhandler]])

    the arguments given by the table arg. The call is equivalent to
    -      func(arg[1], arg[2], ..., arg[n])
    +       func(arg[1], arg[2], ..., arg[n])
     
    where n is the result of getn(arg) (see Section 6.1). +All results from func are simply returned by call.

    By default, -all results from func are just returned by the call. -If the string mode contains "p", -the results are packed in a single table. -That is, call returns just one table; -at index n, the table has the total number of results -from the call; -the first result is at index 1, etc. -For instance, the following calls produce the following results: -

    -a = call(sin, {5})                --> a = 0.0871557 = sin(5)
    -a = call(max, {1,4,5; n=2})       --> a = 4 (only 1 and 4 are arguments)
    -a = call(max, {1,4,5; n=2}, "p")  --> a = {4; n=1}
    -t = {x=1}
    -a = call(next, {t,nil;n=2}, "p")  --> a={"x", 1; n=2}
    -
    -

    -By default, -if an error occurs during the function call, +if an error occurs during the call to func, the error is propagated. If the string mode contains "x", then the call is protected. @@ -1836,96 +2321,168 @@

    call (func, arg [, mode [, errhandler]])

    Instead, it returns nil to signal the error (besides calling the appropriated error handler).

    -If provided, -errhandler is temporarily set as the error function -_ERRORMESSAGE, while func runs. +If errhandler is provided, +the error function _ERRORMESSAGE is temporarily set to errhandler, +while func runs. In particular, if errhandler is nil, no error messages will be issued during the execution of the called function.

    collectgarbage ([limit])

    -Forces a garbage collection cycle. -Returns the number of objects collected. -An optional argument, limit, is a number that -makes the next cycle occur only after that number of new -objects have been created. -If limit is absent or equal to 0, -Lua uses an adaptive algorithm to set this limit. -collectgarbage is equivalent to -the API function lua_collectgarbage. +

    +Sets the garbage-collection threshold for the given limit +(in Kbytes), and checks it against the byte counter. +If the new threshold is smaller than the byte counter, +then Lua immediately runs the garbage collector (see Section 5.6). +If limit is absent, it defaults to zero +(thus forcing a garbage-collection cycle). +

    +

    copytagmethods (tagto, tagfrom)

    + +Copies all tag methods from one tag to another; +returns tagto.

    dofile (filename)

    Receives a file name, -opens the file, and executes the file contents as a Lua chunk, +opens the named file, and executes its contents as a Lua chunk, or as pre-compiled chunks. When called without arguments, dofile executes the contents of the standard input (stdin). If there is any error executing the file, then dofile returns nil. Otherwise, it returns the values returned by the chunk, -or a non nil value if the chunk returns no values. -It issues an error when called with a non string argument. -dofile is equivalent to the API function lua_dofile. +or a non-nil value if the chunk returns no values. +It issues an error when called with a non-string argument.

    dostring (string [, chunkname])

    Executes a given string as a Lua chunk. If there is any error executing the string, -dostring returns nil. +then dostring returns nil. Otherwise, it returns the values returned by the chunk, -or a non nil value if the chunk returns no values. -An optional second parameter (chunkname) +or a non-nil value if the chunk returns no values. +The optional parameter chunkname is the ``name of the chunk'', used in error messages and debug information. -dostring is equivalent to the API function lua_dostring. -

    - -

    newtag ()

    -Returns a new tag. -newtag is equivalent to the API function lua_newtag.

    -

    next (table, index)

    -Allows a program to traverse all fields of a table. -Its first argument is a table and its second argument -is an index in this table. -It returns the next index of the table and the -value associated with the index. -When called with nil as its second argument, -the function returns the first index -of the table (and its associated value). -When called with the last index, -or with nil in an empty table, -it returns nil. + +

    error (message)

    +Calls the error handler (see Section 4.7) and then terminates +the last protected function called +(in C: lua_dofile, lua_dostring, +lua_dobuffer, or lua_callfunction; +in Lua: dofile, dostring, or call in protected mode). +If message is nil, then the error handler is not called. +Function error never returns.

    -Lua has no declaration of fields; +

    foreach (table, func)

    +Executes the given func over all elements of table. +For each element, the function is called with the index and +respective value as arguments. +If the function returns any non-nil value, +then the loop is broken, and this value is returned +as the final value of foreach. +This function could be defined in Lua: +
    +       function foreach (t, f)
    +         for i, v in t do
    +           local res = f(i, v)
    +           if res then return res end
    +         end
    +       end
    +
    +

    +The behavior of foreach is undefined if you change +the table t during the traversal. +

    +

    +

    foreachi (table, func)

    +Executes the given func over the +numerical indices of table. +For each index, the function is called with the index and +respective value as arguments. +Indices are visited in sequential order, +from 1 to n, +where n is the result of getn(table) (see Section 6.1). +If the function returns any non-nil value, +then the loop is broken, and this value is returned +as the final value of foreachi. +This function could be defined in Lua: +
    +       function foreachi (t, f)
    +         for i=1,getn(t) do
    +           local res = f(i, t[i])
    +           if res then return res end
    +         end
    +       end
    +
    +

    +

    +

    getglobal (name)

    +Gets the value of a global variable, +or calls a tag method for ``getglobal''. +Its full semantics is explained in Section 4.8. +The string name does not need to be a +syntactically valid variable name. +

    + +

    getn (table)

    +Returns the ``size'' of a table, when seen as a list. +If the table has an n field with a numeric value, +this value is the ``size'' of the table. +Otherwise, the ``size'' is the largest numerical index with a non-nil +value in the table. +This function could be defined in Lua: +
    +       function getn (t)
    +         if type(t.n) == "number" then return t.n end
    +         local max = 0
    +         for i, _ in t do
    +           if type(i) == "number" and i>max then max=i end
    +         end
    +         return max
    +       end
    +
    +

    +

    gettagmethod (tag, event)

    + +Returns the current tag method +for a given pair (tag, event). +This function cannot be used to get a tag method for the ``gc'' event. +(Such tag methods can only be manipulated by C code.) +

    +

    globals ([table])

    +Returns the current table of globals. +If the argument table is given, +then it also sets this table as the table of globals. +

    + +

    newtag ()

    +Returns a new tag. +

    +

    next (table, [index])

    +Allows a program to traverse all fields of a table. +Its first argument is a table and its second argument +is an index in this table. +next returns the next index of the table and the +value associated with the index. +When called with nil as its second argument, +next returns the first index +of the table and its associated value. +When called with the last index, +or with nil in an empty table, +next returns nil. +If the second argument is absent, then it is interpreted as nil. +

    +Lua has no declaration of fields; semantically, there is no difference between a field not present in a table or a field with value nil. -Therefore, the function only considers fields with non nil values. +Therefore, next only considers fields with non-nil values. The order in which the indices are enumerated is not specified, even for numeric indices (to traverse a table in numeric order, -use a counter or the function foreachi). -If the table indices are modified in any way during a traversal, -the semantics of next is undefined. -

    -This function cannot be written with the standard API. +use a numerical for or the function foreachi).

    -

    nextvar (name)

    -This function is similar to the function next, -but iterates instead over the global variables. -Its single argument is the name of a global variable, -or nil to get a first name. -Similarly to next, it returns the name of another variable -and its value, -or nil if there are no more variables. -There can be no creation of new global variables during the traversal; -otherwise the semantics of nextvar is undefined. -

    -This function cannot be written with the standard API. -

    -

    tostring (e)

    -Receives an argument of any type and -converts it to a string in a reasonable format. -For complete control on how numbers are converted, -use function format. +The behavior of next is undefined if you change +the table during the traversal.

    print (e1, e2, ...)

    Receives any number of arguments, @@ -1935,342 +2492,225 @@

    print (e1, e2, ...)

    for instance for debugging. See Section 6.4 for functions for formatted output.

    - -

    _ALERT (message)

    -Prints its only string argument to stderr. -All error messages in Lua are printed through this function. -Therefore, a program may redefine it -to change the way such messages are shown -(for instance, for systems without stderr). -

    -

    tonumber (e [, base])

    -Receives one argument, -and tries to convert it to a number. -If the argument is already a number or a string convertible -to a number, then tonumber returns that number; -otherwise, it returns nil. -

    -An optional argument specifies the base to interpret the numeral. -The base may be any integer between 2 and 36 inclusive. -In bases above 10, the letter `A' (either upper or lower case) -represents 10, `B' represents 11, and so forth, with `Z' representing 35. -

    -In base 10 (the default), the number may have a decimal part, -as well as an optional exponent part (see Section 4.3). -In other bases, only integers are accepted. -

    - -

    type (v)

    -Allows Lua to test the type of a value. -It receives one argument, and returns its type, coded as a string. -The possible results of this function are -"nil" (a string, not the value nil), -"number", -"string", -"table", -"function", -and "userdata". -

    -

    tag (v)

    -Allows Lua to test the tag of a value (see Section 3). -It receives one argument, and returns its tag (a number). -tag is equivalent to the API function lua_tag. -

    -

    settag (t, tag)

    -Sets the tag of a given table (see Section 3). -tag must be a value created with newtag -(see Section 6.1). -It returns the value of its first argument (the table). -For security reasons, -it is impossible to change the tag of a userdata from Lua. -

    -

    -

    assert (v [, message])

    -Issues an ``assertion failed!'' error -when its argument is nil. -This function is equivalent to the following Lua function: -
    -      function assert (v, m)
    -        if not v then
    -          m = m or ""
    -          error("assertion failed!  " .. m)
    -        end
    -      end
    -
    -

    - -

    error (message)

    -Calls the error handler and then terminates -the last protected function called -(in C: lua_dofile, lua_dostring, -lua_dobuffer, or lua_callfunction; -in Lua: dofile, dostring, or call in protected mode). -If message is nil, the error handler is not called. -Function error never returns. -error is equivalent to the API function lua_error. -

    -

    rawgettable (table, index)

    +

    rawget (table, index)

    Gets the real value of table[index], without invoking any tag method. table must be a table, and index is any value different from nil.

    -

    rawsettable (table, index, value)

    +

    rawset (table, index, value)

    Sets the real value of table[index] to value, without invoking any tag method. table must be a table, index is any value different from nil, and value is any Lua value.

    -

    rawsetglobal (name, value)

    -Assigns the given value to a global variable. -The string name does not need to be a -syntactically valid variable name. -Therefore, -this function can set global variables with strange names like -"m v 1" or 34. -Function rawsetglobal returns the value of its second argument. -

    setglobal (name, value)

    -Assigns the given value to a global variable, -or calls a tag method. +Sets the named global variable to the given value, +or calls a tag method for ``setglobal''. Its full semantics is explained in Section 4.8. The string name does not need to be a syntactically valid variable name. -Function setglobal returns the value of its second argument. -

    -

    rawgetglobal (name)

    -Retrieves the value of a global variable. -The string name does not need to be a -syntactically valid variable name.

    -

    getglobal (name)

    -Retrieves the value of a global variable, -or calls a tag method. -Its full semantics is explained in Section 4.8. -The string name does not need to be a -syntactically valid variable name. +

    settag (t, tag)

    +Sets the tag of a given table (see Section 3). +tag must be a value created with newtag +(see Section 6.1). +settag returns the value of its first argument (the table). +For the safety of host programs, +it is impossible to change the tag of a userdata from Lua.

    settagmethod (tag, event, newmethod)

    -Sets a new tag method to the given pair (tag, event). -It returns the old method. +Sets a new tag method to the given pair (tag, event) and +returns the old method. If newmethod is nil, -settagmethod restores the default behavior for the given event. -

    -

    gettagmethod (tag, event)

    - -Returns the current tag method -for a given pair (tag, event). -

    -

    copytagmethods (tagto, tagfrom)

    - -Copies all tag methods from one tag to another; -it returns tagto. -

    - -

    getn (table)

    -Returns the ``size'' of a table, when seen as a list. -If the table has an n field with a numeric value, -this is its ``size''. -Otherwise, the size is the largest numerical index with a non-nil -value in the table. -This function could be defined in Lua: -
    -      function getn (t)
    -        if type(t.n) == 'number' then return t.n end
    -        local max = 0
    -        local i = next(t, nil)
    -        while i do
    -          if type(i) == 'number' and i>max then max=i end
    -          i = next(t, i)
    -        end
    -        return max
    -      end
    -
    +then settagmethod restores the default behavior for the given event. +This function cannot be used to set a tag method for the ``gc'' event. +(Such tag methods can only be manipulated by C code.)

    +

    sort (table [, comp])

    +Sorts table elements in a given order, in-place, +from table[1] to table[n], +where n is the result of getn(table) (see Section 6.1). +If comp is given, +then it must be a function that receives two table elements, +and returns true (that is, a value different from nil) +when the first is less than the second +(so that not comp(a[i+1], a[i]) will be true after the sort). +If comp is not given, +then the standard Lua operator < is used instead.

    -

    foreach (table, function)

    -Executes the given function over all elements of table. -For each element, the function is called with the index and -respective value as arguments. -If the function returns any non-nil value, -the loop is broken, and the value is returned -as the final value of foreach. +The sort algorithm is not stable +(that is, elements considered equal by the given order +may have their relative positions changed by the sort).

    -This function could be defined in Lua: -

    -      function foreach (t, f)
    -        local i, v = next(t, nil)
    -        while i do
    -          local res = f(i, v)
    -          if res then return res end
    -          i, v = next(t, i)
    -        end
    -      end
    -
    + +

    tag (v)

    +Allows Lua programs to test the tag of a value (see Section 3). +It receives one argument, and returns its tag (a number).

    +

    tonumber (e [, base])

    +Tries to convert its argument to a number. +If the argument is already a number or a string convertible +to a number, then tonumber returns that number; +otherwise, it returns nil.

    -

    foreachi (table, function)

    -Executes the given function over the -numerical indices of table. -For each index, the function is called with the index and -respective value as arguments. -Indices are visited in sequential order, -from 1 to n, -where n is the result of getn(table) (see Section 6.1). -If the function returns any non-nil value, -the loop is broken, and the value is returned -as the final value of foreachi. +An optional argument specifies the base to interpret the numeral. +The base may be any integer between 2 and 36, inclusive. +In bases above 10, the letter `A' (either upper or lower case) +represents 10, `B' represents 11, and so forth, with `Z' representing 35. +In base 10 (the default), the number may have a decimal part, +as well as an optional exponent part (see Section 4.2). +In other bases, only unsigned integers are accepted.

    -This function could be defined in Lua: -

    -      function foreachi (t, f)
    -        local i, n = 1, getn(t)
    -        while i <= n do
    -          local res = f(i, t[i])
    -          if res then return res end
    -          i = i+1
    -        end
    -      end
    -
    +

    tostring (e)

    +Receives an argument of any type and +converts it to a string in a reasonable format. +For complete control of how numbers are converted, +use function format.

    -

    foreachvar (function)

    -Executes function over all global variables. -For each variable, -the function is called with its name and its value as arguments. -If the function returns any non-nil value, -the loop is broken, and the value is returned -as the final value of foreachvar.

    -This function could be defined in Lua: -

    -      function foreachvar (f)
    -        local n, v = nextvar(nil)
    -        while n do
    -          local res = f(n, v)
    -          if res then return res end
    -          n, v = nextvar(n)
    -        end
    -      end
    -

    tinsert (table [, pos] , value)

    Inserts element value at table position pos, -shifting other elements to open space. -The default value for pos is n+1 -(where n is the result of getn(table) (see Section 6.1)) +shifting other elements to open space, if necessary. +The default value for pos is n+1, +where n is the result of getn(table) (see Section 6.1), so that a call tinsert(t,x) inserts x at the end of table t. -

    -This function also sets or increments the field n of the table, +This function also sets or increments the field n of the table to n+1. -

    This function is equivalent to the following Lua function, -except that the table accesses are all raw (that is, without tag methods): -

    -      function tinsert (t, ...)
    -        local pos, value
    -        local n = getn(t)
    -        if arg.n == 1 then
    -          pos = n+1; value = arg[1]
    -        else
    -          pos = arg[1]; value = arg[2]
    -        end
    -        t.n = n+1;
    -        while n >= pos do
    -          t[n+1] = t[n]
    -          n = n-1
    -        end
    -        t[pos] = value
    -      end
    +except that the table accesses are all raw
    +(that is, without tag methods):
    +
    +       function tinsert (t, ...)
    +         local pos, value
    +         local n = getn(t)
    +         if arg.n == 1 then
    +           pos, value = n+1, arg[1]
    +         else
    +           pos, value = arg[1], arg[2]
    +         end
    +         t.n = n+1;
    +         for i=n,pos,-1 do
    +           t[i+1] = t[i]
    +         end
    +         t[pos] = value
    +       end
     

    tremove (table [, pos])

    Removes from table the element at position pos, -shifting other elements to close the space. +shifting other elements to close the space, if necessary. Returns the value of the removed element. -The default value for pos is n -(where n is the result of getn(table) (see Section 6.1)), +The default value for pos is n, +where n is the result of getn(table) (see Section 6.1), so that a call tremove(t) removes the last element of table t. -

    -This function also sets or decrements the field n of the table, +This function also sets or decrements the field n of the table to n-1.

    This function is equivalent to the following Lua function, -except that the table accesses are all raw (that is, without tag methods): -

    -      function tremove (t, pos)
    -        local n = getn(t)
    -        pos = pos or n
    -        local value = t[pos]
    -        if n<=0 then return end
    -        while pos < n do
    -          t[pos] = t[pos+1]
    -          pos = pos+1
    -        end
    -        t[n] = nil
    -        t.n = n-1
    -        return value
    -      end
    +except that the table accesses are all raw
    +(that is, without tag methods):
    +
    +       function tremove (t, pos)
    +         local n = getn(t)
    +         if n<=0 then return end
    +         pos = pos or n
    +         local value = t[pos]
    +         for i=pos,n-1 do
    +           t[i] = t[i+1]
    +         end
    +         t[n] = nil
    +         t.n = n-1
    +         return value
    +       end
     

    -

    sort (table [, comp])

    -Sorts table elements in a given order, in-place, -from table[1] to table[n], -where n is the result of getn(table) (see Section 6.1). -If comp is given, -it must be a function that receives two table elements, -and returns true when the first is less than the second -(so that not comp(a[i+1], a[i]) will be true after the sort). -If comp is not given, -the standard < Lua operator is used instead. -

    -Function sort returns the (sorted) table. + +

    type (v)

    +Allows Lua programs to test the type of a value. +It receives one argument, and returns its type, coded as a string. +The possible results of this function are +"nil" (a string, not the value nil), +"number", +"string", +"table", +"function", +and "userdata".

    6.2 - String Manipulation

    This library provides generic functions for string manipulation, such as finding and extracting substrings and pattern matching. -When indexing a string, the first character is at position 1 +When indexing a string in Lua, the first character is at position 1 (not at 0, as in C). +Also, +indices are allowed to be negative and are intepreted as indexing backwards, +from the end of the string. Thus, the last character is at position -1, +and so on. +

    +

    strbyte (s [, i])

    +Returns the internal numerical code of the i-th character of s. +If i is absent, then it is assumed to be 1. +i may be negative. +

    +Numerical codes are not necessarily portable across platforms.

    -

    strfind (str, pattern [, init [, plain]])

    +

    strchar (i1, i2, ...)

    +Receives 0 or more integers. +Returns a string with length equal to the number of arguments, +wherein each character has the internal numerical code equal +to its correspondent argument. +

    +Numerical codes are not necessarily portable across platforms. +

    +

    strfind (s, pattern [, init [, plain]])

    Looks for the first match of -pattern in str. -If it finds one, then it returns the indices on str +pattern in s. +If it finds one, then strfind returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. -If the pattern specifies captures, +If the pattern specifies captures (see gsub below), the captured strings are returned as extra results. -A third optional numerical argument specifies where to start the search; -its default value is 1. -If init is negative, -it is replaced by the length of the string minus its -absolute value plus 1. -Therefore, -1 points to the last character of str. -A value of 1 as a fourth optional argument +A third, optional numerical argument init specifies +where to start the search; +its default value is 1, and may be negative. +A value of 1 as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain ``find substring'' operation, with no characters in pattern being considered ``magic''. +Note that if plain is given, then init must be given too.

    strlen (s)

    Receives a string and returns its length. +The empty string "" has length 0. +Embedded zeros are counted, +and so "a\000b\000c" has length 5. +

    +

    strlower (s)

    +Receives a string and returns a copy of that string with all +upper case letters changed to lower case. +All other characters are left unchanged. +The definition of what is an upper-case +letter depends on the current locale. +

    +

    strrep (s, n)

    +Returns a string that is the concatenation of n copies of +the string s.

    strsub (s, i [, j])

    Returns another string, which is a substring of s, -starting at i and running until j. -If i or j are negative, -they are replaced by the length of the string minus their -absolute value plus 1. -Therefore, -1 points to the last character of s -and -2 to the previous one. -If j is absent, it is assumed to be equal to -1 +starting at i and running until j; +i and j may be negative, +If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call strsub(s,1,j) returns a prefix of s @@ -2278,13 +2718,6 @@

    strsub (s, i [, j])

    and the call strsub(s, -i) returns a suffix of s with length i.

    -

    strlower (s)

    -Receives a string and returns a copy of that string with all -upper case letters changed to lower case. -All other characters are left unchanged. -The definition of what is an upper case -letter depends on the current locale. -

    strupper (s)

    Receives a string and returns a copy of that string with all lower case letters changed to upper case. @@ -2292,47 +2725,25 @@

    strupper (s)

    The definition of what is a lower case letter depends on the current locale.

    -

    strrep (s, n)

    -Returns a string that is the concatenation of n copies of -the string s. -

    -

    strbyte (s [, i])

    -Returns the internal numerical code of the character s[i]. -If i is absent, then it is assumed to be 1. -If i is negative, -it is replaced by the length of the string minus its -absolute value plus 1. -Therefore, -1 points to the last character of s. -

    -Note that numerical codes are not necessarily portable across platforms. -

    -

    strchar (i1, i2, ...)

    -Receives 0 or more integers. -Returns a string with length equal to the number of arguments, -wherein each character has the internal numerical code equal -to its correspondent argument. -

    -Note that numerical codes are not necessarily portable across platforms. -

    format (formatstring, e1, e2, ...)

    Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of -standard C functions. +standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported, and there is an extra option, q. -This option formats a string in a form suitable to be safely read +The q option formats a string in a form suitable to be safely read back by the Lua interpreter: The string is written between double quotes, -and all double quotes, returns and backslashes in the string +and all double quotes, returns, and backslashes in the string are correctly escaped when written. For instance, the call
    -format('%q', 'a string with "quotes" and \n new line')
    +       format('%q', 'a string with "quotes" and \n new line')
     
    will produce the string:
    @@ -2340,7 +2751,7 @@ 

    format (formatstring, e1, e2, ...)

    new line"

    -Conversions can be applied to the n-th argument in the argument list, +Conversions can be applied to the n-th argument in the argument list, rather than the next unused argument. In this case, the conversion character % is replaced by the sequence %d$, where d is a @@ -2359,20 +2770,22 @@

    format (formatstring, e1, e2, ...)

    For example, "%*g" can be simulated with "%"..width.."g".

    -Note: function format can only be used with strings that do not contain zeros. +Neither the format string nor the string values to be formatted with +%s can contain embedded zeros. +%q handles string values with embedded zeros.

    gsub (s, pat, repl [, n])

    -Returns a copy of s, -where all occurrences of the pattern pat have been +Returns a copy of s +in which all occurrences of the pattern pat have been replaced by a replacement string specified by repl. -This function also returns, as a second value, +gsub also returns, as a second value, the total number of substitutions made.

    If repl is a string, then its value is used for replacement. Any sequence in repl of the form %n with n between 1 and 9 -stands for the value of the n-th captured substring. +stands for the value of the n-th captured substring.

    If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, @@ -2381,35 +2794,35 @@

    gsub (s, pat, repl [, n])

    then it is used as the replacement string; otherwise, the replacement string is the empty string.

    -A last optional parameter n limits +The last, optional parameter n limits the maximum number of substitutions to occur. For instance, when n is 1 only the first occurrence of pat is replaced.

    Here are some examples:

    -  x = gsub("hello world", "(%w+)", "%1 %1")
    -  --> x="hello hello world world"
    +   x = gsub("hello world", "(%w+)", "%1 %1")
    +   --> x="hello hello world world"
     

    - x = gsub("hello world", "(%w+)", "%1 %1", 1) - --> x="hello hello world" + x = gsub("hello world", "(%w+)", "%1 %1", 1) + --> x="hello hello world"

    - x = gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") - --> x="world hello Lua from" + x = gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") + --> x="world hello Lua from"

    - x = gsub("home = $HOME, user = $USER", "%$(%w+)", getenv) - --> x="home = /home/roberto, user = roberto" (for instance) + x = gsub("home = $HOME, user = $USER", "%$(%w+)", getenv) + --> x="home = /home/roberto, user = roberto" (for instance)

    - x = gsub("4+5 = $return 4+5$", "%$(.-)%$", dostring) - --> x="4+5 = 9" + x = gsub("4+5 = $return 4+5$", "%$(.-)%$", dostring) + --> x="4+5 = 9"

    - local t = {name="lua", version="3.2"} - x = gsub("$name - $version", "%$(%w+)", function (v) return %t[v] end) - --> x="lua - 3.2" + local t = {name="lua", version="4.0"} + x = gsub("$name - $version", "%$(%w+)", function (v) return %t[v] end) + --> x="lua - 4.0"

    - t = {n=0} - gsub("first second word", "(%w+)", function (w) tinsert(%t, w) end) - --> t={"first", "second", "word"; n=3} + t = {n=0} + gsub("first second word", "(%w+)", function (w) tinsert(%t, w) end) + --> t={"first", "second", "word"; n=3}

    @@ -2420,7 +2833,7 @@

    Character Class:

    a character class is used to represent a set of characters. The following combinations are allowed in describing a character class:
    -
    x
    (where x is any character not in the list +
    x
    (where x is any magic characters ^$()%.[]*+-?) - represents the character x itself.
    .
    - (a dot) represents all characters. @@ -2432,37 +2845,44 @@

    Character Class:

    %s
    - represents all space characters.
    %u
    - represents all upper case letters.
    %w
    - represents all alphanumeric characters. -
    %x
    - represents all hexa-decimal digits. +
    %x
    - represents all hexadecimal digits.
    %z
    - represents the character with representation 0. -
    %x
    (where x is any non alphanumeric character) - +
    %x
    (where x is any non-alphanumeric character) - represents the character x. -This is the standard way to escape the magic characters ()%.[]*-?. -It is strongly recommended that any control character (even the non magic), -when used to represent itself in a pattern, should be preceded by a %. +This is the standard way to escape the magic characters. +We recommend that any punctuation character (even the non magic) +should be preceded by a % +when used to represent itself in a pattern. +

    [char-set]
    - -Represents the class which is the union of all -characters in char-set. -To include a ] in char-set, it must be the first character. +represents the class which is the union of all +characters in char-set. A range of characters may be specified by separating the end characters of the range with a -. -If - appears as the first or last character of char-set, -then it represents itself. -All classes %x described above can also be used as +All classes %x described above may also be used as components in a char-set. All other characters in char-set represent themselves. -E.g., assuming an ascii character set, -[%dA-Fa-f] specifies the hexa-decimal digits. +For example, [%w_] (or [_%w]) +represents all alphanumeric characters plus the underscore, +[0-7] represents the octal digits, +and [0-7%l%-] represents the octal digits plus +the lower case letters plus the - character. +

    +The interaction between ranges and classes is not defined. +Therefore, patterns like [%a-z] or [a-%%] +have no meaning. +

    [^char-set]
    - -represents the complement of char-set, -where char-set is interpreted as above. +represents the complement of char-set, +where char-set is interpreted as above.
    For all classes represented by single letters (%a, %c, ...), -the correspondent upper-case letter represents the complement of the class. +the corresponding upper-case letter represents the complement of the class. For instance, %S represents all non-space characters.

    The definitions of letter, space, etc. depend on the current locale. In particular, the class [a-z] may not be equivalent to %l. -The second form should be preferred for more portable programs. +The second form should be preferred for portability.

    Pattern Item:

    a pattern item may be @@ -2488,15 +2908,15 @@

    Pattern Item:

    which matches 0 or 1 occurrence of a character in the class;
  • %n, for n between 1 and 9; -such item matches a sub-string equal to the n-th captured string +such item matches a sub-string equal to the n-th captured string (see below);
  • %bxy, where x and y are two distinct characters; -such item matches strings that start with x, end with y, +such item matches strings that start with x, end with y, and where the x and y are balanced. -That means that, if one reads the string from left to write, -counting plus 1 for an x and minus 1 for a y, -the ending y is the first where the count reaches 0. +This means that, if one reads the string from left to right, +counting +1 for an x and -1 for a y, +the ending y is the first y where the count reaches 0. For instance, the item %b() matches expressions with balanced parentheses. @@ -2507,10 +2927,12 @@

    Pattern:

    beginning of the subject string. A $ at the end of a pattern anchors the match at the end of the subject string. +At other positions, +^ and $ have no special meaning and represent themselves.

    Captures:

    -a pattern may contain sub-patterns enclosed in parentheses, -that describe captures. +A pattern may contain sub-patterns enclosed in parentheses, +they describe captures. When a match succeeds, the sub-strings of the subject string that match captures are stored (captured) for future use. Captures are numbered according to their left parentheses. @@ -2520,43 +2942,44 @@

    Captures:

    the character matching . is captured with number 2, and the part matching %s* has number 3.

    +A pattern cannot contain embedded zeros. Use %z instead. +

    6.3 - Mathematical Functions

    -This library is an interface to some functions of the standard C math library. +This library is an interface to some functions of the standard C math library. In addition, it registers a tag method for the binary operator ^ that returns x^y when applied to numbers x^y.

    The library provides the following functions: - - - - - + + + +

    -abs acos asin atan atan2 ceil cos deg   floor log log10
    -max min  mod  rad  sin   sqrt tan frexp ldexp
    -random   randomseed
    +       abs  acos  asin  atan  atan2  ceil  cos  deg    exp    floor   log  log10
    +       max  min   mod   rad   sin    sqrt  tan  frexp  ldexp  random  randomseed
     
    plus a global variable PI. Most of them -are only interfaces to the homonymous functions in the C library, +are only interfaces to the homonymous functions in the C library, except that, for the trigonometric functions, all angles are expressed in degrees, not radians. -Functions deg and rad can be used to convert +The functions deg and rad can be used to convert between radians and degrees.

    The function max returns the maximum value of its numeric arguments. Similarly, min computes the minimum. -Both can be used with 1, 2 or more arguments. +Both can be used with 1, 2, or more arguments.

    The functions random and randomseed are interfaces to the simple random generator functions rand and srand, provided by ANSI C. +(No guarantees can be given for their statistical properties.) The function random, when called without arguments, returns a pseudo-random real number in the range [0,1). When called with a number n, @@ -2574,17 +2997,15 @@

    6.4 - I/O Facilities

    These handles are stored in two Lua global variables, called _INPUT and _OUTPUT. The global variables -_STDIN, _STDOUT and _STDERR +_STDIN, _STDOUT, and _STDERR are initialized with file descriptors for -stdin, stdout and stderr. +stdin, stdout, and stderr. Initially, _INPUT=_STDIN and _OUTPUT=_STDOUT.

    -A file handle is a userdata containing the file stream FILE*, +A file handle is a userdata containing the file stream (FILE*), and with a distinctive tag created by the I/O library. -Whenever a file handle is collected by the garbage collector, -its correspondent stream is automatically closed.

    Unless otherwise stated, all I/O functions return nil on failure and @@ -2598,18 +3019,19 @@

    openfile (filename, mode)

    or, in case of errors, nil plus a string describing the error. This function does not modify either _INPUT or _OUTPUT.

    -The string mode can be any of the following: +The mode string can be any of the following:

    -
    "r"
    read mode; -
    "w"
    write mode; -
    "a"
    append mode; -
    "r+"
    update mode, all previous data is preserved; -
    "w+"
    update mode, all previous data is erased; -
    "a+"
    append update mode, previous data is preserved, +
    ``r''
    read mode; +
    ``w''
    write mode; +
    ``a''
    append mode; +
    ``r+''
    update mode, all previous data is preserved; +
    ``w+''
    update mode, all previous data is erased; +
    ``a+''
    append update mode, previous data is preserved, writing is only allowed at the end of file.
    -The string mode may also have a b at the end, +The mode string may also have a b at the end, which is needed in some systems to open the file in binary mode. +This string is exactlty what is used in the standard C function fopen.

    closefile (handle)

    @@ -2626,18 +3048,15 @@

    readfrom (filename)

    When called without parameters, it closes the _INPUT file, and restores stdin as the value of _INPUT. -

    If this function fails, it returns nil, plus a string describing the error.

    - -System dependent: if filename starts with a |, +If filename starts with a |, then a piped input is opened, via function popen. Not all systems implement pipes. Moreover, the number of files that can be open at the same time is usually limited and depends on the system. -

    writeto (filename)

    @@ -2653,25 +3072,23 @@

    writeto (filename)

    this function closes the _OUTPUT file, and restores stdout as the value of _OUTPUT. -

    If this function fails, it returns nil, plus a string describing the error.

    - -System dependent: if filename starts with a |, -then a piped output is opened, via function popen. +If filename starts with a |, +then a piped input is opened, via function popen. Not all systems implement pipes. Moreover, the number of files that can be open at the same time is usually limited and depends on the system. -

    appendto (filename)

    Opens a file named filename and sets it as the value of _OUTPUT. Unlike the writeto operation, -this function does not erase any previous content of the file. +this function does not erase any previous contents of the file; +instead, anything written to the file is appended to its end. If this function fails, it returns nil, plus a string describing the error.

    @@ -2691,7 +3108,7 @@

    flush ([filehandle])

    Saves any written data to the given file. If filehandle is not specified, -flushes all open files. +then flush flushes all open files. If this function fails, it returns nil, plus a string describing the error.

    @@ -2702,9 +3119,9 @@

    seek (filehandle [, whence] [, offset])

    to the position given by offset plus a base specified by the string whence, as follows:
    -
    "set"
    base is position 0 (beginning of the file); -
    "cur"
    base is current position; -
    "end"
    base is end of file; +
    ``set''
    base is position 0 (beginning of the file); +
    ``cur''
    base is current position; +
    ``end''
    base is end of file;
    In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. @@ -2724,62 +3141,35 @@

    tmpname ()

    Returns a string with a file name that can safely be used for a temporary file. -The file must be explicitly removed when no longer needed. +The file must be explicitly opened before its use +and removed when no longer needed.

    -

    read ([filehandle,] readpattern1, ...)

    +

    read ([filehandle,] format1, ...)

    Reads file _INPUT, or filehandle if this argument is given, -according to read patterns, which specify how much to read. -For each pattern, -the function returns a string with the characters read, -even if the pattern succeeds only partially, -or nil if the read pattern fails and -the result string would be empty. -When called without patterns, -it uses a default pattern that reads the next line +according to the given formats, which specify what to read. +For each format, +the function returns a string (or a number) with the characters read, +or nil if it cannot read data with the specified format. +When called without formats, +it uses a default format that reads the next line (see below).

    -A read pattern is a sequence of read pattern items. -An item may be a single character class -or a character class followed by ?, by *, or by +. -A single character class reads the next character from the input -if it belongs to the class, otherwise it fails. -A character class followed by ? reads the next character -from the input if it belongs to the class; -it never fails. -A character class followed by * reads until a character that -does not belong to the class, or end of file; -since it can match a sequence of zero characters, it never fails. -A character class followed by + reads until a character that -does not belong to the class, or end of file; -it fails if it cannot read at least one character. -Note that the behavior of read patterns is slightly different from -the regular pattern matching behavior, -where a * expands to the maximum length such that -the rest of the pattern does not fail. -With the read pattern behavior -there is no need for backtracking the reading. -

    -A pattern item may contain sub-patterns enclosed in curly brackets, -that describe skips. -Characters matching a skip are read, -but are not included in the resulting string. -

    -There are some predefined patterns, as follows: +The available formats are

    ``*n''
    reads a number; -this is the only pattern that returns a number instead of a string. -
    ``*l''
    returns the next line +this is the only format that returns a number instead of a string. +
    ``*l''
    reads the next line (skipping the end of line), or nil on end of file. -This is the default pattern. -It is equivalent to the pattern "[^\n]*{\n}". -
    ``*a''
    reads the whole file. -It is equivalent to the pattern ".*". -
    ``*w''
    returns the next word -(maximal sequence of non white-space characters), +This is the default format. +
    ``*a''
    reads the whole file, starting at the current position. +On end of file, it returns the empty string. +
    ``*w''
    reads the next word +(maximal sequence of non--white-space characters), skipping spaces if necessary, or nil on end of file. -It is equivalent to the pattern "{%s*}%S+". +
    number
    reads a string with up to that number of characters, +or nil on end of file.

    write ([filehandle, ] value1, ...)

    @@ -2793,41 +3183,45 @@

    write ([filehandle, ] value1, ...)

    If this function fails, it returns nil, plus a string describing the error.

    + + +

    6.5 - System Facilities

    +

    +

    clock ()

    +

    +Returns an approximation of the amount of CPU time +used by the program, in seconds. +

    date ([format])

    Returns a string containing date and time formatted according to the given string format, -following the same rules of the ANSI C function strftime. +following the same rules of the ANSI C function strftime. When called without arguments, it returns a reasonable date and time representation that depends on -the host system and on the locale. +the host system and on the current locale.

    -

    clock ()

    +

    execute (command)

    -Returns an approximation of the amount of CPU time -used by the program, in seconds. +This function is equivalent to the C function system. +It passes command to be executed by an operating system shell. +It returns a status code, which is system-dependent.

    exit ([code])

    -Calls the C function exit, +Calls the C function exit, with an optional code, to terminate the program. -The default value for code is 1. +The default value for code is the success code.

    getenv (varname)

    Returns the value of the process environment variable varname, or nil if the variable is not defined.

    -

    execute (command)

    -

    -This function is equivalent to the C function system. -It passes command to be executed by an operating system shell. -It returns an error code, which is system-dependent. -

    setlocale (locale [, category])

    -This function is an interface to the ANSI C function setlocale. +This function is an interface to the ANSI C function setlocale. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", @@ -2841,7 +3235,7 @@

    setlocale (locale [, category])


    -

    7 - The Debugger Interface

    +

    7 - The Debug Interface

    Lua has no built-in debugging facilities. Instead, it offers a special interface, @@ -2849,264 +3243,302 @@

    7 - The Debugger Interface

    which allows the construction of different kinds of debuggers, profilers, and other tools that need ``inside information'' from the interpreter. -This interface is declared in the header file luadebug.h. +This interface is declared in luadebug.h.

    7.1 - Stack and Function Information

    -The main function to get information about the interpreter stack -is + +The main function to get information about the interpreter stack is

    -lua_Function lua_stackedfunction (int level);
    +       int lua_getstack (lua_State *L, int level, lua_Debug *ar);
     
    -It returns a handle (lua_Function) to the activation record +It fills parts of a lua_Debug structure with +an identification of the activation record of the function executing at a given level. Level 0 is the current running function, -while level n+1 is the function that has called level n. -When called with a level greater than the stack depth, -lua_stackedfunction returns LUA_NOOBJECT. -

    -The type lua_Function is just another name -to lua_Object. -Although, in this library, -a lua_Function can be used wherever a lua_Object is required, -when a parameter has type lua_Function -it accepts only a handle returned by -lua_stackedfunction. -

    -Three other functions produce extra information about a function: -

    -void lua_funcinfo (lua_Object func, char **source, int *linedefined);
    -int lua_currentline (lua_Function func);
    -char *lua_getobjname (lua_Object o, char **name);
    -
    -lua_funcinfo gives the source and the line where the -given function has been defined: +whereas level n+1 is the function that has called level n. +Usually, lua_getstack returns 1; +when called with a level greater than the stack depth, +it returns 0. +

    + +The structure lua_Debug is used to carry different pieces of +information about an active function: +

    +      typedef struct lua_Debug {
    +        const char *event;     /* "call", "return" */
    +        int currentline;       /* (l) */
    +        const char *name;      /* (n) */
    +        const char *namewhat;  /* (n) global, tag method, local, field */
    +        int nups;              /* (u) number of upvalues */
    +        int linedefined;       /* (S) */
    +        const char *what;      /* (S) "Lua" function, "C" function, Lua "main" */
    +        const char *source;    /* (S) */
    +        char short_src[LUA_IDSIZE]; /* (S) */
    +

    + /* private part */ + ... + } lua_Debug; +

    +lua_getstack fills only the private part +of this structure, for future use. +To fill in the other fields of lua_Debug with useful information, +call +
    +       int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
    +
    +This function returns 0 on error +(e.g., an invalid option in what). +Each character in the string what +selects some fields of ar to be filled, +as indicated by the letter in parentheses in the definition of lua_Debug: +`S' fills in the fields source, linedefined, +and what; +`l' fills in the field currentline, etc. +Moreover, `f' pushes onto the stack the function that is +running at the given level. +

    +To get information about a function that is not active (that is, +it is not in the stack), +you push the function onto the stack, +and start the what string with the character >. +For instance, to know in which line a function f was defined, +you can write +

    +       lua_Debug ar;
    +       lua_getglobal(L, "f");
    +       lua_getinfo(L, ">S", &ar);
    +       printf("%d\n", ar.linedefined);
    +
    +The fields of lua_Debug have the following meaning: +
    +

    +

    source
    If the function was defined in a string, source is that string; -If the function was defined in a file, +if the function was defined in a file, source starts with a @ followed by the file name. -If the ``function'' is in fact the main code of a chunk, -then linedefined is 0. -If the function is a C function, -then linedefined is -1, and filename is "(C)". -

    -The function lua_currentline gives the current line where -a given function is executing. -It only works if the function has been compiled with debug -information. -When no line information is available, -lua_currentline returns -1.

    -The generation of debug information is controled by an internal flag, -which can be switched with -

    -int lua_setdebug (int debug);
    -
    -This function sets the flag and returns its previous value. -This flag can also be set from Lua (see Section 4.9). +
    short_src
    +A ``printable'' version of source, to be used in error messages. +

    +

    linedefined
    +the line number where the definition of the function starts. +

    +

    what
    the string "Lua" if this is a Lua function, +"C" if this is a C function, +or "main" if this is the main part of a chunk. +

    +

    currentline
    +the current line where the given function is executing. +When no line information is available, +currentline is set to -1.

    -Function lua_getobjname tries to find a reasonable name for -a given function. +

    name
    +a reasonable name for the given function. Because functions in Lua are first class values, they do not have a fixed name: Some functions may be the value of many global variables, while others may be stored only in a table field. -Function lua_getobjname checks whether the given +The lua_getinfo function checks whether the given function is a tag method or the value of a global variable. -If the given function is a tag method, then lua_getobjname -returns the string "tag-method", -and name is set to point to the event name. +If the given function is a tag method, +then name points to the event name. If the given function is the value of a global variable, -then lua_getobjname returns the string "global", -and name points to the variable name. +then name points to the variable name. If the given function is neither a tag method nor a global variable, -then lua_getobjname returns the empty string, -and name is set to NULL. +then name is set to NULL. +

    +

    namewhat
    +Explains the previous field. +If the function is a global variable, +namewhat is "global"; +if the function is a tag method, +namewhat is "tag-method"; +otherwise namewhat is "" (the empty string). +

    +

    nups
    +Number of upvalues of a function. +

    +

    +

    7.2 - Manipulating Local Variables

    +For the manipulation of local variables, +luadebug.h uses indices: +The first parameter or local variable has index 1, and so on, +until the last active local variable. +

    + The following functions allow the manipulation of the local variables of a given activation record. -They only work if the function has been compiled with debug -information (see Section 4.9). -Moreover, for these functions, a local variable becomes -visible in the line after its definition. -

    -lua_Object lua_getlocal (lua_Function func, int local_number, char **name);
    -int lua_setlocal (lua_Function func, int local_number);
    -
    -lua_getlocal returns the value of a local variable, -and sets name to point to the variable name. -local_number is an index for local variables. -The first parameter has index 1, and so on, until the -last active local variable. -When called with a local_number greater than the -number of active local variables, -or if the activation record has no debug information, -lua_getlocal returns LUA_NOOBJECT. -Formal parameters are the first local variables. -

    -The function lua_setlocal sets the local variable -local_number to the value previously pushed on the stack -(see Section 5.2). -If the function succeeds, then it returns 1. -If local_number is greater than the number -of active local variables, -or if the activation record has no debug information, -then this function fails and returns 0. -

    +

    +       const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
    +       const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
    +
    +The parameter ar must be a valid activation record, +filled by a previous call to lua_getstack or +given as argument to a hook (see Section 7.3). +Function lua_getlocal gets the index of a local variable +(n), pushes its value onto the stack, +and returns its name. +For lua_setlocal, +you push the new value onto the stack, +and the function assigns that value to the variable and returns its name. +Both functions return NULL on failure; +that happens if the index is greater than +the number of active local variables. +

    +As an example, the following function lists the names of all +local variables for a function at a given level of the stack: +

    +       int listvars (lua_State *L, int level) {
    +         lua_Debug ar;
    +         int i = 1;
    +         const char *name;
    +         if (lua_getstack(L, level, &ar) == 0)
    +           return 0;  /* failure: no such level in the stack */
    +         while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
    +           printf("%s\n", name);
    +           lua_pop(L, 1);  /* remove variable value */
    +         }
    +         return 1;
    +       }
    +
    +

    +

    +

    7.3 - Hooks

    The Lua interpreter offers two hooks for debugging purposes: +a call hook and a line hook. +Both have the same type, +

    -typedef void (*lua_CHFunction) (lua_Function func, char *file, int line);
    -lua_CHFunction lua_setcallhook (lua_CHFunction func);
    -

    -typedef void (*lua_LHFunction) (int line); -lua_LHFunction lua_setlinehook (lua_LHFunction func); + typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); +

    +and you can set them with the following functions: + +
    +       lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
    +       lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
     
    -The first hook is called whenever the interpreter enters or leaves a -function. -When entering a function, -its parameters are a handle to the function activation record, -plus the file and the line where the function is defined -(the same information which is provided by lua_funcinfo); -when leaving a function, func is LUA_NOOBJECT, -file is "(return)", and line is 0. -

    -The other hook is called every time the interpreter changes -the line of code it is executing. -Its only parameter is the line number -(the same information which is provided by the call -lua_currentline(lua_stackedfunction(0))). -This second hook is called only if the active function -has been compiled with debug information (see Section 4.9). -

    A hook is disabled when its value is NULL, which is the initial value of both hooks. -Both lua_setcallhook and lua_setlinehook +The functions lua_setcallhook and lua_setlinehook set their corresponding hooks and return their previous values.

    +The call hook is called whenever the +interpreter enters or leaves a function. +The event field of ar has the strings "call" +or "return". +This ar can then be used in calls to lua_getinfo, +lua_getlocal, and lua_setlocal +to get more information about the function and to manipulate its +local variables. +

    +The line hook is called every time the interpreter changes +the line of code it is executing. +The event field of ar has the string "line", +and the currentline field has the line number. +Again, you can use this ar in other calls to the debug API. +

    +While Lua is running a hook, it disables other calls to hooks. +Therefore, if a hook calls Lua to execute a function or a chunk, +this execution ocurrs without any calls to hooks.

    -

    7.4 - The Reflexive Debugger Interface

    +

    7.4 - The Reflexive Debug Interface

    The library ldblib provides -the functionallity of the debugger interface to Lua programs. +the functionality of the debug interface to Lua programs. If you want to use this library, your host application must open it, -calling lua_dblibopen. +by calling lua_dblibopen. +

    You should exert great care when using this library. The functions provided here should be used exclusively for debugging -and similar tasks (e.g. profiling). +and similar tasks (e.g., profiling). Please resist the temptation to use them as a usual programming tool. They are slow and violate some (otherwise) secure aspects of the -language (e.g. privacy of local variables). +language (e.g., privacy of local variables). As a general rule, if your program does not need this library, do not open it.

    -

    funcinfo (function)

    +

    getinfo (function, [what])

    -This function returns a table with information about the given function. -The table contains the following fields: -

    -
    kind
    : may be "C", if this is a C function, -"chunk", if this is the main part of a chunk, -or "Lua" if this is a Lua function. -

    -

    source
    the source where the function was defined. -If the function was defined in a string, -source is that string; -If the function was defined in a file, -source starts with a @ followed by the file name. -

    -

    def_line
    the line where the function was defined in the source -(only valid if this is a Lua function). +This function returns a table with information about a function. +You can give the function directly, +or you can give a number as the value of function, +which means the function running at level function of the stack: +Level 0 is the current function (getinfo itself); +level 1 is the function that called getinfo; +and so on. +If function is a number larger than the number of active functions, +then getinfo returns nil.

    -

    where
    can be "global" if this function has a global name, -or "tag-method" if this function is a tag method handler. +The returned table contains all the fields returned by lua_getinfo, +with the string what describing what to get. +The default for what is to get all information available.

    -

    name
    if where = global, -name is the global name of the function; -if where = tag-method, -name is the event name of the tag method. -
    +For instance, the expression getinfo(1,"n").name returns +the name of the current function, if a reasonable name can be found, +and getinfo(print) returns a table with all available information +about the print function.

    -

    getstack (index)

    -This function returns a table with informations about the function -running at level index of the stack. -Index 0 is the current function (getstack itself). -If index is bigger than the number of active functions, -the function returns nil. -The table contains all the fields returned by funcinfo, -plus the following: -

    -
    func
    the function at that level. -
    current
    the current line on the function execution; -this will be available only when the function is -precompiled with debug information. -
    +

    getlocal (level, local)

    -

    getlocal (index [, local])

    -

    -This function returns information about the local variables of the -function at level index of the stack. -It can be called in three ways. -When called without a local argument, -it returns a table, which associates variable names to their values. -When called with a name (a string) as local, -it returns the value of the local variable with that name. -Finally, when called with an index (a number), -it returns the value and the name of the local variable -with that index. -(The first parameter has index 1, and so on, +This function returns the name and the value of the local variable +with index local of the function at level level of the stack. +(The first parameter or local variable has index 1, and so on, until the last active local variable.) -In that case, the function returns nil if there is no local -variable with the given index. -The specification by index is the only way to distinguish -homonym variables in a function. +The function returns nil if there is no local +variable with the given index, +and raises an error when called with a level out of range. +(You can call getinfo to check whether the level is valid.)

    -

    setlocal (index, local, newvalue)

    +

    setlocal (level, local, value)

    -This function changes the values of the local variables of the -function at level index of the stack. -The local variable can be specified by name or by index; -see function getlocal. +This function assigns the value value to the local variable +with index local of the function at level level of the stack. +The function returns nil if there is no local +variable with the given index, +and raises an error when called with a level out of range.

    setcallhook (hook)

    Sets the function hook as the call hook; this hook will be called every time the interpreter starts and exits the execution of a function. -When Lua enters a function, -the hook is called with the function been called, -plus the source and the line where the function is defined. -When Lua exits a function, -the hook is called with no arguments. -

    +The only argument to the call hook is the event name ("call" or +"return"). +You can call getinfo with level 2 to get more information about +the function being called or returning +(level 0 is the getinfo function, +and level 1 is the hook function). When called without arguments, this function turns off call hooks. +setcallhook returns the old hook.

    setlinehook (hook)

    Sets the function hook as the line hook; this hook will be called every time the interpreter changes the line of code it is executing. -The only argument to the hook is the line number the interpreter -is about to execut. -This hook is called only if the active function -has been compiled with debug information (see Section 4.9). -

    +The only argument to the line hook is the line number the interpreter +is about to execute. When called without arguments, this function turns off line hooks. +setlinehook returns the old hook.

    @@ -3116,60 +3548,96 @@

    setlinehook (hook)

    8 - Lua Stand-alone

    Although Lua has been designed as an extension language, -the language can also be used as a stand-alone interpreter. -An implementation of such an interpreter, +to be embedded in a host C program, +it is frequently used as a stand-alone language. +An interpreter for Lua as a stand-alone language, called simply lua, is provided with the standard distribution. This program can be called with any sequence of the following arguments:

    -
    -v
    prints version information. -
    -d
    turns on debug information. -
    -e stat
    executes stat as a Lua chunk. -
    -i
    runs interactively, -accepting commands from standard input until an EOF. -Each line entered is immediately executed. -
    -q
    same as -i, but without a prompt (quiet mode). -
    -
    executes stdin as a file. -
    var=value
    sets global var with string "value". -
    filename
    executes file filename as a Lua chunk. +
    -sNUM
    sets the stack size to NUM +(if present, this must be the first option); +
    -
    executes stdin as a file; +
    -c
    calls lua_close after running all arguments; +
    -e \rmstat
    executes string stat; +
    -f filename
    executes file filename with the +remaining arguments in table arg; +
    -i
    enters interactive mode with prompt; +
    -q
    enters interactive mode without prompt; +
    -v
    prints version information; +
    var=value
    sets global var to string "value"; +
    filename
    executes file filename.
    When called without arguments, -Lua behaves as lua -v -i when stdin is a terminal, +lua behaves as lua -v -i when stdin is a terminal, and as lua - otherwise.

    -All arguments are handled in order. +All arguments are handled in order, except -c. For instance, an invocation like

    -$ lua -i a=test prog.lua
    +       $ lua -i a=test prog.lua
     
    -will first interact with the user until an EOF, +will first interact with the user until an EOF in stdin, then will set a to "test", and finally will run the file prog.lua. +(Here, +$ is the shell prompt. Your prompt may be different.)

    -When in interactive mode, +When the option -f filename is used, +all remaining arguments in the command line +are passed to the Lua program filename in a table called arg. +In this table, +the field n gets the index of the last argument, +and the field 0 gets "filename". +For instance, in the call +

    +       $ lua a.lua -f b.lua t1 t3
    +
    +the interpreter first runs the file a.lua, +then creates a table +
    +       arg = {"t1", "t3";  n = 2, [0] = "b.lua"}
    +
    +and finally runs the file b.lua. + +The stand-alone interpreter also provides a getargs function that +can be used to access all command line arguments. +For instance, if you call Lua with the line +
    +       $ lua -c a b
    +
    +then a call to getargs in a or b will return the table +
    +       {[0] = "lua", [1] = "-c", [2] = "a", [3] = "b", n = 3}
    +
    +

    +In interactive mode, a multi-line statement can be written finishing intermediate -lines with a backslash (\). -The prompt presented is the value of the global variable _PROMPT. -Therefore, the prompt can be changed like below: +lines with a backslash (`\'). +If the global variable _PROMPT is defined as a string, +then its value is used as the prompt. +Therefore, the prompt can be changed directly on the command line:

    -$ lua _PROMPT='myprompt> ' -i
    +       $ lua _PROMPT='myprompt> ' -i
     
    +or in any Lua programs by assigning to _PROMPT.

    In Unix systems, Lua scripts can be made into executable programs -by using the #! form, -as in #!/usr/local/bin/lua. +by using chmod +x and the #! form, +as in #!/usr/local/bin/lua, +or #!/usr/local/bin/lua -f to get other arguments. +


    Acknowledgments

    The authors would like to thank CENPES/PETROBRAS which, -jointly with TeCGraf, used extensively early versions of -this system and gave valuable comments. +jointly with TeCGraf, used early versions of +this system extensively and gave valuable comments. The authors would also like to thank Carlos Henrique Levy, who found the name of the game. -Lua means moon in Portuguese. -

    +Lua means ``moon'' in Portuguese.

    @@ -3177,60 +3645,153 @@

    Acknowledgments

    Incompatibilities with Previous Versions

    -Although great care has been taken to avoid incompatibilities with +Lua 4.0 is a major revision of the language. +We took a great care to avoid incompatibilities with the previous public versions of Lua, -some differences had to be introduced. +but some differences had to be introduced. Here is a list of all these incompatibilities.

    -

    Incompatibilities with version 3.1

    +

    +

    Incompatibilities with version 3.2

    +

    +

    Changes in the Language

      +

      +

    • +All pragmas ($debug, $if, ...) have been removed. +

      +

    • +for, break, and in are now reserved words. +

      +

    • +Garbage-collection tag methods for tables is now obsolete. +

      +

    • +There is now only one tag method for order operators. +

      +

    • +In nested function calls like f(g(x)), +all return values from g are passed as arguments to f. +This only happens when g is the last +or the only argument to f. +

    • -In the debug API, the old variables lua_debug, -lua_callhook and lua_linehook now live inside lua_state. -Therefore, they are no longer directly accessible, and must be -manipulated only through the new functions lua_setdebug, -lua_setcallhook and lua_setlinehook. +The pre-compiler may assume that some operators are associative, +for optimizations. +This may cause problems if these operators +have non-associative tag methods.

    • Old pre-compiled code is obsolete, and must be re-compiled. +

    -

    Incompatibilities with version 3.0

    +

    +

    Changes in the Libraries

      -

    • To support multiple contexts, -Lua 3.1 must be explicitly opened before used, -with function lua_open. -However, all standard libraries check whether Lua is already opened, -so any existing program that opens at least one standard -library before calling Lua does not need to be modified. +
    • +When traversing a table with next or foreach, +the table cannot be modified in any way.

      -

    • Function dostring no longer accepts an optional second argument, -with a temporary error handler. -This facility is now provided by function call. +
    • +General read patterns are now obsolete.

      -

    • Function gsub no longer accepts an optional fourth argument -(a callback data, a table). -Closures replace this feature with advantage. +
    • +The functions rawgettable and rawsettable +have been renamed to rawget and rawset.

      -

    • The syntax for function declaration is now more restricted; -for instance, the old syntax function f[exp] (x) ... end is not -accepted in Lua 3.1. -In these cases, -programs should use an explicit assignment instead, such as -f[exp] = function (x) ... end. +
    • +The functions foreachvar, nextvar, +rawsetglobal, and rawgetglobal are obsolete. +You can get their functionality using table operations +over the table of globals, +which is returned by globals.

      -

    • Old pre-compiled code is obsolete, and must be re-compiled. +
    • +setglobal and sort no longer return a value; +type no longer returns a second value.

      -

    • The option a=b in Lua stand-alone now sets a to the -string b, and not to the value of b. +
    • +The p option in function call is now obsolete.

    +

    +

    Changes in the API

    +
      +

      +

    • +The API has been completely rewritten: +It is now fully reentrant and much clearer. +

      +

    • +The debug API has been completely rewritten. +

      +

    +

    + + +


    +

    The Complete Syntax of Lua

    +

    + +

    +

    +

    + chunk ::= {stat [`;']} +

    + block ::= chunk +

    + stat ::= varlist1 `=' explist1
    | functioncall
    | do block end
    | while exp1 do block end
    | repeat block until exp1
    | if exp1 then block {elseif exp1 then block} [else block] end
    | return [explist1]
    | break
    | for `name' `=' exp1 `,' exp1 [`,' exp1] do block end
    | for `name' `,' `name' in exp1 do block end
    | function funcname `(' [parlist1] `)' block end
    | local declist [init] +

    + funcname ::= `name' | `name' `.' `name' | `name' `:' `name' +

    + varlist1 ::= var {`,' var} +

    + var ::= `name' | varorfunc `[' exp1 `]' | varorfunc `.' `name' +

    + varorfunc ::= var | functioncall +

    + declist ::= `name' {`,' `name'} +

    + init ::= `=' explist1 +

    + explist1 ::= {exp1 `,'} exp +

    + exp1 ::= exp +

    + exp ::= nil | `number' | `literal' | var | function | upvalue
    | functioncall | tableconstructor | `(' exp `)' | exp binop exp | unop exp +

    +

    + functioncall ::= varorfunc args | varorfunc `:' `name' args +

    + args ::= `(' [explist1] `)' | tableconstructor | `literal' +

    + function ::= function `(' [parlist1] `)' block end +

    + parlist1 ::= `...' | `name' {`,' `name'} [`,' `...'] +

    + upvalue ::= `%' `name' +

    + tableconstructor ::= `{' fieldlist `}' + fieldlist ::= lfieldlist | ffieldlist | lfieldlist `;' ffieldlist | ffieldlist `;' lfieldlist + lfieldlist ::= [lfieldlist1] + ffieldlist ::= [ffieldlist1] + lfieldlist1 ::= exp {`,' exp} [`,'] + ffieldlist1 ::= ffield {`,' ffield} [`,'] + ffield ::= `[' exp `]' `=' exp | `name' `=' exp +

    + binop ::= `+' | `-' | `*' | `/' | `\^{ ' | `..'
    | `<' | `<=' | `>' | `>=' | `==' | `\ { '=}
    | and | or} +

    + unop ::= `-' | not +

    +

    +


    Last update: -Wed Jul 7 13:36:24 EST 1999 +Mon Nov 6 17:37:03 EDT 2000 by lhf. diff --git a/doc/readme.html b/doc/readme.html index dd75b1d137..a574eccd36 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -6,24 +6,29 @@
    -

    Lua documentation

    +

    +Lua +Documentation +


    Last update: -Wed Jul 7 13:24:17 EST 1999 +Mon Nov 6 19:13:31 EDT 2000 by lhf. diff --git a/etc/Makefile b/etc/Makefile index 216d3ef632..a776869733 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -4,21 +4,35 @@ LUA= .. include $(LUA)/config -ALL= bin2c min trace +LIBLUA=$(LIB)/liblua.a +ALL= bin2c min trace lua.def + +x: + @echo 'choose a target:' all $(ALL) all: $(ALL) -bin2c: bin2c.c - $(CC) -o $@ $< +bin2c: bin2c.c + $(CC) $(CFLAGS) -o $@ $@.c + +min: min.c $(LIBLUA) + $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua + +trace: trace.c $(LIBLUA) + $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib -lm + +def: lua.def -min: min.c $(LIB)/liblua.a - $(CC) $(CFLAGS) -o $@ $< -L$(LIB) -llua +lua.def: $(INC)/lua.h + $(BIN)/lua def.lua < $(INC)/lua.h > $@ + # cat $(INC)/l*.h | $(BIN)/lua def.lua > $@ -trace: trace.c $(LIB)/liblua.a - $(CC) $(CFLAGS) -o $@ $< -L$(LIB) -llua +stdcall: + mkdir -p Stdcall + grep -l _API $(LUA)/src/*.[ch] $(LUA)/src/*/*.[ch] | xargs -n1 -i echo $(BIN)/lua stdcall.lua '<{}' '>Stdcall/{}' -$(LIB)/liblua.a: - cd ../src; make +$(LIBLUA): + cd ../src; $(MAKE) clean: rm -f $(ALL) diff --git a/etc/README b/etc/README index 002190aeff..eaae1c3ddf 100644 --- a/etc/README +++ b/etc/README @@ -2,25 +2,42 @@ This directory contains some code that might be useful. bin2c.c This program converts files to byte arrays that are automatically - run with lua_dobuffer. - This allows C programs to include all necessary Lua code, even in - precompiled form. - Even if the code is included in source form, bin2c is useful because it - avoids the hassle of having to quote special characters in C strings. + run with lua_dobuffer. This allows C programs to include all necessary + Lua code, even in precompiled form. Even if the code is included in + source form, bin2c is useful because it avoids the hassle of having to + quote special characters in C strings. Example of usage: Run bin2c file1 file2 ... > init.h. Then, in your C program, just do #include "init.h" anywhere in the *body* of a function. This will be equivalent to calling - lua_dofile("file1"); lua_dofile("file2"); ... + lua_dofile(L,"file1"); lua_dofile(L,"file2"); ... + Note that the Lua state is called "L". If you use a different name, + say "mystate", just #define L mystate before #include "init.h". + +def.lua + A Lua script for creating .DEF for Windows DLLs. + Just do "make def" to create lua.def. min.c - The smallest Lua interpreter possible. + A minimal Lua interpreter. + +lua.ico + A Lua icon for Windows. + It was drawn by hand by Markus Gritsch . + +lua.xpm + The same icon as lua.ico, but in XPM format. + It was converted with ImageMagick by Andy Tai . + +lua.magic + Data for teaching file(1) about Lua precompiled chunks. + +stdcall.lua + A Lua script for changing the calling convention to __stdcall. + Do "make stdcall" and new modules will be created in stdcall/. setfallback.lua - An implementation of fallbacks on top of tag methods. - Useful if you have Lua code written for version 2.5 or earlier, - which uses setfallback. - If you have C code that uses lua_setfallback, then define LUA_COMPAT2_5 - before building Lua (see config). + A Lua implementation of fallbacks on top of tag methods. + You only need this module if you have Lua code that uses setfallback. trace.c A simple execution tracer. An example of how to use the debugging hooks. diff --git a/etc/bin2c.c b/etc/bin2c.c index fca82a556d..ac95a6e8bc 100644 --- a/etc/bin2c.c +++ b/etc/bin2c.c @@ -2,7 +2,7 @@ * bin2c.c * convert binary files to byte arrays * Luiz Henrique de Figueiredo (lhf@tecgraf.puc-rio.br) -* 24 Nov 98 12:15:27 +* 11 Sep 2000 22:37:14 */ #include @@ -45,7 +45,7 @@ void fdump(char* fn, int n) void emit(char* fn, int n) { - printf(" lua_dobuffer(B%d,sizeof(B%d),\"%s\");\n",n,n,fn); + printf(" lua_dobuffer(L,B%d,sizeof(B%d),\"%s\");\n",n,n,fn); } int main(int argc, char* argv[]) @@ -61,7 +61,7 @@ int main(int argc, char* argv[]) { int i; printf("/* #include'ing this file in a C program is equivalent to calling\n"); - for (i=1; ilua.def + +T=read"*a" +write("LIBRARY LUA\nVERSION ") +gsub(T,"LUA_VERSION.-(%d+%.%d+)",write) +write("\nEXPORTS\n") +gsub(T,"(lua_%w+)%s+%(",function (f) write(" ",f,"\n") end) diff --git a/etc/lua.ico b/etc/lua.ico new file mode 100644 index 0000000000000000000000000000000000000000..ccbabc4e2004683f29598a991006d7caff6d837d GIT binary patch literal 1078 zcma)5y>7xl4E|D3VJbX9VX7GW1~6FSw!BIQq_T0tNo32b^bxZ4H5fZGR7xh?&v!Y3 zDh3=J`#b+#Yy%W{!g4u>(a#g`Mme7+yefc~5wPOflDr`o81qe{?|t$BfABsDzNw;V z8cH*0{6W<;G9Np#7ik(qoR4aR5-A@{5)}DJ9&}FRBA#X_5+im4-kQSzMF^)-t2(Vi ztw-^|Sn8@O_lM9`oos+0wMZGt&`Bq(aK&XCv1Gfr&Jtd6%lKPdD{s=unqGWyb3%y{X9SS{jB~HMh0oKMISQrDC zJ;K?)>ElnpmN^UNE-rXxtyk{c#rCe~`P=qnFT7 bCxwx*w%~s~=?o*z_6Fk4@7l(poWF`cPpA(! literal 0 HcmV?d00001 diff --git a/etc/lua.magic b/etc/lua.magic new file mode 100644 index 0000000000..eb78f8d0db --- /dev/null +++ b/etc/lua.magic @@ -0,0 +1,10 @@ + +# Lua precompiled files +0 string \33Lua precompiled chunk for Lua +>4 byte 0x23 2.3 +>4 byte 0x24 2.4 +>4 byte 0x25 2.5 +>4 byte 0x30 3.0 +>4 byte 0x31 3.1 +>4 byte 0x32 3.2 +>4 byte 0x40 4.0 diff --git a/etc/lua.xpm b/etc/lua.xpm new file mode 100644 index 0000000000..d3dcd379af --- /dev/null +++ b/etc/lua.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static char *magick[] = { +/* columns rows colors chars-per-pixel */ +"32 32 6 1", +" c Gray0", +". c #000000008080", +"X c #808080808080", +"o c #c0c0c0c0c0c0", +"O c Gray100", +"+ c None", +/* pixels */ +"++++++++++++++++++++++++++ooo+++", +"++++++++++++++++++++++++oX...Xo+", +"++++++++++++++++++++++++X.....X+", +"+++++++++++++++++++++++o.......o", +"+++++++++XX......XX++++o.......o", +"+++++++X............X++o.......o", +"+++++o................o+X.....X+", +"++++X..................XoX...Xo+", +"+++X..............XXX...X+ooo+++", +"++o.............XoOOOoX..o++++++", +"++..............oOOOOOo...++++++", +"+X.............XOOOOOOOX..X+++++", +"+..............XOOOOOOOX...+++++", +"X..............XOOOOOOOX...X++++", +"X...............oOOOOOo....X++++", +"................XoOOOoX.....++++", +"....XO............XXX.......++++", +"....XO......................++++", +"....XO.....OX..OX.XOOOo.....++++", +"....XO.....OX..OX.OoXXOX....++++", +"....XO.....OX..OX....XOX....++++", +"X...XO.....OX..OX..OOoOX...X++++", +"X...XO.....OX..OX.OX..OX...X++++", +"+...XOXXXX.OoXoOX.OXXXOX...+++++", +"+X..XOOOOO.XOOXOX.XOOOXo..X+++++", +"++........................++++++", +"++o......................o++++++", +"+++X....................X+++++++", +"++++X..................X++++++++", +"+++++o................o+++++++++", +"+++++++X............X+++++++++++", +"+++++++++XX......XX+++++++++++++" +}; diff --git a/etc/min.c b/etc/min.c index 7d45f5b6a6..0579ed3f61 100644 --- a/etc/min.c +++ b/etc/min.c @@ -1,13 +1,32 @@ /* * min.c * a minimal Lua interpreter. loads stdin only. -* no standard library, only builtin functions. +* no standard library, only a "print" function. */ +#include #include "lua.h" +/* a simple "print". based on the code in lbaselib.c */ +static int print(lua_State *L) +{ + int n=lua_gettop(L); + int i; + for (i=1; i<=n; i++) + { + if (i>1) printf("\t"); + if (lua_isstring(L,i)) + printf("%s",lua_tostring(L,i)); + else + printf("%s:%p",lua_typename(L,lua_type(L,i)),lua_topointer(L,i)); + } + printf("\n"); + return 0; +} + int main(void) { - lua_open(); - return lua_dofile(0); + lua_State *L=lua_open(0); + lua_register(L,"print",print); + return lua_dofile(L,NULL); } diff --git a/etc/stdcall.lua b/etc/stdcall.lua new file mode 100644 index 0000000000..7eac5c2ec0 --- /dev/null +++ b/etc/stdcall.lua @@ -0,0 +1,10 @@ +-- stdcall.lua +-- add __stdcall where appropriate +-- usage: lua stdcall.lua s_lua.h +-- usage: lua stdcall.lua s_lapi.c + +T=read"*a" +T=gsub(T,"(lua_%w+%s+%()","__stdcall %1") +T=gsub(T,"(%*lua_CFunction)","__stdcall %1") + +write(T) diff --git a/etc/trace.c b/etc/trace.c index 2c92850f41..7c0b86ed9a 100644 --- a/etc/trace.c +++ b/etc/trace.c @@ -6,44 +6,51 @@ #include #include #include "lua.h" +#include "lualib.h" #include "luadebug.h" +lua_State *lua_state = NULL; +#define L lua_state /* lazy! */ + static FILE* LOG; /* output file */ -static int L=0; /* indentation level */ +static int I=0; /* indentation level */ -static void linehook(int line) +static void linehook(lua_State *L, lua_Debug *ar) { - fprintf(LOG,"%*sLINE(%d)\t-- %d\n",L,"",line,L); + fprintf(LOG,"%*sdo_line(%d)\t-- %d\n",I,"",ar->currentline,I); } -static void callhook(lua_Function func, char* file, int line) +static void callhook(lua_State *L, lua_Debug *ar) { - fprintf(LOG,"%*sCALL('%s',%d)\t-- %d\n",L,"",file,line,L); - if (line==0 && strcmp(file,"(return)")==0) --L; else ++L; + fprintf(LOG,"%*sdo_%s\t-- %p %d\n",I,"",ar->event,ar->_func,I); + if (*ar->event=='r') --I; else ++I; } void start_trace(FILE* logfile) { - lua_setlinehook(linehook); - lua_setcallhook(callhook); - lua_setdebug(1); + lua_setlinehook(L,linehook); + lua_setcallhook(L,callhook); LOG=logfile; } void stop_trace(void) { - lua_setlinehook(NULL); - lua_setcallhook(NULL); - lua_setdebug(0); + lua_setlinehook(L,NULL); + lua_setcallhook(L,NULL); fclose(LOG); } int main(void) { int rc; - lua_open(); + L=lua_open(0); + lua_baselibopen(L); + lua_iolibopen(L); + lua_strlibopen(L); + lua_mathlibopen(L); + lua_dblibopen(L); start_trace(stderr); - rc=lua_dofile(0); + rc=lua_dofile(L,0); stop_trace(); return rc; } diff --git a/include/Makefile b/include/Makefile index 48f12a799e..0a2dfd95b7 100644 --- a/include/Makefile +++ b/include/Makefile @@ -1,4 +1,4 @@ -# makefile for lua distribution (includes) +# makefile for Lua distribution (includes) LUA= .. diff --git a/include/lauxlib.h b/include/lauxlib.h index 28a4664798..9df0c8e8b4 100644 --- a/include/lauxlib.h +++ b/include/lauxlib.h @@ -1,53 +1,100 @@ /* -** $Id: lauxlib.h,v 1.12 1999/03/10 14:19:41 roberto Exp $ +** $Id: lauxlib.h,v 1.30 2000/10/30 12:38:50 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ -#ifndef auxlib_h -#define auxlib_h +#ifndef lauxlib_h +#define lauxlib_h +#include +#include + #include "lua.h" +#ifndef LUALIB_API +#define LUALIB_API extern +#endif + + struct luaL_reg { - char *name; + const char *name; lua_CFunction func; }; -#define luaL_arg_check(cond,numarg,extramsg) if (!(cond)) \ - luaL_argerror(numarg,extramsg) - -void luaL_openlib (struct luaL_reg *l, int n); -void luaL_argerror (int numarg, char *extramsg); -#define luaL_check_string(n) (luaL_check_lstr((n), NULL)) -char *luaL_check_lstr (int numArg, long *len); -#define luaL_opt_string(n, d) (luaL_opt_lstr((n), (d), NULL)) -char *luaL_opt_lstr (int numArg, char *def, long *len); -double luaL_check_number (int numArg); -#define luaL_check_int(n) ((int)luaL_check_number(n)) -#define luaL_check_long(n) ((long)luaL_check_number(n)) -double luaL_opt_number (int numArg, double def); -#define luaL_opt_int(n,d) ((int)luaL_opt_number(n,d)) -#define luaL_opt_long(n,d) ((long)luaL_opt_number(n,d)) -lua_Object luaL_functionarg (int arg); -lua_Object luaL_tablearg (int arg); -lua_Object luaL_nonnullarg (int numArg); -void luaL_verror (char *fmt, ...); -char *luaL_openspace (int size); -void luaL_resetbuffer (void); -void luaL_addchar (int c); -int luaL_getsize (void); -void luaL_addsize (int n); -int luaL_newbuffer (int size); -void luaL_oldbuffer (int old); -char *luaL_buffer (void); -int luaL_findstring (char *name, char *list[]); -void luaL_chunkid (char *out, char *source, int len); -void luaL_filesource (char *out, char *filename, int len); +LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n); +LUALIB_API void luaL_argerror (lua_State *L, int numarg, const char *extramsg); +LUALIB_API const char *luaL_check_lstr (lua_State *L, int numArg, size_t *len); +LUALIB_API const char *luaL_opt_lstr (lua_State *L, int numArg, const char *def, size_t *len); +LUALIB_API double luaL_check_number (lua_State *L, int numArg); +LUALIB_API double luaL_opt_number (lua_State *L, int numArg, double def); + +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg); +LUALIB_API void luaL_checktype (lua_State *L, int narg, int t); +LUALIB_API void luaL_checkany (lua_State *L, int narg); + +LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...); +LUALIB_API int luaL_findstring (const char *name, const char *const list[]); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define luaL_arg_check(L, cond,numarg,extramsg) if (!(cond)) \ + luaL_argerror(L, numarg,extramsg) +#define luaL_check_string(L,n) (luaL_check_lstr(L, (n), NULL)) +#define luaL_opt_string(L,n,d) (luaL_opt_lstr(L, (n), (d), NULL)) +#define luaL_check_int(L,n) ((int)luaL_check_number(L, n)) +#define luaL_check_long(L,n) ((long)luaL_check_number(L, n)) +#define luaL_opt_int(L,n,d) ((int)luaL_opt_number(L, n,d)) +#define luaL_opt_long(L,n,d) ((long)luaL_opt_number(L, n,d)) +#define luaL_openl(L,a) luaL_openlib(L, a, (sizeof(a)/sizeof(a[0]))) + + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + +#ifndef LUAL_BUFFERSIZE +#define LUAL_BUFFERSIZE BUFSIZ +#endif + + +typedef struct luaL_Buffer { + char *p; /* current position in buffer */ + int level; + lua_State *L; + char buffer[LUAL_BUFFERSIZE]; +} luaL_Buffer; + +#define luaL_putchar(B,c) \ + ((void)((B)->p < &(B)->buffer[LUAL_BUFFERSIZE] || luaL_prepbuffer(B)), \ + (*(B)->p++ = (char)(c))) + +#define luaL_addsize(B,n) ((B)->p += (n)) + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B); +LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B); +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s); +LUALIB_API void luaL_addvalue (luaL_Buffer *B); +LUALIB_API void luaL_pushresult (luaL_Buffer *B); + + +/* }====================================================== */ #endif + + diff --git a/include/lua.h b/include/lua.h index 03ebe7d036..1b2715341b 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.32b 1999/05/11 20:29:19 roberto Exp $ +** $Id: lua.h,v 1.79 2000/10/31 12:44:07 roberto Exp $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -11,154 +11,208 @@ #ifndef lua_h #define lua_h -#define LUA_VERSION "Lua 3.2.2" -#define LUA_COPYRIGHT "Copyright (C) 1994-1999 TeCGraf, PUC-Rio" + +/* definition of `size_t' */ +#include + + +/* mark for all API functions */ +#ifndef LUA_API +#define LUA_API extern +#endif + + +#define LUA_VERSION "Lua 4.0" +#define LUA_COPYRIGHT "Copyright (C) 1994-2000 TeCGraf, PUC-Rio" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" -#define LUA_NOOBJECT 0 +/* name of global variable with error handler */ +#define LUA_ERRORMESSAGE "_ERRORMESSAGE" -#define LUA_ANYTAG (-1) -typedef struct lua_State lua_State; -extern lua_State *lua_state; +/* pre-defined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) +#define LUA_REFREGISTRY 0 + +/* pre-defined tags */ +#define LUA_ANYTAG (-1) +#define LUA_NOTAG (-2) -typedef void (*lua_CFunction) (void); -typedef unsigned int lua_Object; -void lua_open (void); -void lua_close (void); -lua_State *lua_setstate (lua_State *st); +/* option for multiple returns in lua_call */ +#define LUA_MULTRET (-1) -lua_Object lua_settagmethod (int tag, char *event); /* In: new method */ -lua_Object lua_gettagmethod (int tag, char *event); -int lua_newtag (void); -int lua_copytagmethods (int tagto, int tagfrom); -void lua_settag (int tag); /* In: object */ +/* minimum stack available for a C function */ +#define LUA_MINSTACK 20 -void lua_error (char *s); -int lua_dofile (char *filename); /* Out: returns */ -int lua_dostring (char *string); /* Out: returns */ -int lua_dobuffer (char *buff, int size, char *name); - /* Out: returns */ -int lua_callfunction (lua_Object f); - /* In: parameters; Out: returns */ -void lua_beginblock (void); -void lua_endblock (void); +/* error codes for lua_do* */ +#define LUA_ERRRUN 1 +#define LUA_ERRFILE 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 -lua_Object lua_lua2C (int number); -#define lua_getparam(_) lua_lua2C(_) -#define lua_getresult(_) lua_lua2C(_) -int lua_isnil (lua_Object object); -int lua_istable (lua_Object object); -int lua_isuserdata (lua_Object object); -int lua_iscfunction (lua_Object object); -int lua_isnumber (lua_Object object); -int lua_isstring (lua_Object object); -int lua_isfunction (lua_Object object); +typedef struct lua_State lua_State; + +typedef int (*lua_CFunction) (lua_State *L); -double lua_getnumber (lua_Object object); -char *lua_getstring (lua_Object object); -long lua_strlen (lua_Object object); -lua_CFunction lua_getcfunction (lua_Object object); -void *lua_getuserdata (lua_Object object); +/* +** types returned by `lua_type' +*/ +#define LUA_TNONE (-1) +#define LUA_TUSERDATA 0 +#define LUA_TNIL 1 +#define LUA_TNUMBER 2 +#define LUA_TSTRING 3 +#define LUA_TTABLE 4 +#define LUA_TFUNCTION 5 -void lua_pushnil (void); -void lua_pushnumber (double n); -void lua_pushlstring (char *s, long len); -void lua_pushstring (char *s); -void lua_pushcclosure (lua_CFunction fn, int n); -void lua_pushusertag (void *u, int tag); -void lua_pushobject (lua_Object object); -lua_Object lua_pop (void); -lua_Object lua_getglobal (char *name); -lua_Object lua_rawgetglobal (char *name); -void lua_setglobal (char *name); /* In: value */ -void lua_rawsetglobal (char *name); /* In: value */ +/* +** state manipulation +*/ +LUA_API lua_State *lua_open (int stacksize); +LUA_API void lua_close (lua_State *L); -void lua_settable (void); /* In: table, index, value */ -void lua_rawsettable (void); /* In: table, index, value */ -lua_Object lua_gettable (void); /* In: table, index */ -lua_Object lua_rawgettable (void); /* In: table, index */ -int lua_tag (lua_Object object); +/* +** basic stack manipulation +*/ +LUA_API int lua_gettop (lua_State *L); +LUA_API void lua_settop (lua_State *L, int index); +LUA_API void lua_pushvalue (lua_State *L, int index); +LUA_API void lua_remove (lua_State *L, int index); +LUA_API void lua_insert (lua_State *L, int index); +LUA_API int lua_stackspace (lua_State *L); -char *lua_nextvar (char *varname); /* Out: value */ -int lua_next (lua_Object o, int i); - /* Out: ref, value */ -int lua_ref (int lock); /* In: value */ -lua_Object lua_getref (int ref); -void lua_unref (int ref); +/* +** access functions (stack -> C) +*/ -lua_Object lua_createtable (void); +LUA_API int lua_type (lua_State *L, int index); +LUA_API const char *lua_typename (lua_State *L, int t); +LUA_API int lua_isnumber (lua_State *L, int index); +LUA_API int lua_isstring (lua_State *L, int index); +LUA_API int lua_iscfunction (lua_State *L, int index); +LUA_API int lua_tag (lua_State *L, int index); -long lua_collectgarbage (long limit); +LUA_API int lua_equal (lua_State *L, int index1, int index2); +LUA_API int lua_lessthan (lua_State *L, int index1, int index2); +LUA_API double lua_tonumber (lua_State *L, int index); +LUA_API const char *lua_tostring (lua_State *L, int index); +LUA_API size_t lua_strlen (lua_State *L, int index); +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index); +LUA_API void *lua_touserdata (lua_State *L, int index); +LUA_API const void *lua_topointer (lua_State *L, int index); -/* =============================================================== */ -/* some useful macros/functions */ -#define lua_call(name) lua_callfunction(lua_getglobal(name)) +/* +** push functions (C -> stack) +*/ +LUA_API void lua_pushnil (lua_State *L); +LUA_API void lua_pushnumber (lua_State *L, double n); +LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len); +LUA_API void lua_pushstring (lua_State *L, const char *s); +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); +LUA_API void lua_pushusertag (lua_State *L, void *u, int tag); -#define lua_pushref(ref) lua_pushobject(lua_getref(ref)) -#define lua_refobject(o,l) (lua_pushobject(o), lua_ref(l)) +/* +** get functions (Lua -> stack) +*/ +LUA_API void lua_getglobal (lua_State *L, const char *name); +LUA_API void lua_gettable (lua_State *L, int index); +LUA_API void lua_rawget (lua_State *L, int index); +LUA_API void lua_rawgeti (lua_State *L, int index, int n); +LUA_API void lua_getglobals (lua_State *L); +LUA_API void lua_gettagmethod (lua_State *L, int tag, const char *event); +LUA_API int lua_getref (lua_State *L, int ref); +LUA_API void lua_newtable (lua_State *L); -#define lua_register(n,f) (lua_pushcfunction(f), lua_setglobal(n)) -#define lua_pushuserdata(u) lua_pushusertag(u, 0) +/* +** set functions (stack -> Lua) +*/ +LUA_API void lua_setglobal (lua_State *L, const char *name); +LUA_API void lua_settable (lua_State *L, int index); +LUA_API void lua_rawset (lua_State *L, int index); +LUA_API void lua_rawseti (lua_State *L, int index, int n); +LUA_API void lua_setglobals (lua_State *L); +LUA_API void lua_settagmethod (lua_State *L, int tag, const char *event); +LUA_API int lua_ref (lua_State *L, int lock); -#define lua_pushcfunction(f) lua_pushcclosure(f, 0) -#define lua_clonetag(t) lua_copytagmethods(lua_newtag(), (t)) +/* +** "do" functions (run Lua code) +*/ +LUA_API int lua_call (lua_State *L, int nargs, int nresults); +LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults); +LUA_API int lua_dofile (lua_State *L, const char *filename); +LUA_API int lua_dostring (lua_State *L, const char *str); +LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name); -lua_Object lua_seterrormethod (void); /* In: new method */ +/* +** Garbage-collection functions +*/ +LUA_API int lua_getgcthreshold (lua_State *L); +LUA_API int lua_getgccount (lua_State *L); +LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold); -/* ========================================================================== -** for compatibility with old versions. Avoid using these macros/functions -** If your program does need any of these, define LUA_COMPAT2_5 +/* +** miscellaneous functions */ +LUA_API int lua_newtag (lua_State *L); +LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom); +LUA_API void lua_settag (lua_State *L, int tag); +LUA_API void lua_error (lua_State *L, const char *s); -#ifdef LUA_COMPAT2_5 +LUA_API void lua_unref (lua_State *L, int ref); +LUA_API int lua_next (lua_State *L, int index); +LUA_API int lua_getn (lua_State *L, int index); -lua_Object lua_setfallback (char *event, lua_CFunction fallback); +LUA_API void lua_concat (lua_State *L, int n); -#define lua_storeglobal lua_setglobal -#define lua_type lua_tag +LUA_API void *lua_newuserdata (lua_State *L, size_t size); -#define lua_lockobject(o) lua_refobject(o,1) -#define lua_lock() lua_ref(1) -#define lua_getlocked lua_getref -#define lua_pushlocked lua_pushref -#define lua_unlock lua_unref -#define lua_pushliteral(o) lua_pushstring(o) +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ -#define lua_getindexed(o,n) (lua_pushobject(o), lua_pushnumber(n), lua_gettable()) -#define lua_getfield(o,f) (lua_pushobject(o), lua_pushstring(f), lua_gettable()) +#define lua_pop(L,n) lua_settop(L, -(n)-1) -#define lua_copystring(o) (strdup(lua_getstring(o))) +#define lua_register(L,n,f) (lua_pushcfunction(L, f), lua_setglobal(L, n)) +#define lua_pushuserdata(L,u) lua_pushusertag(L, u, 0) +#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) +#define lua_clonetag(L,t) lua_copytagmethods(L, lua_newtag(L), (t)) -#define lua_getsubscript lua_gettable -#define lua_storesubscript lua_settable +#define lua_isfunction(L,n) (lua_type(L,n) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L,n) == LUA_TTABLE) +#define lua_isuserdata(L,n) (lua_type(L,n) == LUA_TUSERDATA) +#define lua_isnil(L,n) (lua_type(L,n) == LUA_TNIL) +#define lua_isnull(L,n) (lua_type(L,n) == LUA_TNONE) -#endif +#define lua_getregistry(L) lua_getref(L, LUA_REFREGISTRY) #endif /****************************************************************************** -* Copyright (c) 1994-1999 TeCGraf, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2000 TeCGraf, PUC-Rio. All rights reserved. * * Permission is hereby granted, without written agreement and without license * or royalty fees, to use, copy, modify, and distribute this software and its @@ -191,3 +245,4 @@ lua_Object lua_setfallback (char *event, lua_CFunction fallback); * * This implementation contains no third-party code. ******************************************************************************/ + diff --git a/include/luadebug.h b/include/luadebug.h index 1dc9f206ea..77753d3712 100644 --- a/include/luadebug.h +++ b/include/luadebug.h @@ -1,5 +1,5 @@ /* -** $Id: luadebug.h,v 1.6 1999/03/04 21:17:26 roberto Exp $ +** $Id: luadebug.h,v 1.17 2000/10/30 12:38:50 roberto Exp $ ** Debugging API ** See Copyright Notice in lua.h */ @@ -11,24 +11,36 @@ #include "lua.h" -typedef lua_Object lua_Function; +typedef struct lua_Debug lua_Debug; /* activation record */ +typedef struct lua_Localvar lua_Localvar; -typedef void (*lua_LHFunction) (int line); -typedef void (*lua_CHFunction) (lua_Function func, char *file, int line); +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); -lua_Function lua_stackedfunction (int level); -void lua_funcinfo (lua_Object func, char **source, int *linedefined); -int lua_currentline (lua_Function func); -char *lua_getobjname (lua_Object o, char **name); -lua_Object lua_getlocal (lua_Function func, int local_number, char **name); -int lua_setlocal (lua_Function func, int local_number); +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); -int lua_nups (lua_Function func); +LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func); +LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func); -lua_LHFunction lua_setlinehook (lua_LHFunction func); -lua_CHFunction lua_setcallhook (lua_CHFunction func); -int lua_setdebug (int debug); + +#define LUA_IDSIZE 60 + +struct lua_Debug { + const char *event; /* `call', `return' */ + int currentline; /* (l) */ + const char *name; /* (n) */ + const char *namewhat; /* (n) `global', `tag method', `local', `field' */ + int nups; /* (u) number of upvalues */ + int linedefined; /* (S) */ + const char *what; /* (S) `Lua' function, `C' function, Lua `main' */ + const char *source; /* (S) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + struct lua_TObject *_func; /* active function */ +}; #endif diff --git a/include/lualib.h b/include/lualib.h index c7187868d3..fe48cb1012 100644 --- a/include/lualib.h +++ b/include/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.6 1999/05/05 19:23:11 roberto Exp $ +** $Id: lualib.h,v 1.14 2000/10/27 16:15:53 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -10,27 +10,25 @@ #include "lua.h" -void lua_iolibopen (void); -void lua_strlibopen (void); -void lua_mathlibopen (void); -void lua_dblibopen (void); - -void lua_userinit (void); +#ifndef LUALIB_API +#define LUALIB_API extern +#endif -/* To keep compatibility with old versions */ +#define LUA_ALERT "_ALERT" -#define iolib_open lua_iolibopen -#define strlib_open lua_strlibopen -#define mathlib_open lua_mathlibopen +LUALIB_API void lua_baselibopen (lua_State *L); +LUALIB_API void lua_iolibopen (lua_State *L); +LUALIB_API void lua_strlibopen (lua_State *L); +LUALIB_API void lua_mathlibopen (lua_State *L); +LUALIB_API void lua_dblibopen (lua_State *L); /* Auxiliary functions (private) */ -char *luaI_classend (char *p); -int luaI_singlematch (int c, char *p, char *ep); +const char *luaI_classend (lua_State *L, const char *p); +int luaI_singlematch (int c, const char *p, const char *ep); #endif - diff --git a/src/Makefile b/src/Makefile index 7d01a92412..66e0ea8d9e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -# makefile for lua basic library +# makefile for Lua core library LUA= .. @@ -6,9 +6,8 @@ include $(LUA)/config OBJS= \ lapi.o \ - lauxlib.o \ - lbuffer.o \ - lbuiltin.o \ + lcode.o \ + ldebug.o \ ldo.o \ lfunc.o \ lgc.o \ @@ -19,6 +18,7 @@ OBJS= \ lstate.o \ lstring.o \ ltable.o \ + ltests.o \ ltm.o \ lundump.o \ lvm.o \ @@ -26,9 +26,8 @@ OBJS= \ SRCS= \ lapi.c \ - lauxlib.c \ - lbuffer.c \ - lbuiltin.c \ + lcode.c \ + ldebug.c \ ldo.c \ lfunc.c \ lgc.c \ @@ -39,16 +38,19 @@ SRCS= \ lstate.c \ lstring.c \ ltable.c \ + ltests.c \ ltm.c \ lundump.c \ lvm.c \ lzio.c \ lapi.h \ - lbuiltin.h \ + lcode.h \ + ldebug.h \ ldo.h \ lfunc.h \ lgc.h \ llex.h \ + llimits.h \ lmem.h \ lobject.h \ lopcodes.h \ diff --git a/src/lapi.c b/src/lapi.c index 16bd9ff936..e80023428e 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,15 +1,15 @@ /* -** $Id: lapi.c,v 1.47b 1999/06/22 20:37:23 roberto Exp $ +** $Id: lapi.c,v 1.110 2000/10/30 12:50:09 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ -#include #include +#include "lua.h" + #include "lapi.h" -#include "lauxlib.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" @@ -19,676 +19,476 @@ #include "lstring.h" #include "ltable.h" #include "ltm.h" -#include "lua.h" -#include "luadebug.h" #include "lvm.h" -char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" - "$Authors: " LUA_AUTHORS " $"; - - - -TObject *luaA_Address (lua_Object o) { - return (o != LUA_NOOBJECT) ? Address(o) : NULL; -} - - -static lua_Type normalized_type (TObject *o) -{ - int t = ttype(o); - switch (t) { - case LUA_T_PMARK: - return LUA_T_PROTO; - case LUA_T_CMARK: - return LUA_T_CPROTO; - case LUA_T_CLMARK: - return LUA_T_CLOSURE; - default: - return t; - } -} +const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" + "$Authors: " LUA_AUTHORS " $"; -static void set_normalized (TObject *d, TObject *s) -{ - d->value = s->value; - d->ttype = normalized_type(s); -} +#define Index(L,i) ((i) >= 0 ? (L->Cbase+((i)-1)) : (L->top+(i))) -static TObject *luaA_protovalue (TObject *o) -{ - return (normalized_type(o) == LUA_T_CLOSURE) ? protovalue(o) : o; -} +#define api_incr_top(L) incr_top -void luaA_packresults (void) -{ - luaV_pack(L->Cstack.lua2C, L->Cstack.num, L->stack.top); - incr_top; -} -int luaA_passresults (void) { - L->Cstack.base = L->Cstack.lua2C; /* position of first result */ - return L->Cstack.num; +TObject *luaA_index (lua_State *L, int index) { + return Index(L, index); } -static void checkCparams (int nParams) -{ - if (L->stack.top-L->stack.stack < L->Cstack.base+nParams) - lua_error("API error - wrong number of arguments in C2lua stack"); -} - - -static lua_Object put_luaObject (TObject *o) { - luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); - L->stack.stack[L->Cstack.base++] = *o; - return L->Cstack.base; /* this is +1 real position (see Ref) */ +static TObject *luaA_indexAcceptable (lua_State *L, int index) { + if (index >= 0) { + TObject *o = L->Cbase+(index-1); + if (o >= L->top) return NULL; + else return o; + } + else return L->top+index; } -static lua_Object put_luaObjectonTop (void) { - luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); - L->stack.stack[L->Cstack.base++] = *(--L->stack.top); - return L->Cstack.base; /* this is +1 real position (see Ref) */ +void luaA_pushobject (lua_State *L, const TObject *o) { + *L->top = *o; + incr_top; } - -static void top2LC (int n) { - /* Put the 'n' elements on the top as the Lua2C contents */ - L->Cstack.base = (L->stack.top-L->stack.stack); /* new base */ - L->Cstack.lua2C = L->Cstack.base-n; /* position of the new results */ - L->Cstack.num = n; /* number of results */ +LUA_API int lua_stackspace (lua_State *L) { + return (L->stack_last - L->top); } -lua_Object lua_pop (void) { - checkCparams(1); - return put_luaObjectonTop(); -} - /* -** Get a parameter, returning the object handle or LUA_NOOBJECT on error. -** 'number' must be 1 to get the first parameter. +** basic stack manipulation */ -lua_Object lua_lua2C (int number) -{ - if (number <= 0 || number > L->Cstack.num) return LUA_NOOBJECT; - /* Ref(L->stack.stack+(L->Cstack.lua2C+number-1)) == - L->stack.stack+(L->Cstack.lua2C+number-1)-L->stack.stack+1 == */ - return L->Cstack.lua2C+number; -} -int lua_callfunction (lua_Object function) -{ - if (function == LUA_NOOBJECT) - return 1; - else { - luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); - set_normalized(L->stack.stack+L->Cstack.base, Address(function)); - return luaD_protectedrun(); - } +LUA_API int lua_gettop (lua_State *L) { + return (L->top - L->Cbase); } -lua_Object lua_gettagmethod (int tag, char *event) -{ - return put_luaObject(luaT_gettagmethod(tag, event)); +LUA_API void lua_settop (lua_State *L, int index) { + if (index >= 0) + luaD_adjusttop(L, L->Cbase, index); + else + L->top = L->top+index+1; /* index is negative */ } -lua_Object lua_settagmethod (int tag, char *event) -{ - checkCparams(1); - luaT_settagmethod(tag, event, L->stack.top-1); - return put_luaObjectonTop(); +LUA_API void lua_remove (lua_State *L, int index) { + StkId p = luaA_index(L, index); + while (++p < L->top) *(p-1) = *p; + L->top--; } -lua_Object lua_seterrormethod (void) { - lua_Object temp; - checkCparams(1); - temp = lua_getglobal("_ERRORMESSAGE"); - lua_setglobal("_ERRORMESSAGE"); - return temp; +LUA_API void lua_insert (lua_State *L, int index) { + StkId p = luaA_index(L, index); + StkId q; + for (q = L->top; q>p; q--) + *q = *(q-1); + *p = *L->top; } -lua_Object lua_gettable (void) -{ - checkCparams(2); - luaV_gettable(); - return put_luaObjectonTop(); +LUA_API void lua_pushvalue (lua_State *L, int index) { + *L->top = *luaA_index(L, index); + api_incr_top(L); } -lua_Object lua_rawgettable (void) { - checkCparams(2); - if (ttype(L->stack.top-2) != LUA_T_ARRAY) - lua_error("indexed expression not a table in rawgettable"); - *(L->stack.top-2) = *luaH_get(avalue(L->stack.top-2), L->stack.top-1); - --L->stack.top; - return put_luaObjectonTop(); -} - -void lua_settable (void) { - checkCparams(3); - luaD_checkstack(3); /* may need that to call T.M. */ - luaV_settable(L->stack.top-3); - L->stack.top -= 2; /* pop table and index */ -} +/* +** access functions (stack -> C) +*/ -void lua_rawsettable (void) { - checkCparams(3); - luaV_rawsettable(L->stack.top-3); +LUA_API int lua_type (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL) ? LUA_TNONE : ttype(o); } - -lua_Object lua_createtable (void) -{ - TObject o; - luaC_checkGC(); - avalue(&o) = luaH_new(0); - ttype(&o) = LUA_T_ARRAY; - return put_luaObject(&o); +LUA_API const char *lua_typename (lua_State *L, int t) { + UNUSED(L); + return (t == LUA_TNONE) ? "no value" : luaO_typenames[t]; } -lua_Object lua_getglobal (char *name) -{ - luaD_checkstack(2); /* may need that to call T.M. */ - luaV_getglobal(luaS_new(name)); - return put_luaObjectonTop(); +LUA_API int lua_iscfunction (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL) ? 0 : iscfunction(o); } +LUA_API int lua_isnumber (lua_State *L, int index) { + TObject *o = luaA_indexAcceptable(L, index); + return (o == NULL) ? 0 : (tonumber(o) == 0); +} -lua_Object lua_rawgetglobal (char *name) -{ - TaggedString *ts = luaS_new(name); - return put_luaObject(&ts->u.s.globalval); +LUA_API int lua_isstring (lua_State *L, int index) { + int t = lua_type(L, index); + return (t == LUA_TSTRING || t == LUA_TNUMBER); } -void lua_setglobal (char *name) -{ - checkCparams(1); - luaD_checkstack(2); /* may need that to call T.M. */ - luaV_setglobal(luaS_new(name)); +LUA_API int lua_tag (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL) ? LUA_NOTAG : luaT_tag(o); } +LUA_API int lua_equal (lua_State *L, int index1, int index2) { + StkId o1 = luaA_indexAcceptable(L, index1); + StkId o2 = luaA_indexAcceptable(L, index2); + if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */ + else return luaO_equalObj(o1, o2); +} -void lua_rawsetglobal (char *name) -{ - TaggedString *ts = luaS_new(name); - checkCparams(1); - luaS_rawsetglobal(ts, --L->stack.top); +LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { + StkId o1 = luaA_indexAcceptable(L, index1); + StkId o2 = luaA_indexAcceptable(L, index2); + if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */ + else return luaV_lessthan(L, o1, o2, L->top); } -int lua_isnil (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_NIL); +LUA_API double lua_tonumber (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL || tonumber(o)) ? 0 : nvalue(o); } -int lua_istable (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_ARRAY); +LUA_API const char *lua_tostring (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL || tostring(L, o)) ? NULL : svalue(o); } -int lua_isuserdata (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_USERDATA); +LUA_API size_t lua_strlen (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL || tostring(L, o)) ? 0 : tsvalue(o)->len; } -int lua_iscfunction (lua_Object o) -{ - return (lua_tag(o) == LUA_T_CPROTO); +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->f.c; } -int lua_isnumber (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (tonumber(Address(o)) == 0); +LUA_API void *lua_touserdata (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL || ttype(o) != LUA_TUSERDATA) ? NULL : + tsvalue(o)->u.d.value; } -int lua_isstring (lua_Object o) -{ - int t = lua_tag(o); - return (t == LUA_T_STRING) || (t == LUA_T_NUMBER); +LUA_API const void *lua_topointer (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + if (o == NULL) return NULL; + switch (ttype(o)) { + case LUA_TTABLE: + return hvalue(o); + case LUA_TFUNCTION: + return clvalue(o); + default: return NULL; + } } -int lua_isfunction (lua_Object o) -{ - int t = lua_tag(o); - return (t == LUA_T_PROTO) || (t == LUA_T_CPROTO); -} -double lua_getnumber (lua_Object object) -{ - if (object == LUA_NOOBJECT) return 0.0; - if (tonumber(Address(object))) return 0.0; - else return (nvalue(Address(object))); -} +/* +** push functions (C -> stack) +*/ -char *lua_getstring (lua_Object object) -{ - luaC_checkGC(); /* "tostring" may create a new string */ - if (object == LUA_NOOBJECT || tostring(Address(object))) - return NULL; - else return (svalue(Address(object))); -} -long lua_strlen (lua_Object object) -{ - luaC_checkGC(); /* "tostring" may create a new string */ - if (object == LUA_NOOBJECT || tostring(Address(object))) - return 0L; - else return (tsvalue(Address(object))->u.s.len); +LUA_API void lua_pushnil (lua_State *L) { + ttype(L->top) = LUA_TNIL; + api_incr_top(L); } -void *lua_getuserdata (lua_Object object) -{ - if (object == LUA_NOOBJECT || ttype(Address(object)) != LUA_T_USERDATA) - return NULL; - else return tsvalue(Address(object))->u.d.v; -} -lua_CFunction lua_getcfunction (lua_Object object) -{ - if (!lua_iscfunction(object)) - return NULL; - else return fvalue(luaA_protovalue(Address(object))); +LUA_API void lua_pushnumber (lua_State *L, double n) { + nvalue(L->top) = n; + ttype(L->top) = LUA_TNUMBER; + api_incr_top(L); } -void lua_pushnil (void) -{ - ttype(L->stack.top) = LUA_T_NIL; - incr_top; +LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { + tsvalue(L->top) = luaS_newlstr(L, s, len); + ttype(L->top) = LUA_TSTRING; + api_incr_top(L); } -void lua_pushnumber (double n) -{ - ttype(L->stack.top) = LUA_T_NUMBER; - nvalue(L->stack.top) = n; - incr_top; -} -void lua_pushlstring (char *s, long len) -{ - tsvalue(L->stack.top) = luaS_newlstr(s, len); - ttype(L->stack.top) = LUA_T_STRING; - incr_top; - luaC_checkGC(); -} - -void lua_pushstring (char *s) -{ +LUA_API void lua_pushstring (lua_State *L, const char *s) { if (s == NULL) - lua_pushnil(); + lua_pushnil(L); else - lua_pushlstring(s, strlen(s)); + lua_pushlstring(L, s, strlen(s)); } -void lua_pushcclosure (lua_CFunction fn, int n) -{ - if (fn == NULL) - lua_error("API error - attempt to push a NULL Cfunction"); - checkCparams(n); - ttype(L->stack.top) = LUA_T_CPROTO; - fvalue(L->stack.top) = fn; - incr_top; - luaV_closure(n); - luaC_checkGC(); -} -void lua_pushusertag (void *u, int tag) -{ - if (tag < 0 && tag != LUA_ANYTAG) - luaT_realtag(tag); /* error if tag is not valid */ - tsvalue(L->stack.top) = luaS_createudata(u, tag); - ttype(L->stack.top) = LUA_T_USERDATA; - incr_top; - luaC_checkGC(); +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + luaV_Cclosure(L, fn, n); } -void luaA_pushobject (TObject *o) -{ - *L->stack.top = *o; - incr_top; -} -void lua_pushobject (lua_Object o) { - if (o == LUA_NOOBJECT) - lua_error("API error - attempt to push a NOOBJECT"); - set_normalized(L->stack.top, Address(o)); - incr_top; +LUA_API void lua_pushusertag (lua_State *L, void *u, int tag) { + /* ORDER LUA_T */ + if (!(tag == LUA_ANYTAG || tag == LUA_TUSERDATA || validtag(tag))) + luaO_verror(L, "invalid tag for a userdata (%d)", tag); + tsvalue(L->top) = luaS_createudata(L, u, tag); + ttype(L->top) = LUA_TUSERDATA; + api_incr_top(L); } -int lua_tag (lua_Object lo) -{ - if (lo == LUA_NOOBJECT) - return LUA_T_NIL; - else { - TObject *o = Address(lo); - int t; - switch (t = ttype(o)) { - case LUA_T_USERDATA: - return o->value.ts->u.d.tag; - case LUA_T_ARRAY: - return o->value.a->htag; - case LUA_T_PMARK: - return LUA_T_PROTO; - case LUA_T_CMARK: - return LUA_T_CPROTO; - case LUA_T_CLOSURE: case LUA_T_CLMARK: - return o->value.cl->consts[0].ttype; -#ifdef DEBUG - case LUA_T_LINE: - LUA_INTERNALERROR("invalid type"); -#endif - default: - return t; - } - } -} - -void lua_settag (int tag) -{ - checkCparams(1); - luaT_realtag(tag); - switch (ttype(L->stack.top-1)) { - case LUA_T_ARRAY: - (L->stack.top-1)->value.a->htag = tag; - break; - case LUA_T_USERDATA: - (L->stack.top-1)->value.ts->u.d.tag = tag; - break; - default: - luaL_verror("cannot change the tag of a %.20s", - luaO_typename(L->stack.top-1)); - } - L->stack.top--; -} +/* +** get functions (Lua -> stack) +*/ -TaggedString *luaA_nextvar (TaggedString *g) { - if (g == NULL) - g = (TaggedString *)L->rootglobal.next; /* first variable */ - else { - /* check whether name is in global var list */ - luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected"); - g = (TaggedString *)g->head.next; /* get next */ - } - while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ - g = (TaggedString *)g->head.next; - if (g) { - ttype(L->stack.top) = LUA_T_STRING; tsvalue(L->stack.top) = g; - incr_top; - luaA_pushobject(&g->u.s.globalval); - } - return g; +LUA_API void lua_getglobal (lua_State *L, const char *name) { + StkId top = L->top; + *top = *luaV_getglobal(L, luaS_new(L, name)); + L->top = top; + api_incr_top(L); } -char *lua_nextvar (char *varname) { - TaggedString *g = (varname == NULL) ? NULL : luaS_new(varname); - g = luaA_nextvar(g); - if (g) { - top2LC(2); - return g->str; - } - else { - top2LC(0); - return NULL; - } +LUA_API void lua_gettable (lua_State *L, int index) { + StkId t = Index(L, index); + StkId top = L->top; + *(top-1) = *luaV_gettable(L, t); + L->top = top; /* tag method may change top */ } -int luaA_next (Hash *t, int i) { - int tsize = nhash(t); - for (; itop - 1) = *luaH_get(L, hvalue(t), L->top - 1); } -int lua_next (lua_Object o, int i) { - TObject *t = Address(o); - if (ttype(t) != LUA_T_ARRAY) - lua_error("API error - object is not a table in `lua_next'"); - i = luaA_next(avalue(t), i); - top2LC((i==0) ? 0 : 2); - return i; +LUA_API void lua_rawgeti (lua_State *L, int index, int n) { + StkId o = Index(L, index); + LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected"); + *L->top = *luaH_getnum(hvalue(o), n); + api_incr_top(L); } - -/* -** {====================================================== -** To manipulate some state information -** ======================================================= -*/ - -lua_State *lua_setstate (lua_State *st) { - lua_State *old = lua_state; - lua_state = st; - return old; +LUA_API void lua_getglobals (lua_State *L) { + hvalue(L->top) = L->gt; + ttype(L->top) = LUA_TTABLE; + api_incr_top(L); } -lua_LHFunction lua_setlinehook (lua_LHFunction func) { - lua_LHFunction old = L->linehook; - L->linehook = func; - return old; -} -lua_CHFunction lua_setcallhook (lua_CHFunction func) { - lua_CHFunction old = L->callhook; - L->callhook = func; - return old; +LUA_API int lua_getref (lua_State *L, int ref) { + if (ref == LUA_REFNIL) + ttype(L->top) = LUA_TNIL; + else if (0 <= ref && ref < L->refSize && + (L->refArray[ref].st == LOCK || L->refArray[ref].st == HOLD)) + *L->top = L->refArray[ref].o; + else + return 0; + api_incr_top(L); + return 1; } -int lua_setdebug (int debug) { - int old = L->debug; - L->debug = debug; - return old; + +LUA_API void lua_newtable (lua_State *L) { + hvalue(L->top) = luaH_new(L, 0); + ttype(L->top) = LUA_TTABLE; + api_incr_top(L); } -/* }====================================================== */ /* -** {====================================================== -** Debug interface -** ======================================================= +** set functions (stack -> Lua) */ -lua_Function lua_stackedfunction (int level) -{ - StkId i; - for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--) { - int t = L->stack.stack[i].ttype; - if (t == LUA_T_CLMARK || t == LUA_T_PMARK || t == LUA_T_CMARK) - if (level-- == 0) - return Ref(L->stack.stack+i); - } - return LUA_NOOBJECT; +LUA_API void lua_setglobal (lua_State *L, const char *name) { + StkId top = L->top; + luaV_setglobal(L, luaS_new(L, name)); + L->top = top-1; /* remove element from the top */ } -int lua_nups (lua_Function func) { - TObject *o = luaA_Address(func); - return (!o || normalized_type(o) != LUA_T_CLOSURE) ? 0 : o->value.cl->nelems; +LUA_API void lua_settable (lua_State *L, int index) { + StkId t = Index(L, index); + StkId top = L->top; + luaV_settable(L, t, top-2); + L->top = top-2; /* pop index and value */ } -int lua_currentline (lua_Function func) -{ - TObject *f = Address(func); - return (f+1 < L->stack.top && (f+1)->ttype == LUA_T_LINE) ? - (f+1)->value.i : -1; +LUA_API void lua_rawset (lua_State *L, int index) { + StkId t = Index(L, index); + LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected"); + *luaH_set(L, hvalue(t), L->top-2) = *(L->top-1); + L->top -= 2; } -lua_Object lua_getlocal (lua_Function func, int local_number, char **name) { - /* check whether func is a Lua function */ - if (lua_tag(func) != LUA_T_PROTO) - return LUA_NOOBJECT; - else { - TObject *f = Address(func); - TProtoFunc *fp = luaA_protovalue(f)->value.tf; - *name = luaF_getlocalname(fp, local_number, lua_currentline(func)); - if (*name) { - /* if "*name", there must be a LUA_T_LINE */ - /* therefore, f+2 points to function base */ - return put_luaObject((f+2)+(local_number-1)); - } - else - return LUA_NOOBJECT; - } +LUA_API void lua_rawseti (lua_State *L, int index, int n) { + StkId o = Index(L, index); + LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected"); + *luaH_setint(L, hvalue(o), n) = *(L->top-1); + L->top--; } -int lua_setlocal (lua_Function func, int local_number) -{ - /* check whether func is a Lua function */ - if (lua_tag(func) != LUA_T_PROTO) - return 0; - else { - TObject *f = Address(func); - TProtoFunc *fp = luaA_protovalue(f)->value.tf; - char *name = luaF_getlocalname(fp, local_number, lua_currentline(func)); - checkCparams(1); - --L->stack.top; - if (name) { - /* if "name", there must be a LUA_T_LINE */ - /* therefore, f+2 points to function base */ - *((f+2)+(local_number-1)) = *L->stack.top; - return 1; - } - else - return 0; - } +LUA_API void lua_setglobals (lua_State *L) { + StkId newtable = --L->top; + LUA_ASSERT(ttype(newtable) == LUA_TTABLE, "table expected"); + L->gt = hvalue(newtable); } -void lua_funcinfo (lua_Object func, char **source, int *linedefined) { - if (!lua_isfunction(func)) - lua_error("API error - `funcinfo' called with a non-function value"); +LUA_API int lua_ref (lua_State *L, int lock) { + int ref; + if (ttype(L->top-1) == LUA_TNIL) + ref = LUA_REFNIL; else { - TObject *f = luaA_protovalue(Address(func)); - if (normalized_type(f) == LUA_T_PROTO) { - *source = tfvalue(f)->source->str; - *linedefined = tfvalue(f)->lineDefined; + if (L->refFree != NONEXT) { /* is there a free place? */ + ref = L->refFree; + L->refFree = L->refArray[ref].st; } - else { - *source = "(C)"; - *linedefined = -1; + else { /* no more free places */ + luaM_growvector(L, L->refArray, L->refSize, 1, struct Ref, + "reference table overflow", MAX_INT); + L->nblocks += sizeof(struct Ref); + ref = L->refSize++; } + L->refArray[ref].o = *(L->top-1); + L->refArray[ref].st = lock ? LOCK : HOLD; } + L->top--; + return ref; } -static int checkfunc (TObject *o) -{ - return luaO_equalObj(o, L->stack.top); -} - +/* +** "do" functions (run Lua code) +** (most of them are in ldo.c) +*/ -char *lua_getobjname (lua_Object o, char **name) -{ /* try to find a name for given function */ - set_normalized(L->stack.top, Address(o)); /* to be accessed by "checkfunc" */ - if ((*name = luaS_travsymbol(checkfunc)) != NULL) - return "global"; - else if ((*name = luaT_travtagmethods(checkfunc)) != NULL) - return "tag-method"; - else return ""; +LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults) { + luaD_call(L, L->top-(nargs+1), nresults); } -/* }====================================================== */ - /* -** {====================================================== -** BLOCK mechanism -** ======================================================= +** Garbage-collection functions */ +/* GC values are expressed in Kbytes: #bytes/2^10 */ +#define GCscale(x) ((int)((x)>>10)) +#define GCunscale(x) ((unsigned long)(x)<<10) -#ifndef MAX_C_BLOCKS -#define MAX_C_BLOCKS 1000 /* arbitrary limit */ -#endif - +LUA_API int lua_getgcthreshold (lua_State *L) { + return GCscale(L->GCthreshold); +} -void lua_beginblock (void) { - luaM_growvector(L->Cblocks, L->numCblocks, 1, struct C_Lua_Stack, - "too many nested blocks", MAX_C_BLOCKS); - L->Cblocks[L->numCblocks] = L->Cstack; - L->numCblocks++; +LUA_API int lua_getgccount (lua_State *L) { + return GCscale(L->nblocks); } -void lua_endblock (void) { - --L->numCblocks; - L->Cstack = L->Cblocks[L->numCblocks]; - luaD_adjusttop(L->Cstack.base); +LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { + if (newthreshold > GCscale(ULONG_MAX)) + L->GCthreshold = ULONG_MAX; + else + L->GCthreshold = GCunscale(newthreshold); + luaC_checkGC(L); } +/* +** miscellaneous functions +*/ -int lua_ref (int lock) { - int ref; - checkCparams(1); - ref = luaC_ref(L->stack.top-1, lock); - L->stack.top--; - return ref; +LUA_API void lua_settag (lua_State *L, int tag) { + luaT_realtag(L, tag); + switch (ttype(L->top-1)) { + case LUA_TTABLE: + hvalue(L->top-1)->htag = tag; + break; + case LUA_TUSERDATA: + tsvalue(L->top-1)->u.d.tag = tag; + break; + default: + luaO_verror(L, "cannot change the tag of a %.20s", + luaO_typename(L->top-1)); + } } - -lua_Object lua_getref (int ref) { - TObject *o = luaC_getref(ref); - return (o ? put_luaObject(o) : LUA_NOOBJECT); +LUA_API void lua_unref (lua_State *L, int ref) { + if (ref >= 0) { + LUA_ASSERT(ref < L->refSize && L->refArray[ref].st < 0, "invalid ref"); + L->refArray[ref].st = L->refFree; + L->refFree = ref; + } } -/* }====================================================== */ +LUA_API int lua_next (lua_State *L, int index) { + StkId t = luaA_index(L, index); + Node *n; + LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected"); + n = luaH_next(L, hvalue(t), luaA_index(L, -1)); + if (n) { + *(L->top-1) = *key(n); + *L->top = *val(n); + api_incr_top(L); + return 1; + } + else { /* no more elements */ + L->top -= 1; /* remove key */ + return 0; + } +} -#ifdef LUA_COMPAT2_5 -/* -** API: set a function as a fallback -*/ +LUA_API int lua_getn (lua_State *L, int index) { + Hash *h = hvalue(luaA_index(L, index)); + const TObject *value = luaH_getstr(h, luaS_new(L, "n")); /* value = h.n */ + if (ttype(value) == LUA_TNUMBER) + return (int)nvalue(value); + else { + Number max = 0; + int i = h->size; + Node *n = h->node; + while (i--) { + if (ttype(key(n)) == LUA_TNUMBER && + ttype(val(n)) != LUA_TNIL && + nvalue(key(n)) > max) + max = nvalue(key(n)); + n++; + } + return (int)max; + } +} + -static void do_unprotectedrun (lua_CFunction f, int nParams, int nResults) { - luaD_openstack(nParams); - (L->stack.top-nParams)->ttype = LUA_T_CPROTO; - (L->stack.top-nParams)->value.f = f; - luaD_calln(nParams, nResults); +LUA_API void lua_concat (lua_State *L, int n) { + StkId top = L->top; + luaV_strconc(L, n, top); + L->top = top-(n-1); + luaC_checkGC(L); } -lua_Object lua_setfallback (char *name, lua_CFunction fallback) { - lua_pushstring(name); - lua_pushcfunction(fallback); - do_unprotectedrun(luaT_setfallback, 2, 1); - return put_luaObjectonTop(); +LUA_API void *lua_newuserdata (lua_State *L, size_t size) { + TString *ts = luaS_newudata(L, size, NULL); + tsvalue(L->top) = ts; + ttype(L->top) = LUA_TUSERDATA; + api_incr_top(L); + return ts->u.d.value; } -#endif diff --git a/src/lapi.h b/src/lapi.h index 638a847fc7..5cefdc7aec 100644 --- a/src/lapi.h +++ b/src/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 1.4 1999/02/23 14:57:28 roberto Exp $ +** $Id: lapi.h,v 1.20 2000/08/31 14:08:27 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -8,15 +8,10 @@ #define lapi_h -#include "lua.h" #include "lobject.h" -TObject *luaA_Address (lua_Object o); -void luaA_pushobject (TObject *o); -void luaA_packresults (void); -int luaA_passresults (void); -TaggedString *luaA_nextvar (TaggedString *g); -int luaA_next (Hash *t, int i); +TObject *luaA_index (lua_State *L, int index); +void luaA_pushobject (lua_State *L, const TObject *o); #endif diff --git a/src/lauxlib.c b/src/lauxlib.c deleted file mode 100644 index db929c4f90..0000000000 --- a/src/lauxlib.c +++ /dev/null @@ -1,133 +0,0 @@ -/* -** $Id: lauxlib.c,v 1.17 1999/03/11 18:59:19 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - - -#include -#include -#include - -/* Please Notice: This file uses only the official API of Lua -** Any function declared here could be written as an application function. -** With care, these functions can be used by other libraries. -*/ - -#include "lauxlib.h" -#include "lua.h" -#include "luadebug.h" - - - -int luaL_findstring (char *name, char *list[]) { - int i; - for (i=0; list[i]; i++) - if (strcmp(list[i], name) == 0) - return i; - return -1; /* name not found */ -} - -void luaL_argerror (int numarg, char *extramsg) { - lua_Function f = lua_stackedfunction(0); - char *funcname; - lua_getobjname(f, &funcname); - numarg -= lua_nups(f); - if (funcname == NULL) - funcname = "?"; - if (extramsg == NULL) - luaL_verror("bad argument #%d to function `%.50s'", numarg, funcname); - else - luaL_verror("bad argument #%d to function `%.50s' (%.100s)", - numarg, funcname, extramsg); -} - -char *luaL_check_lstr (int numArg, long *len) -{ - lua_Object o = lua_getparam(numArg); - luaL_arg_check(lua_isstring(o), numArg, "string expected"); - if (len) *len = lua_strlen(o); - return lua_getstring(o); -} - -char *luaL_opt_lstr (int numArg, char *def, long *len) -{ - return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : - luaL_check_lstr(numArg, len); -} - -double luaL_check_number (int numArg) -{ - lua_Object o = lua_getparam(numArg); - luaL_arg_check(lua_isnumber(o), numArg, "number expected"); - return lua_getnumber(o); -} - - -double luaL_opt_number (int numArg, double def) -{ - return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : - luaL_check_number(numArg); -} - - -lua_Object luaL_tablearg (int arg) -{ - lua_Object o = lua_getparam(arg); - luaL_arg_check(lua_istable(o), arg, "table expected"); - return o; -} - -lua_Object luaL_functionarg (int arg) -{ - lua_Object o = lua_getparam(arg); - luaL_arg_check(lua_isfunction(o), arg, "function expected"); - return o; -} - -lua_Object luaL_nonnullarg (int numArg) -{ - lua_Object o = lua_getparam(numArg); - luaL_arg_check(o != LUA_NOOBJECT, numArg, "value expected"); - return o; -} - -void luaL_openlib (struct luaL_reg *l, int n) -{ - int i; - lua_open(); /* make sure lua is already open */ - for (i=0; i - -#include "lauxlib.h" -#include "lmem.h" -#include "lstate.h" - - -/*------------------------------------------------------- -** Auxiliary buffer --------------------------------------------------------*/ - - -#define EXTRABUFF 32 - - -#define openspace(size) if (L->Mbuffnext+(size) > L->Mbuffsize) Openspace(size) - -static void Openspace (int size) { - lua_State *l = L; /* to optimize */ - size += EXTRABUFF; - l->Mbuffsize = l->Mbuffnext+size; - luaM_growvector(l->Mbuffer, l->Mbuffnext, size, char, arrEM, MAX_INT); -} - - -char *luaL_openspace (int size) { - openspace(size); - return L->Mbuffer+L->Mbuffnext; -} - - -void luaL_addchar (int c) { - openspace(1); - L->Mbuffer[L->Mbuffnext++] = (char)c; -} - - -void luaL_resetbuffer (void) { - L->Mbuffnext = L->Mbuffbase; -} - - -void luaL_addsize (int n) { - L->Mbuffnext += n; -} - -int luaL_getsize (void) { - return L->Mbuffnext-L->Mbuffbase; -} - -int luaL_newbuffer (int size) { - int old = L->Mbuffbase; - openspace(size); - L->Mbuffbase = L->Mbuffnext; - return old; -} - - -void luaL_oldbuffer (int old) { - L->Mbuffnext = L->Mbuffbase; - L->Mbuffbase = old; -} - - -char *luaL_buffer (void) { - return L->Mbuffer+L->Mbuffbase; -} - diff --git a/src/lbuiltin.c b/src/lbuiltin.c deleted file mode 100644 index c88ccd41e8..0000000000 --- a/src/lbuiltin.c +++ /dev/null @@ -1,736 +0,0 @@ -/* -** $Id: lbuiltin.c,v 1.59 1999/06/17 17:04:03 roberto Exp $ -** Built-in functions -** See Copyright Notice in lua.h -*/ - - -#include -#include -#include -#include - -#include "lapi.h" -#include "lauxlib.h" -#include "lbuiltin.h" -#include "ldo.h" -#include "lfunc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lua.h" -#include "lundump.h" -#include "lvm.h" - - - -/* -** {====================================================== -** Auxiliary functions -** ======================================================= -*/ - - -static void pushtagstring (TaggedString *s) { - TObject o; - o.ttype = LUA_T_STRING; - o.value.ts = s; - luaA_pushobject(&o); -} - - -static real getsize (Hash *h) { - real max = 0; - int i; - for (i = 0; inode+i; - if (ttype(ref(n)) == LUA_T_NUMBER && - ttype(val(n)) != LUA_T_NIL && - nvalue(ref(n)) > max) - max = nvalue(ref(n)); - } - return max; -} - - -static real getnarg (Hash *a) { - TObject index; - TObject *value; - /* value = table.n */ - ttype(&index) = LUA_T_STRING; - tsvalue(&index) = luaS_new("n"); - value = luaH_get(a, &index); - return (ttype(value) == LUA_T_NUMBER) ? nvalue(value) : getsize(a); -} - - -static Hash *gethash (int arg) { - return avalue(luaA_Address(luaL_tablearg(arg))); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Functions that use only the official API -** ======================================================= -*/ - - -/* -** If your system does not support "stderr", redefine this function, or -** redefine _ERRORMESSAGE so that it won't need _ALERT. -*/ -static void luaB_alert (void) { - fputs(luaL_check_string(1), stderr); -} - - -/* -** Standard implementation of _ERRORMESSAGE. -** The library "iolib" redefines _ERRORMESSAGE for better error information. -*/ -static void error_message (void) { - lua_Object al = lua_rawgetglobal("_ALERT"); - if (lua_isfunction(al)) { /* avoid error loop if _ALERT is not defined */ - char buff[600]; - sprintf(buff, "lua error: %.500s\n", luaL_check_string(1)); - lua_pushstring(buff); - lua_callfunction(al); - } -} - - -/* -** If your system does not support "stdout", just remove this function. -** If you need, you can define your own "print" function, following this -** model but changing "fputs" to put the strings at a proper place -** (a console window or a log file, for instance). -*/ -#ifndef MAXPRINT -#define MAXPRINT 40 /* arbitrary limit */ -#endif - -static void luaB_print (void) { - lua_Object args[MAXPRINT]; - lua_Object obj; - int n = 0; - int i; - while ((obj = lua_getparam(n+1)) != LUA_NOOBJECT) { - luaL_arg_check(n < MAXPRINT, n+1, "too many arguments"); - args[n++] = obj; - } - for (i=0; i0) fputs("\t", stdout); - fputs(lua_getstring(obj), stdout); - } - fputs("\n", stdout); -} - - -static void luaB_tonumber (void) { - int base = luaL_opt_int(2, 10); - if (base == 10) { /* standard conversion */ - lua_Object o = lua_getparam(1); - if (lua_isnumber(o)) lua_pushnumber(lua_getnumber(o)); - else lua_pushnil(); /* not a number */ - } - else { - char *s = luaL_check_string(1); - long n; - luaL_arg_check(0 <= base && base <= 36, 2, "base out of range"); - n = strtol(s, &s, base); - while (isspace((unsigned char)*s)) s++; /* skip trailing spaces */ - if (*s) lua_pushnil(); /* invalid format: return nil */ - else lua_pushnumber(n); - } -} - - -static void luaB_error (void) { - lua_error(lua_getstring(lua_getparam(1))); -} - -static void luaB_setglobal (void) { - char *n = luaL_check_string(1); - lua_Object value = luaL_nonnullarg(2); - lua_pushobject(value); - lua_setglobal(n); - lua_pushobject(value); /* return given value */ -} - -static void luaB_rawsetglobal (void) { - char *n = luaL_check_string(1); - lua_Object value = luaL_nonnullarg(2); - lua_pushobject(value); - lua_rawsetglobal(n); - lua_pushobject(value); /* return given value */ -} - -static void luaB_getglobal (void) { - lua_pushobject(lua_getglobal(luaL_check_string(1))); -} - -static void luaB_rawgetglobal (void) { - lua_pushobject(lua_rawgetglobal(luaL_check_string(1))); -} - -static void luaB_luatag (void) { - lua_pushnumber(lua_tag(lua_getparam(1))); -} - -static void luaB_settag (void) { - lua_Object o = luaL_tablearg(1); - lua_pushobject(o); - lua_settag(luaL_check_int(2)); - lua_pushobject(o); /* return first argument */ -} - -static void luaB_newtag (void) { - lua_pushnumber(lua_newtag()); -} - -static void luaB_copytagmethods (void) { - lua_pushnumber(lua_copytagmethods(luaL_check_int(1), - luaL_check_int(2))); -} - -static void luaB_rawgettable (void) { - lua_pushobject(luaL_nonnullarg(1)); - lua_pushobject(luaL_nonnullarg(2)); - lua_pushobject(lua_rawgettable()); -} - -static void luaB_rawsettable (void) { - lua_pushobject(luaL_nonnullarg(1)); - lua_pushobject(luaL_nonnullarg(2)); - lua_pushobject(luaL_nonnullarg(3)); - lua_rawsettable(); -} - -static void luaB_settagmethod (void) { - lua_Object nf = luaL_nonnullarg(3); - lua_pushobject(nf); - lua_pushobject(lua_settagmethod(luaL_check_int(1), luaL_check_string(2))); -} - -static void luaB_gettagmethod (void) { - lua_pushobject(lua_gettagmethod(luaL_check_int(1), luaL_check_string(2))); -} - -static void luaB_seterrormethod (void) { - lua_Object nf = luaL_functionarg(1); - lua_pushobject(nf); - lua_pushobject(lua_seterrormethod()); -} - -static void luaB_collectgarbage (void) { - lua_pushnumber(lua_collectgarbage(luaL_opt_int(1, 0))); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Functions that could use only the official API but -** do not, for efficiency. -** ======================================================= -*/ - -static void luaB_dostring (void) { - long l; - char *s = luaL_check_lstr(1, &l); - if (*s == ID_CHUNK) - lua_error("`dostring' cannot run pre-compiled code"); - if (lua_dobuffer(s, l, luaL_opt_string(2, s)) == 0) - if (luaA_passresults() == 0) - lua_pushuserdata(NULL); /* at least one result to signal no errors */ -} - - -static void luaB_dofile (void) { - char *fname = luaL_opt_string(1, NULL); - if (lua_dofile(fname) == 0) - if (luaA_passresults() == 0) - lua_pushuserdata(NULL); /* at least one result to signal no errors */ -} - - -static void luaB_call (void) { - lua_Object f = luaL_nonnullarg(1); - Hash *arg = gethash(2); - char *options = luaL_opt_string(3, ""); - lua_Object err = lua_getparam(4); - int narg = (int)getnarg(arg); - int i, status; - if (err != LUA_NOOBJECT) { /* set new error method */ - lua_pushobject(err); - err = lua_seterrormethod(); - } - /* push arg[1...n] */ - luaD_checkstack(narg); - for (i=0; istack.top++) = *luaH_getint(arg, i+1); - status = lua_callfunction(f); - if (err != LUA_NOOBJECT) { /* restore old error method */ - lua_pushobject(err); - lua_seterrormethod(); - } - if (status != 0) { /* error in call? */ - if (strchr(options, 'x')) { - lua_pushnil(); - return; /* return nil to signal the error */ - } - else - lua_error(NULL); - } - else { /* no errors */ - if (strchr(options, 'p')) - luaA_packresults(); - else - luaA_passresults(); - } -} - - -static void luaB_nextvar (void) { - TObject *o = luaA_Address(luaL_nonnullarg(1)); - TaggedString *g; - if (ttype(o) == LUA_T_NIL) - g = NULL; - else { - luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected"); - g = tsvalue(o); - } - if (!luaA_nextvar(g)) - lua_pushnil(); -} - - -static void luaB_next (void) { - Hash *a = gethash(1); - TObject *k = luaA_Address(luaL_nonnullarg(2)); - int i = (ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1; - if (luaA_next(a, i) == 0) - lua_pushnil(); -} - - -static void luaB_tostring (void) { - lua_Object obj = lua_getparam(1); - TObject *o = luaA_Address(obj); - char buff[64]; - switch (ttype(o)) { - case LUA_T_NUMBER: - lua_pushstring(lua_getstring(obj)); - return; - case LUA_T_STRING: - lua_pushobject(obj); - return; - case LUA_T_ARRAY: - sprintf(buff, "table: %p", (void *)o->value.a); - break; - case LUA_T_CLOSURE: - sprintf(buff, "function: %p", (void *)o->value.cl); - break; - case LUA_T_PROTO: - sprintf(buff, "function: %p", (void *)o->value.tf); - break; - case LUA_T_CPROTO: - sprintf(buff, "function: %p", (void *)o->value.f); - break; - case LUA_T_USERDATA: - sprintf(buff, "userdata: %p", o->value.ts->u.d.v); - break; - case LUA_T_NIL: - lua_pushstring("nil"); - return; - default: - LUA_INTERNALERROR("invalid type"); - } - lua_pushstring(buff); -} - - -static void luaB_type (void) { - lua_Object o = luaL_nonnullarg(1); - lua_pushstring(luaO_typename(luaA_Address(o))); - lua_pushnumber(lua_tag(o)); -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** "Extra" functions -** These functions can be written in Lua, so you can -** delete them if you need a tiny Lua implementation. -** If you delete them, remove their entries in array -** "builtin_funcs". -** ======================================================= -*/ - -static void luaB_assert (void) { - lua_Object p = lua_getparam(1); - if (p == LUA_NOOBJECT || lua_isnil(p)) - luaL_verror("assertion failed! %.100s", luaL_opt_string(2, "")); -} - - -static void luaB_foreachi (void) { - Hash *t = gethash(1); - int i; - int n = (int)getnarg(t); - TObject f; - /* 'f' cannot be a pointer to TObject, because it is on the stack, and the - stack may be reallocated by the call. Moreover, some C compilers do not - initialize structs, so we must do the assignment after the declaration */ - f = *luaA_Address(luaL_functionarg(2)); - luaD_checkstack(3); /* for f, ref, and val */ - for (i=1; i<=n; i++) { - *(L->stack.top++) = f; - ttype(L->stack.top) = LUA_T_NUMBER; nvalue(L->stack.top++) = i; - *(L->stack.top++) = *luaH_getint(t, i); - luaD_calln(2, 1); - if (ttype(L->stack.top-1) != LUA_T_NIL) - return; - L->stack.top--; - } -} - - -static void luaB_foreach (void) { - Hash *a = gethash(1); - int i; - TObject f; /* see comment in 'foreachi' */ - f = *luaA_Address(luaL_functionarg(2)); - luaD_checkstack(3); /* for f, ref, and val */ - for (i=0; inhash; i++) { - Node *nd = &(a->node[i]); - if (ttype(val(nd)) != LUA_T_NIL) { - *(L->stack.top++) = f; - *(L->stack.top++) = *ref(nd); - *(L->stack.top++) = *val(nd); - luaD_calln(2, 1); - if (ttype(L->stack.top-1) != LUA_T_NIL) - return; - L->stack.top--; /* remove result */ - } - } -} - - -static void luaB_foreachvar (void) { - GCnode *g; - TObject f; /* see comment in 'foreachi' */ - f = *luaA_Address(luaL_functionarg(1)); - luaD_checkstack(4); /* for extra var name, f, var name, and globalval */ - for (g = L->rootglobal.next; g; g = g->next) { - TaggedString *s = (TaggedString *)g; - if (s->u.s.globalval.ttype != LUA_T_NIL) { - pushtagstring(s); /* keep (extra) s on stack to avoid GC */ - *(L->stack.top++) = f; - pushtagstring(s); - *(L->stack.top++) = s->u.s.globalval; - luaD_calln(2, 1); - if (ttype(L->stack.top-1) != LUA_T_NIL) { - L->stack.top--; - *(L->stack.top-1) = *L->stack.top; /* remove extra s */ - return; - } - L->stack.top-=2; /* remove result and extra s */ - } - } -} - - -static void luaB_getn (void) { - lua_pushnumber(getnarg(gethash(1))); -} - - -static void luaB_tinsert (void) { - Hash *a = gethash(1); - lua_Object v = lua_getparam(3); - int n = (int)getnarg(a); - int pos; - if (v != LUA_NOOBJECT) - pos = luaL_check_int(2); - else { /* called with only 2 arguments */ - v = luaL_nonnullarg(2); - pos = n+1; - } - luaV_setn(a, n+1); /* a.n = n+1 */ - for ( ;n>=pos; n--) - luaH_move(a, n, n+1); /* a[n+1] = a[n] */ - luaH_setint(a, pos, luaA_Address(v)); /* a[pos] = v */ -} - - -static void luaB_tremove (void) { - Hash *a = gethash(1); - int n = (int)getnarg(a); - int pos = luaL_opt_int(2, n); - if (n <= 0) return; /* table is "empty" */ - luaA_pushobject(luaH_getint(a, pos)); /* result = a[pos] */ - for ( ;posstack.top) = *luaA_Address(f); - *(L->stack.top+1) = *a; - *(L->stack.top+2) = *b; - L->stack.top += 3; - luaD_calln(2, 1); - } - else { /* a < b? */ - *(L->stack.top) = *a; - *(L->stack.top+1) = *b; - L->stack.top += 2; - luaV_comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); - } - return ttype(--(L->stack.top)) != LUA_T_NIL; -} - -static void auxsort (Hash *a, int l, int u, lua_Object f) { - while (l < u) { /* for tail recursion */ - TObject *P; - int i, j; - /* sort elements a[l], a[(l+u)/2] and a[u] */ - if (sort_comp(f, luaH_getint(a, u), luaH_getint(a, l))) /* a[l]>a[u]? */ - swap(a, l, u); - if (u-l == 1) break; /* only 2 elements */ - i = (l+u)/2; - P = luaH_getint(a, i); - if (sort_comp(f, P, luaH_getint(a, l))) /* a[l]>a[i]? */ - swap(a, l, i); - else if (sort_comp(f, luaH_getint(a, u), P)) /* a[i]>a[u]? */ - swap(a, i, u); - if (u-l == 2) break; /* only 3 elements */ - P = L->stack.top++; - *P = *luaH_getint(a, i); /* save pivot on stack (for GC) */ - swap(a, i, u-1); /* put median element as pivot (a[u-1]) */ - /* a[l] <= P == a[u-1] <= a[u], only needs to sort from l+1 to u-2 */ - i = l; j = u-1; - for (;;) { - /* invariant: a[l..i] <= P <= a[j..u] */ - while (sort_comp(f, luaH_getint(a, ++i), P)) /* stop when a[i] >= P */ - if (i>u) lua_error("invalid order function for sorting"); - while (sort_comp(f, P, luaH_getint(a, --j))) /* stop when a[j] <= P */ - if (jstack.top--; /* remove pivot from stack */ - /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ - /* adjust so that smaller "half" is in [j..i] and larger one in [l..u] */ - if (i-l < u-i) { - j=l; i=i-1; l=i+2; - } - else { - j=i+1; i=u; u=j-2; - } - auxsort(a, j, i, f); /* call recursively the smaller one */ - } /* repeat the routine for the larger one */ -} - -static void luaB_sort (void) { - lua_Object t = lua_getparam(1); - Hash *a = gethash(1); - int n = (int)getnarg(a); - lua_Object func = lua_getparam(2); - luaL_arg_check(func == LUA_NOOBJECT || lua_isfunction(func), 2, - "function expected"); - luaD_checkstack(4); /* for Pivot, f, a, b (sort_comp) */ - auxsort(a, 1, n, func); - lua_pushobject(t); -} - -/* }}===================================================== */ - - -/* -** ====================================================== */ - - - -#ifdef DEBUG -/* -** {====================================================== -** some DEBUG functions -** ======================================================= -*/ - -static void mem_query (void) { - lua_pushnumber(totalmem); - lua_pushnumber(numblocks); -} - - -static void query_strings (void) { - lua_pushnumber(L->string_root[luaL_check_int(1)].nuse); -} - - -static void countlist (void) { - char *s = luaL_check_string(1); - GCnode *l = (s[0]=='t') ? L->roottable.next : (s[0]=='c') ? L->rootcl.next : - (s[0]=='p') ? L->rootproto.next : L->rootglobal.next; - int i=0; - while (l) { - i++; - l = l->next; - } - lua_pushnumber(i); -} - - -static void testC (void) { -#define getnum(s) ((*s++) - '0') -#define getname(s) (nome[0] = *s++, nome) - - static int locks[10]; - lua_Object reg[10]; - char nome[2]; - char *s = luaL_check_string(1); - nome[1] = 0; - for (;;) { - switch (*s++) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - lua_pushnumber(*(s-1) - '0'); - break; - - case 'c': reg[getnum(s)] = lua_createtable(); break; - case 'C': { lua_CFunction f = lua_getcfunction(lua_getglobal(getname(s))); - lua_pushcclosure(f, getnum(s)); - break; - } - case 'P': reg[getnum(s)] = lua_pop(); break; - case 'g': { int n=getnum(s); reg[n]=lua_getglobal(getname(s)); break; } - case 'G': { int n = getnum(s); - reg[n] = lua_rawgetglobal(getname(s)); - break; - } - case 'l': locks[getnum(s)] = lua_ref(1); break; - case 'L': locks[getnum(s)] = lua_ref(0); break; - case 'r': { int n=getnum(s); reg[n]=lua_getref(locks[getnum(s)]); break; } - case 'u': lua_unref(locks[getnum(s)]); break; - case 'p': { int n = getnum(s); reg[n] = lua_getparam(getnum(s)); break; } - case '=': lua_setglobal(getname(s)); break; - case 's': lua_pushstring(getname(s)); break; - case 'o': lua_pushobject(reg[getnum(s)]); break; - case 'f': lua_call(getname(s)); break; - case 'i': reg[getnum(s)] = lua_gettable(); break; - case 'I': reg[getnum(s)] = lua_rawgettable(); break; - case 't': lua_settable(); break; - case 'T': lua_rawsettable(); break; - case 'N' : lua_pushstring(lua_nextvar(lua_getstring(reg[getnum(s)]))); - break; - case 'n' : { int n=getnum(s); - n=lua_next(reg[n], (int)lua_getnumber(reg[getnum(s)])); - lua_pushnumber(n); break; - } - default: luaL_verror("unknown command in `testC': %c", *(s-1)); - } - if (*s == 0) return; - if (*s++ != ' ') lua_error("missing ` ' between commands in `testC'"); - } -} - -/* }====================================================== */ -#endif - - - -static struct luaL_reg builtin_funcs[] = { -#ifdef LUA_COMPAT2_5 - {"setfallback", luaT_setfallback}, -#endif -#ifdef DEBUG - {"testC", testC}, - {"totalmem", mem_query}, - {"count", countlist}, - {"querystr", query_strings}, -#endif - {"_ALERT", luaB_alert}, - {"_ERRORMESSAGE", error_message}, - {"call", luaB_call}, - {"collectgarbage", luaB_collectgarbage}, - {"copytagmethods", luaB_copytagmethods}, - {"dofile", luaB_dofile}, - {"dostring", luaB_dostring}, - {"error", luaB_error}, - {"getglobal", luaB_getglobal}, - {"gettagmethod", luaB_gettagmethod}, - {"newtag", luaB_newtag}, - {"next", luaB_next}, - {"nextvar", luaB_nextvar}, - {"print", luaB_print}, - {"rawgetglobal", luaB_rawgetglobal}, - {"rawgettable", luaB_rawgettable}, - {"rawsetglobal", luaB_rawsetglobal}, - {"rawsettable", luaB_rawsettable}, - {"seterrormethod", luaB_seterrormethod}, - {"setglobal", luaB_setglobal}, - {"settag", luaB_settag}, - {"settagmethod", luaB_settagmethod}, - {"tag", luaB_luatag}, - {"tonumber", luaB_tonumber}, - {"tostring", luaB_tostring}, - {"type", luaB_type}, - /* "Extra" functions */ - {"assert", luaB_assert}, - {"foreach", luaB_foreach}, - {"foreachi", luaB_foreachi}, - {"foreachvar", luaB_foreachvar}, - {"getn", luaB_getn}, - {"sort", luaB_sort}, - {"tinsert", luaB_tinsert}, - {"tremove", luaB_tremove} -}; - - -#define INTFUNCSIZE (sizeof(builtin_funcs)/sizeof(builtin_funcs[0])) - - -void luaB_predefine (void) { - /* pre-register mem error messages, to avoid loop when error arises */ - luaS_newfixedstring(tableEM); - luaS_newfixedstring(memEM); - luaL_openlib(builtin_funcs, (sizeof(builtin_funcs)/sizeof(builtin_funcs[0]))); - lua_pushstring(LUA_VERSION); - lua_setglobal("_VERSION"); -} - diff --git a/src/lbuiltin.h b/src/lbuiltin.h deleted file mode 100644 index bcb11fc06b..0000000000 --- a/src/lbuiltin.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -** $Id: lbuiltin.h,v 1.1 1997/09/16 19:25:59 roberto Exp $ -** Built-in functions -** See Copyright Notice in lua.h -*/ - -#ifndef lbuiltin_h -#define lbuiltin_h - - -void luaB_predefine (void); - - -#endif diff --git a/src/lcode.c b/src/lcode.c new file mode 100644 index 0000000000..6882240d4b --- /dev/null +++ b/src/lcode.c @@ -0,0 +1,701 @@ +/* +** $Id: lcode.c,v 1.51 2000/09/29 12:42:13 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + + +#include "stdlib.h" + +#include "lua.h" + +#include "lcode.h" +#include "ldo.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +void luaK_error (LexState *ls, const char *msg) { + luaX_error(ls, msg, ls->t.token); +} + + +/* +** Returns the the previous instruction, for optimizations. +** If there is a jump target between this and the current instruction, +** returns a dummy instruction to avoid wrong optimizations. +*/ +static Instruction previous_instruction (FuncState *fs) { + if (fs->pc > fs->lasttarget) /* no jumps to current position? */ + return fs->f->code[fs->pc-1]; /* returns previous instruction */ + else + return CREATE_0(OP_END); /* no optimizations after an `END' */ +} + + +int luaK_jump (FuncState *fs) { + int j = luaK_code1(fs, OP_JMP, NO_JUMP); + if (j == fs->lasttarget) { /* possible jumps to this jump? */ + luaK_concat(fs, &j, fs->jlt); /* keep them on hold */ + fs->jlt = NO_JUMP; + } + return j; +} + + +static void luaK_fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + if (dest == NO_JUMP) + SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */ + else { /* jump is relative to position following jump instruction */ + int offset = dest-(pc+1); + if (abs(offset) > MAXARG_S) + luaK_error(fs->ls, "control structure too long"); + SETARG_S(*jmp, offset); + } +} + + +static int luaK_getjump (FuncState *fs, int pc) { + int offset = GETARG_S(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +/* +** returns current `pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +** discharge list of jumps to last target. +*/ +int luaK_getlabel (FuncState *fs) { + if (fs->pc != fs->lasttarget) { + int lasttarget = fs->lasttarget; + fs->lasttarget = fs->pc; + luaK_patchlist(fs, fs->jlt, lasttarget); /* discharge old list `jlt' */ + fs->jlt = NO_JUMP; /* nobody jumps to this new label (yet) */ + } + return fs->pc; +} + + +void luaK_deltastack (FuncState *fs, int delta) { + fs->stacklevel += delta; + if (fs->stacklevel > fs->f->maxstacksize) { + if (fs->stacklevel > MAXSTACK) + luaK_error(fs->ls, "function or expression too complex"); + fs->f->maxstacksize = fs->stacklevel; + } +} + + +void luaK_kstr (LexState *ls, int c) { + luaK_code1(ls->fs, OP_PUSHSTRING, c); +} + + +static int number_constant (FuncState *fs, Number r) { + /* check whether `r' has appeared within the last LOOKBACKNUMS entries */ + Proto *f = fs->f; + int c = f->nknum; + int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS; + while (--c >= lim) + if (f->knum[c] == r) return c; + /* not found; create a new entry */ + luaM_growvector(fs->L, f->knum, f->nknum, 1, Number, + "constant table overflow", MAXARG_U); + c = f->nknum++; + f->knum[c] = r; + return c; +} + + +void luaK_number (FuncState *fs, Number f) { + if (f <= (Number)MAXARG_S && (Number)(int)f == f) + luaK_code1(fs, OP_PUSHINT, (int)f); /* f has a short integer value */ + else + luaK_code1(fs, OP_PUSHNUM, number_constant(fs, f)); +} + + +void luaK_adjuststack (FuncState *fs, int n) { + if (n > 0) + luaK_code1(fs, OP_POP, n); + else + luaK_code1(fs, OP_PUSHNIL, -n); +} + + +int luaK_lastisopen (FuncState *fs) { + /* check whether last instruction is an open function call */ + Instruction i = previous_instruction(fs); + if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) + return 1; + else return 0; +} + + +void luaK_setcallreturns (FuncState *fs, int nresults) { + if (luaK_lastisopen(fs)) { /* expression is an open function call? */ + SETARG_B(fs->f->code[fs->pc-1], nresults); /* set number of results */ + luaK_deltastack(fs, nresults); /* push results */ + } +} + + +static int discharge (FuncState *fs, expdesc *var) { + switch (var->k) { + case VLOCAL: + luaK_code1(fs, OP_GETLOCAL, var->u.index); + break; + case VGLOBAL: + luaK_code1(fs, OP_GETGLOBAL, var->u.index); + break; + case VINDEXED: + luaK_code0(fs, OP_GETTABLE); + break; + case VEXP: + return 0; /* nothing to do */ + } + var->k = VEXP; + var->u.l.t = var->u.l.f = NO_JUMP; + return 1; +} + + +static void discharge1 (FuncState *fs, expdesc *var) { + discharge(fs, var); + /* if it has jumps then it is already discharged */ + if (var->u.l.t == NO_JUMP && var->u.l.f == NO_JUMP) + luaK_setcallreturns(fs, 1); /* call must return 1 value */ +} + + +void luaK_storevar (LexState *ls, const expdesc *var) { + FuncState *fs = ls->fs; + switch (var->k) { + case VLOCAL: + luaK_code1(fs, OP_SETLOCAL, var->u.index); + break; + case VGLOBAL: + luaK_code1(fs, OP_SETGLOBAL, var->u.index); + break; + case VINDEXED: /* table is at top-3; pop 3 elements after operation */ + luaK_code2(fs, OP_SETTABLE, 3, 3); + break; + default: + LUA_INTERNALERROR("invalid var kind to store"); + } +} + + +static OpCode invertjump (OpCode op) { + switch (op) { + case OP_JMPNE: return OP_JMPEQ; + case OP_JMPEQ: return OP_JMPNE; + case OP_JMPLT: return OP_JMPGE; + case OP_JMPLE: return OP_JMPGT; + case OP_JMPGT: return OP_JMPLE; + case OP_JMPGE: return OP_JMPLT; + case OP_JMPT: case OP_JMPONT: return OP_JMPF; + case OP_JMPF: case OP_JMPONF: return OP_JMPT; + default: + LUA_INTERNALERROR("invalid jump instruction"); + return OP_END; /* to avoid warnings */ + } +} + + +static void luaK_patchlistaux (FuncState *fs, int list, int target, + OpCode special, int special_target) { + Instruction *code = fs->f->code; + while (list != NO_JUMP) { + int next = luaK_getjump(fs, list); + Instruction *i = &code[list]; + OpCode op = GET_OPCODE(*i); + if (op == special) /* this `op' already has a value */ + luaK_fixjump(fs, list, special_target); + else { + luaK_fixjump(fs, list, target); /* do the patch */ + if (op == OP_JMPONT) /* remove eventual values */ + SET_OPCODE(*i, OP_JMPT); + else if (op == OP_JMPONF) + SET_OPCODE(*i, OP_JMPF); + } + list = next; + } +} + + +void luaK_patchlist (FuncState *fs, int list, int target) { + if (target == fs->lasttarget) /* same target that list `jlt'? */ + luaK_concat(fs, &fs->jlt, list); /* delay fixing */ + else + luaK_patchlistaux(fs, list, target, OP_END, 0); +} + + +static int need_value (FuncState *fs, int list, OpCode hasvalue) { + /* check whether list has a jump without a value */ + for (; list != NO_JUMP; list = luaK_getjump(fs, list)) + if (GET_OPCODE(fs->f->code[list]) != hasvalue) return 1; + return 0; /* not found */ +} + + +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (*l1 == NO_JUMP) + *l1 = l2; + else { + int list = *l1; + for (;;) { /* traverse `l1' */ + int next = luaK_getjump(fs, list); + if (next == NO_JUMP) { /* end of list? */ + luaK_fixjump(fs, list, l2); + return; + } + list = next; + } + } +} + + +static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) { + int prevpos; /* position of last instruction */ + Instruction *previous; + int *golist, *exitlist; + if (!invert) { + golist = &v->u.l.f; /* go if false */ + exitlist = &v->u.l.t; /* exit if true */ + } + else { + golist = &v->u.l.t; /* go if true */ + exitlist = &v->u.l.f; /* exit if false */ + } + discharge1(fs, v); + prevpos = fs->pc-1; + previous = &fs->f->code[prevpos]; + LUA_ASSERT(*previous==previous_instruction(fs), "no jump allowed here"); + if (!ISJUMP(GET_OPCODE(*previous))) + prevpos = luaK_code1(fs, jump, NO_JUMP); + else { /* last instruction is already a jump */ + if (invert) + SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); + } + luaK_concat(fs, exitlist, prevpos); /* insert last jump in `exitlist' */ + luaK_patchlist(fs, *golist, luaK_getlabel(fs)); + *golist = NO_JUMP; +} + + +void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) { + luaK_testgo(fs, v, 1, keepvalue ? OP_JMPONF : OP_JMPF); +} + + +static void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) { + luaK_testgo(fs, v, 0, keepvalue ? OP_JMPONT : OP_JMPT); +} + + +static int code_label (FuncState *fs, OpCode op, int arg) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_code1(fs, op, arg); +} + + +void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { + FuncState *fs = ls->fs; + if (!discharge(fs, v)) { /* `v' is an expression? */ + OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]); + if (!ISJUMP(previous) && v->u.l.f == NO_JUMP && v->u.l.t == NO_JUMP) { + /* expression has no jumps */ + if (onlyone) + luaK_setcallreturns(fs, 1); /* call must return 1 value */ + } + else { /* expression has jumps */ + int final; /* position after whole expression */ + int j = NO_JUMP; /* eventual jump over values */ + int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */ + int p_1 = NO_JUMP; /* position of an eventual PUSHINT */ + if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF) + || need_value(fs, v->u.l.t, OP_JMPONT)) { + /* expression needs values */ + if (ISJUMP(previous)) + luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */ + else { + j = code_label(fs, OP_JMP, NO_JUMP); /* to jump over both pushes */ + /* correct stack for compiler and symbolic execution */ + luaK_adjuststack(fs, 1); + } + p_nil = code_label(fs, OP_PUSHNILJMP, 0); + p_1 = code_label(fs, OP_PUSHINT, 1); + luaK_patchlist(fs, j, luaK_getlabel(fs)); + } + final = luaK_getlabel(fs); + luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final); + luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final); + v->u.l.f = v->u.l.t = NO_JUMP; + } + } +} + + +void luaK_prefix (LexState *ls, UnOpr op, expdesc *v) { + FuncState *fs = ls->fs; + if (op == OPR_MINUS) { + luaK_tostack(ls, v, 1); + luaK_code0(fs, OP_MINUS); + } + else { /* op == NOT */ + Instruction *previous; + discharge1(fs, v); + previous = &fs->f->code[fs->pc-1]; + if (ISJUMP(GET_OPCODE(*previous))) + SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); + else + luaK_code0(fs, OP_NOT); + /* interchange true and false lists */ + { int temp = v->u.l.f; v->u.l.f = v->u.l.t; v->u.l.t = temp; } + } +} + + +void luaK_infix (LexState *ls, BinOpr op, expdesc *v) { + FuncState *fs = ls->fs; + switch (op) { + case OPR_AND: + luaK_goiftrue(fs, v, 1); + break; + case OPR_OR: + luaK_goiffalse(fs, v, 1); + break; + default: + luaK_tostack(ls, v, 1); /* all other binary operators need a value */ + } +} + + + +static const struct { + OpCode opcode; /* opcode for each binary operator */ + int arg; /* default argument for the opcode */ +} codes[] = { /* ORDER OPR */ + {OP_ADD, 0}, {OP_SUB, 0}, {OP_MULT, 0}, {OP_DIV, 0}, + {OP_POW, 0}, {OP_CONCAT, 2}, + {OP_JMPNE, NO_JUMP}, {OP_JMPEQ, NO_JUMP}, + {OP_JMPLT, NO_JUMP}, {OP_JMPLE, NO_JUMP}, + {OP_JMPGT, NO_JUMP}, {OP_JMPGE, NO_JUMP} +}; + + +void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2) { + FuncState *fs = ls->fs; + switch (op) { + case OPR_AND: { + LUA_ASSERT(v1->u.l.t == NO_JUMP, "list must be closed"); + discharge1(fs, v2); + v1->u.l.t = v2->u.l.t; + luaK_concat(fs, &v1->u.l.f, v2->u.l.f); + break; + } + case OPR_OR: { + LUA_ASSERT(v1->u.l.f == NO_JUMP, "list must be closed"); + discharge1(fs, v2); + v1->u.l.f = v2->u.l.f; + luaK_concat(fs, &v1->u.l.t, v2->u.l.t); + break; + } + default: { + luaK_tostack(ls, v2, 1); /* `v2' must be a value */ + luaK_code1(fs, codes[op].opcode, codes[op].arg); + } + } +} + + +static void codelineinfo (FuncState *fs) { + Proto *f = fs->f; + LexState *ls = fs->ls; + if (ls->lastline > fs->lastline) { + luaM_growvector(fs->L, f->lineinfo, f->nlineinfo, 2, int, + "line info overflow", MAX_INT); + if (ls->lastline > fs->lastline+1) + f->lineinfo[f->nlineinfo++] = -(ls->lastline - (fs->lastline+1)); + f->lineinfo[f->nlineinfo++] = fs->pc; + fs->lastline = ls->lastline; + } +} + + +int luaK_code0 (FuncState *fs, OpCode o) { + return luaK_code2(fs, o, 0, 0); +} + + +int luaK_code1 (FuncState *fs, OpCode o, int arg1) { + return luaK_code2(fs, o, arg1, 0); +} + + +int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { + Instruction i = previous_instruction(fs); + int delta = luaK_opproperties[o].push - luaK_opproperties[o].pop; + int optm = 0; /* 1 when there is an optimization */ + switch (o) { + case OP_CLOSURE: { + delta = -arg2+1; + break; + } + case OP_SETTABLE: { + delta = -arg2; + break; + } + case OP_SETLIST: { + if (arg2 == 0) return NO_JUMP; /* nothing to do */ + delta = -arg2; + break; + } + case OP_SETMAP: { + if (arg1 == 0) return NO_JUMP; /* nothing to do */ + delta = -2*arg1; + break; + } + case OP_RETURN: { + if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) { + SET_OPCODE(i, OP_TAILCALL); + SETARG_B(i, arg1); + optm = 1; + } + break; + } + case OP_PUSHNIL: { + if (arg1 == 0) return NO_JUMP; /* nothing to do */ + delta = arg1; + switch(GET_OPCODE(i)) { + case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); optm = 1; break; + default: break; + } + break; + } + case OP_POP: { + if (arg1 == 0) return NO_JUMP; /* nothing to do */ + delta = -arg1; + switch(GET_OPCODE(i)) { + case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); optm = 1; break; + default: break; + } + break; + } + case OP_GETTABLE: { + switch(GET_OPCODE(i)) { + case OP_PUSHSTRING: /* `t.x' */ + SET_OPCODE(i, OP_GETDOTTED); + optm = 1; + break; + case OP_GETLOCAL: /* `t[i]' */ + SET_OPCODE(i, OP_GETINDEXED); + optm = 1; + break; + default: break; + } + break; + } + case OP_ADD: { + switch(GET_OPCODE(i)) { + case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */ + default: break; + } + break; + } + case OP_SUB: { + switch(GET_OPCODE(i)) { + case OP_PUSHINT: /* `a-k' */ + i = CREATE_S(OP_ADDI, -GETARG_S(i)); + optm = 1; + break; + default: break; + } + break; + } + case OP_CONCAT: { + delta = -arg1+1; + switch(GET_OPCODE(i)) { + case OP_CONCAT: /* `a..b..c' */ + SETARG_U(i, GETARG_U(i)+1); + optm = 1; + break; + default: break; + } + break; + } + case OP_MINUS: { + switch(GET_OPCODE(i)) { + case OP_PUSHINT: /* `-k' */ + SETARG_S(i, -GETARG_S(i)); + optm = 1; + break; + case OP_PUSHNUM: /* `-k' */ + SET_OPCODE(i, OP_PUSHNEGNUM); + optm = 1; + break; + default: break; + } + break; + } + case OP_JMPNE: { + if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */ + i = CREATE_S(OP_JMPT, NO_JUMP); + optm = 1; + } + break; + } + case OP_JMPEQ: { + if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */ + i = CREATE_0(OP_NOT); + delta = -1; /* just undo effect of previous PUSHNIL */ + optm = 1; + } + break; + } + case OP_JMPT: + case OP_JMPONT: { + switch (GET_OPCODE(i)) { + case OP_NOT: { + i = CREATE_S(OP_JMPF, NO_JUMP); + optm = 1; + break; + } + case OP_PUSHINT: { + if (o == OP_JMPT) { /* JMPONT must keep original integer value */ + i = CREATE_S(OP_JMP, NO_JUMP); + optm = 1; + } + break; + } + case OP_PUSHNIL: { + if (GETARG_U(i) == 1) { + fs->pc--; /* erase previous instruction */ + luaK_deltastack(fs, -1); /* correct stack */ + return NO_JUMP; + } + break; + } + default: break; + } + break; + } + case OP_JMPF: + case OP_JMPONF: { + switch (GET_OPCODE(i)) { + case OP_NOT: { + i = CREATE_S(OP_JMPT, NO_JUMP); + optm = 1; + break; + } + case OP_PUSHINT: { /* `while 1 do ...' */ + fs->pc--; /* erase previous instruction */ + luaK_deltastack(fs, -1); /* correct stack */ + return NO_JUMP; + } + case OP_PUSHNIL: { /* `repeat ... until nil' */ + if (GETARG_U(i) == 1) { + i = CREATE_S(OP_JMP, NO_JUMP); + optm = 1; + } + break; + } + default: break; + } + break; + } + case OP_GETDOTTED: + case OP_GETINDEXED: + case OP_TAILCALL: + case OP_ADDI: { + LUA_INTERNALERROR("instruction used only for optimizations"); + break; + } + default: { + LUA_ASSERT(delta != VD, "invalid delta"); + break; + } + } + luaK_deltastack(fs, delta); + if (optm) { /* optimize: put instruction in place of last one */ + fs->f->code[fs->pc-1] = i; /* change previous instruction */ + return fs->pc-1; /* do not generate new instruction */ + } + /* else build new instruction */ + switch ((enum Mode)luaK_opproperties[o].mode) { + case iO: i = CREATE_0(o); break; + case iU: i = CREATE_U(o, arg1); break; + case iS: i = CREATE_S(o, arg1); break; + case iAB: i = CREATE_AB(o, arg1, arg2); break; + } + codelineinfo(fs); + /* put new instruction in code array */ + luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction, + "code size overflow", MAX_INT); + fs->f->code[fs->pc] = i; + return fs->pc++; +} + + +const struct OpProperties luaK_opproperties[NUM_OPCODES] = { + {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, 0, 0}, /* OP_PUSHNILJMP */ + {iS, 0, 0}, /* OP_FORPREP */ + {iS, 0, 3}, /* OP_FORLOOP */ + {iS, 2, 0}, /* OP_LFORPREP */ + {iS, 0, 3}, /* OP_LFORLOOP */ + {iAB, VD, 0} /* OP_CLOSURE */ +}; + diff --git a/src/lcode.h b/src/lcode.h new file mode 100644 index 0000000000..3f0a209a94 --- /dev/null +++ b/src/lcode.h @@ -0,0 +1,70 @@ +/* +** $Id: lcode.h,v 1.16 2000/08/09 14:49:13 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lcode_h +#define lcode_h + +#include "llex.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lparser.h" + + +/* +** Marks the end of a patch list. It is an invalid value both as an absolute +** address, and as a list link (would link an element to itself). +*/ +#define NO_JUMP (-1) + + +/* +** grep "ORDER OPR" if you change these enums +*/ +typedef enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_POW, + OPR_CONCAT, + OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR +} BinOpr; + +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; + + +enum Mode {iO, iU, iS, iAB}; /* instruction format */ + +#define VD 100 /* flag for variable delta */ + +extern const struct OpProperties { + char mode; + unsigned char push; + unsigned char pop; +} luaK_opproperties[]; + + +void luaK_error (LexState *ls, const char *msg); +int luaK_code0 (FuncState *fs, OpCode o); +int luaK_code1 (FuncState *fs, OpCode o, int arg1); +int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2); +int luaK_jump (FuncState *fs); +void luaK_patchlist (FuncState *fs, int list, int target); +void luaK_concat (FuncState *fs, int *l1, int l2); +void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue); +int luaK_getlabel (FuncState *fs); +void luaK_deltastack (FuncState *fs, int delta); +void luaK_kstr (LexState *ls, int c); +void luaK_number (FuncState *fs, Number f); +void luaK_adjuststack (FuncState *fs, int n); +int luaK_lastisopen (FuncState *fs); +void luaK_setcallreturns (FuncState *fs, int nresults); +void luaK_tostack (LexState *ls, expdesc *v, int onlyone); +void luaK_storevar (LexState *ls, const expdesc *var); +void luaK_prefix (LexState *ls, UnOpr op, expdesc *v); +void luaK_infix (LexState *ls, BinOpr op, expdesc *v); +void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2); + + +#endif diff --git a/src/ldebug.c b/src/ldebug.c new file mode 100644 index 0000000000..a5a2ab1d90 --- /dev/null +++ b/src/ldebug.c @@ -0,0 +1,466 @@ +/* +** $Id: ldebug.c,v 1.50 2000/10/30 12:38:50 roberto Exp $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + + +#include + +#include "lua.h" + +#include "lapi.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "luadebug.h" + + + +static const char *getfuncname (lua_State *L, StkId f, const char **name); + + +static void setnormalized (TObject *d, const TObject *s) { + if (ttype(s) == LUA_TMARK) { + clvalue(d) = infovalue(s)->func; + ttype(d) = LUA_TFUNCTION; + } + else *d = *s; +} + + +static int isLmark (StkId o) { + return (o && ttype(o) == LUA_TMARK && !infovalue(o)->func->isC); +} + + +LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func) { + lua_Hook oldhook = L->callhook; + L->callhook = func; + return oldhook; +} + + +LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) { + lua_Hook oldhook = L->linehook; + L->linehook = func; + return oldhook; +} + + +static StkId aux_stackedfunction (lua_State *L, int level, StkId top) { + int i; + for (i = (top-1) - L->stack; i>=0; i--) { + if (is_T_MARK(L->stack[i].ttype)) { + if (level == 0) + return L->stack+i; + level--; + } + } + return NULL; +} + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + StkId f = aux_stackedfunction(L, level, L->top); + if (f == NULL) return 0; /* there is no such level */ + else { + ar->_func = f; + return 1; + } +} + + +static int nups (StkId f) { + switch (ttype(f)) { + case LUA_TFUNCTION: + return clvalue(f)->nupvalues; + case LUA_TMARK: + return infovalue(f)->func->nupvalues; + default: + return 0; + } +} + + +int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) { + int refi; + if (lineinfo == NULL || pc == -1) + return -1; /* no line info or function is not active */ + refi = prefi ? *prefi : 0; + if (lineinfo[refi] < 0) + refline += -lineinfo[refi++]; + LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); + while (lineinfo[refi] > pc) { + refline--; + refi--; + if (lineinfo[refi] < 0) + refline -= -lineinfo[refi--]; + LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); + } + for (;;) { + int nextline = refline + 1; + int nextref = refi + 1; + if (lineinfo[nextref] < 0) + nextline += -lineinfo[nextref++]; + LUA_ASSERT(lineinfo[nextref] >= 0, "invalid line info"); + if (lineinfo[nextref] > pc) + break; + refline = nextline; + refi = nextref; + } + if (prefi) *prefi = refi; + return refline; +} + + +static int currentpc (StkId f) { + CallInfo *ci = infovalue(f); + LUA_ASSERT(isLmark(f), "function has no pc"); + if (ci->pc) + return (*ci->pc - ci->func->f.l->code) - 1; + else + return -1; /* function is not active */ +} + + +static int currentline (StkId f) { + if (!isLmark(f)) + return -1; /* only active lua functions have current-line information */ + else { + CallInfo *ci = infovalue(f); + int *lineinfo = ci->func->f.l->lineinfo; + return luaG_getline(lineinfo, currentpc(f), 1, NULL); + } +} + + + +static Proto *getluaproto (StkId f) { + return (isLmark(f) ? infovalue(f)->func->f.l : NULL); +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + const char *name; + StkId f = ar->_func; + Proto *fp = getluaproto(f); + if (!fp) return NULL; /* `f' is not a Lua function? */ + name = luaF_getlocalname(fp, n, currentpc(f)); + if (!name) return NULL; + luaA_pushobject(L, (f+1)+(n-1)); /* push value */ + return name; +} + + +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { + const char *name; + StkId f = ar->_func; + Proto *fp = getluaproto(f); + L->top--; /* pop new value */ + if (!fp) return NULL; /* `f' is not a Lua function? */ + name = luaF_getlocalname(fp, n, currentpc(f)); + if (!name || name[0] == '(') return NULL; /* `(' starts private locals */ + *((f+1)+(n-1)) = *L->top; + return name; +} + + +static void infoLproto (lua_Debug *ar, Proto *f) { + ar->source = f->source->str; + ar->linedefined = f->lineDefined; + ar->what = "Lua"; +} + + +static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) { + Closure *cl = NULL; + switch (ttype(func)) { + case LUA_TFUNCTION: + cl = clvalue(func); + break; + case LUA_TMARK: + cl = infovalue(func)->func; + break; + default: + lua_error(L, "value for `lua_getinfo' is not a function"); + } + if (cl->isC) { + ar->source = "=C"; + ar->linedefined = -1; + ar->what = "C"; + } + else + infoLproto(ar, cl->f.l); + luaO_chunkid(ar->short_src, ar->source, sizeof(ar->short_src)); + if (ar->linedefined == 0) + ar->what = "main"; +} + + +static const char *travtagmethods (lua_State *L, const TObject *o) { + if (ttype(o) == LUA_TFUNCTION) { + int e; + for (e=0; elast_tag; t++) + if (clvalue(o) == luaT_gettm(L, t, e)) + return luaT_eventname[e]; + } + } + return NULL; +} + + +static const char *travglobals (lua_State *L, const TObject *o) { + Hash *g = L->gt; + int i; + for (i=0; isize; i++) { + if (luaO_equalObj(o, val(node(g, i))) && + ttype(key(node(g, i))) == LUA_TSTRING) + return tsvalue(key(node(g, i)))->str; + } + return NULL; +} + + +static void getname (lua_State *L, StkId f, lua_Debug *ar) { + TObject o; + setnormalized(&o, f); + /* try to find a name for given function */ + if ((ar->name = travglobals(L, &o)) != NULL) + ar->namewhat = "global"; + /* not found: try tag methods */ + else if ((ar->name = travtagmethods(L, &o)) != NULL) + ar->namewhat = "tag-method"; + else ar->namewhat = ""; /* not found at all */ +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + StkId func; + int isactive = (*what != '>'); + if (isactive) + func = ar->_func; + else { + what++; /* skip the '>' */ + func = L->top - 1; + } + for (; *what; what++) { + switch (*what) { + case 'S': { + funcinfo(L, ar, func); + break; + } + case 'l': { + ar->currentline = currentline(func); + break; + } + case 'u': { + ar->nups = nups(func); + break; + } + case 'n': { + ar->namewhat = (isactive) ? getfuncname(L, func, &ar->name) : NULL; + if (ar->namewhat == NULL) + getname(L, func, ar); + break; + } + case 'f': { + setnormalized(L->top, func); + incr_top; /* push function */ + break; + } + default: return 0; /* invalid option */ + } + } + if (!isactive) L->top--; /* pop function */ + return 1; +} + + +/* +** {====================================================== +** Symbolic Execution +** ======================================================= +*/ + + +static int pushpc (int *stack, int pc, int top, int n) { + while (n--) + stack[top++] = pc-1; + return top; +} + + +static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { + int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */ + 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++]; + LUA_ASSERT(0 <= top && top <= pt->maxstacksize, "wrong stack"); + switch (GET_OPCODE(i)) { + case OP_RETURN: { + LUA_ASSERT(top >= GETARG_U(i), "wrong stack"); + top = GETARG_U(i); + break; + } + case OP_TAILCALL: { + LUA_ASSERT(top >= GETARG_A(i), "wrong stack"); + top = GETARG_B(i); + break; + } + case OP_CALL: { + int nresults = GETARG_B(i); + if (nresults == MULT_RET) nresults = 1; + LUA_ASSERT(top >= GETARG_A(i), "wrong stack"); + top = pushpc(stack, pc, GETARG_A(i), nresults); + break; + } + case OP_PUSHNIL: { + top = pushpc(stack, pc, top, GETARG_U(i)); + 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_CLOSURE: { + top -= GETARG_B(i); + stack[top++] = pc-1; + break; + } + case OP_JMPONT: + case OP_JMPONF: { + int newpc = pc + GETARG_S(i); + /* jump is forward and do not skip `lastpc'? */ + if (pc < newpc && newpc <= lastpc) { + stack[top-1] = pc-1; /* value comes from `and'/`or' */ + pc = newpc; /* do the jump */ + } + else + top--; /* do not jump; pop value */ + break; + } + default: { + OpCode op = GET_OPCODE(i); + LUA_ASSERT(luaK_opproperties[op].push != VD, + "invalid opcode for default"); + top -= luaK_opproperties[op].pop; + LUA_ASSERT(top >= 0, "wrong stack"); + top = pushpc(stack, pc, top, luaK_opproperties[op].push); + } + } + } + return code[stack[stackpos]]; +} + + +static const char *getobjname (lua_State *L, StkId obj, const char **name) { + StkId func = aux_stackedfunction(L, 0, obj); + if (!isLmark(func)) + return NULL; /* not an active Lua function */ + else { + Proto *p = infovalue(func)->func->f.l; + int pc = currentpc(func); + int stackpos = obj - (func+1); /* func+1 == function base */ + Instruction i = luaG_symbexec(p, pc, stackpos); + LUA_ASSERT(pc != -1, "function must be active"); + 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); + LUA_ASSERT(*name, "local must exist"); + return "local"; + } + case OP_PUSHSELF: + case OP_GETDOTTED: { + *name = p->kstr[GETARG_U(i)]->str; + return "field"; + } + default: + return NULL; /* no useful name found */ + } + } +} + + +static const char *getfuncname (lua_State *L, StkId f, const char **name) { + StkId func = aux_stackedfunction(L, 0, f); /* calling function */ + if (!isLmark(func)) + return NULL; /* not an active Lua function */ + else { + Proto *p = infovalue(func)->func->f.l; + int pc = currentpc(func); + Instruction i; + if (pc == -1) return NULL; /* function is not activated */ + i = p->code[pc]; + switch (GET_OPCODE(i)) { + case OP_CALL: case OP_TAILCALL: + return getobjname(L, (func+1)+GETARG_A(i), name); + default: + return NULL; /* no useful name found */ + } + } +} + + +/* }====================================================== */ + + +void luaG_typeerror (lua_State *L, StkId o, const char *op) { + const char *name; + const char *kind = getobjname(L, o, &name); + const char *t = luaO_typename(o); + if (kind) + luaO_verror(L, "attempt to %.30s %.20s `%.40s' (a %.10s value)", + op, kind, name, t); + else + luaO_verror(L, "attempt to %.30s a %.10s value", op, t); +} + + +void luaG_binerror (lua_State *L, StkId p1, int t, const char *op) { + if (ttype(p1) == t) p1++; + LUA_ASSERT(ttype(p1) != t, "must be an error"); + luaG_typeerror(L, p1, op); +} + + +void luaG_ordererror (lua_State *L, StkId top) { + const char *t1 = luaO_typename(top-2); + const char *t2 = luaO_typename(top-1); + if (t1[2] == t2[2]) + luaO_verror(L, "attempt to compare two %.10s values", t1); + else + luaO_verror(L, "attempt to compare %.10s with %.10s", t1, t2); +} + diff --git a/src/ldebug.h b/src/ldebug.h new file mode 100644 index 0000000000..d4b2d3b08a --- /dev/null +++ b/src/ldebug.h @@ -0,0 +1,21 @@ +/* +** $Id: ldebug.h,v 1.7 2000/10/05 12:14:08 roberto Exp $ +** Auxiliary functions from Debug Interface module +** See Copyright Notice in lua.h +*/ + +#ifndef ldebug_h +#define ldebug_h + + +#include "lstate.h" +#include "luadebug.h" + + +void luaG_typeerror (lua_State *L, StkId o, const char *op); +void luaG_binerror (lua_State *L, StkId p1, int t, const char *op); +int luaG_getline (int *lineinfo, int pc, int refline, int *refi); +void luaG_ordererror (lua_State *L, StkId top); + + +#endif diff --git a/src/ldo.c b/src/ldo.c index 281a4ec4da..fbb892a5a0 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.45b 1999/06/22 20:37:23 roberto Exp $ +** $Id: ldo.c,v 1.109 2000/10/30 12:38:50 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -10,378 +10,376 @@ #include #include -#include "lauxlib.h" +#include "lua.h" + +#include "ldebug.h" #include "ldo.h" -#include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" +#include "ltable.h" #include "ltm.h" -#include "lua.h" -#include "luadebug.h" #include "lundump.h" #include "lvm.h" #include "lzio.h" +/* space to handle stack overflow errors */ +#define EXTRA_STACK (2*LUA_MINSTACK) -#ifndef STACK_LIMIT -#define STACK_LIMIT 6000 /* arbitrary limit */ -#endif - - - -#define STACK_UNIT 128 - -#ifdef DEBUG -#undef STACK_UNIT -#define STACK_UNIT 2 -#endif - - -void luaD_init (void) { - L->stack.stack = luaM_newvector(STACK_UNIT, TObject); - L->stack.top = L->stack.stack; - L->stack.last = L->stack.stack+(STACK_UNIT-1); +void luaD_init (lua_State *L, int stacksize) { + L->stack = luaM_newvector(L, stacksize+EXTRA_STACK, TObject); + L->nblocks += stacksize*sizeof(TObject); + L->stack_last = L->stack+(stacksize-1); + L->stacksize = stacksize; + L->Cbase = L->top = L->stack; } -void luaD_checkstack (int n) { - struct Stack *S = &L->stack; - if (S->last-S->top <= n) { - StkId top = S->top-S->stack; - int stacksize = (S->last-S->stack)+STACK_UNIT+n; - luaM_reallocvector(S->stack, stacksize, TObject); - S->last = S->stack+(stacksize-1); - S->top = S->stack + top; - if (stacksize >= STACK_LIMIT) { /* stack overflow? */ - if (lua_stackedfunction(100) == LUA_NOOBJECT) /* 100 funcs on stack? */ - lua_error("Lua2C - C2Lua overflow"); /* doesn't look like a rec. loop */ - else - lua_error("stack size overflow"); +void luaD_checkstack (lua_State *L, int n) { + if (L->stack_last - L->top <= n) { /* stack overflow? */ + if (L->stack_last-L->stack > (L->stacksize-1)) { + /* overflow while handling overflow */ + luaD_breakrun(L, LUA_ERRERR); /* break run without error message */ + } + else { + L->stack_last += EXTRA_STACK; /* to be used by error message */ + lua_error(L, "stack overflow"); } } } +static void restore_stack_limit (lua_State *L) { + if (L->top - L->stack < L->stacksize - 1) + L->stack_last = L->stack + (L->stacksize-1); +} + + /* -** Adjust stack. Set top to the given value, pushing NILs if needed. +** Adjust stack. Set top to base+extra, pushing NILs if needed. +** (we cannot add base+extra unless we are sure it fits in the stack; +** otherwise the result of such operation on pointers is undefined) */ -void luaD_adjusttop (StkId newtop) { - int diff = newtop-(L->stack.top-L->stack.stack); +void luaD_adjusttop (lua_State *L, StkId base, int extra) { + int diff = extra-(L->top-base); if (diff <= 0) - L->stack.top += diff; + L->top = base+extra; else { - luaD_checkstack(diff); + luaD_checkstack(L, diff); while (diff--) - ttype(L->stack.top++) = LUA_T_NIL; + ttype(L->top++) = LUA_TNIL; } } /* -** Open a hole below "nelems" from the L->stack.top. +** Open a hole inside the stack at `pos' */ -void luaD_openstack (int nelems) { - luaO_memup(L->stack.top-nelems+1, L->stack.top-nelems, - nelems*sizeof(TObject)); +static void luaD_openstack (lua_State *L, StkId pos) { + int i = L->top-pos; + while (i--) pos[i+1] = pos[i]; incr_top; } -void luaD_lineHook (int line) { - struct C_Lua_Stack oldCLS = L->Cstack; - StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack; - L->Cstack.num = 0; - (*L->linehook)(line); - L->stack.top = L->stack.stack+old_top; - L->Cstack = oldCLS; +static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) { + StkId old_Cbase = L->Cbase; + StkId old_top = L->Cbase = L->top; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + L->allowhooks = 0; /* cannot call hooks inside a hook */ + (*hook)(L, ar); + LUA_ASSERT(L->allowhooks == 0, "invalid allow"); + L->allowhooks = 1; + L->top = old_top; + L->Cbase = old_Cbase; } -void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn) { - struct C_Lua_Stack oldCLS = L->Cstack; - StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack; - L->Cstack.num = 0; - if (isreturn) - (*L->callhook)(LUA_NOOBJECT, "(return)", 0); - else { - TObject *f = L->stack.stack+base-1; - if (tf) - (*L->callhook)(Ref(f), tf->source->str, tf->lineDefined); - else - (*L->callhook)(Ref(f), "(C)", -1); +void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) { + if (L->allowhooks) { + lua_Debug ar; + ar._func = func; + ar.event = "line"; + ar.currentline = line; + dohook(L, &ar, linehook); } - L->stack.top = L->stack.stack+old_top; - L->Cstack = oldCLS; } -/* -** Call a C function. -** Cstack.num is the number of arguments; Cstack.lua2C points to the -** first argument. Returns an index to the first result from C. -*/ -static StkId callC (lua_CFunction f, StkId base) { - struct C_Lua_Stack *cls = &L->Cstack; - struct C_Lua_Stack oldCLS = *cls; - StkId firstResult; - int numarg = (L->stack.top-L->stack.stack) - base; - cls->num = numarg; - cls->lua2C = base; - cls->base = base+numarg; /* == top-stack */ - if (L->callhook) - luaD_callHook(base, NULL, 0); - (*f)(); /* do the actual call */ - if (L->callhook) /* func may have changed callhook */ - luaD_callHook(base, NULL, 1); - firstResult = cls->base; - *cls = oldCLS; - return firstResult; +static void luaD_callHook (lua_State *L, StkId func, lua_Hook callhook, + const char *event) { + if (L->allowhooks) { + lua_Debug ar; + ar._func = func; + ar.event = event; + infovalue(func)->pc = NULL; /* function is not active */ + dohook(L, &ar, callhook); + } } -static StkId callCclosure (struct Closure *cl, lua_CFunction f, StkId base) { - TObject *pbase; - int nup = cl->nelems; /* number of upvalues */ - luaD_checkstack(nup); - pbase = L->stack.stack+base; /* care: previous call may change this */ - /* open space for upvalues as extra arguments */ - luaO_memup(pbase+nup, pbase, (L->stack.top-pbase)*sizeof(TObject)); - /* copy upvalues into stack */ - memcpy(pbase, cl->consts+1, nup*sizeof(TObject)); - L->stack.top += nup; - return callC(f, base); +static StkId callCclosure (lua_State *L, const struct Closure *cl, StkId base) { + int nup = cl->nupvalues; /* number of upvalues */ + StkId old_Cbase = L->Cbase; + int n; + L->Cbase = base; /* new base for C function */ + luaD_checkstack(L, nup+LUA_MINSTACK); /* ensure minimum stack size */ + for (n=0; ntop++) = cl->upvalue[n]; + n = (*cl->f.c)(L); /* do the actual call */ + L->Cbase = old_Cbase; /* restore old C base */ + return L->top - n; /* return index of first result */ } -void luaD_callTM (TObject *f, int nParams, int nResults) { - luaD_openstack(nParams); - *(L->stack.top-nParams-1) = *f; - luaD_calln(nParams, nResults); +void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults) { + StkId base = L->top - nParams; + luaD_openstack(L, base); + clvalue(base) = f; + ttype(base) = LUA_TFUNCTION; + luaD_call(L, base, nResults); } /* -** Call a function (C or Lua). The parameters must be on the stack, -** between [top-nArgs,top). The function to be called is right below the -** arguments. -** When returns, the results are on the stack, between [top-nArgs-1,top). -** The number of results is nResults, unless nResults=MULT_RET. -*/ -void luaD_calln (int nArgs, int nResults) { - struct Stack *S = &L->stack; /* to optimize */ - StkId base = (S->top-S->stack)-nArgs; - TObject *func = S->stack+base-1; +** Call a function (C or Lua). The function to be called is at *func. +** The arguments are on the stack, right after the function. +** When returns, the results are on the stack, starting at the original +** function position. +** The number of results is nResults, unless nResults=LUA_MULTRET. +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + lua_Hook callhook; StkId firstResult; - int i; - switch (ttype(func)) { - case LUA_T_CPROTO: - ttype(func) = LUA_T_CMARK; - firstResult = callC(fvalue(func), base); - break; - case LUA_T_PROTO: - ttype(func) = LUA_T_PMARK; - firstResult = luaV_execute(NULL, tfvalue(func), base); - break; - case LUA_T_CLOSURE: { - Closure *c = clvalue(func); - TObject *proto = &(c->consts[0]); - ttype(func) = LUA_T_CLMARK; - firstResult = (ttype(proto) == LUA_T_CPROTO) ? - callCclosure(c, fvalue(proto), base) : - luaV_execute(c, tfvalue(proto), base); - break; - } - default: { /* func is not a function */ - /* Check the tag method for invalid functions */ - TObject *im = luaT_getimbyObj(func, IM_FUNCTION); - if (ttype(im) == LUA_T_NIL) - lua_error("call expression not a function"); - luaD_callTM(im, (S->top-S->stack)-(base-1), nResults); - return; + CallInfo ci; + Closure *cl; + if (ttype(func) != LUA_TFUNCTION) { + /* `func' is not a function; check the `function' tag method */ + Closure *tm = luaT_gettmbyObj(L, func, TM_FUNCTION); + if (tm == NULL) + luaG_typeerror(L, func, "call"); + luaD_openstack(L, func); + clvalue(func) = tm; /* tag method is the new function to be called */ + ttype(func) = LUA_TFUNCTION; + } + cl = clvalue(func); + ci.func = cl; + infovalue(func) = &ci; + ttype(func) = LUA_TMARK; + callhook = L->callhook; + if (callhook) + luaD_callHook(L, func, callhook, "call"); + firstResult = (cl->isC ? callCclosure(L, cl, func+1) : + luaV_execute(L, cl, func+1)); + if (callhook) /* same hook that was active at entry */ + luaD_callHook(L, func, callhook, "return"); + LUA_ASSERT(ttype(func) == LUA_TMARK, "invalid tag"); + /* move results to `func' (to erase parameters and function) */ + if (nResults == LUA_MULTRET) { + while (firstResult < L->top) /* copy all results */ + *func++ = *firstResult++; + L->top = func; + } + else { /* copy at most `nResults' */ + for (; nResults > 0 && firstResult < L->top; nResults--) + *func++ = *firstResult++; + L->top = func; + for (; nResults > 0; nResults--) { /* if there are not enough results */ + ttype(L->top) = LUA_TNIL; /* adjust the stack */ + incr_top; /* must check stack space */ } } - /* adjust the number of results */ - if (nResults == MULT_RET) - nResults = (S->top-S->stack)-firstResult; - else - luaD_adjusttop(firstResult+nResults); - /* move results to base-1 (to erase parameters and function) */ - base--; - for (i=0; istack+base+i) = *(S->stack+firstResult+i); - S->top -= firstResult-base; + luaC_checkGC(L); } /* -** Traverse all objects on L->stack.stack +** Execute a protected call. */ -void luaD_travstack (int (*fn)(TObject *)) -{ - StkId i; - for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--) - fn(L->stack.stack+i); +struct CallS { /* data to `f_call' */ + StkId func; + int nresults; +}; + +static void f_call (lua_State *L, void *ud) { + struct CallS *c = (struct CallS *)ud; + luaD_call(L, c->func, c->nresults); } - -static void message (char *s) { - TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval); - if (ttype(em) == LUA_T_PROTO || ttype(em) == LUA_T_CPROTO || - ttype(em) == LUA_T_CLOSURE) { - *L->stack.top = *em; - incr_top; - lua_pushstring(s); - luaD_calln(1, 0); - } -} - -/* -** Reports an error, and jumps up to the available recover label -*/ -void lua_error (char *s) { - if (s) message(s); - if (L->errorJmp) - longjmp(L->errorJmp->b, 1); - else { - message("exit(1). Unable to recover.\n"); - exit(1); - } -} - - -/* -** Execute a protected call. Assumes that function is at L->Cstack.base and -** parameters are on top of it. Leave nResults on the stack. -*/ -int luaD_protectedrun (void) { - volatile struct C_Lua_Stack oldCLS = L->Cstack; - struct lua_longjmp myErrorJmp; - volatile int status; - struct lua_longjmp *volatile oldErr = L->errorJmp; - L->errorJmp = &myErrorJmp; - if (setjmp(myErrorJmp.b) == 0) { - StkId base = L->Cstack.base; - luaD_calln((L->stack.top-L->stack.stack)-base-1, MULT_RET); - L->Cstack.lua2C = base; /* position of the new results */ - L->Cstack.num = (L->stack.top-L->stack.stack) - base; - L->Cstack.base = base + L->Cstack.num; /* incorporate results on stack */ - status = 0; - } - else { /* an error occurred: restore L->Cstack and L->stack.top */ - L->Cstack = oldCLS; - L->stack.top = L->stack.stack+L->Cstack.base; - status = 1; - } - L->errorJmp = oldErr; +LUA_API int lua_call (lua_State *L, int nargs, int nresults) { + StkId func = L->top - (nargs+1); /* function to be called */ + struct CallS c; + int status; + c.func = func; c.nresults = nresults; + status = luaD_runprotected(L, f_call, &c); + if (status != 0) /* an error occurred? */ + L->top = func; /* remove parameters from the stack */ return status; } /* -** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load +** Execute a protected parser. */ -static int protectedparser (ZIO *z, int bin) { - volatile struct C_Lua_Stack oldCLS = L->Cstack; - struct lua_longjmp myErrorJmp; - volatile int status; - TProtoFunc *volatile tf; - struct lua_longjmp *volatile oldErr = L->errorJmp; - L->errorJmp = &myErrorJmp; - if (setjmp(myErrorJmp.b) == 0) { - tf = bin ? luaU_undump1(z) : luaY_parser(z); - status = 0; - } - else { /* an error occurred: restore L->Cstack and L->stack.top */ - L->Cstack = oldCLS; - L->stack.top = L->stack.stack+L->Cstack.base; - tf = NULL; - status = 1; - } - L->errorJmp = oldErr; - if (status) return 1; /* error code */ - if (tf == NULL) return 2; /* 'natural' end */ - luaD_adjusttop(L->Cstack.base+1); /* one slot for the pseudo-function */ - L->stack.stack[L->Cstack.base].ttype = LUA_T_PROTO; - L->stack.stack[L->Cstack.base].value.tf = tf; - luaV_closure(0); - return 0; -} - +struct ParserS { /* data to `f_parser' */ + ZIO *z; + int bin; +}; -static int do_main (ZIO *z, int bin) { - int status; - int debug = L->debug; /* save debug status */ - do { - long old_blocks = (luaC_checkGC(), L->nblocks); - status = protectedparser(z, bin); - if (status == 1) return 1; /* error */ - else if (status == 2) return 0; /* 'natural' end */ - else { - unsigned long newelems2 = 2*(L->nblocks-old_blocks); - L->GCthreshold += newelems2; - status = luaD_protectedrun(); - L->GCthreshold -= newelems2; - } - } while (bin && status == 0); - L->debug = debug; /* restore debug status */ - return status; +static void f_parser (lua_State *L, void *ud) { + struct ParserS *p = (struct ParserS *)ud; + Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z); + luaV_Lclosure(L, tf, 0); } -void luaD_gcIM (TObject *o) -{ - TObject *im = luaT_getimbyObj(o, IM_GC); - if (ttype(im) != LUA_T_NIL) { - *L->stack.top = *o; - incr_top; - luaD_callTM(im, 1, 0); +static int protectedparser (lua_State *L, ZIO *z, int bin) { + struct ParserS p; + unsigned long old_blocks; + int status; + p.z = z; p.bin = bin; + luaC_checkGC(L); + old_blocks = L->nblocks; + status = luaD_runprotected(L, f_parser, &p); + if (status == 0) { + /* add new memory to threshold (as it probably will stay) */ + L->GCthreshold += (L->nblocks - old_blocks); } + else if (status == LUA_ERRRUN) /* an error occurred: correct error code */ + status = LUA_ERRSYNTAX; + return status; } -#define MAXFILENAME 260 /* maximum part of a file name kept */ - -int lua_dofile (char *filename) { +static int parse_file (lua_State *L, const char *filename) { ZIO z; int status; - int c; - int bin; - char source[MAXFILENAME]; + int bin; /* flag for file mode */ + int c; /* look ahead char */ FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); - if (f == NULL) - return 2; - luaL_filesource(source, filename, sizeof(source)); + if (f == NULL) return LUA_ERRFILE; /* unable to open file */ c = fgetc(f); ungetc(c, f); bin = (c == ID_CHUNK); if (bin && f != stdin) { f = freopen(filename, "rb", f); /* set binary mode */ - if (f == NULL) return 2; + if (f == NULL) return LUA_ERRFILE; /* unable to reopen file */ } - luaZ_Fopen(&z, f, source); - status = do_main(&z, bin); + lua_pushstring(L, "@"); + lua_pushstring(L, (filename == NULL) ? "(stdin)" : filename); + lua_concat(L, 2); + filename = lua_tostring(L, -1); /* filename = '@'..filename */ + lua_pop(L, 1); /* OK: there is no GC during parser */ + luaZ_Fopen(&z, f, filename); + status = protectedparser(L, &z, bin); if (f != stdin) fclose(f); return status; } -int lua_dostring (char *str) { - return lua_dobuffer(str, strlen(str), str); +LUA_API int lua_dofile (lua_State *L, const char *filename) { + int status = parse_file(L, filename); + if (status == 0) /* parse OK? */ + status = lua_call(L, 0, LUA_MULTRET); /* call main */ + return status; } -int lua_dobuffer (char *buff, int size, char *name) { +static int parse_buffer (lua_State *L, const char *buff, size_t size, + const char *name) { ZIO z; if (!name) name = "?"; luaZ_mopen(&z, buff, size, name); - return do_main(&z, buff[0]==ID_CHUNK); + return protectedparser(L, &z, buff[0]==ID_CHUNK); } + +LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name) { + int status = parse_buffer(L, buff, size, name); + if (status == 0) /* parse OK? */ + status = lua_call(L, 0, LUA_MULTRET); /* call main */ + return status; +} + + +LUA_API int lua_dostring (lua_State *L, const char *str) { + return lua_dobuffer(L, str, strlen(str), str); +} + + +/* +** {====================================================== +** Error-recover functions (based on long jumps) +** ======================================================= +*/ + +/* chain list of long jump buffers */ +struct lua_longjmp { + jmp_buf b; + struct lua_longjmp *previous; + volatile int status; /* error code */ +}; + + +static void message (lua_State *L, const char *s) { + const TObject *em = luaH_getglobal(L, LUA_ERRORMESSAGE); + if (ttype(em) == LUA_TFUNCTION) { + *L->top = *em; + incr_top; + lua_pushstring(L, s); + luaD_call(L, L->top-2, 0); + } +} + + +/* +** Reports an error, and jumps up to the available recovery label +*/ +LUA_API void lua_error (lua_State *L, const char *s) { + if (s) message(L, s); + luaD_breakrun(L, LUA_ERRRUN); +} + + +void luaD_breakrun (lua_State *L, int errcode) { + if (L->errorJmp) { + L->errorJmp->status = errcode; + longjmp(L->errorJmp->b, 1); + } + else { + if (errcode != LUA_ERRMEM) + message(L, "unable to recover; exiting\n"); + exit(EXIT_FAILURE); + } +} + + +int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) { + StkId oldCbase = L->Cbase; + StkId oldtop = L->top; + struct lua_longjmp lj; + int allowhooks = L->allowhooks; + lj.status = 0; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + if (setjmp(lj.b) == 0) + (*f)(L, ud); + else { /* an error occurred: restore the state */ + L->allowhooks = allowhooks; + L->Cbase = oldCbase; + L->top = oldtop; + restore_stack_limit(L); + } + L->errorJmp = lj.previous; /* restore old error handler */ + return lj.status; +} + +/* }====================================================== */ + diff --git a/src/ldo.h b/src/ldo.h index 01eec54092..3fba1f5650 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.6 1999/06/22 20:37:23 roberto Exp $ +** $Id: ldo.h,v 1.28 2000/10/06 12:45:25 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -12,35 +12,22 @@ #include "lstate.h" -#define MULT_RET 255 - - - /* ** macro to increment stack top. ** There must be always an empty slot at the L->stack.top */ -#define incr_top { if (L->stack.top >= L->stack.last) luaD_checkstack(1); \ - L->stack.top++; } - - -/* macros to convert from lua_Object to (TObject *) and back */ +#define incr_top {if (L->top == L->stack_last) luaD_checkstack(L, 1); L->top++;} -#define Address(lo) ((lo)+L->stack.stack-1) -#define Ref(st) ((st)-L->stack.stack+1) +void luaD_init (lua_State *L, int stacksize); +void luaD_adjusttop (lua_State *L, StkId base, int extra); +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, Closure *f, int nParams, int nResults); +void luaD_checkstack (lua_State *L, int n); -void luaD_init (void); -void luaD_adjusttop (StkId newtop); -void luaD_openstack (int nelems); -void luaD_lineHook (int line); -void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn); -void luaD_calln (int nArgs, int nResults); -void luaD_callTM (TObject *f, int nParams, int nResults); -int luaD_protectedrun (void); -void luaD_gcIM (TObject *o); -void luaD_travstack (int (*fn)(TObject *)); -void luaD_checkstack (int n); +void luaD_breakrun (lua_State *L, int errcode); +int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud); #endif diff --git a/src/lfunc.c b/src/lfunc.c index 7494e2cd1b..6841ef71a5 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 1.10 1999/03/04 21:17:26 roberto Exp $ +** $Id: lfunc.c,v 1.34 2000/10/30 12:20:29 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -7,92 +7,103 @@ #include +#include "lua.h" + #include "lfunc.h" #include "lmem.h" #include "lstate.h" -#define gcsizeproto(p) 5 /* approximate "weight" for a prototype */ -#define gcsizeclosure(c) 1 /* approximate "weight" for a closure */ +#define sizeclosure(n) ((int)sizeof(Closure) + (int)sizeof(TObject)*((n)-1)) -Closure *luaF_newclosure (int nelems) -{ - Closure *c = (Closure *)luaM_malloc(sizeof(Closure)+nelems*sizeof(TObject)); - luaO_insertlist(&(L->rootcl), (GCnode *)c); - L->nblocks += gcsizeclosure(c); - c->nelems = nelems; +Closure *luaF_newclosure (lua_State *L, int nelems) { + int size = sizeclosure(nelems); + Closure *c = (Closure *)luaM_malloc(L, size); + c->next = L->rootcl; + L->rootcl = c; + c->mark = c; + c->nupvalues = nelems; + L->nblocks += size; return c; } -TProtoFunc *luaF_newproto (void) -{ - TProtoFunc *f = luaM_new(TProtoFunc); +Proto *luaF_newproto (lua_State *L) { + Proto *f = luaM_new(L, Proto); + f->knum = NULL; + f->nknum = 0; + f->kstr = NULL; + f->nkstr = 0; + f->kproto = NULL; + f->nkproto = 0; f->code = NULL; + f->ncode = 0; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->marked = 0; + f->lineinfo = NULL; + f->nlineinfo = 0; + f->nlocvars = 0; + f->locvars = NULL; f->lineDefined = 0; f->source = NULL; - f->consts = NULL; - f->nconsts = 0; - f->locvars = NULL; - luaO_insertlist(&(L->rootproto), (GCnode *)f); - L->nblocks += gcsizeproto(f); + f->next = L->rootproto; /* chain in list of protos */ + L->rootproto = f; return f; } +static size_t protosize (Proto *f) { + return sizeof(Proto) + + f->nknum*sizeof(Number) + + f->nkstr*sizeof(TString *) + + f->nkproto*sizeof(Proto *) + + f->ncode*sizeof(Instruction) + + f->nlocvars*sizeof(struct LocVar) + + f->nlineinfo*sizeof(int); +} -static void freefunc (TProtoFunc *f) -{ - luaM_free(f->code); - luaM_free(f->locvars); - luaM_free(f->consts); - luaM_free(f); + +void luaF_protook (lua_State *L, Proto *f, int pc) { + f->ncode = pc; /* signal that proto was properly created */ + L->nblocks += protosize(f); } -void luaF_freeproto (TProtoFunc *l) -{ - while (l) { - TProtoFunc *next = (TProtoFunc *)l->head.next; - L->nblocks -= gcsizeproto(l); - freefunc(l); - l = next; - } +void luaF_freeproto (lua_State *L, Proto *f) { + if (f->ncode > 0) /* function was properly created? */ + L->nblocks -= protosize(f); + luaM_free(L, f->code); + luaM_free(L, f->locvars); + luaM_free(L, f->kstr); + luaM_free(L, f->knum); + luaM_free(L, f->kproto); + luaM_free(L, f->lineinfo); + luaM_free(L, f); } -void luaF_freeclosure (Closure *l) -{ - while (l) { - Closure *next = (Closure *)l->head.next; - L->nblocks -= gcsizeclosure(l); - luaM_free(l); - l = next; - } +void luaF_freeclosure (lua_State *L, Closure *c) { + L->nblocks -= sizeclosure(c->nupvalues); + luaM_free(L, c); } /* -** Look for n-th local variable at line "line" in function "func". +** Look for n-th local variable at line `line' in function `func'. ** Returns NULL if not found. */ -char *luaF_getlocalname (TProtoFunc *func, int local_number, int line) -{ - int count = 0; - char *varname = NULL; - LocVar *lv = func->locvars; - if (lv == NULL) - return NULL; - for (; lv->line != -1 && lv->line < line; lv++) { - if (lv->varname) { /* register */ - if (++count == local_number) - varname = lv->varname->str; +const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { + int i; + for (i = 0; inlocvars && f->locvars[i].startpc <= pc; i++) { + if (pc < f->locvars[i].endpc) { /* is variable active? */ + local_number--; + if (local_number == 0) + return f->locvars[i].varname->str; } - else /* unregister */ - if (--count < local_number) - varname = NULL; } - return varname; + return NULL; /* not found */ } diff --git a/src/lfunc.h b/src/lfunc.h index cade80a203..32afbc5d30 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,6 +1,6 @@ /* -** $Id: lfunc.h,v 1.5 1997/12/15 16:17:20 roberto Exp $ -** Lua Function structures +** $Id: lfunc.h,v 1.13 2000/09/29 12:42:13 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -12,12 +12,13 @@ -TProtoFunc *luaF_newproto (void); -Closure *luaF_newclosure (int nelems); -void luaF_freeproto (TProtoFunc *l); -void luaF_freeclosure (Closure *l); +Proto *luaF_newproto (lua_State *L); +void luaF_protook (lua_State *L, Proto *f, int pc); +Closure *luaF_newclosure (lua_State *L, int nelems); +void luaF_freeproto (lua_State *L, Proto *f); +void luaF_freeclosure (lua_State *L, Closure *c); -char *luaF_getlocalname (TProtoFunc *func, int local_number, int line); +const char *luaF_getlocalname (const Proto *func, int local_number, int pc); #endif diff --git a/src/lgc.c b/src/lgc.c index e153ce8c04..6b916a8b23 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,9 +1,10 @@ /* -** $Id: lgc.c,v 1.23 1999/03/04 21:17:26 roberto Exp $ +** $Id: lgc.c,v 1.72 2000/10/26 12:47:05 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ +#include "lua.h" #include "ldo.h" #include "lfunc.h" @@ -14,262 +15,339 @@ #include "lstring.h" #include "ltable.h" #include "ltm.h" -#include "lua.h" +typedef struct GCState { + Hash *tmark; /* list of marked tables to be visited */ + Closure *cmark; /* list of marked closures to be visited */ +} GCState; -static int markobject (TObject *o); +static void markobject (GCState *st, TObject *o); -/* -** ======================================================= -** REF mechanism -** ======================================================= -*/ +/* mark a string; marks larger than 1 cannot be changed */ +#define strmark(s) {if ((s)->marked == 0) (s)->marked = 1;} -int luaC_ref (TObject *o, int lock) { - int ref; - if (ttype(o) == LUA_T_NIL) - ref = -1; /* special ref for nil */ - else { - for (ref=0; refrefSize; ref++) - if (L->refArray[ref].status == FREE) - break; - if (ref == L->refSize) { /* no more empty spaces? */ - luaM_growvector(L->refArray, L->refSize, 1, struct ref, refEM, MAX_INT); - L->refSize++; - } - L->refArray[ref].o = *o; - L->refArray[ref].status = lock ? LOCK : HOLD; + + +static void protomark (Proto *f) { + if (!f->marked) { + int i; + f->marked = 1; + strmark(f->source); + for (i=0; inkstr; i++) + strmark(f->kstr[i]); + for (i=0; inkproto; i++) + protomark(f->kproto[i]); + for (i=0; inlocvars; i++) /* mark local-variable names */ + strmark(f->locvars[i].varname); } - return ref; } -void lua_unref (int ref) -{ - if (ref >= 0 && ref < L->refSize) - L->refArray[ref].status = FREE; +static void markstack (lua_State *L, GCState *st) { + StkId o; + for (o=L->stack; otop; o++) + markobject(st, o); } -TObject* luaC_getref (int ref) -{ - if (ref == -1) - return &luaO_nilobject; - if (ref >= 0 && ref < L->refSize && - (L->refArray[ref].status == LOCK || L->refArray[ref].status == HOLD)) - return &L->refArray[ref].o; - else - return NULL; +static void marklock (lua_State *L, GCState *st) { + int i; + for (i=0; irefSize; i++) { + if (L->refArray[i].st == LOCK) + markobject(st, &L->refArray[i].o); + } } -static void travlock (void) -{ - int i; - for (i=0; irefSize; i++) - if (L->refArray[i].status == LOCK) - markobject(&L->refArray[i].o); +static void markclosure (GCState *st, Closure *cl) { + if (!ismarked(cl)) { + if (!cl->isC) + protomark(cl->f.l); + cl->mark = st->cmark; /* chain it for later traversal */ + st->cmark = cl; + } +} + + +static void marktagmethods (lua_State *L, GCState *st) { + int e; + for (e=0; elast_tag; t++) { + Closure *cl = luaT_gettm(L, t, e); + if (cl) markclosure(st, cl); + } + } +} + + +static void markobject (GCState *st, TObject *o) { + switch (ttype(o)) { + case LUA_TUSERDATA: case LUA_TSTRING: + strmark(tsvalue(o)); + break; + case LUA_TMARK: + markclosure(st, infovalue(o)->func); + break; + case LUA_TFUNCTION: + markclosure(st, clvalue(o)); + break; + case LUA_TTABLE: { + if (!ismarked(hvalue(o))) { + hvalue(o)->mark = st->tmark; /* chain it in list of marked */ + st->tmark = hvalue(o); + } + break; + } + default: break; /* numbers, etc */ + } +} + + +static void markall (lua_State *L) { + GCState st; + st.cmark = NULL; + st.tmark = L->gt; /* put table of globals in mark list */ + L->gt->mark = NULL; + marktagmethods(L, &st); /* mark tag methods */ + markstack(L, &st); /* mark stack objects */ + marklock(L, &st); /* mark locked objects */ + for (;;) { /* mark tables and closures */ + if (st.cmark) { + int i; + Closure *f = st.cmark; /* get first closure from list */ + st.cmark = f->mark; /* remove it from list */ + for (i=0; inupvalues; i++) /* mark its upvalues */ + markobject(&st, &f->upvalue[i]); + } + else if (st.tmark) { + int i; + Hash *h = st.tmark; /* get first table from list */ + st.tmark = h->mark; /* remove it from list */ + for (i=0; isize; i++) { + Node *n = node(h, i); + if (ttype(key(n)) != LUA_TNIL) { + if (ttype(val(n)) == LUA_TNIL) + luaH_remove(h, key(n)); /* dead element; try to remove it */ + markobject(&st, &n->key); + markobject(&st, &n->val); + } + } + } + else break; /* nothing else to mark */ + } } -static int ismarked (TObject *o) -{ +static int hasmark (const TObject *o) { /* valid only for locked objects */ switch (o->ttype) { - case LUA_T_STRING: case LUA_T_USERDATA: - return o->value.ts->head.marked; - case LUA_T_ARRAY: - return o->value.a->head.marked; - case LUA_T_CLOSURE: - return o->value.cl->head.marked; - case LUA_T_PROTO: - return o->value.tf->head.marked; -#ifdef DEBUG - case LUA_T_LINE: case LUA_T_CLMARK: - case LUA_T_CMARK: case LUA_T_PMARK: - LUA_INTERNALERROR("invalid type"); -#endif - default: /* nil, number or cproto */ + case LUA_TSTRING: case LUA_TUSERDATA: + return tsvalue(o)->marked; + case LUA_TTABLE: + return ismarked(hvalue(o)); + case LUA_TFUNCTION: + return ismarked(clvalue(o)); + default: /* number */ return 1; } } -static void invalidaterefs (void) -{ +/* macro for internal debugging; check if a link of free refs is valid */ +#define VALIDLINK(L, st,n) (NONEXT <= (st) && (st) < (n)) + +static void invalidaterefs (lua_State *L) { + int n = L->refSize; int i; - for (i=0; irefSize; i++) - if (L->refArray[i].status == HOLD && !ismarked(&L->refArray[i].o)) - L->refArray[i].status = COLLECTED; + for (i=0; irefArray[i]; + if (r->st == HOLD && !hasmark(&r->o)) + r->st = COLLECTED; + LUA_ASSERT((r->st == LOCK && hasmark(&r->o)) || + (r->st == HOLD && hasmark(&r->o)) || + r->st == COLLECTED || + r->st == NONEXT || + (r->st < n && VALIDLINK(L, L->refArray[r->st].st, n)), + "inconsistent ref table"); + } + LUA_ASSERT(VALIDLINK(L, L->refFree, n), "inconsistent ref table"); } -void luaC_hashcallIM (Hash *l) -{ - TObject t; - ttype(&t) = LUA_T_ARRAY; - for (; l; l=(Hash *)l->head.next) { - avalue(&t) = l; - luaD_gcIM(&t); +static void collectproto (lua_State *L) { + Proto **p = &L->rootproto; + Proto *next; + while ((next = *p) != NULL) { + if (next->marked) { + next->marked = 0; + p = &next->next; + } + else { + *p = next->next; + luaF_freeproto(L, next); + } } } -void luaC_strcallIM (TaggedString *l) -{ - TObject o; - ttype(&o) = LUA_T_USERDATA; - for (; l; l=(TaggedString *)l->head.next) - if (l->constindex == -1) { /* is userdata? */ - tsvalue(&o) = l; - luaD_gcIM(&o); +static void collectclosure (lua_State *L) { + Closure **p = &L->rootcl; + Closure *next; + while ((next = *p) != NULL) { + if (ismarked(next)) { + next->mark = next; /* unmark */ + p = &next->next; + } + else { + *p = next->next; + luaF_freeclosure(L, next); } + } } - -static GCnode *listcollect (GCnode *l) -{ - GCnode *frees = NULL; - while (l) { - GCnode *next = l->next; - l->marked = 0; - while (next && !next->marked) { - l->next = next->next; - next->next = frees; - frees = next; - next = l->next; +static void collecttable (lua_State *L) { + Hash **p = &L->roottable; + Hash *next; + while ((next = *p) != NULL) { + if (ismarked(next)) { + next->mark = next; /* unmark */ + p = &next->next; + } + else { + *p = next->next; + luaH_free(L, next); } - l = next; } - return frees; } -static void strmark (TaggedString *s) -{ - if (!s->head.marked) - s->head.marked = 1; +static void checktab (lua_State *L, stringtable *tb) { + if (tb->nuse < (lint32)(tb->size/4) && tb->size > 10) + luaS_resize(L, tb, tb->size/2); /* table is too big */ } -static void protomark (TProtoFunc *f) { - if (!f->head.marked) { - int i; - f->head.marked = 1; - strmark(f->source); - for (i=0; inconsts; i++) - markobject(&f->consts[i]); +static void collectstrings (lua_State *L, int all) { + int i; + for (i=0; istrt.size; i++) { /* for each list */ + TString **p = &L->strt.hash[i]; + TString *next; + while ((next = *p) != NULL) { + if (next->marked && !all) { /* preserve? */ + if (next->marked < FIXMARK) /* does not change FIXMARKs */ + next->marked = 0; + p = &next->nexthash; + } + else { /* collect */ + *p = next->nexthash; + L->strt.nuse--; + L->nblocks -= sizestring(next->len); + luaM_free(L, next); + } + } } + checktab(L, &L->strt); } -static void closuremark (Closure *f) -{ - if (!f->head.marked) { - int i; - f->head.marked = 1; - for (i=f->nelems; i>=0; i--) - markobject(&f->consts[i]); +static void collectudata (lua_State *L, int all) { + int i; + for (i=0; iudt.size; i++) { /* for each list */ + TString **p = &L->udt.hash[i]; + TString *next; + while ((next = *p) != NULL) { + LUA_ASSERT(next->marked <= 1, "udata cannot be fixed"); + if (next->marked && !all) { /* preserve? */ + next->marked = 0; + p = &next->nexthash; + } + else { /* collect */ + int tag = next->u.d.tag; + *p = next->nexthash; + next->nexthash = L->TMtable[tag].collected; /* chain udata */ + L->TMtable[tag].collected = next; + L->nblocks -= sizestring(next->len); + L->udt.nuse--; + } + } } + checktab(L, &L->udt); } -static void hashmark (Hash *h) -{ - if (!h->head.marked) { - int i; - h->head.marked = 1; - for (i=0; iref); - markobject(&n->val); - } - } +#define MINBUFFER 256 +static void checkMbuffer (lua_State *L) { + if (L->Mbuffsize > MINBUFFER*2) { /* is buffer too big? */ + size_t newsize = L->Mbuffsize/2; /* still larger than MINBUFFER */ + L->nblocks += (newsize - L->Mbuffsize)*sizeof(char); + L->Mbuffsize = newsize; + luaM_reallocvector(L, L->Mbuffer, newsize, char); } } -static void globalmark (void) -{ - TaggedString *g; - for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next){ - LUA_ASSERT(g->constindex >= 0, "userdata in global list"); - if (g->u.s.globalval.ttype != LUA_T_NIL) { - markobject(&g->u.s.globalval); - strmark(g); /* cannot collect non nil global variables */ - } +static void callgcTM (lua_State *L, const TObject *o) { + Closure *tm = luaT_gettmbyObj(L, o, TM_GC); + if (tm != NULL) { + int oldah = L->allowhooks; + L->allowhooks = 0; /* stop debug hooks during GC tag methods */ + luaD_checkstack(L, 2); + clvalue(L->top) = tm; + ttype(L->top) = LUA_TFUNCTION; + *(L->top+1) = *o; + L->top += 2; + luaD_call(L, L->top-2, 0); + L->allowhooks = oldah; /* restore hooks */ } } -static int markobject (TObject *o) -{ - switch (ttype(o)) { - case LUA_T_USERDATA: case LUA_T_STRING: - strmark(tsvalue(o)); - break; - case LUA_T_ARRAY: - hashmark(avalue(o)); - break; - case LUA_T_CLOSURE: case LUA_T_CLMARK: - closuremark(o->value.cl); - break; - case LUA_T_PROTO: case LUA_T_PMARK: - protomark(o->value.tf); - break; - default: break; /* numbers, cprotos, etc */ +static void callgcTMudata (lua_State *L) { + int tag; + TObject o; + ttype(&o) = LUA_TUSERDATA; + L->GCthreshold = 2*L->nblocks; /* avoid GC during tag methods */ + for (tag=L->last_tag; tag>=0; tag--) { /* for each tag (in reverse order) */ + TString *udata; + while ((udata = L->TMtable[tag].collected) != NULL) { + L->TMtable[tag].collected = udata->nexthash; /* remove it from list */ + tsvalue(&o) = udata; + callgcTM(L, &o); + luaM_free(L, udata); + } } - return 0; } - -static void markall (void) -{ - luaD_travstack(markobject); /* mark stack objects */ - globalmark(); /* mark global variable values and names */ - travlock(); /* mark locked objects */ - luaT_travtagmethods(markobject); /* mark fallbacks */ +void luaC_collect (lua_State *L, int all) { + collectudata(L, all); + callgcTMudata(L); + collectstrings(L, all); + collecttable(L); + collectproto(L); + collectclosure(L); } -long lua_collectgarbage (long limit) -{ - unsigned long recovered = L->nblocks; /* to subtract nblocks after gc */ - Hash *freetable; - TaggedString *freestr; - TProtoFunc *freefunc; - Closure *freeclos; - markall(); - invalidaterefs(); - freestr = luaS_collector(); - freetable = (Hash *)listcollect(&(L->roottable)); - freefunc = (TProtoFunc *)listcollect(&(L->rootproto)); - freeclos = (Closure *)listcollect(&(L->rootcl)); - L->GCthreshold *= 4; /* to avoid GC during GC */ - luaC_hashcallIM(freetable); /* GC tag methods for tables */ - luaC_strcallIM(freestr); /* GC tag methods for userdata */ - luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */ - luaH_free(freetable); - luaS_free(freestr); - luaF_freeproto(freefunc); - luaF_freeclosure(freeclos); - recovered = recovered-L->nblocks; - L->GCthreshold = (limit == 0) ? 2*L->nblocks : L->nblocks+limit; - return recovered; +static void luaC_collectgarbage (lua_State *L) { + markall(L); + invalidaterefs(L); /* check unlocked references */ + luaC_collect(L, 0); + checkMbuffer(L); + L->GCthreshold = 2*L->nblocks; /* set new threshold */ + callgcTM(L, &luaO_nilobject); } -void luaC_checkGC (void) -{ +void luaC_checkGC (lua_State *L) { if (L->nblocks >= L->GCthreshold) - lua_collectgarbage(0); + luaC_collectgarbage(L); } diff --git a/src/lgc.h b/src/lgc.h index 38b09553be..87a14d1695 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 1.4 1997/12/01 20:31:25 roberto Exp $ +** $Id: lgc.h,v 1.8 2000/10/02 14:47:43 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -11,11 +11,8 @@ #include "lobject.h" -void luaC_checkGC (void); -TObject* luaC_getref (int ref); -int luaC_ref (TObject *o, int lock); -void luaC_hashcallIM (Hash *l); -void luaC_strcallIM (TaggedString *l); +void luaC_collect (lua_State *L, int all); +void luaC_checkGC (lua_State *L); #endif diff --git a/src/lib/Makefile b/src/lib/Makefile index 5d8664c9ab..081b886721 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -1,4 +1,4 @@ -# makefile for lua standard library +# makefile for Lua standard library LUA= ../.. @@ -7,8 +7,8 @@ include $(LUA)/config # actually only used in liolib.c EXTRA_DEFS= $(POPEN) -OBJS= linit.o ldblib.o liolib.o lmathlib.o lstrlib.o -SRCS= linit.c ldblib.c liolib.c lmathlib.c lstrlib.c +OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o lstrlib.o +SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c T= $(LIB)/liblualib.a diff --git a/src/lib/README b/src/lib/README index e8e599c8a7..c04a12e26f 100644 --- a/src/lib/README +++ b/src/lib/README @@ -1,4 +1,6 @@ This is the standard Lua library. It is implemented entirely on top of the official Lua API as declared in lua.h, -using src/lauxlib.c, which contains several useful functions. -The code can be read as an example of how to export C functions to Lua. +using lauxlib.c, which contains several useful functions for writing libraries. +We encourage developers to use lauxlib.c in their own libraries. +The code of the standard library can be read as an example of how to export +C functions to Lua. diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c new file mode 100644 index 0000000000..4bdaeeff8e --- /dev/null +++ b/src/lib/lauxlib.c @@ -0,0 +1,216 @@ +/* +** $Id: lauxlib.c,v 1.43 2000/10/30 13:07:48 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +/* This file uses only the official API of Lua. +** Any function declared here could be written as an application function. +** With care, these functions can be used by other libraries. +*/ + +#include "lua.h" + +#include "lauxlib.h" +#include "luadebug.h" + + + +LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { + int i; + for (i=0; list[i]; i++) + if (strcmp(list[i], name) == 0) + return i; + return -1; /* name not found */ +} + +LUALIB_API void luaL_argerror (lua_State *L, int narg, const char *extramsg) { + lua_Debug ar; + lua_getstack(L, 0, &ar); + lua_getinfo(L, "n", &ar); + if (ar.name == NULL) + ar.name = "?"; + luaL_verror(L, "bad argument #%d to `%.50s' (%.100s)", + narg, ar.name, extramsg); +} + + +static void type_error (lua_State *L, int narg, int t) { + char buff[50]; + sprintf(buff, "%.8s expected, got %.8s", lua_typename(L, t), + lua_typename(L, lua_type(L, narg))); + luaL_argerror(L, narg, buff); +} + + +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { + if (space > lua_stackspace(L)) + luaL_verror(L, "stack overflow (%.30s)", mes); +} + + +LUALIB_API void luaL_checktype(lua_State *L, int narg, int t) { + if (lua_type(L, narg) != t) + type_error(L, narg, t); +} + + +LUALIB_API void luaL_checkany (lua_State *L, int narg) { + if (lua_type(L, narg) == LUA_TNONE) + luaL_argerror(L, narg, "value expected"); +} + + +LUALIB_API const char *luaL_check_lstr (lua_State *L, int narg, size_t *len) { + const char *s = lua_tostring(L, narg); + if (!s) type_error(L, narg, LUA_TSTRING); + if (len) *len = lua_strlen(L, narg); + return s; +} + + +LUALIB_API const char *luaL_opt_lstr (lua_State *L, int narg, const char *def, size_t *len) { + if (lua_isnull(L, narg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_check_lstr(L, narg, len); +} + + +LUALIB_API double luaL_check_number (lua_State *L, int narg) { + double d = lua_tonumber(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + type_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API double luaL_opt_number (lua_State *L, int narg, double def) { + if (lua_isnull(L, narg)) return def; + else return luaL_check_number(L, narg); +} + + +LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n) { + int i; + for (i=0; ip == (B)->buffer) +#define bufflen(B) ((B)->p - (B)->buffer) +#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) + +#define LIMIT (LUA_MINSTACK/2) + + +static int emptybuffer (luaL_Buffer *B) { + size_t l = bufflen(B); + if (l == 0) return 0; /* put nothing on stack */ + else { + lua_pushlstring(B->L, B->buffer, l); + B->p = B->buffer; + B->level++; + return 1; + } +} + + +static void adjuststack (luaL_Buffer *B) { + if (B->level > 1) { + lua_State *L = B->L; + int toget = 1; /* number of levels to concat */ + size_t toplen = lua_strlen(L, -1); + do { + size_t l = lua_strlen(L, -(toget+1)); + if (B->level - toget + 1 >= LIMIT || toplen > l) { + toplen += l; + toget++; + } + else break; + } while (toget < B->level); + if (toget >= 2) { + lua_concat(L, toget); + B->level = B->level - toget + 1; + } + } +} + + +LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { + if (emptybuffer(B)) + adjuststack(B); + return B->buffer; +} + + +LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { + while (l--) + luaL_putchar(B, *s++); +} + + +LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { + luaL_addlstring(B, s, strlen(s)); +} + + +LUALIB_API void luaL_pushresult (luaL_Buffer *B) { + emptybuffer(B); + if (B->level == 0) + lua_pushlstring(B->L, NULL, 0); + else if (B->level > 1) + lua_concat(B->L, B->level); + B->level = 1; +} + + +LUALIB_API void luaL_addvalue (luaL_Buffer *B) { + lua_State *L = B->L; + size_t vl = lua_strlen(L, -1); + if (vl <= bufffree(B)) { /* fit into buffer? */ + memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */ + B->p += vl; + lua_pop(L, 1); /* remove from stack */ + } + else { + if (emptybuffer(B)) + lua_insert(L, -2); /* put buffer before new value */ + B->level++; /* add new value into B stack */ + adjuststack(B); + } +} + + +LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + B->L = L; + B->p = B->buffer; + B->level = 0; +} + +/* }====================================================== */ diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c new file mode 100644 index 0000000000..1ff475f9f7 --- /dev/null +++ b/src/lib/lbaselib.c @@ -0,0 +1,651 @@ +/* +** $Id: lbaselib.c,v 1.17 2000/11/06 13:45:18 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "luadebug.h" +#include "lualib.h" + + + +/* +** If your system does not support `stderr', redefine this function, or +** redefine _ERRORMESSAGE so that it won't need _ALERT. +*/ +static int luaB__ALERT (lua_State *L) { + fputs(luaL_check_string(L, 1), stderr); + return 0; +} + + +/* +** Basic implementation of _ERRORMESSAGE. +** The library `liolib' redefines _ERRORMESSAGE for better error information. +*/ +static int luaB__ERRORMESSAGE (lua_State *L) { + luaL_checktype(L, 1, LUA_TSTRING); + lua_getglobal(L, LUA_ALERT); + if (lua_isfunction(L, -1)) { /* avoid error loop if _ALERT is not defined */ + lua_Debug ar; + lua_pushstring(L, "error: "); + lua_pushvalue(L, 1); + if (lua_getstack(L, 1, &ar)) { + lua_getinfo(L, "Sl", &ar); + if (ar.source && ar.currentline > 0) { + char buff[100]; + sprintf(buff, "\n <%.70s: line %d>", ar.short_src, ar.currentline); + lua_pushstring(L, buff); + lua_concat(L, 2); + } + } + lua_pushstring(L, "\n"); + lua_concat(L, 3); + lua_rawcall(L, 1, 0); + } + return 0; +} + + +/* +** If your system does not support `stdout', you can just remove this function. +** If you need, you can define your own `print' function, following this +** model but changing `fputs' to put the strings at a proper place +** (a console window or a log file, for instance). +*/ +static int luaB_print (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + const char *s; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_rawcall(L, 1, 1); + s = lua_tostring(L, -1); /* get result */ + if (s == NULL) + lua_error(L, "`tostring' must return a string to `print'"); + if (i>1) fputs("\t", stdout); + fputs(s, stdout); + lua_pop(L, 1); /* pop result */ + } + fputs("\n", stdout); + return 0; +} + + +static int luaB_tonumber (lua_State *L) { + int base = luaL_opt_int(L, 2, 10); + if (base == 10) { /* standard conversion */ + luaL_checkany(L, 1); + if (lua_isnumber(L, 1)) { + lua_pushnumber(L, lua_tonumber(L, 1)); + return 1; + } + } + else { + const char *s1 = luaL_check_string(L, 1); + char *s2; + unsigned long n; + luaL_arg_check(L, 2 <= base && base <= 36, 2, "base out of range"); + n = strtoul(s1, &s2, base); + if (s1 != s2) { /* at least one valid digit? */ + while (isspace((unsigned char)*s2)) s2++; /* skip trailing spaces */ + if (*s2 == '\0') { /* no invalid trailing characters? */ + lua_pushnumber(L, n); + return 1; + } + } + } + lua_pushnil(L); /* else not a number */ + return 1; +} + + +static int luaB_error (lua_State *L) { + lua_error(L, luaL_opt_string(L, 1, NULL)); + return 0; /* to avoid warnings */ +} + +static int luaB_setglobal (lua_State *L) { + luaL_checkany(L, 2); + lua_setglobal(L, luaL_check_string(L, 1)); + return 0; +} + +static int luaB_getglobal (lua_State *L) { + lua_getglobal(L, luaL_check_string(L, 1)); + return 1; +} + +static int luaB_tag (lua_State *L) { + luaL_checkany(L, 1); + lua_pushnumber(L, lua_tag(L, 1)); + return 1; +} + +static int luaB_settag (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, 1); /* push table */ + lua_settag(L, luaL_check_int(L, 2)); + return 1; /* return table */ +} + +static int luaB_newtag (lua_State *L) { + lua_pushnumber(L, lua_newtag(L)); + return 1; +} + +static int luaB_copytagmethods (lua_State *L) { + lua_pushnumber(L, lua_copytagmethods(L, luaL_check_int(L, 1), + luaL_check_int(L, 2))); + return 1; +} + +static int luaB_globals (lua_State *L) { + lua_getglobals(L); /* value to be returned */ + if (!lua_isnull(L, 1)) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, 1); /* new table of globals */ + lua_setglobals(L); + } + return 1; +} + +static int luaB_rawget (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_rawget(L, -2); + return 1; +} + +static int luaB_rawset (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_rawset(L, -3); + return 1; +} + +static int luaB_settagmethod (lua_State *L) { + int tag = luaL_check_int(L, 1); + const char *event = luaL_check_string(L, 2); + luaL_arg_check(L, lua_isfunction(L, 3) || lua_isnil(L, 3), 3, + "function or nil expected"); + if (strcmp(event, "gc") == 0) + lua_error(L, "deprecated use: cannot set the `gc' tag method from Lua"); + lua_gettagmethod(L, tag, event); + lua_pushvalue(L, 3); + lua_settagmethod(L, tag, event); + return 1; +} + + +static int luaB_gettagmethod (lua_State *L) { + int tag = luaL_check_int(L, 1); + const char *event = luaL_check_string(L, 2); + if (strcmp(event, "gc") == 0) + lua_error(L, "deprecated use: cannot get the `gc' tag method from Lua"); + lua_gettagmethod(L, tag, event); + return 1; +} + + +static int luaB_gcinfo (lua_State *L) { + lua_pushnumber(L, lua_getgccount(L)); + lua_pushnumber(L, lua_getgcthreshold(L)); + return 2; +} + + +static int luaB_collectgarbage (lua_State *L) { + lua_setgcthreshold(L, luaL_opt_int(L, 1, 0)); + return 0; +} + + +static int luaB_type (lua_State *L) { + luaL_checkany(L, 1); + lua_pushstring(L, lua_typename(L, lua_type(L, 1))); + return 1; +} + + +static int luaB_next (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1)) + return 2; + else { + lua_pushnil(L); + return 1; + } +} + + +static int passresults (lua_State *L, int status, int oldtop) { + static const char *const errornames[] = + {"ok", "run-time error", "file error", "syntax error", + "memory error", "error in error handling"}; + if (status == 0) { + int nresults = lua_gettop(L) - oldtop; + if (nresults > 0) + return nresults; /* results are already on the stack */ + else { + lua_pushuserdata(L, NULL); /* at least one result to signal no errors */ + return 1; + } + } + else { /* error */ + lua_pushnil(L); + lua_pushstring(L, errornames[status]); /* error code */ + return 2; + } +} + +static int luaB_dostring (lua_State *L) { + int oldtop = lua_gettop(L); + size_t l; + const char *s = luaL_check_lstr(L, 1, &l); + if (*s == '\27') /* binary files start with ESC... */ + lua_error(L, "`dostring' cannot run pre-compiled code"); + return passresults(L, lua_dobuffer(L, s, l, luaL_opt_string(L, 2, s)), oldtop); +} + + +static int luaB_dofile (lua_State *L) { + int oldtop = lua_gettop(L); + const char *fname = luaL_opt_string(L, 1, NULL); + return passresults(L, lua_dofile(L, fname), oldtop); +} + + +static int luaB_call (lua_State *L) { + int oldtop; + const char *options = luaL_opt_string(L, 3, ""); + int err = 0; /* index of old error method */ + int i, status; + int n; + luaL_checktype(L, 2, LUA_TTABLE); + n = lua_getn(L, 2); + if (!lua_isnull(L, 4)) { /* set new error method */ + lua_getglobal(L, LUA_ERRORMESSAGE); + err = lua_gettop(L); /* get index */ + lua_pushvalue(L, 4); + lua_setglobal(L, LUA_ERRORMESSAGE); + } + oldtop = lua_gettop(L); /* top before function-call preparation */ + /* push function */ + lua_pushvalue(L, 1); + luaL_checkstack(L, n, "too many arguments"); + for (i=0; i=pos; n--) { + lua_rawgeti(L, 1, n); + lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ + } + lua_pushvalue(L, v); + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int luaB_tremove (lua_State *L) { + int pos, n; + luaL_checktype(L, 1, LUA_TTABLE); + n = lua_getn(L, 1); + pos = luaL_opt_int(L, 2, n); + if (n <= 0) return 0; /* table is "empty" */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos= P */ + while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i>u) lua_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* repeat --j until a[j] <= P */ + while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j #include #include -#include "lauxlib.h" #include "lua.h" + +#include "lauxlib.h" #include "luadebug.h" #include "lualib.h" -static void settabss (lua_Object t, char *i, char *v) { - lua_pushobject(t); - lua_pushstring(i); - lua_pushstring(v); - lua_settable(); +static void settabss (lua_State *L, const char *i, const char *v) { + lua_pushstring(L, i); + lua_pushstring(L, v); + lua_settable(L, -3); } -static void settabsi (lua_Object t, char *i, int v) { - lua_pushobject(t); - lua_pushstring(i); - lua_pushnumber(v); - lua_settable(); +static void settabsi (lua_State *L, const char *i, int v) { + lua_pushstring(L, i); + lua_pushnumber(L, v); + lua_settable(L, -3); } -static lua_Object getfuncinfo (lua_Object func) { - lua_Object result = lua_createtable(); - char *str; - int line; - lua_funcinfo(func, &str, &line); - if (line == -1) /* C function? */ - settabss(result, "kind", "C"); - else if (line == 0) { /* "main"? */ - settabss(result, "kind", "chunk"); - settabss(result, "source", str); +static int getinfo (lua_State *L) { + lua_Debug ar; + const char *options = luaL_opt_string(L, 2, "flnSu"); + char buff[20]; + if (lua_isnumber(L, 1)) { + if (!lua_getstack(L, (int)lua_tonumber(L, 1), &ar)) { + lua_pushnil(L); /* level out of range */ + return 1; } - else { /* Lua function */ - settabss(result, "kind", "Lua"); - settabsi(result, "def_line", line); - settabss(result, "source", str); } - if (line != 0) { /* is it not a "main"? */ - char *kind = lua_getobjname(func, &str); - if (*kind) { - settabss(result, "name", str); - settabss(result, "where", kind); + else if (lua_isfunction(L, 1)) { + lua_pushvalue(L, 1); + sprintf(buff, ">%.10s", options); + options = buff; + } + else + luaL_argerror(L, 1, "function or level expected"); + if (!lua_getinfo(L, options, &ar)) + luaL_argerror(L, 2, "invalid option"); + lua_newtable(L); + for (; *options; options++) { + switch (*options) { + case 'S': + settabss(L, "source", ar.source); + if (ar.source) + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabss(L, "what", ar.what); + break; + case 'l': + settabsi(L, "currentline", ar.currentline); + break; + case 'u': + settabsi(L, "nups", ar.nups); + break; + case 'n': + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + break; + case 'f': + lua_pushstring(L, "func"); + lua_pushvalue(L, -3); + lua_settable(L, -3); + break; } } - return result; + return 1; /* return table */ } - - -static void getstack (void) { - lua_Object func = lua_stackedfunction(luaL_check_int(1)); - if (func == LUA_NOOBJECT) /* level out of range? */ - return; - else { - lua_Object result = getfuncinfo(func); - int currline = lua_currentline(func); - if (currline > 0) - settabsi(result, "current", currline); - lua_pushobject(result); - lua_pushstring("func"); - lua_pushobject(func); - lua_settable(); /* result.func = func */ - lua_pushobject(result); + + +static int getlocal (lua_State *L) { + lua_Debug ar; + const char *name; + if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ + luaL_argerror(L, 1, "level out of range"); + name = lua_getlocal(L, &ar, luaL_check_int(L, 2)); + if (name) { + lua_pushstring(L, name); + lua_pushvalue(L, -2); + return 2; } -} - - -static void funcinfo (void) { - lua_pushobject(getfuncinfo(luaL_functionarg(1))); -} - - -static int findlocal (lua_Object func, int arg) { - lua_Object v = lua_getparam(arg); - if (lua_isnumber(v)) - return (int)lua_getnumber(v); else { - char *name = luaL_check_string(arg); - int i = 0; - int result = -1; - char *vname; - while (lua_getlocal(func, ++i, &vname) != LUA_NOOBJECT) { - if (strcmp(name, vname) == 0) - result = i; /* keep looping to get the last var with this name */ - } - if (result == -1) - luaL_verror("no local variable `%.50s' at given level", name); - return result; + lua_pushnil(L); + return 1; } } -static void getlocal (void) { - lua_Object func = lua_stackedfunction(luaL_check_int(1)); - lua_Object val; - char *name; - if (func == LUA_NOOBJECT) /* level out of range? */ - return; /* return nil */ - else if (lua_getparam(2) != LUA_NOOBJECT) { /* 2nd argument? */ - if ((val = lua_getlocal(func, findlocal(func, 2), &name)) != LUA_NOOBJECT) { - lua_pushobject(val); - lua_pushstring(name); - } - /* else return nil */ - } - else { /* collect all locals in a table */ - lua_Object result = lua_createtable(); - int i; - for (i=1; ;i++) { - if ((val = lua_getlocal(func, i, &name)) == LUA_NOOBJECT) - break; - lua_pushobject(result); - lua_pushstring(name); - lua_pushobject(val); - lua_settable(); /* result[name] = value */ - } - lua_pushobject(result); - } +static int setlocal (lua_State *L) { + lua_Debug ar; + if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ + luaL_argerror(L, 1, "level out of range"); + luaL_checkany(L, 3); + lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2))); + return 1; } -static void setlocal (void) { - lua_Object func = lua_stackedfunction(luaL_check_int(1)); - int numvar; - luaL_arg_check(func != LUA_NOOBJECT, 1, "level out of range"); - numvar = findlocal(func, 2); - lua_pushobject(luaL_nonnullarg(3)); - if (!lua_setlocal(func, numvar)) - lua_error("no such local variable"); -} +/* dummy variables (to define unique addresses) */ +static char key1, key2; +#define KEY_CALLHOOK (&key1) +#define KEY_LINEHOOK (&key2) -static int linehook = -1; /* Lua reference to line hook function */ -static int callhook = -1; /* Lua reference to call hook function */ +static void hookf (lua_State *L, void *key) { + lua_getregistry(L); + lua_pushuserdata(L, key); + lua_gettable(L, -2); + if (lua_isfunction(L, -1)) { + lua_pushvalue(L, 1); + lua_rawcall(L, 1, 0); + } + else + lua_pop(L, 1); /* pop result from gettable */ + lua_pop(L, 1); /* pop table */ +} -static void dohook (int ref) { - lua_LHFunction oldlinehook = lua_setlinehook(NULL); - lua_CHFunction oldcallhook = lua_setcallhook(NULL); - lua_callfunction(lua_getref(ref)); - lua_setlinehook(oldlinehook); - lua_setcallhook(oldcallhook); +static void callf (lua_State *L, lua_Debug *ar) { + lua_pushstring(L, ar->event); + hookf(L, KEY_CALLHOOK); } -static void linef (int line) { - lua_pushnumber(line); - dohook(linehook); +static void linef (lua_State *L, lua_Debug *ar) { + lua_pushnumber(L, ar->currentline); + hookf(L, KEY_LINEHOOK); } -static void callf (lua_Function func, char *file, int line) { - if (func != LUA_NOOBJECT) { - lua_pushobject(func); - lua_pushstring(file); - lua_pushnumber(line); - } - dohook(callhook); +static void sethook (lua_State *L, void *key, lua_Hook hook, + lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) { + lua_settop(L, 1); + if (lua_isnil(L, 1)) + (*sethookf)(L, NULL); + else if (lua_isfunction(L, 1)) + (*sethookf)(L, hook); + else + luaL_argerror(L, 1, "function expected"); + lua_getregistry(L); + lua_pushuserdata(L, key); + lua_pushvalue(L, -1); /* dup key */ + lua_gettable(L, -3); /* get old value */ + lua_pushvalue(L, -2); /* key (again) */ + lua_pushvalue(L, 1); + lua_settable(L, -5); /* set new value */ } -static void setcallhook (void) { - lua_Object f = lua_getparam(1); - lua_unref(callhook); - if (f == LUA_NOOBJECT) { - callhook = -1; - lua_setcallhook(NULL); - } - else { - lua_pushobject(f); - callhook = lua_ref(1); - lua_setcallhook(callf); - } +static int setcallhook (lua_State *L) { + sethook(L, KEY_CALLHOOK, callf, lua_setcallhook); + return 1; } -static void setlinehook (void) { - lua_Object f = lua_getparam(1); - lua_unref(linehook); - if (f == LUA_NOOBJECT) { - linehook = -1; - lua_setlinehook(NULL); - } - else { - lua_pushobject(f); - linehook = lua_ref(1); - lua_setlinehook(linef); - } +static int setlinehook (lua_State *L) { + sethook(L, KEY_LINEHOOK, linef, lua_setlinehook); + return 1; } -static struct luaL_reg dblib[] = { - {"funcinfo", funcinfo}, +static const struct luaL_reg dblib[] = { {"getlocal", getlocal}, - {"getstack", getstack}, + {"getinfo", getinfo}, {"setcallhook", setcallhook}, {"setlinehook", setlinehook}, {"setlocal", setlocal} }; -void lua_dblibopen (void) { - luaL_openlib(dblib, (sizeof(dblib)/sizeof(dblib[0]))); +LUALIB_API void lua_dblibopen (lua_State *L) { + luaL_openl(L, dblib); } diff --git a/src/lib/linit.c b/src/lib/linit.c deleted file mode 100644 index be57aae7ae..0000000000 --- a/src/lib/linit.c +++ /dev/null @@ -1,17 +0,0 @@ -/* -** $Id: linit.c,v 1.1 1999/01/08 16:49:32 roberto Exp $ -** Initialization of libraries for lua.c -** See Copyright Notice in lua.h -*/ - -#include "lua.h" -#include "lualib.h" - - -void lua_userinit (void) { - lua_iolibopen(); - lua_strlibopen(); - lua_mathlibopen(); - lua_dblibopen(); -} - diff --git a/src/lib/liolib.c b/src/lib/liolib.c index d833cec54c..70f8057ac9 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,67 +1,78 @@ /* -** $Id: liolib.c,v 1.41 1999/06/23 13:48:39 roberto Exp $ +** $Id: liolib.c,v 1.91 2000/10/31 13:10:24 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ -#include +#include #include #include #include #include -#include "lauxlib.h" #include "lua.h" + +#include "lauxlib.h" #include "luadebug.h" #include "lualib.h" #ifndef OLD_ANSI +#include #include +#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s)) +#define free(b) if (b) (free)(b) #else /* no support for locale and for strerror: fake them */ -#define setlocale(a,b) 0 +#define setlocale(a,b) ((void)a, strcmp((b),"C")==0?"C":NULL) #define LC_ALL 0 #define LC_COLLATE 0 #define LC_CTYPE 0 #define LC_MONETARY 0 #define LC_NUMERIC 0 #define LC_TIME 0 -#define strerror(e) "(no error message provided by operating system)" +#define strerror(e) "generic I/O error" +#define errno (-1) #endif -#define IOTAG 1 - -#define FIRSTARG 2 /* 1st is upvalue */ - -#define CLOSEDTAG(tag) ((tag)-1) /* assume that CLOSEDTAG = iotag-1 */ - - -#define FINPUT "_INPUT" -#define FOUTPUT "_OUTPUT" - #ifdef POPEN -FILE *popen(); -int pclose(); -#define CLOSEFILE(f) {if (pclose(f) == -1) fclose(f);} +/* FILE *popen(); +int pclose(); */ +#define CLOSEFILE(L, f) ((pclose(f) == -1) ? fclose(f) : 0) #else /* no support for popen */ #define popen(x,y) NULL /* that is, popen always fails */ -#define CLOSEFILE(f) {fclose(f);} +#define CLOSEFILE(L, f) (fclose(f)) #endif +#define INFILE 0 +#define OUTFILE 1 + +typedef struct IOCtrl { + int ref[2]; /* ref for strings _INPUT/_OUTPUT */ + int iotag; /* tag for file handles */ + int closedtag; /* tag for closed handles */ +} IOCtrl; + + + +static const char *const filenames[] = {"_INPUT", "_OUTPUT"}; -static void pushresult (int i) { - if (i) - lua_pushuserdata(NULL); + +static int pushresult (lua_State *L, int i) { + if (i) { + lua_pushuserdata(L, NULL); + return 1; + } else { - lua_pushnil(); - lua_pushstring(strerror(errno)); - lua_pushnumber(errno); + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + lua_pushnumber(L, errno); + return 3;; } } @@ -72,138 +83,138 @@ static void pushresult (int i) { ** ======================================================= */ -static int gettag (void) { - return (int)lua_getnumber(lua_getparam(IOTAG)); -} - -static int ishandle (lua_Object f) { - if (lua_isuserdata(f)) { - int tag = gettag(); - if (lua_tag(f) == CLOSEDTAG(tag)) - lua_error("cannot access a closed file"); - return lua_tag(f) == tag; +static FILE *gethandle (lua_State *L, IOCtrl *ctrl, int f) { + void *p = lua_touserdata(L, f); + if (p != NULL) { /* is `f' a userdata ? */ + int ftag = lua_tag(L, f); + if (ftag == ctrl->iotag) /* does it have the correct tag? */ + return (FILE *)p; + else if (ftag == ctrl->closedtag) + lua_error(L, "cannot access a closed file"); + /* else go through */ } - else return 0; + return NULL; } -static FILE *getfilebyname (char *name) { - lua_Object f = lua_getglobal(name); - if (!ishandle(f)) - luaL_verror("global variable `%.50s' is not a file handle", name); - return lua_getuserdata(f); -} - - -static FILE *getfile (int arg) { - lua_Object f = lua_getparam(arg); - return (ishandle(f)) ? lua_getuserdata(f) : NULL; +static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) { + FILE *f = gethandle(L, ctrl, arg); + luaL_arg_check(L, f, arg, "invalid file handle"); + return f; } -static FILE *getnonullfile (int arg) { - FILE *f = getfile(arg); - luaL_arg_check(f, arg, "invalid file handle"); +static FILE *getfilebyref (lua_State *L, IOCtrl *ctrl, int inout) { + FILE *f; + lua_getglobals(L); + lua_getref(L, ctrl->ref[inout]); + lua_rawget(L, -2); + f = gethandle(L, ctrl, -1); + if (f == NULL) + luaL_verror(L, "global variable `%.10s' is not a file handle", + filenames[inout]); return f; } -static FILE *getfileparam (char *name, int *arg) { - FILE *f = getfile(*arg); - if (f) { - (*arg)++; - return f; - } - else - return getfilebyname(name); +static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f, + const char *name) { + lua_pushusertag(L, f, ctrl->iotag); + lua_setglobal(L, name); } -static void closefile (FILE *f) { - if (f != stdin && f != stdout) { - int tag = gettag(); - CLOSEFILE(f); - lua_pushusertag(f, tag); - lua_settag(CLOSEDTAG(tag)); - } -} +#define setfile(L,ctrl,f,inout) (setfilebyname(L,ctrl,f,filenames[inout])) -static void io_close (void) { - closefile(getnonullfile(FIRSTARG)); +static int setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) { + if (f == NULL) + return pushresult(L, 0); + else { + setfile(L, ctrl, f, inout); + lua_pushusertag(L, f, ctrl->iotag); + return 1; + } } -static void gc_close (void) { - FILE *f = getnonullfile(FIRSTARG); - if (f != stdin && f != stdout && f != stderr) { - CLOSEFILE(f); +static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) { + if (f == stdin || f == stdout || f == stderr) + return 1; + else { + lua_pushusertag(L, f, ctrl->iotag); + lua_settag(L, ctrl->closedtag); + return (CLOSEFILE(L, f) == 0); } } -static void io_open (void) { - FILE *f = fopen(luaL_check_string(FIRSTARG), luaL_check_string(FIRSTARG+1)); - if (f) lua_pushusertag(f, gettag()); - else pushresult(0); +static int io_close (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + lua_pop(L, 1); /* remove upvalue */ + return pushresult(L, closefile(L, ctrl, getnonullfile(L, ctrl, 1))); } -static void setfile (FILE *f, char *name, int tag) { - lua_pushusertag(f, tag); - lua_setglobal(name); +static int file_collect (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f = getnonullfile(L, ctrl, 1); + if (f != stdin && f != stdout && f != stderr) + CLOSEFILE(L, f); + return 0; } -static void setreturn (FILE *f, char *name) { - if (f == NULL) - pushresult(0); - else { - int tag = gettag(); - setfile(f, name, tag); - lua_pushusertag(f, tag); +static int io_open (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f; + lua_pop(L, 1); /* remove upvalue */ + f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2)); + if (f) { + lua_pushusertag(L, f, ctrl->iotag); + return 1; } + else + return pushresult(L, 0); } -static void io_readfrom (void) { + +static int io_fromto (lua_State *L, int inout, const char *mode) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); FILE *current; - lua_Object f = lua_getparam(FIRSTARG); - if (f == LUA_NOOBJECT) { - closefile(getfilebyname(FINPUT)); - current = stdin; + lua_pop(L, 1); /* remove upvalue */ + if (lua_isnull(L, 1)) { + closefile(L, ctrl, getfilebyref(L, ctrl, inout)); + current = (inout == 0) ? stdin : stdout; } - else if (lua_tag(f) == gettag()) /* deprecated option */ - current = lua_getuserdata(f); + else if (lua_tag(L, 1) == ctrl->iotag) /* deprecated option */ + current = (FILE *)lua_touserdata(L, 1); else { - char *s = luaL_check_string(FIRSTARG); - current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); + const char *s = luaL_check_string(L, 1); + current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode); } - setreturn(current, FINPUT); + return setreturn(L, ctrl, current, inout); } -static void io_writeto (void) { - FILE *current; - lua_Object f = lua_getparam(FIRSTARG); - if (f == LUA_NOOBJECT) { - closefile(getfilebyname(FOUTPUT)); - current = stdout; - } - else if (lua_tag(f) == gettag()) /* deprecated option */ - current = lua_getuserdata(f); - else { - char *s = luaL_check_string(FIRSTARG); - current = (*s == '|') ? popen(s+1,"w") : fopen(s, "w"); - } - setreturn(current, FOUTPUT); +static int io_readfrom (lua_State *L) { + return io_fromto(L, INFILE, "r"); } -static void io_appendto (void) { - FILE *current = fopen(luaL_check_string(FIRSTARG), "a"); - setreturn(current, FOUTPUT); +static int io_writeto (lua_State *L) { + return io_fromto(L, OUTFILE, "w"); +} + + +static int io_appendto (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *current; + lua_pop(L, 1); /* remove upvalue */ + current = fopen(luaL_check_string(L, 1), "a"); + return setreturn(L, ctrl, current, OUTFILE); } @@ -215,6 +226,9 @@ static void io_appendto (void) { */ + +#ifdef LUA_COMPAT_READPATTERN + /* ** We cannot lookahead without need, because this can lock stdin. ** This flag signals when we need to read a next char. @@ -222,9 +236,11 @@ static void io_appendto (void) { #define NEED_OTHER (EOF-1) /* just some flag different from EOF */ -static int read_pattern (FILE *f, char *p) { +static int read_pattern (lua_State *L, FILE *f, const char *p) { int inskip = 0; /* {skip} level */ int c = NEED_OTHER; + luaL_Buffer b; + luaL_buffinit(L, &b); while (*p != '\0') { switch (*p) { case '{': @@ -232,17 +248,17 @@ static int read_pattern (FILE *f, char *p) { p++; continue; case '}': - if (!inskip) lua_error("unbalanced braces in read pattern"); + if (!inskip) lua_error(L, "unbalanced braces in read pattern"); inskip--; p++; continue; default: { - char *ep = luaI_classend(p); /* get what is next */ + const char *ep = luaI_classend(L, p); /* get what is next */ int m; /* match result */ if (c == NEED_OTHER) c = getc(f); m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); if (m) { - if (!inskip) luaL_addchar(c); + if (!inskip) luaL_putchar(&b, c); c = NEED_OTHER; } switch (*ep) { @@ -253,7 +269,7 @@ static int read_pattern (FILE *f, char *p) { while (m) { /* reads the same item until it fails */ c = getc(f); m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); - if (m && !inskip) luaL_addchar(c); + if (m && !inskip) luaL_putchar(&b, c); } /* go through to continue reading the pattern */ case '?': /* optional */ @@ -267,116 +283,210 @@ static int read_pattern (FILE *f, char *p) { } } break_while: if (c != NEED_OTHER) ungetc(c, f); + luaL_pushresult(&b); /* close buffer */ return (*p == '\0'); } +#else + +#define read_pattern(L, f, p) (lua_error(L, "read patterns are deprecated"), 0) -static int read_number (FILE *f) { +#endif + + +static int read_number (lua_State *L, FILE *f) { double d; if (fscanf(f, "%lf", &d) == 1) { - lua_pushnumber(d); + lua_pushnumber(L, d); return 1; } else return 0; /* read fails */ } -#define HUNK_LINE 1024 -#define HUNK_FILE BUFSIZ +static int read_word (lua_State *L, FILE *f) { + int c; + luaL_Buffer b; + luaL_buffinit(L, &b); + do { c = fgetc(f); } while (isspace(c)); /* skip spaces */ + while (c != EOF && !isspace(c)) { + luaL_putchar(&b, c); + c = fgetc(f); + } + ungetc(c, f); + luaL_pushresult(&b); /* close buffer */ + return (lua_strlen(L, -1) > 0); +} -static int read_line (FILE *f) { - /* equivalent to: return read_pattern(f, "[^\n]*{\n}"); */ - int n; - char *b; - do { - b = luaL_openspace(HUNK_LINE); - if (!fgets(b, HUNK_LINE, f)) return 0; /* read fails */ - n = strlen(b); - luaL_addsize(n); - } while (b[n-1] != '\n'); - luaL_addsize(-1); /* remove '\n' */ - return 1; + +static int read_line (lua_State *L, FILE *f) { + int n = 0; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + char *p = luaL_prepbuffer(&b); + if (!fgets(p, LUAL_BUFFERSIZE, f)) /* read fails? */ + break; + n = strlen(p); + if (p[n-1] != '\n') + luaL_addsize(&b, n); + else { + luaL_addsize(&b, n-1); /* do not add the `\n' */ + break; + } + } + luaL_pushresult(&b); /* close buffer */ + return (n > 0); /* read something? */ } -static void read_file (FILE *f) { - /* equivalent to: return read_pattern(f, ".*"); */ - int n; - do { - char *b = luaL_openspace(HUNK_FILE); - n = fread(b, sizeof(char), HUNK_FILE, f); - luaL_addsize(n); - } while (n==HUNK_FILE); +static void read_file (lua_State *L, FILE *f) { + size_t len = 0; + size_t size = BUFSIZ; + char *buffer = NULL; + for (;;) { + char *newbuffer = (char *)realloc(buffer, size); + if (newbuffer == NULL) { + free(buffer); + lua_error(L, "not enough memory to read a file"); + } + buffer = newbuffer; + len += fread(buffer+len, sizeof(char), size-len, f); + if (len < size) break; /* did not read all it could */ + size *= 2; + } + lua_pushlstring(L, buffer, len); + free(buffer); } -static void io_read (void) { - static char *options[] = {"*n", "*l", "*a", ".*", "*w", NULL}; - int arg = FIRSTARG; - FILE *f = getfileparam(FINPUT, &arg); - char *p = luaL_opt_string(arg++, "*l"); - do { /* repeat for each part */ - long l; +static int read_chars (lua_State *L, FILE *f, size_t n) { + char *buffer; + size_t n1; + char statbuff[BUFSIZ]; + if (n <= BUFSIZ) + buffer = statbuff; + else { + buffer = (char *)malloc(n); + if (buffer == NULL) + lua_error(L, "not enough memory to read a file"); + } + n1 = fread(buffer, sizeof(char), n, f); + lua_pushlstring(L, buffer, n1); + if (buffer != statbuff) free(buffer); + return (n1 > 0 || n == 0); +} + + +static int io_read (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + int lastarg = lua_gettop(L) - 1; + int firstarg = 1; + FILE *f = gethandle(L, ctrl, firstarg); + int n; + if (f) firstarg++; + else f = getfilebyref(L, ctrl, INFILE); /* get _INPUT */ + lua_pop(L, 1); + if (firstarg > lastarg) { /* no arguments? */ + lua_settop(L, 0); /* erase upvalue and other eventual garbage */ + firstarg = lastarg = 1; /* correct indices */ + lua_pushstring(L, "*l"); /* push default argument */ + } + else /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, lastarg-firstarg+1+LUA_MINSTACK, "too many arguments"); + for (n = firstarg; n<=lastarg; n++) { int success; - luaL_resetbuffer(); - switch (luaL_findstring(p, options)) { - case 0: /* number */ - if (!read_number(f)) return; /* read fails */ - continue; /* number is already pushed; avoid the "pushstring" */ - case 1: /* line */ - success = read_line(f); - break; - case 2: case 3: /* file */ - read_file(f); - success = 1; /* always success */ - break; - case 4: /* word */ - success = read_pattern(f, "{%s*}%S+"); - break; - default: - success = read_pattern(f, p); + if (lua_isnumber(L, n)) + success = read_chars(L, f, (size_t)lua_tonumber(L, n)); + else { + const char *p = luaL_check_string(L, n); + if (p[0] != '*') + success = read_pattern(L, f, p); /* deprecated! */ + else { + switch (p[1]) { + case 'n': /* number */ + if (!read_number(L, f)) goto endloop; /* read fails */ + continue; /* number is already pushed; avoid the "pushstring" */ + case 'l': /* line */ + success = read_line(L, f); + break; + case 'a': /* file */ + read_file(L, f); + success = 1; /* always success */ + break; + case 'w': /* word */ + success = read_word(L, f); + break; + default: + luaL_argerror(L, n, "invalid format"); + success = 0; /* to avoid warnings */ + } + } } - l = luaL_getsize(); - if (!success && l==0) return; /* read fails */ - lua_pushlstring(luaL_buffer(), l); - } while ((p = luaL_opt_string(arg++, NULL)) != NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + break; /* read fails */ + } + } endloop: + return n - firstarg; } /* }====================================================== */ -static void io_write (void) { - int arg = FIRSTARG; - FILE *f = getfileparam(FOUTPUT, &arg); +static int io_write (lua_State *L) { + int lastarg = lua_gettop(L) - 1; + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + int arg = 1; int status = 1; - char *s; - long l; - while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL) - status = status && ((long)fwrite(s, 1, l, f) == l); - pushresult(status); + FILE *f = gethandle(L, ctrl, arg); + if (f) arg++; + else f = getfilebyref(L, ctrl, OUTFILE); /* get _OUTPUT */ + for (; arg <= lastarg; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { /* LUA_NUMBER */ + /* optimization: could be done exactly as for strings */ + status = status && fprintf(f, "%.16g", lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_check_lstr(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + pushresult(L, status); + return 1; } -static void io_seek (void) { - static int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; - static char *modenames[] = {"set", "cur", "end", NULL}; - FILE *f = getnonullfile(FIRSTARG); - int op = luaL_findstring(luaL_opt_string(FIRSTARG+1, "cur"), modenames); - long offset = luaL_opt_long(FIRSTARG+2, 0); - luaL_arg_check(op != -1, FIRSTARG+1, "invalid mode"); +static int io_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f; + int op; + long offset; + lua_pop(L, 1); /* remove upvalue */ + f = getnonullfile(L, ctrl, 1); + op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames); + offset = luaL_opt_long(L, 3, 0); + luaL_arg_check(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) - pushresult(0); /* error */ - else - lua_pushnumber(ftell(f)); + return pushresult(L, 0); /* error */ + else { + lua_pushnumber(L, ftell(f)); + return 1; + } } -static void io_flush (void) { - FILE *f = getfile(FIRSTARG); - luaL_arg_check(f || lua_getparam(FIRSTARG) == LUA_NOOBJECT, FIRSTARG, - "invalid file handle"); - pushresult(fflush(f) == 0); +static int io_flush (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); + FILE *f; + lua_pop(L, 1); /* remove upvalue */ + f = gethandle(L, ctrl, 1); + luaL_arg_check(L, f || lua_isnull(L, 1), 1, "invalid file handle"); + return pushresult(L, fflush(f) == 0); } /* }====================================================== */ @@ -388,145 +498,165 @@ static void io_flush (void) { ** ======================================================= */ -static void io_execute (void) { - lua_pushnumber(system(luaL_check_string(1))); +static int io_execute (lua_State *L) { + lua_pushnumber(L, system(luaL_check_string(L, 1))); + return 1; } -static void io_remove (void) { - pushresult(remove(luaL_check_string(1)) == 0); +static int io_remove (lua_State *L) { + return pushresult(L, remove(luaL_check_string(L, 1)) == 0); } -static void io_rename (void) { - pushresult(rename(luaL_check_string(1), - luaL_check_string(2)) == 0); +static int io_rename (lua_State *L) { + return pushresult(L, rename(luaL_check_string(L, 1), + luaL_check_string(L, 2)) == 0); } -static void io_tmpname (void) { - lua_pushstring(tmpnam(NULL)); +static int io_tmpname (lua_State *L) { + lua_pushstring(L, tmpnam(NULL)); + return 1; } -static void io_getenv (void) { - lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */ +static int io_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_check_string(L, 1))); /* if NULL push nil */ + return 1; } -static void io_clock (void) { - lua_pushnumber(((double)clock())/CLOCKS_PER_SEC); +static int io_clock (lua_State *L) { + lua_pushnumber(L, ((double)clock())/CLOCKS_PER_SEC); + return 1; } -static void io_date (void) { +static int io_date (lua_State *L) { char b[256]; - char *s = luaL_opt_string(1, "%c"); - struct tm *tm; + const char *s = luaL_opt_string(L, 1, "%c"); + struct tm *stm; time_t t; - time(&t); tm = localtime(&t); - if (strftime(b,sizeof(b),s,tm)) - lua_pushstring(b); + time(&t); stm = localtime(&t); + if (strftime(b, sizeof(b), s, stm)) + lua_pushstring(L, b); else - lua_error("invalid `date' format"); + lua_error(L, "invalid `date' format"); + return 1; } -static void setloc (void) { - static int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, - LC_TIME}; - static char *catnames[] = {"all", "collate", "ctype", "monetary", +static int setloc (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; - int op = luaL_findstring(luaL_opt_string(2, "all"), catnames); - luaL_arg_check(op != -1, 2, "invalid option"); - lua_pushstring(setlocale(cat[op], luaL_check_string(1))); + int op = luaL_findstring(luaL_opt_string(L, 2, "all"), catnames); + luaL_arg_check(L, op != -1, 2, "invalid option"); + lua_pushstring(L, setlocale(cat[op], luaL_check_string(L, 1))); + return 1; } -static void io_exit (void) { - lua_Object o = lua_getparam(1); - exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1); +static int io_exit (lua_State *L) { + exit(luaL_opt_int(L, 1, EXIT_SUCCESS)); + return 0; /* to avoid warnings */ } /* }====================================================== */ -static void io_debug (void) { +static int io_debug (lua_State *L) { for (;;) { char buffer[250]; fprintf(stderr, "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) - return; - lua_dostring(buffer); + return 0; + lua_dostring(L, buffer); + lua_settop(L, 0); /* remove eventual returns */ } } +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ -#define MESSAGESIZE 150 -#define MAXMESSAGE (MESSAGESIZE*10) - - -#define MAXSRC 60 - - -static void errorfb (void) { - char buff[MAXMESSAGE]; +static int errorfb (lua_State *L) { int level = 1; /* skip level 0 (it's this function) */ - lua_Object func; - sprintf(buff, "lua error: %.200s\n", lua_getstring(lua_getparam(1))); - while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) { - char *name; - int currentline; - char *chunkname; - char buffchunk[MAXSRC]; - int linedefined; - lua_funcinfo(func, &chunkname, &linedefined); - luaL_chunkid(buffchunk, chunkname, sizeof(buffchunk)); - if (level == 2) strcat(buff, "Active Stack:\n"); - strcat(buff, " "); - if (strlen(buff) > MAXMESSAGE-MESSAGESIZE) { - strcat(buff, "...\n"); - break; /* buffer is full */ + int firstpart = 1; /* still before eventual `...' */ + lua_Debug ar; + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addstring(&b, "error: "); + luaL_addstring(&b, luaL_check_string(L, 1)); + luaL_addstring(&b, "\n"); + while (lua_getstack(L, level++, &ar)) { + char buff[120]; /* enough to fit following `sprintf's */ + if (level == 2) + luaL_addstring(&b, "stack traceback:\n"); + else if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (!lua_getstack(L, level+LEVELS2, &ar)) + level--; /* keep going */ + else { + luaL_addstring(&b, " ...\n"); /* too many levels */ + while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + level++; + } + firstpart = 0; + continue; } - switch (*lua_getobjname(func, &name)) { - case 'g': - sprintf(buff+strlen(buff), "function `%.50s'", name); + sprintf(buff, "%4d: ", level-1); + luaL_addstring(&b, buff); + lua_getinfo(L, "Snl", &ar); + switch (*ar.namewhat) { + case 'g': case 'l': /* global, local */ + sprintf(buff, "function `%.50s'", ar.name); break; - case 't': - sprintf(buff+strlen(buff), "`%.50s' tag method", name); + case 'f': /* field */ + sprintf(buff, "method `%.50s'", ar.name); + break; + case 't': /* tag method */ + sprintf(buff, "`%.50s' tag method", ar.name); break; default: { - if (linedefined == 0) - sprintf(buff+strlen(buff), "main of %.70s", buffchunk); - else if (linedefined < 0) - sprintf(buff+strlen(buff), "%.70s", buffchunk); + if (*ar.what == 'm') /* main? */ + sprintf(buff, "main of %.70s", ar.short_src); + else if (*ar.what == 'C') /* C function? */ + sprintf(buff, "%.70s", ar.short_src); else - sprintf(buff+strlen(buff), "function <%d:%.70s>", - linedefined, buffchunk); - chunkname = NULL; + sprintf(buff, "function <%d:%.70s>", ar.linedefined, ar.short_src); + ar.source = NULL; /* do not print source again */ } } - if ((currentline = lua_currentline(func)) > 0) - sprintf(buff+strlen(buff), " at line %d", currentline); - if (chunkname) - sprintf(buff+strlen(buff), " [%.70s]", buffchunk); - strcat(buff, "\n"); + luaL_addstring(&b, buff); + if (ar.currentline > 0) { + sprintf(buff, " at line %d", ar.currentline); + luaL_addstring(&b, buff); + } + if (ar.source) { + sprintf(buff, " [%.70s]", ar.short_src); + luaL_addstring(&b, buff); + } + luaL_addstring(&b, "\n"); } - func = lua_rawgetglobal("_ALERT"); - if (lua_isfunction(func)) { /* avoid error loop if _ALERT is not defined */ - lua_pushstring(buff); - lua_callfunction(func); + luaL_pushresult(&b); + lua_getglobal(L, LUA_ALERT); + if (lua_isfunction(L, -1)) { /* avoid loop if _ALERT is not defined */ + lua_pushvalue(L, -2); /* error message */ + lua_rawcall(L, 1, 0); } + return 0; } -static struct luaL_reg iolib[] = { - {"_ERRORMESSAGE", errorfb}, +static const struct luaL_reg iolib[] = { + {LUA_ERRORMESSAGE, errorfb}, {"clock", io_clock}, {"date", io_date}, {"debug", io_debug}, @@ -540,7 +670,7 @@ static struct luaL_reg iolib[] = { }; -static struct luaL_reg iolibtag[] = { +static const struct luaL_reg iolibtag[] = { {"appendto", io_appendto}, {"closefile", io_close}, {"flush", io_flush}, @@ -553,31 +683,36 @@ static struct luaL_reg iolibtag[] = { }; -static void openwithtags (void) { - int i; - int iotag = lua_newtag(); - lua_newtag(); /* alloc CLOSEDTAG: assume that CLOSEDTAG = iotag-1 */ +static void openwithcontrol (lua_State *L) { + IOCtrl *ctrl = (IOCtrl *)lua_newuserdata(L, sizeof(IOCtrl)); + unsigned int i; + ctrl->iotag = lua_newtag(L); + ctrl->closedtag = lua_newtag(L); for (i=0; iref[INFILE] = lua_ref(L, 1); + lua_pushstring(L, filenames[OUTFILE]); + ctrl->ref[OUTFILE] = lua_ref(L, 1); /* predefined file handles */ - setfile(stdin, FINPUT, iotag); - setfile(stdout, FOUTPUT, iotag); - setfile(stdin, "_STDIN", iotag); - setfile(stdout, "_STDOUT", iotag); - setfile(stderr, "_STDERR", iotag); - /* close file when collected */ - lua_pushnumber(iotag); - lua_pushcclosure(gc_close, 1); - lua_settagmethod(iotag, "gc"); -} - -void lua_iolibopen (void) { - /* register lib functions */ - luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0]))); - openwithtags(); + setfile(L, ctrl, stdin, INFILE); + setfile(L, ctrl, stdout, OUTFILE); + setfilebyname(L, ctrl, stdin, "_STDIN"); + setfilebyname(L, ctrl, stdout, "_STDOUT"); + setfilebyname(L, ctrl, stderr, "_STDERR"); + /* close files when collected */ + lua_pushcclosure(L, file_collect, 1); /* pops `ctrl' from stack */ + lua_settagmethod(L, ctrl->iotag, "gc"); +} + + +LUALIB_API void lua_iolibopen (lua_State *L) { + luaL_openl(L, iolib); + openwithcontrol(L); } diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c index 19cb11c211..c062cf4975 100644 --- a/src/lib/lmathlib.c +++ b/src/lib/lmathlib.c @@ -1,6 +1,6 @@ /* -** $Id: lmathlib.c,v 1.17 1999/07/07 17:54:08 roberto Exp $ -** Lua standard mathematical library +** $Id: lmathlib.c,v 1.32 2000/10/31 13:10:24 roberto Exp $ +** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -8,14 +8,15 @@ #include #include -#include "lauxlib.h" #include "lua.h" + +#include "lauxlib.h" #include "lualib.h" #undef PI -#define PI (3.14159265358979323846) -#define RADIANS_PER_DEGREE (PI/180.0) +#define PI (3.14159265358979323846) +#define RADIANS_PER_DEGREE (PI/180.0) @@ -32,139 +33,173 @@ #endif -static void math_abs (void) { - lua_pushnumber(fabs(luaL_check_number(1))); +static int math_abs (lua_State *L) { + lua_pushnumber(L, fabs(luaL_check_number(L, 1))); + return 1; } -static void math_sin (void) { - lua_pushnumber(sin(TORAD(luaL_check_number(1)))); +static int math_sin (lua_State *L) { + lua_pushnumber(L, sin(TORAD(luaL_check_number(L, 1)))); + return 1; } -static void math_cos (void) { - lua_pushnumber(cos(TORAD(luaL_check_number(1)))); +static int math_cos (lua_State *L) { + lua_pushnumber(L, cos(TORAD(luaL_check_number(L, 1)))); + return 1; } -static void math_tan (void) { - lua_pushnumber(tan(TORAD(luaL_check_number(1)))); +static int math_tan (lua_State *L) { + lua_pushnumber(L, tan(TORAD(luaL_check_number(L, 1)))); + return 1; } -static void math_asin (void) { - lua_pushnumber(FROMRAD(asin(luaL_check_number(1)))); +static int math_asin (lua_State *L) { + lua_pushnumber(L, FROMRAD(asin(luaL_check_number(L, 1)))); + return 1; } -static void math_acos (void) { - lua_pushnumber(FROMRAD(acos(luaL_check_number(1)))); +static int math_acos (lua_State *L) { + lua_pushnumber(L, FROMRAD(acos(luaL_check_number(L, 1)))); + return 1; } -static void math_atan (void) { - lua_pushnumber(FROMRAD(atan(luaL_check_number(1)))); +static int math_atan (lua_State *L) { + lua_pushnumber(L, FROMRAD(atan(luaL_check_number(L, 1)))); + return 1; } -static void math_atan2 (void) { - lua_pushnumber(FROMRAD(atan2(luaL_check_number(1), luaL_check_number(2)))); +static int math_atan2 (lua_State *L) { + lua_pushnumber(L, FROMRAD(atan2(luaL_check_number(L, 1), luaL_check_number(L, 2)))); + return 1; } -static void math_ceil (void) { - lua_pushnumber(ceil(luaL_check_number(1))); +static int math_ceil (lua_State *L) { + lua_pushnumber(L, ceil(luaL_check_number(L, 1))); + return 1; } -static void math_floor (void) { - lua_pushnumber(floor(luaL_check_number(1))); +static int math_floor (lua_State *L) { + lua_pushnumber(L, floor(luaL_check_number(L, 1))); + return 1; } -static void math_mod (void) { - lua_pushnumber(fmod(luaL_check_number(1), luaL_check_number(2))); +static int math_mod (lua_State *L) { + lua_pushnumber(L, fmod(luaL_check_number(L, 1), luaL_check_number(L, 2))); + return 1; } -static void math_sqrt (void) { - lua_pushnumber(sqrt(luaL_check_number(1))); +static int math_sqrt (lua_State *L) { + lua_pushnumber(L, sqrt(luaL_check_number(L, 1))); + return 1; } -static void math_pow (void) { - lua_pushnumber(pow(luaL_check_number(1), luaL_check_number(2))); +static int math_pow (lua_State *L) { + lua_pushnumber(L, pow(luaL_check_number(L, 1), luaL_check_number(L, 2))); + return 1; } -static void math_log (void) { - lua_pushnumber(log(luaL_check_number(1))); +static int math_log (lua_State *L) { + lua_pushnumber(L, log(luaL_check_number(L, 1))); + return 1; } -static void math_log10 (void) { - lua_pushnumber(log10(luaL_check_number(1))); +static int math_log10 (lua_State *L) { + lua_pushnumber(L, log10(luaL_check_number(L, 1))); + return 1; } -static void math_exp (void) { - lua_pushnumber(exp(luaL_check_number(1))); +static int math_exp (lua_State *L) { + lua_pushnumber(L, exp(luaL_check_number(L, 1))); + return 1; } -static void math_deg (void) { - lua_pushnumber(luaL_check_number(1)/RADIANS_PER_DEGREE); +static int math_deg (lua_State *L) { + lua_pushnumber(L, luaL_check_number(L, 1)/RADIANS_PER_DEGREE); + return 1; } -static void math_rad (void) { - lua_pushnumber(luaL_check_number(1)*RADIANS_PER_DEGREE); +static int math_rad (lua_State *L) { + lua_pushnumber(L, luaL_check_number(L, 1)*RADIANS_PER_DEGREE); + return 1; } -static void math_frexp (void) { +static int math_frexp (lua_State *L) { int e; - lua_pushnumber(frexp(luaL_check_number(1), &e)); - lua_pushnumber(e); + lua_pushnumber(L, frexp(luaL_check_number(L, 1), &e)); + lua_pushnumber(L, e); + return 2; } -static void math_ldexp (void) { - lua_pushnumber(ldexp(luaL_check_number(1), luaL_check_int(2))); +static int math_ldexp (lua_State *L) { + lua_pushnumber(L, ldexp(luaL_check_number(L, 1), luaL_check_int(L, 2))); + return 1; } -static void math_min (void) { - int i = 1; - double dmin = luaL_check_number(i); - while (lua_getparam(++i) != LUA_NOOBJECT) { - double d = luaL_check_number(i); +static int math_min (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + double dmin = luaL_check_number(L, 1); + int i; + for (i=2; i<=n; i++) { + double d = luaL_check_number(L, i); if (d < dmin) dmin = d; } - lua_pushnumber(dmin); + lua_pushnumber(L, dmin); + return 1; } -static void math_max (void) { - int i = 1; - double dmax = luaL_check_number(i); - while (lua_getparam(++i) != LUA_NOOBJECT) { - double d = luaL_check_number(i); +static int math_max (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + double dmax = luaL_check_number(L, 1); + int i; + for (i=2; i<=n; i++) { + double d = luaL_check_number(L, i); if (d > dmax) dmax = d; } - lua_pushnumber(dmax); + lua_pushnumber(L, dmax); + return 1; } -static void math_random (void) { +static int math_random (lua_State *L) { /* the '%' avoids the (rare) case of r==1, and is needed also because on - some systems (SunOS!) "rand()" may return a value bigger than RAND_MAX */ + some systems (SunOS!) "rand()" may return a value larger than RAND_MAX */ double r = (double)(rand()%RAND_MAX) / (double)RAND_MAX; - int l = luaL_opt_int(1, 0); - if (l == 0) - lua_pushnumber(r); - else { - int u = luaL_opt_int(2, 0); - if (u == 0) { - u = l; - l = 1; + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, r); /* Number between 0 and 1 */ + break; + } + case 1: { /* only upper limit */ + int u = luaL_check_int(L, 1); + luaL_arg_check(L, 1<=u, 1, "interval is empty"); + lua_pushnumber(L, (int)(r*u)+1); /* integer between 1 and `u' */ + break; + } + case 2: { /* lower and upper limits */ + int l = luaL_check_int(L, 1); + int u = luaL_check_int(L, 2); + luaL_arg_check(L, l<=u, 2, "interval is empty"); + lua_pushnumber(L, (int)(r*(u-l+1))+l); /* integer between `l' and `u' */ + break; } - luaL_arg_check(l<=u, 1, "interval is empty"); - lua_pushnumber((int)(r*(u-l+1))+l); + default: lua_error(L, "wrong number of arguments"); } + return 1; } -static void math_randomseed (void) { - srand(luaL_check_int(1)); +static int math_randomseed (lua_State *L) { + srand(luaL_check_int(L, 1)); + return 0; } -static struct luaL_reg mathlib[] = { +static const struct luaL_reg mathlib[] = { {"abs", math_abs}, {"sin", math_sin}, {"cos", math_cos}, @@ -193,11 +228,11 @@ static struct luaL_reg mathlib[] = { /* ** Open math library */ -void lua_mathlibopen (void) { - luaL_openlib(mathlib, (sizeof(mathlib)/sizeof(mathlib[0]))); - lua_pushcfunction(math_pow); - lua_pushnumber(0); /* to get its tag */ - lua_settagmethod(lua_tag(lua_pop()), "pow"); - lua_pushnumber(PI); lua_setglobal("PI"); +LUALIB_API void lua_mathlibopen (lua_State *L) { + luaL_openl(L, mathlib); + lua_pushcfunction(L, math_pow); + lua_settagmethod(L, LUA_TNUMBER, "pow"); + lua_pushnumber(L, PI); + lua_setglobal(L, "PI"); } diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index b47e21d3af..8f286982ad 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,112 +1,111 @@ /* -** $Id: lstrlib.c,v 1.32 1999/06/17 17:04:03 roberto Exp $ -** Standard library for strings and pattern-matching +** $Id: lstrlib.c,v 1.56 2000/10/27 16:15:53 roberto Exp $ +** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ #include +#include #include #include #include -#include "lauxlib.h" #include "lua.h" -#include "lualib.h" - - - -static void addnchar (char *s, int n) -{ - char *b = luaL_openspace(n); - memcpy(b, s, n); - luaL_addsize(n); -} +#include "lauxlib.h" +#include "lualib.h" -static void str_len (void) -{ - long l; - luaL_check_lstr(1, &l); - lua_pushnumber(l); -} -static void closeandpush (void) { - lua_pushlstring(luaL_buffer(), luaL_getsize()); +static int str_len (lua_State *L) { + size_t l; + luaL_check_lstr(L, 1, &l); + lua_pushnumber(L, l); + return 1; } -static long posrelat (long pos, long len) { +static long posrelat (long pos, size_t len) { /* relative string position: negative means back from end */ - return (pos>=0) ? pos : len+pos+1; + return (pos>=0) ? pos : (long)len+pos+1; } -static void str_sub (void) { - long l; - char *s = luaL_check_lstr(1, &l); - long start = posrelat(luaL_check_long(2), l); - long end = posrelat(luaL_opt_long(3, -1), l); +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_check_lstr(L, 1, &l); + long start = posrelat(luaL_check_long(L, 2), l); + long end = posrelat(luaL_opt_long(L, 3, -1), l); if (start < 1) start = 1; - if (end > l) end = l; + if (end > (long)l) end = l; if (start <= end) - lua_pushlstring(s+start-1, end-start+1); - else lua_pushstring(""); + lua_pushlstring(L, s+start-1, end-start+1); + else lua_pushstring(L, ""); + return 1; } -static void str_lower (void) { - long l; - int i; - char *s = luaL_check_lstr(1, &l); - luaL_resetbuffer(); +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_check_lstr(L, 1, &l); + luaL_buffinit(L, &b); for (i=0; i 0) - addnchar(s, l); - closeandpush(); + luaL_addlstring(&b, s, l); + luaL_pushresult(&b); + return 1; } -static void str_byte (void) { - long l; - char *s = luaL_check_lstr(1, &l); - long pos = posrelat(luaL_opt_long(2, 1), l); - luaL_arg_check(0level; i++) { - int l = cap->capture[i].len; - if (l == -1) lua_error("unfinished capture"); - lua_pushlstring(cap->capture[i].init, l); - } -} - - -static int check_cap (int l, struct Capture *cap) { +static int check_capture (lua_State *L, int l, struct Capture *cap) { l -= '1'; if (!(0 <= l && l < cap->level && cap->capture[l].len != -1)) - lua_error("invalid capture index"); + lua_error(L, "invalid capture index"); return l; } -static int capture_to_close (struct Capture *cap) { +static int capture_to_close (lua_State *L, struct Capture *cap) { int level = cap->level; for (level--; level>=0; level--) if (cap->capture[level].len == -1) return level; - lua_error("invalid pattern capture"); + lua_error(L, "invalid pattern capture"); return 0; /* to avoid warnings */ } -char *luaI_classend (char *p) { +const char *luaI_classend (lua_State *L, const char *p) { switch (*p++) { case ESC: - if (*p == '\0') - luaL_verror("incorrect pattern (ends with `%c')", ESC); + if (*p == '\0') lua_error(L, "malformed pattern (ends with `%')"); return p+1; case '[': if (*p == '^') p++; - if (*p == ']') p++; - p = strchr(p, ']'); - if (!p) lua_error("incorrect pattern (missing `]')"); + do { /* look for a ']' */ + if (*p == '\0') lua_error(L, "malformed pattern (missing `]')"); + if (*(p++) == ESC && *p != '\0') p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); return p+1; default: return p; @@ -181,7 +170,7 @@ char *luaI_classend (char *p) { } -static int matchclass (int c, int cl) { +static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; @@ -201,36 +190,36 @@ static int matchclass (int c, int cl) { -static int matchbracketclass (int c, char *p, char *end) { +static int matchbracketclass (int c, const char *p, const char *endclass) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the '^' */ } - while (++p < end) { + while (++p < endclass) { if (*p == ESC) { p++; - if ((p < end) && matchclass(c, (unsigned char)*p)) + if (match_class(c, (unsigned char)*p)) return sig; } - else if ((*(p+1) == '-') && (p+2 < end)) { + else if ((*(p+1) == '-') && (p+2 < endclass)) { p+=2; if ((int)(unsigned char)*(p-2) <= c && c <= (int)(unsigned char)*p) return sig; } - else if ((unsigned char)*p == c) return sig; + else if ((int)(unsigned char)*p == c) return sig; } return !sig; } -int luaI_singlematch (int c, char *p, char *ep) { +int luaI_singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': /* matches any char */ return 1; case ESC: - return matchclass(c, (unsigned char)*(p+1)); + return match_class(c, (unsigned char)*(p+1)); case '[': return matchbracketclass(c, p, ep-1); default: @@ -239,12 +228,14 @@ int luaI_singlematch (int c, char *p, char *ep) { } -static char *match (char *s, char *p, struct Capture *cap); +static const char *match (lua_State *L, const char *s, const char *p, + struct Capture *cap); -static char *matchbalance (char *s, char *p, struct Capture *cap) { +static const char *matchbalance (lua_State *L, const char *s, const char *p, + struct Capture *cap) { if (*p == 0 || *(p+1) == 0) - lua_error("unbalanced pattern"); + lua_error(L, "unbalanced pattern"); if (*s != *p) return NULL; else { int b = *p; @@ -261,13 +252,14 @@ static char *matchbalance (char *s, char *p, struct Capture *cap) { } -static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) { - int i = 0; /* counts maximum expand for item */ +static const char *max_expand (lua_State *L, const char *s, const char *p, + const char *ep, struct Capture *cap) { + long i = 0; /* counts maximum expand for item */ while ((s+i)src_end && luaI_singlematch((unsigned char)*(s+i), p, ep)) i++; - /* keeps trying to match mith the maximum repetitions */ + /* keeps trying to match with the maximum repetitions */ while (i>=0) { - char *res = match((s+i), ep+1, cap); + const char *res = match(L, (s+i), ep+1, cap); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } @@ -275,9 +267,10 @@ static char *max_expand (char *s, char *p, char *ep, struct Capture *cap) { } -static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) { +static const char *min_expand (lua_State *L, const char *s, const char *p, + const char *ep, struct Capture *cap) { for (;;) { - char *res = match(s, ep+1, cap); + const char *res = match(L, s, ep+1, cap); if (res != NULL) return res; else if (ssrc_end && luaI_singlematch((unsigned char)*s, p, ep)) @@ -287,56 +280,60 @@ static char *min_expand (char *s, char *p, char *ep, struct Capture *cap) { } -static char *start_capt (char *s, char *p, struct Capture *cap) { - char *res; +static const char *start_capture (lua_State *L, const char *s, const char *p, + struct Capture *cap) { + const char *res; int level = cap->level; - if (level >= MAX_CAPT) lua_error("too many captures"); + if (level >= MAX_CAPTURES) lua_error(L, "too many captures"); cap->capture[level].init = s; cap->capture[level].len = -1; cap->level = level+1; - if ((res=match(s, p+1, cap)) == NULL) /* match failed? */ + if ((res=match(L, s, p+1, cap)) == NULL) /* match failed? */ cap->level--; /* undo capture */ return res; } -static char *end_capt (char *s, char *p, struct Capture *cap) { - int l = capture_to_close(cap); - char *res; +static const char *end_capture (lua_State *L, const char *s, const char *p, + struct Capture *cap) { + int l = capture_to_close(L, cap); + const char *res; cap->capture[l].len = s - cap->capture[l].init; /* close capture */ - if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ + if ((res = match(L, s, p+1, cap)) == NULL) /* match failed? */ cap->capture[l].len = -1; /* undo capture */ return res; } -static char *match_capture (char *s, int level, struct Capture *cap) { - int l = check_cap(level, cap); - int len = cap->capture[l].len; - if (cap->src_end-s >= len && +static const char *match_capture (lua_State *L, const char *s, int level, + struct Capture *cap) { + int l = check_capture(L, level, cap); + size_t len = cap->capture[l].len; + if ((size_t)(cap->src_end-s) >= len && memcmp(cap->capture[l].init, s, len) == 0) return s+len; else return NULL; } -static char *match (char *s, char *p, struct Capture *cap) { +static const char *match (lua_State *L, const char *s, const char *p, + struct Capture *cap) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': /* start capture */ - return start_capt(s, p, cap); + return start_capture(L, s, p, cap); case ')': /* end capture */ - return end_capt(s, p, cap); + return end_capture(L, s, p, cap); case ESC: /* may be %[0-9] or %b */ if (isdigit((unsigned char)(*(p+1)))) { /* capture? */ - s = match_capture(s, *(p+1), cap); + s = match_capture(L, s, *(p+1), cap); if (s == NULL) return NULL; - p+=2; goto init; /* else return match(p+2, s, cap) */ + p+=2; goto init; /* else return match(L, s, p+2, cap) */ } else if (*(p+1) == 'b') { /* balanced string? */ - s = matchbalance(s, p+2, cap); + s = matchbalance(L, s, p+2, cap); if (s == NULL) return NULL; - p+=4; goto init; /* else return match(p+4, s, cap); */ + p+=4; goto init; /* else return match(L, s, p+4, cap); */ } else goto dflt; /* case default */ case '\0': /* end of pattern */ @@ -346,178 +343,208 @@ static char *match (char *s, char *p, struct Capture *cap) { return (s == cap->src_end) ? s : NULL; /* check end of string */ else goto dflt; default: dflt: { /* it is a pattern item */ - char *ep = luaI_classend(p); /* points to what is next */ + const char *ep = luaI_classend(L, p); /* points to what is next */ int m = ssrc_end && luaI_singlematch((unsigned char)*s, p, ep); switch (*ep) { case '?': { /* optional */ - char *res; - if (m && ((res=match(s+1, ep+1, cap)) != NULL)) + const char *res; + if (m && ((res=match(L, s+1, ep+1, cap)) != NULL)) return res; - p=ep+1; goto init; /* else return match(s, ep+1, cap); */ + p=ep+1; goto init; /* else return match(L, s, ep+1, cap); */ } case '*': /* 0 or more repetitions */ - return max_expand(s, p, ep, cap); + return max_expand(L, s, p, ep, cap); case '+': /* 1 or more repetitions */ - return (m ? max_expand(s+1, p, ep, cap) : NULL); + return (m ? max_expand(L, s+1, p, ep, cap) : NULL); case '-': /* 0 or more repetitions (minimum) */ - return min_expand(s, p, ep, cap); + return min_expand(L, s, p, ep, cap); default: if (!m) return NULL; - s++; p=ep; goto init; /* else return match(s+1, ep, cap); */ + s++; p=ep; goto init; /* else return match(L, s+1, ep, cap); */ + } + } + } +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative `l1' */ + else { + const char *init; /* to search for a `*s2' inside `s1' */ + l2--; /* 1st char will be checked by `memchr' */ + l1 = l1-l2; /* `s2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct `l1' and `s1' to try again */ + l1 -= init-s1; + s1 = init; } } + return NULL; /* not found */ } } -static void str_find (void) { - long l; - char *s = luaL_check_lstr(1, &l); - char *p = luaL_check_string(2); - long init = posrelat(luaL_opt_long(3, 1), l) - 1; +static int push_captures (lua_State *L, struct Capture *cap) { + int i; + luaL_checkstack(L, cap->level, "too many captures"); + for (i=0; ilevel; i++) { + int l = cap->capture[i].len; + if (l == -1) lua_error(L, "unfinished capture"); + lua_pushlstring(L, cap->capture[i].init, l); + } + return cap->level; /* number of strings pushed */ +} + + +static int str_find (lua_State *L) { + size_t l1, l2; + const char *s = luaL_check_lstr(L, 1, &l1); + const char *p = luaL_check_lstr(L, 2, &l2); + long init = posrelat(luaL_opt_long(L, 3, 1), l1) - 1; struct Capture cap; - luaL_arg_check(0 <= init && init <= l, 3, "out of range"); - if (lua_getparam(4) != LUA_NOOBJECT || - strpbrk(p, SPECIALS) == NULL) { /* no special characters? */ - char *s2 = strstr(s+init, p); + luaL_arg_check(L, 0 <= init && (size_t)init <= l1, 3, "out of range"); + if (lua_gettop(L) > 3 || /* extra argument? */ + strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ + const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { - lua_pushnumber(s2-s+1); - lua_pushnumber(s2-s+strlen(p)); - return; + lua_pushnumber(L, s2-s+1); + lua_pushnumber(L, s2-s+l2); + return 2; } } else { int anchor = (*p == '^') ? (p++, 1) : 0; - char *s1=s+init; - cap.src_end = s+l; + const char *s1=s+init; + cap.src_end = s+l1; do { - char *res; + const char *res; cap.level = 0; - if ((res=match(s1, p, &cap)) != NULL) { - lua_pushnumber(s1-s+1); /* start */ - lua_pushnumber(res-s); /* end */ - push_captures(&cap); - return; + if ((res=match(L, s1, p, &cap)) != NULL) { + lua_pushnumber(L, s1-s+1); /* start */ + lua_pushnumber(L, res-s); /* end */ + return push_captures(L, &cap) + 2; } } while (s1++capture[level].init, cap->capture[level].len); + int level = check_capture(L, news[i], cap); + luaL_addlstring(b, cap->capture[level].init, cap->capture[level].len); } } } } else { /* is a function */ - lua_Object res; - int status; - int oldbuff; - lua_beginblock(); - push_captures(cap); - /* function may use buffer, so save it and create a new one */ - oldbuff = luaL_newbuffer(0); - status = lua_callfunction(newp); - /* restore old buffer */ - luaL_oldbuffer(oldbuff); - if (status != 0) { - lua_endblock(); - lua_error(NULL); - } - res = lua_getresult(1); - if (lua_isstring(res)) - addnchar(lua_getstring(res), lua_strlen(res)); - lua_endblock(); + int n; + lua_pushvalue(L, 3); + n = push_captures(L, cap); + lua_rawcall(L, n, 1); + if (lua_isstring(L, -1)) + luaL_addvalue(b); /* add return to accumulated result */ + else + lua_pop(L, 1); /* function result is not a string: pop it */ } } -static void str_gsub (void) { - long srcl; - char *src = luaL_check_lstr(1, &srcl); - char *p = luaL_check_string(2); - lua_Object newp = lua_getparam(3); - int max_s = luaL_opt_int(4, srcl+1); +static int str_gsub (lua_State *L) { + size_t srcl; + const char *src = luaL_check_lstr(L, 1, &srcl); + const char *p = luaL_check_string(L, 2); + int max_s = luaL_opt_int(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; struct Capture cap; - luaL_arg_check(lua_isstring(newp) || lua_isfunction(newp), 3, - "string or function expected"); - luaL_resetbuffer(); + luaL_Buffer b; + luaL_arg_check(L, + lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), + 3, "string or function expected"); + luaL_buffinit(L, &b); cap.src_end = src+srcl; while (n < max_s) { - char *e; + const char *e; cap.level = 0; - e = match(src, p, &cap); + e = match(L, src, p, &cap); if (e) { n++; - add_s(newp, &cap); + add_s(L, &b, &cap); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < cap.src_end) - luaL_addchar(*src++); + luaL_putchar(&b, *src++); else break; if (anchor) break; } - addnchar(src, cap.src_end-src); - closeandpush(); - lua_pushnumber(n); /* number of substitutions */ + luaL_addlstring(&b, src, cap.src_end-src); + luaL_pushresult(&b); + lua_pushnumber(L, n); /* number of substitutions */ + return 2; } /* }====================================================== */ -static void luaI_addquoted (int arg) { - long l; - char *s = luaL_check_lstr(arg, &l); - luaL_addchar('"'); +static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { + size_t l; + const char *s = luaL_check_lstr(L, arg, &l); + luaL_putchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': - luaL_addchar('\\'); - luaL_addchar(*s); + luaL_putchar(b, '\\'); + luaL_putchar(b, *s); break; - case '\0': addnchar("\\000", 4); break; - default: luaL_addchar(*s); + case '\0': luaL_addlstring(b, "\\000", 4); break; + default: luaL_putchar(b, *s); } s++; } - luaL_addchar('"'); + luaL_putchar(b, '"'); } +/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ +#define MAX_ITEM 512 /* maximum size of each format specification (such as '%-099.99d') */ -#define MAX_FORMAT 20 /* arbitrary limit */ +#define MAX_FORMAT 20 -static void str_format (void) { +static int str_format (lua_State *L) { int arg = 1; - char *strfrmt = luaL_check_string(arg); - luaL_resetbuffer(); + const char *strfrmt = luaL_check_string(L, arg); + luaL_Buffer b; + luaL_buffinit(L, &b); while (*strfrmt) { if (*strfrmt != '%') - luaL_addchar(*strfrmt++); + luaL_putchar(&b, *strfrmt++); else if (*++strfrmt == '%') - luaL_addchar(*strfrmt++); /* %% */ + luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ struct Capture cap; char form[MAX_FORMAT]; /* to store the format ('%...') */ - char *buff; /* to store the formatted item */ - char *initf = strfrmt; + char buff[MAX_ITEM]; /* to store the formatted item */ + const char *initf = strfrmt; form[0] = '%'; if (isdigit((unsigned char)*initf) && *(initf+1) == '$') { arg = *initf - '0'; @@ -526,33 +553,33 @@ static void str_format (void) { arg++; cap.src_end = strfrmt+strlen(strfrmt)+1; cap.level = 0; - strfrmt = match(initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); + strfrmt = match(L, initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); if (cap.capture[0].len > 2 || cap.capture[1].len > 2 || /* < 100? */ strfrmt-initf > MAX_FORMAT-2) - lua_error("invalid format (width or precision too long)"); + lua_error(L, "invalid format (width or precision too long)"); strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */ form[strfrmt-initf+2] = 0; - buff = luaL_openspace(512); /* 512 > size of format('%99.99f', -1e308) */ switch (*strfrmt++) { case 'c': case 'd': case 'i': - sprintf(buff, form, luaL_check_int(arg)); + sprintf(buff, form, luaL_check_int(L, arg)); break; case 'o': case 'u': case 'x': case 'X': - sprintf(buff, form, (unsigned int)luaL_check_number(arg)); + sprintf(buff, form, (unsigned int)luaL_check_number(L, arg)); break; case 'e': case 'E': case 'f': case 'g': case 'G': - sprintf(buff, form, luaL_check_number(arg)); + sprintf(buff, form, luaL_check_number(L, arg)); break; case 'q': - luaI_addquoted(arg); + luaI_addquoted(L, &b, arg); continue; /* skip the "addsize" at the end */ case 's': { - long l; - char *s = luaL_check_lstr(arg, &l); + size_t l; + const char *s = luaL_check_lstr(L, arg, &l); if (cap.capture[1].len == 0 && l >= 100) { - /* no precision and string is too big to be formatted; + /* no precision and string is too long to be formatted; keep original string */ - addnchar(s, l); + lua_pushvalue(L, arg); + luaL_addvalue(&b); continue; /* skip the "addsize" at the end */ } else { @@ -561,16 +588,17 @@ static void str_format (void) { } } default: /* also treat cases 'pnLlh' */ - lua_error("invalid option in `format'"); + lua_error(L, "invalid option in `format'"); } - luaL_addsize(strlen(buff)); + luaL_addlstring(&b, buff, strlen(buff)); } } - closeandpush(); /* push the result */ + luaL_pushresult(&b); + return 1; } -static struct luaL_reg strlib[] = { +static const struct luaL_reg strlib[] = { {"strlen", str_len}, {"strsub", str_sub}, {"strlower", str_lower}, @@ -588,7 +616,6 @@ static struct luaL_reg strlib[] = { /* ** Open string library */ -void strlib_open (void) -{ - luaL_openlib(strlib, (sizeof(strlib)/sizeof(strlib[0]))); +LUALIB_API void lua_strlibopen (lua_State *L) { + luaL_openl(L, strlib); } diff --git a/src/llex.c b/src/llex.c index 2d607d996f..4f511ab933 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,71 +1,85 @@ /* -** $Id: llex.c,v 1.36 1999/06/17 17:04:03 roberto Exp $ +** $Id: llex.c,v 1.72 2000/10/20 16:39:03 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #include +#include #include -#include "lauxlib.h" +#include "lua.h" + #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" +#include "ltable.h" #include "luadebug.h" #include "lzio.h" -#define next(LS) (LS->current = zgetc(LS->lex_z)) - +#define next(LS) (LS->current = zgetc(LS->z)) -#define save(c) luaL_addchar(c) -#define save_and_next(LS) (save(LS->current), next(LS)) -char *reserved [] = {"and", "do", "else", "elseif", "end", "function", - "if", "local", "nil", "not", "or", "repeat", "return", "then", - "until", "while"}; +/* ORDER RESERVED */ +static const char *const token2string [] = { + "and", "break", "do", "else", "elseif", "end", "for", + "function", "if", "local", "nil", "not", "or", "repeat", "return", "then", + "until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", ""}; -void luaX_init (void) { +void luaX_init (lua_State *L) { int i; - for (i=0; i<(sizeof(reserved)/sizeof(reserved[0])); i++) { - TaggedString *ts = luaS_new(reserved[i]); - ts->head.marked = FIRST_RESERVED+i; /* reserved word (always > 255) */ + for (i=0; imarked = (unsigned char)(RESERVEDMARK+i); /* reserved word */ } } #define MAXSRC 80 -void luaX_syntaxerror (LexState *ls, char *s, char *token) { + +void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) { + if (val > limit) { + char buff[100]; + sprintf(buff, "too many %.50s (limit=%d)", msg, limit); + luaX_error(ls, buff, ls->t.token); + } +} + + +void luaX_syntaxerror (LexState *ls, const char *s, const char *token) { char buff[MAXSRC]; - luaL_chunkid(buff, zname(ls->lex_z), sizeof(buff)); - if (token[0] == '\0') - token = ""; - luaL_verror("%.100s;\n last token read: `%.50s' at line %d in %.80s", + luaO_chunkid(buff, ls->source->str, sizeof(buff)); + luaO_verror(ls->L, "%.99s;\n last token read: `%.30s' at line %d in %.80s", s, token, ls->linenumber, buff); } -void luaX_error (LexState *ls, char *s) { - save('\0'); - luaX_syntaxerror(ls, s, luaL_buffer()); +void luaX_error (LexState *ls, const char *s, int token) { + char buff[TOKEN_LEN]; + luaX_token2str(token, buff); + if (buff[0] == '\0') + luaX_syntaxerror(ls, s, ls->L->Mbuffer); + else + luaX_syntaxerror(ls, s, buff); } void luaX_token2str (int token, char *s) { - if (token < 255) { + if (token < 256) { s[0] = (char)token; s[1] = '\0'; } else - strcpy(s, reserved[token-FIRST_RESERVED]); + strcpy(s, token2string[token-FIRST_RESERVED]); } @@ -76,200 +90,199 @@ static void luaX_invalidchar (LexState *ls, int c) { } -static void firstline (LexState *LS) -{ - int c = zgetc(LS->lex_z); - if (c == '#') - while ((c=zgetc(LS->lex_z)) != '\n' && c != EOZ) /* skip first line */; - zungetc(LS->lex_z); +static void inclinenumber (LexState *LS) { + next(LS); /* skip '\n' */ + ++LS->linenumber; + luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk"); } -void luaX_setinput (LexState *LS, ZIO *z) -{ - LS->current = '\n'; - LS->linenumber = 0; - LS->iflevel = 0; - LS->ifstate[0].skip = 0; - LS->ifstate[0].elsepart = 1; /* to avoid a free $else */ - LS->lex_z = z; +void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { + LS->L = L; + LS->lookahead.token = TK_EOS; /* no look-ahead token */ + LS->z = z; LS->fs = NULL; - firstline(LS); - luaL_resetbuffer(); + LS->linenumber = 1; + LS->lastline = 1; + LS->source = source; + next(LS); /* read first char */ + if (LS->current == '#') { + do { /* skip first line */ + next(LS); + } while (LS->current != '\n' && LS->current != EOZ); + } } /* ** ======================================================= -** PRAGMAS +** LEXICAL ANALYZER ** ======================================================= */ -#ifndef PRAGMASIZE -#define PRAGMASIZE 80 /* arbitrary limit */ -#endif -static void skipspace (LexState *LS) { - while (LS->current == ' ' || LS->current == '\t' || LS->current == '\r') - next(LS); -} +/* use Mbuffer to store names, literal strings and numbers */ +#define EXTRABUFF 128 +#define checkbuffer(L, n, len) if ((len)+(n) > L->Mbuffsize) \ + luaO_openspace(L, (len)+(n)+EXTRABUFF) -static int checkcond (LexState *LS, char *buff) { - static char *opts[] = {"nil", "1", NULL}; - int i = luaL_findstring(buff, opts); - if (i >= 0) return i; - else if (isalpha((unsigned char)buff[0]) || buff[0] == '_') - return luaS_globaldefined(buff); - else { - luaX_syntaxerror(LS, "invalid $if condition", buff); - return 0; /* to avoid warnings */ - } -} +#define save(L, c, l) (L->Mbuffer[l++] = (char)c) +#define save_and_next(L, LS, l) (save(L, LS->current, l), next(LS)) -static void readname (LexState *LS, char *buff) { - int i = 0; - skipspace(LS); - while (isalnum(LS->current) || LS->current == '_') { - if (i >= PRAGMASIZE) { - buff[PRAGMASIZE] = 0; - luaX_syntaxerror(LS, "pragma too long", buff); - } - buff[i++] = (char)LS->current; - next(LS); - } - buff[i] = 0; +static const char *readname (LexState *LS) { + lua_State *L = LS->L; + size_t l = 0; + checkbuffer(L, 10, l); + do { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + } while (isalnum(LS->current) || LS->current == '_'); + save(L, '\0', l); + return L->Mbuffer; } -static void inclinenumber (LexState *LS); - - -static void ifskip (LexState *LS) { - while (LS->ifstate[LS->iflevel].skip) { - if (LS->current == '\n') - inclinenumber(LS); - else if (LS->current == EOZ) - luaX_error(LS, "input ends inside a $if"); - else next(LS); +/* LUA_NUMBER */ +static void read_number (LexState *LS, int comma, SemInfo *seminfo) { + lua_State *L = LS->L; + size_t l = 0; + checkbuffer(L, 10, l); + if (comma) save(L, '.', l); + while (isdigit(LS->current)) { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); } -} - - -static void inclinenumber (LexState *LS) { - static char *pragmas [] = - {"debug", "nodebug", "endinput", "end", "ifnot", "if", "else", NULL}; - next(LS); /* skip '\n' */ - ++LS->linenumber; - if (LS->current == '$') { /* is a pragma? */ - char buff[PRAGMASIZE+1]; - int ifnot = 0; - int skip = LS->ifstate[LS->iflevel].skip; - next(LS); /* skip $ */ - readname(LS, buff); - switch (luaL_findstring(buff, pragmas)) { - case 0: /* debug */ - if (!skip) L->debug = 1; - break; - case 1: /* nodebug */ - if (!skip) L->debug = 0; - break; - case 2: /* endinput */ - if (!skip) { - LS->current = EOZ; - LS->iflevel = 0; /* to allow $endinput inside a $if */ - } - break; - case 3: /* end */ - if (LS->iflevel-- == 0) - luaX_syntaxerror(LS, "unmatched $end", "$end"); - break; - case 4: /* ifnot */ - ifnot = 1; - /* go through */ - case 5: /* if */ - if (LS->iflevel == MAX_IFS-1) - luaX_syntaxerror(LS, "too many nested $ifs", "$if"); - readname(LS, buff); - LS->iflevel++; - LS->ifstate[LS->iflevel].elsepart = 0; - LS->ifstate[LS->iflevel].condition = checkcond(LS, buff) ? !ifnot : ifnot; - LS->ifstate[LS->iflevel].skip = skip || !LS->ifstate[LS->iflevel].condition; - break; - case 6: /* else */ - if (LS->ifstate[LS->iflevel].elsepart) - luaX_syntaxerror(LS, "unmatched $else", "$else"); - LS->ifstate[LS->iflevel].elsepart = 1; - LS->ifstate[LS->iflevel].skip = LS->ifstate[LS->iflevel-1].skip || - LS->ifstate[LS->iflevel].condition; - break; - default: - luaX_syntaxerror(LS, "unknown pragma", buff); + if (LS->current == '.') { + save_and_next(L, LS, l); + if (LS->current == '.') { + save_and_next(L, LS, l); + save(L, '\0', l); + luaX_error(LS, "ambiguous syntax" + " (decimal point x string concatenation)", TK_NUMBER); } - skipspace(LS); - if (LS->current == '\n') /* pragma must end with a '\n' ... */ - inclinenumber(LS); - else if (LS->current != EOZ) /* or eof */ - luaX_syntaxerror(LS, "invalid pragma format", buff); - ifskip(LS); } + while (isdigit(LS->current)) { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + } + if (LS->current == 'e' || LS->current == 'E') { + save_and_next(L, LS, l); /* read 'E' */ + if (LS->current == '+' || LS->current == '-') + save_and_next(L, LS, l); /* optional exponent sign */ + while (isdigit(LS->current)) { + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + } + } + save(L, '\0', l); + if (!luaO_str2d(L->Mbuffer, &seminfo->r)) + luaX_error(LS, "malformed number", TK_NUMBER); } - -/* -** ======================================================= -** LEXICAL ANALIZER -** ======================================================= -*/ - - - -static int read_long_string (LexState *LS) { +static void read_long_string (LexState *LS, SemInfo *seminfo) { + lua_State *L = LS->L; int cont = 0; + size_t l = 0; + checkbuffer(L, 10, l); + save(L, '[', l); /* save first '[' */ + save_and_next(L, LS, l); /* pass the second '[' */ for (;;) { + checkbuffer(L, 10, l); switch (LS->current) { case EOZ: - luaX_error(LS, "unfinished long string"); - return EOS; /* to avoid warnings */ + save(L, '\0', l); + luaX_error(LS, "unfinished long string", TK_STRING); + break; /* to avoid warnings */ case '[': - save_and_next(LS); + save_and_next(L, LS, l); if (LS->current == '[') { cont++; - save_and_next(LS); + save_and_next(L, LS, l); } continue; case ']': - save_and_next(LS); + save_and_next(L, LS, l); if (LS->current == ']') { if (cont == 0) goto endloop; cont--; - save_and_next(LS); + save_and_next(L, LS, l); } continue; case '\n': - save('\n'); + save(L, '\n', l); inclinenumber(LS); continue; default: - save_and_next(LS); + save_and_next(L, LS, l); } } endloop: - save_and_next(LS); /* skip the second ']' */ - LS->seminfo.ts = luaS_newlstr(L->Mbuffer+(L->Mbuffbase+2), - L->Mbuffnext-L->Mbuffbase-4); - return STRING; + save_and_next(L, LS, l); /* skip the second ']' */ + save(L, '\0', l); + seminfo->ts = luaS_newlstr(L, L->Mbuffer+2, l-5); } -int luaX_lex (LexState *LS) { - luaL_resetbuffer(); +static void read_string (LexState *LS, int del, SemInfo *seminfo) { + lua_State *L = LS->L; + size_t l = 0; + checkbuffer(L, 10, l); + save_and_next(L, LS, l); + while (LS->current != del) { + checkbuffer(L, 10, l); + switch (LS->current) { + case EOZ: case '\n': + save(L, '\0', l); + luaX_error(LS, "unfinished string", TK_STRING); + break; /* to avoid warnings */ + case '\\': + next(LS); /* do not save the '\' */ + switch (LS->current) { + case 'a': save(L, '\a', l); next(LS); break; + case 'b': save(L, '\b', l); next(LS); break; + case 'f': save(L, '\f', l); next(LS); break; + case 'n': save(L, '\n', l); next(LS); break; + case 'r': save(L, '\r', l); next(LS); break; + case 't': save(L, '\t', l); next(LS); break; + case 'v': save(L, '\v', l); next(LS); break; + case '\n': save(L, '\n', l); inclinenumber(LS); break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + int c = 0; + int i = 0; + do { + c = 10*c + (LS->current-'0'); + next(LS); + } while (++i<3 && isdigit(LS->current)); + if (c != (unsigned char)c) { + save(L, '\0', l); + luaX_error(LS, "escape sequence too large", TK_STRING); + } + save(L, c, l); + break; + } + default: /* handles \\, \", \', and \? */ + save_and_next(L, LS, l); + } + break; + default: + save_and_next(L, LS, l); + } + } + save_and_next(L, LS, l); /* skip delimiter */ + save(L, '\0', l); + seminfo->ts = luaS_newlstr(L, L->Mbuffer+1, l-3); +} + + +int luaX_lex (LexState *LS, SemInfo *seminfo) { for (;;) { switch (LS->current) { - case ' ': case '\t': case '\r': /* CR: to avoid problems with DOS */ + case ' ': case '\t': case '\r': /* `\r' to avoid problems with DOS */ next(LS); continue; @@ -277,159 +290,89 @@ int luaX_lex (LexState *LS) { inclinenumber(LS); continue; + case '$': + luaX_error(LS, "unexpected `$' (pragmas are no longer supported)", '$'); + break; + case '-': - save_and_next(LS); + next(LS); if (LS->current != '-') return '-'; do { next(LS); } while (LS->current != '\n' && LS->current != EOZ); - luaL_resetbuffer(); continue; case '[': - save_and_next(LS); + next(LS); if (LS->current != '[') return '['; else { - save_and_next(LS); /* pass the second '[' */ - return read_long_string(LS); + read_long_string(LS, seminfo); + return TK_STRING; } case '=': - save_and_next(LS); + next(LS); if (LS->current != '=') return '='; - else { save_and_next(LS); return EQ; } + else { next(LS); return TK_EQ; } case '<': - save_and_next(LS); + next(LS); if (LS->current != '=') return '<'; - else { save_and_next(LS); return LE; } + else { next(LS); return TK_LE; } case '>': - save_and_next(LS); + next(LS); if (LS->current != '=') return '>'; - else { save_and_next(LS); return GE; } + else { next(LS); return TK_GE; } case '~': - save_and_next(LS); + next(LS); if (LS->current != '=') return '~'; - else { save_and_next(LS); return NE; } + else { next(LS); return TK_NE; } case '"': - case '\'': { - int del = LS->current; - save_and_next(LS); - while (LS->current != del) { - switch (LS->current) { - case EOZ: - case '\n': - luaX_error(LS, "unfinished string"); - return EOS; /* to avoid warnings */ - case '\\': - next(LS); /* do not save the '\' */ - switch (LS->current) { - case 'a': save('\a'); next(LS); break; - case 'b': save('\b'); next(LS); break; - case 'f': save('\f'); next(LS); break; - case 'n': save('\n'); next(LS); break; - case 'r': save('\r'); next(LS); break; - case 't': save('\t'); next(LS); break; - case 'v': save('\v'); next(LS); break; - case '\n': save('\n'); inclinenumber(LS); break; - default : { - if (isdigit(LS->current)) { - int c = 0; - int i = 0; - do { - c = 10*c + (LS->current-'0'); - next(LS); - } while (++i<3 && isdigit(LS->current)); - if (c != (unsigned char)c) - luaX_error(LS, "escape sequence too large"); - save(c); - } - else { /* handles \, ", ', and ? */ - save(LS->current); - next(LS); - } - break; - } - } - break; - default: - save_and_next(LS); - } - } - save_and_next(LS); /* skip delimiter */ - LS->seminfo.ts = luaS_newlstr(L->Mbuffer+(L->Mbuffbase+1), - L->Mbuffnext-L->Mbuffbase-2); - return STRING; - } + case '\'': + read_string(LS, LS->current, seminfo); + return TK_STRING; case '.': - save_and_next(LS); - if (LS->current == '.') - { - save_and_next(LS); - if (LS->current == '.') - { - save_and_next(LS); - return DOTS; /* ... */ + next(LS); + if (LS->current == '.') { + next(LS); + if (LS->current == '.') { + next(LS); + return TK_DOTS; /* ... */ } - else return CONC; /* .. */ + else return TK_CONCAT; /* .. */ } else if (!isdigit(LS->current)) return '.'; - goto fraction; /* LS->current is a digit: goes through to number */ + else { + read_number(LS, 1, seminfo); + return TK_NUMBER; + } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - do { - save_and_next(LS); - } while (isdigit(LS->current)); - if (LS->current == '.') { - save_and_next(LS); - if (LS->current == '.') { - save('.'); - luaX_error(LS, - "ambiguous syntax (decimal point x string concatenation)"); - } - } - fraction: - while (isdigit(LS->current)) - save_and_next(LS); - if (toupper(LS->current) == 'E') { - save_and_next(LS); /* read 'E' */ - save_and_next(LS); /* read '+', '-' or first digit */ - while (isdigit(LS->current)) - save_and_next(LS); - } - save('\0'); - LS->seminfo.r = luaO_str2d(L->Mbuffer+L->Mbuffbase); - if (LS->seminfo.r < 0) - luaX_error(LS, "invalid numeric format"); - return NUMBER; + read_number(LS, 0, seminfo); + return TK_NUMBER; case EOZ: - if (LS->iflevel > 0) - luaX_error(LS, "input ends inside a $if"); - return EOS; + return TK_EOS; + + case '_': goto tname; default: - if (LS->current != '_' && !isalpha(LS->current)) { + if (!isalpha(LS->current)) { int c = LS->current; if (iscntrl(c)) luaX_invalidchar(LS, c); - save_and_next(LS); + next(LS); return c; } - else { /* identifier or reserved word */ - TaggedString *ts; - do { - save_and_next(LS); - } while (isalnum(LS->current) || LS->current == '_'); - save('\0'); - ts = luaS_new(L->Mbuffer+L->Mbuffbase); - if (ts->head.marked >= FIRST_RESERVED) - return ts->head.marked; /* reserved word */ - LS->seminfo.ts = ts; - return NAME; + tname: { /* identifier or reserved word */ + TString *ts = luaS_new(LS->L, readname(LS)); + if (ts->marked >= RESERVEDMARK) /* reserved word? */ + return ts->marked-RESERVEDMARK+FIRST_RESERVED; + seminfo->ts = ts; + return TK_NAME; } } } diff --git a/src/llex.h b/src/llex.h index 7c1a4be1f8..3b37996086 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.12 1999/06/17 17:04:03 roberto Exp $ +** $Id: llex.h,v 1.31 2000/09/27 17:41:58 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -11,53 +11,61 @@ #include "lzio.h" -#define FIRST_RESERVED 260 +#define FIRST_RESERVED 257 -/* maximum length of a reserved word (+1 for terminal 0) */ +/* maximum length of a reserved word (+1 for final 0) */ #define TOKEN_LEN 15 + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER RESERVED" +*/ enum RESERVED { /* terminal symbols denoted by reserved words */ - AND = FIRST_RESERVED, - DO, ELSE, ELSEIF, END, FUNCTION, IF, LOCAL, NIL, NOT, OR, - REPEAT, RETURN, THEN, UNTIL, WHILE, + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FOR, TK_FUNCTION, TK_IF, TK_LOCAL, + TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_UNTIL, TK_WHILE, /* other terminal symbols */ - NAME, CONC, DOTS, EQ, GE, LE, NE, NUMBER, STRING, EOS}; + TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, + TK_STRING, TK_EOS +}; +/* number of reserved words */ +#define NUM_RESERVED ((int)(TK_WHILE-FIRST_RESERVED+1)) -#ifndef MAX_IFS -#define MAX_IFS 5 /* arbitrary limit */ -#endif -/* "ifstate" keeps the state of each nested $if the lexical is dealing with. */ +typedef union { + Number r; + TString *ts; +} SemInfo; /* semantics information */ -struct ifState { - int elsepart; /* true if it's in the $else part */ - int condition; /* true if $if condition is true */ - int skip; /* true if part must be skipped */ -}; + +typedef struct Token { + int token; + SemInfo seminfo; +} Token; typedef struct LexState { - int current; /* look ahead character */ - int token; /* look ahead token */ - struct FuncState *fs; /* 'FuncState' is private for the parser */ - union { - real r; - TaggedString *ts; - } seminfo; /* semantics information */ - struct zio *lex_z; /* input stream */ + int current; /* current character */ + Token t; /* current token */ + Token lookahead; /* look ahead token */ + struct FuncState *fs; /* `FuncState' is private to the parser */ + struct lua_State *L; + struct zio *z; /* input stream */ int linenumber; /* input line counter */ - int iflevel; /* level of nested $if's (for lexical analysis) */ - struct ifState ifstate[MAX_IFS]; + int lastline; /* line of last token `consumed' */ + TString *source; /* current source name */ } LexState; -void luaX_init (void); -void luaX_setinput (LexState *LS, ZIO *z); -int luaX_lex (LexState *LS); -void luaX_syntaxerror (LexState *ls, char *s, char *token); -void luaX_error (LexState *ls, char *s); +void luaX_init (lua_State *L); +void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source); +int luaX_lex (LexState *LS, SemInfo *seminfo); +void luaX_checklimit (LexState *ls, int val, int limit, const char *msg); +void luaX_syntaxerror (LexState *ls, const char *s, const char *token); +void luaX_error (LexState *ls, const char *s, int token); void luaX_token2str (int token, char *s); diff --git a/src/llimits.h b/src/llimits.h new file mode 100644 index 0000000000..b3f5de47e3 --- /dev/null +++ b/src/llimits.h @@ -0,0 +1,204 @@ +/* +** $Id: llimits.h,v 1.19 2000/10/26 12:47:05 roberto Exp $ +** Limits, basic types, and some other "installation-dependent" definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include +#include + + + +/* +** try to find number of bits in an integer +*/ +#ifndef BITS_INT +/* avoid overflows in comparison */ +#if INT_MAX-20 < 32760 +#define BITS_INT 16 +#else +#if INT_MAX > 2147483640L +/* machine has at least 32 bits */ +#define BITS_INT 32 +#else +#error "you must define BITS_INT with number of bits in an integer" +#endif +#endif +#endif + + +/* +** Define the type `number' of Lua +** GREP LUA_NUMBER to change that +*/ +#ifndef LUA_NUM_TYPE +#define LUA_NUM_TYPE double +#endif + +typedef LUA_NUM_TYPE Number; + +/* function to convert a Number to a string */ +#define NUMBER_FMT "%.16g" /* LUA_NUMBER */ +#define lua_number2str(s,n) sprintf((s), NUMBER_FMT, (n)) + +/* function to convert a string to a Number */ +#define lua_str2number(s,p) strtod((s), (p)) + + + +typedef unsigned long lint32; /* unsigned int with at least 32 bits */ + + +#define MAX_SIZET ((size_t)(~(size_t)0)-2) + + +#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ + +/* +** conversion of pointer to int (for hashing only) +** (the shift removes bits that are usually 0 because of alignment) +*/ +#define IntPoint(p) (((unsigned long)(p)) >> 3) + + + +#define MINPOWER2 4 /* minimum size for "growing" vectors */ + + + +#ifndef DEFAULT_STACK_SIZE +#define DEFAULT_STACK_SIZE 1024 +#endif + + + +/* type to ensure maximum alignment */ +union L_Umaxalign { double d; char *s; long l; }; + + + +/* +** type for virtual-machine instructions +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +** For a very small machine, you may change that to 2 bytes (and adjust +** the following limits accordingly) +*/ +typedef unsigned long Instruction; + + +/* +** size and position of opcode arguments. +** For an instruction with 2 bytes, size is 16, and size_b can be 5 +** (accordingly, size_u will be 10, and size_a will be 5) +*/ +#define SIZE_INSTRUCTION 32 +#define SIZE_B 9 + +#define SIZE_OP 6 +#define SIZE_U (SIZE_INSTRUCTION-SIZE_OP) +#define POS_U SIZE_OP +#define POS_B SIZE_OP +#define SIZE_A (SIZE_INSTRUCTION-(SIZE_OP+SIZE_B)) +#define POS_A (SIZE_OP+SIZE_B) + + +/* +** limits for opcode arguments. +** we use (signed) int to manipulate most arguments, +** so they must fit in BITS_INT-1 bits (-1 for sign) +*/ +#if SIZE_U < BITS_INT-1 +#define MAXARG_U ((1<>1) /* `S' is signed */ +#else +#define MAXARG_U MAX_INT +#define MAXARG_S MAX_INT +#endif + +#if SIZE_A < BITS_INT-1 +#define MAXARG_A ((1< MAXARG_B +#undef MAXSTACK +#define MAXSTACK MAXARG_B +#endif + + +/* maximum number of local variables */ +#ifndef MAXLOCALS +#define MAXLOCALS 200 /* arbitrary limit (=MAXSTACK +#undef MAXLOCALS +#define MAXLOCALS (MAXSTACK-1) +#endif + + +/* maximum number of upvalues */ +#ifndef MAXUPVALUES +#define MAXUPVALUES 32 /* arbitrary limit (<=MAXARG_B) */ +#endif +#if MAXUPVALUES>MAXARG_B +#undef MAXUPVALUES +#define MAXUPVALUES MAXARG_B +#endif + + +/* maximum number of variables in the left side of an assignment */ +#ifndef MAXVARSLH +#define MAXVARSLH 100 /* arbitrary limit (=MULT_RET +#undef MAXVARSLH +#define MAXVARSLH (MULT_RET-1) +#endif + + +/* maximum number of parameters in a function */ +#ifndef MAXPARAMS +#define MAXPARAMS 100 /* arbitrary limit (=MAXLOCALS +#undef MAXPARAMS +#define MAXPARAMS (MAXLOCALS-1) +#endif + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 64 +#if LFIELDS_PER_FLUSH>(MAXSTACK/4) +#undef LFIELDS_PER_FLUSH +#define LFIELDS_PER_FLUSH (MAXSTACK/4) +#endif + +/* number of record items to accumulate before a SETMAP instruction */ +/* (each item counts 2 elements on the stack: an index and a value) */ +#define RFIELDS_PER_FLUSH (LFIELDS_PER_FLUSH/2) + + +/* maximum lookback to find a real constant (for code generation) */ +#ifndef LOOKBACKNUMS +#define LOOKBACKNUMS 20 /* arbitrary constant */ +#endif + + +#endif diff --git a/src/lmem.c b/src/lmem.c index 5f840b005a..03a804c9ca 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.17 1999/05/24 17:51:05 roberto Exp $ +** $Id: lmem.c,v 1.39 2000/10/30 16:29:59 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -7,134 +7,144 @@ #include -#include "lmem.h" -#include "lstate.h" #include "lua.h" +#include "ldo.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" -/* -** real ANSI systems do not need these tests; -** but some systems (Sun OS) are not that ANSI... -*/ -#ifdef OLD_ANSI -#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s)) -#define free(b) if (b) (free)(b) -#endif - - -#define MINSIZE 8 /* minimum size for "growing" vectors */ - - - - -static unsigned long power2 (unsigned long n) { - unsigned long p = MINSIZE; - while (p<=n) p<<=1; - return p; -} - - -void *luaM_growaux (void *block, unsigned long nelems, int inc, int size, - char *errormsg, unsigned long limit) { - unsigned long newn = nelems+inc; - if (newn >= limit) lua_error(errormsg); - if ((newn ^ nelems) <= nelems || /* still the same power of 2 limit? */ - (nelems > 0 && newn < MINSIZE)) /* or block already is MINSIZE? */ - return block; /* do not need to reallocate */ - else /* it crossed a power of 2 boundary; grow to next power */ - return luaM_realloc(block, power2(newn)*size); -} -#ifndef DEBUG +#ifdef LUA_DEBUG /* -** generic allocation routine. +** {====================================================================== +** Controlled version for realloc. +** ======================================================================= */ -void *luaM_realloc (void *block, unsigned long size) { - size_t s = (size_t)size; - if (s != size) - lua_error("memory allocation error: block too big"); - if (size == 0) { - free(block); /* block may be NULL, that is OK for free */ - return NULL; - } - block = realloc(block, s); - if (block == NULL) - lua_error(memEM); - return block; -} +#include +#include +#include -#else -/* DEBUG */ +#define realloc(b, s) debug_realloc(b, s) +#define malloc(b) debug_realloc(NULL, b) +#define free(b) debug_realloc(b, 0) -#include +/* ensures maximum alignment for HEADER */ +#define HEADER (sizeof(union L_Umaxalign)) -#define HEADER (sizeof(double)) #define MARKSIZE 16 - -#define MARK 55 +#define MARK 0x55 /* 01010101 (a nice pattern) */ #define blocksize(b) ((unsigned long *)((char *)(b) - HEADER)) -unsigned long numblocks = 0; -unsigned long totalmem = 0; +unsigned long memdebug_numblocks = 0; +unsigned long memdebug_total = 0; +unsigned long memdebug_maxmem = 0; +unsigned long memdebug_memlimit = LONG_MAX; static void *checkblock (void *block) { - if (block == NULL) - return NULL; - else { - unsigned long *b = blocksize(block); - unsigned long size = *b; - int i; - for (i=0;i memdebug_memlimit) + return NULL; /* to test memory allocation errors */ else { - char *newblock = malloc(realsize); + size_t realsize = HEADER+size+MARKSIZE; + char *newblock = (char *)(malloc)(realsize); /* alloc a new block */ int i; + if (realsize < size) return NULL; /* overflow! */ + if (newblock == NULL) return NULL; if (block) { - unsigned long oldsize = *blocksize(block); + size_t oldsize = *blocksize(block); if (oldsize > size) oldsize = size; memcpy(newblock+HEADER, block, oldsize); freeblock(block); /* erase (and check) old copy */ } - if (newblock == NULL) - lua_error(memEM); - totalmem += size; - numblocks++; + memdebug_total += size; + if (memdebug_total > memdebug_maxmem) memdebug_maxmem = memdebug_total; + memdebug_numblocks++; *(unsigned long *)newblock = size; for (i=0;i= limit-inc) lua_error(L, errormsg); + if ((newn ^ nelems) <= nelems || /* still the same power-of-2 limit? */ + (nelems > 0 && newn < MINPOWER2)) /* or block already is MINPOWER2? */ + return block; /* do not need to reallocate */ + else /* it crossed a power-of-2 boundary; grow to next power */ + return luaM_realloc(L, block, luaO_power2(newn)*size); +} + + +/* +** generic allocation routine. +*/ +void *luaM_realloc (lua_State *L, void *block, lint32 size) { + if (size == 0) { + free(block); /* block may be NULL; that is OK for free */ + return NULL; + } + else if (size >= MAX_SIZET) + lua_error(L, "memory allocation error: block too big"); + block = realloc(block, size); + if (block == NULL) { + if (L) + luaD_breakrun(L, LUA_ERRMEM); /* break run without error message */ + else return NULL; /* error before creating state! */ + } + return block; +} + + diff --git a/src/lmem.h b/src/lmem.h index 967899c919..9e7c829d71 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.8 1999/02/26 15:48:55 roberto Exp $ +** $Id: lmem.h,v 1.16 2000/10/30 16:29:59 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -8,32 +8,33 @@ #define lmem_h -#include +#include -/* memory error messages */ -#define codeEM "code size overflow" -#define constantEM "constant table overflow" -#define refEM "reference table overflow" -#define tableEM "table overflow" -#define memEM "not enough memory" -#define arrEM "internal array bigger than `int' limit" +#include "llimits.h" +#include "lua.h" -void *luaM_realloc (void *oldblock, unsigned long size); -void *luaM_growaux (void *block, unsigned long nelems, int inc, int size, - char *errormsg, unsigned long limit); +void *luaM_realloc (lua_State *L, void *oldblock, lint32 size); +void *luaM_growaux (lua_State *L, void *block, size_t nelems, + int inc, size_t size, const char *errormsg, + size_t limit); -#define luaM_free(b) luaM_realloc((b), 0) -#define luaM_malloc(t) luaM_realloc(NULL, (t)) -#define luaM_new(t) ((t *)luaM_malloc(sizeof(t))) -#define luaM_newvector(n,t) ((t *)luaM_malloc((n)*sizeof(t))) -#define luaM_growvector(v,nelems,inc,t,e,l) \ - ((v)=(t *)luaM_growaux(v,nelems,inc,sizeof(t),e,l)) -#define luaM_reallocvector(v,n,t) ((v)=(t *)luaM_realloc(v,(n)*sizeof(t))) +#define luaM_free(L, b) luaM_realloc(L, (b), 0) +#define luaM_malloc(L, t) luaM_realloc(L, NULL, (t)) +#define luaM_new(L, t) ((t *)luaM_malloc(L, sizeof(t))) +#define luaM_newvector(L, n,t) ((t *)luaM_malloc(L, (n)*(lint32)sizeof(t))) +#define luaM_growvector(L, v,nelems,inc,t,e,l) \ + ((v)=(t *)luaM_growaux(L, v,nelems,inc,sizeof(t),e,l)) -#ifdef DEBUG -extern unsigned long numblocks; -extern unsigned long totalmem; +#define luaM_reallocvector(L, v,n,t) \ + ((v)=(t *)luaM_realloc(L, v,(n)*(lint32)sizeof(t))) + + +#ifdef LUA_DEBUG +extern unsigned long memdebug_numblocks; +extern unsigned long memdebug_total; +extern unsigned long memdebug_maxmem; +extern unsigned long memdebug_memlimit; #endif diff --git a/src/lobject.c b/src/lobject.c index 0225e2d8cc..e787fbe82a 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,129 +1,125 @@ /* -** $Id: lobject.c,v 1.19 1999/04/13 19:28:49 roberto Exp $ +** $Id: lobject.c,v 1.55 2000/10/20 16:36:32 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include +#include +#include #include +#include -#include "lobject.h" #include "lua.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" -char *luaO_typenames[] = { /* ORDER LUA_T */ - "userdata", "number", "string", "table", "function", "function", - "nil", "function", "mark", "mark", "mark", "line", NULL -}; -TObject luaO_nilobject = {LUA_T_NIL, {NULL}}; +const TObject luaO_nilobject = {LUA_TNIL, {NULL}}; +const char *const luaO_typenames[] = { + "userdata", "nil", "number", "string", "table", "function" +}; -/* hash dimensions values */ -static long dimensions[] = - {5L, 11L, 23L, 47L, 97L, 197L, 397L, 797L, 1597L, 3203L, 6421L, - 12853L, 25717L, 51437L, 102811L, 205619L, 411233L, 822433L, - 1644817L, 3289613L, 6579211L, 13158023L, MAX_INT}; -int luaO_redimension (int oldsize) -{ - int i; - for (i=0; dimensions[i] oldsize) - return dimensions[i]; - } - lua_error("tableEM"); - return 0; /* to avoid warnings */ +/* +** returns smaller power of 2 larger than `n' (minimum is MINPOWER2) +*/ +lint32 luaO_power2 (lint32 n) { + lint32 p = MINPOWER2; + while (p<=n) p<<=1; + return p; } -int luaO_equalval (TObject *t1, TObject *t2) { +int luaO_equalObj (const TObject *t1, const TObject *t2) { + if (ttype(t1) != ttype(t2)) return 0; switch (ttype(t1)) { - case LUA_T_NIL: return 1; - case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2); - case LUA_T_STRING: case LUA_T_USERDATA: return svalue(t1) == svalue(t2); - case LUA_T_ARRAY: return avalue(t1) == avalue(t2); - case LUA_T_PROTO: return tfvalue(t1) == tfvalue(t2); - case LUA_T_CPROTO: return fvalue(t1) == fvalue(t2); - case LUA_T_CLOSURE: return t1->value.cl == t2->value.cl; + case LUA_TNUMBER: + return nvalue(t1) == nvalue(t2); + case LUA_TSTRING: case LUA_TUSERDATA: + return tsvalue(t1) == tsvalue(t2); + case LUA_TTABLE: + return hvalue(t1) == hvalue(t2); + case LUA_TFUNCTION: + return clvalue(t1) == clvalue(t2); default: - LUA_INTERNALERROR("invalid type"); - return 0; /* UNREACHABLE */ + LUA_ASSERT(ttype(t1) == LUA_TNIL, "invalid type"); + return 1; /* LUA_TNIL */ } } -void luaO_insertlist (GCnode *root, GCnode *node) -{ - node->next = root->next; - root->next = node; - node->marked = 0; +char *luaO_openspace (lua_State *L, size_t n) { + if (n > L->Mbuffsize) { + luaM_reallocvector(L, L->Mbuffer, n, char); + L->nblocks += (n - L->Mbuffsize)*sizeof(char); + L->Mbuffsize = n; + } + return L->Mbuffer; } -#ifdef OLD_ANSI -void luaO_memup (void *dest, void *src, int size) { - while (size--) - ((char *)dest)[size]=((char *)src)[size]; -} - -void luaO_memdown (void *dest, void *src, int size) { - int i; - for (i=0; i>=1) { - if (e & 1) res *= exp; - exp *= exp; - } - return res; +/* this function needs to handle only '%d' and '%.XXs' formats */ +void luaO_verror (lua_State *L, const char *fmt, ...) { + va_list argp; + char buff[MAX_VERROR]; /* to hold formatted message */ + va_start(argp, fmt); + vsprintf(buff, fmt, argp); + va_end(argp); + lua_error(L, buff); } -double luaO_str2d (char *s) { /* LUA_NUMBER */ - double a = 0.0; - int point = 0; - while (isdigit((unsigned char)*s)) { - a = 10.0*a + (*(s++)-'0'); +void luaO_chunkid (char *out, const char *source, int bufflen) { + if (*source == '=') { + strncpy(out, source+1, bufflen); /* remove first char */ + out[bufflen-1] = '\0'; /* ensures null termination */ } - if (*s == '.') { - s++; - while (isdigit((unsigned char)*s)) { - a = 10.0*a + (*(s++)-'0'); - point++; + else { + if (*source == '@') { + int l; + source++; /* skip the `@' */ + bufflen -= sizeof("file `...%s'"); + l = strlen(source); + if (l>bufflen) { + source += (l-bufflen); /* get last part of file name */ + sprintf(out, "file `...%.99s'", source); + } + else + sprintf(out, "file `%.99s'", source); } - } - if (toupper((unsigned char)*s) == 'E') { - int e = 0; - int sig = 1; - s++; - if (*s == '-') { - s++; - sig = -1; + else { + int len = strcspn(source, "\n"); /* stop at first newline */ + bufflen -= sizeof("string \"%.*s...\""); + if (len > bufflen) len = bufflen; + if (source[len] != '\0') { /* must truncate? */ + strcpy(out, "string \""); + out += strlen(out); + strncpy(out, source, len); + strcpy(out+len, "...\""); + } + else + sprintf(out, "string \"%.99s\"", source); } - else if (*s == '+') s++; - if (!isdigit((unsigned char)*s)) return -1; /* no digit in the exponent? */ - do { - e = 10*e + (*(s++)-'0'); - } while (isdigit((unsigned char)*s)); - point -= sig*e; } - while (isspace((unsigned char)*s)) s++; - if (*s != '\0') return -1; /* invalid trailing characters? */ - if (point > 0) - a /= expten(point); - else if (point < 0) - a *= expten(-point); - return a; } - diff --git a/src/lobject.h b/src/lobject.h index f3b21477c4..cb232c770b 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.28 1999/03/16 16:43:27 roberto Exp $ +** $Id: lobject.h,v 1.82 2000/10/30 17:49:19 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -8,197 +8,197 @@ #define lobject_h -#include - +#include "llimits.h" #include "lua.h" -#ifdef DEBUG -#include "lauxlib.h" -#define LUA_INTERNALERROR(s) \ - luaL_verror("INTERNAL ERROR - %s [%s:%d]",(s),__FILE__,__LINE__) -#define LUA_ASSERT(c,s) { if (!(c)) LUA_INTERNALERROR(s); } +#ifdef LUA_DEBUG +#undef NDEBUG +#include +#define LUA_INTERNALERROR(s) assert(((void)s,0)) +#define LUA_ASSERT(c,s) assert(((void)s,(c))) #else -#define LUA_INTERNALERROR(s) /* empty */ -#define LUA_ASSERT(c,s) /* empty */ +#define LUA_INTERNALERROR(s) /* empty */ +#define LUA_ASSERT(c,s) /* empty */ #endif -/* -** "real" is the type "number" of Lua -** GREP LUA_NUMBER to change that -*/ -#ifndef LUA_NUM_TYPE -#define LUA_NUM_TYPE double +#ifdef LUA_DEBUG +/* to avoid warnings, and make sure value is really unused */ +#define UNUSED(x) (x=0, (void)(x)) +#else +#define UNUSED(x) ((void)(x)) /* to avoid warnings */ #endif -typedef LUA_NUM_TYPE real; - -#define Byte lua_Byte /* some systems have Byte as a predefined type */ -typedef unsigned char Byte; /* unsigned 8 bits */ - +/* mark for closures active in the stack */ +#define LUA_TMARK 6 -#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ -typedef unsigned int IntPoint; /* unsigned with same size as a pointer (for hashing) */ +/* tags for values visible from Lua == first user-created tag */ +#define NUM_TAGS 6 -/* -** Lua TYPES -** WARNING: if you change the order of this enumeration, -** grep "ORDER LUA_T" -*/ -typedef enum { - LUA_T_USERDATA = 0, /* tag default for userdata */ - LUA_T_NUMBER = -1, /* fixed tag for numbers */ - LUA_T_STRING = -2, /* fixed tag for strings */ - LUA_T_ARRAY = -3, /* tag default for tables (or arrays) */ - LUA_T_PROTO = -4, /* fixed tag for functions */ - LUA_T_CPROTO = -5, /* fixed tag for Cfunctions */ - LUA_T_NIL = -6, /* last "pre-defined" tag */ - LUA_T_CLOSURE = -7, - LUA_T_CLMARK = -8, /* mark for closures */ - LUA_T_PMARK = -9, /* mark for Lua prototypes */ - LUA_T_CMARK = -10, /* mark for C prototypes */ - LUA_T_LINE = -11 -} lua_Type; - -#define NUM_TAGS 7 +/* check whether `t' is a mark */ +#define is_T_MARK(t) ((t) == LUA_TMARK) typedef union { - lua_CFunction f; /* LUA_T_CPROTO, LUA_T_CMARK */ - real n; /* LUA_T_NUMBER */ - struct TaggedString *ts; /* LUA_T_STRING, LUA_T_USERDATA */ - struct TProtoFunc *tf; /* LUA_T_PROTO, LUA_T_PMARK */ - struct Closure *cl; /* LUA_T_CLOSURE, LUA_T_CLMARK */ - struct Hash *a; /* LUA_T_ARRAY */ - int i; /* LUA_T_LINE */ + struct TString *ts; /* LUA_TSTRING, LUA_TUSERDATA */ + struct Closure *cl; /* LUA_TFUNCTION */ + struct Hash *a; /* LUA_TTABLE */ + struct CallInfo *i; /* LUA_TLMARK */ + Number n; /* LUA_TNUMBER */ } Value; -typedef struct TObject { - lua_Type ttype; +/* Macros to access values */ +#define ttype(o) ((o)->ttype) +#define nvalue(o) ((o)->value.n) +#define tsvalue(o) ((o)->value.ts) +#define clvalue(o) ((o)->value.cl) +#define hvalue(o) ((o)->value.a) +#define infovalue(o) ((o)->value.i) +#define svalue(o) (tsvalue(o)->str) + + +typedef struct lua_TObject { + int ttype; Value value; } TObject; - /* -** generic header for garbage collector lists +** String headers for string table */ -typedef struct GCnode { - struct GCnode *next; - int marked; -} GCnode; - /* -** String headers for string table +** most `malloc' libraries allocate memory in blocks of 8 bytes. TSPACK +** tries to make sizeof(TString) a multiple of this granularity, to reduce +** waste of space. */ +#define TSPACK ((int)sizeof(int)) -typedef struct TaggedString { - GCnode head; - unsigned long hash; - int constindex; /* hint to reuse constants (= -1 if this is a userdata) */ +typedef struct TString { union { - struct { - TObject globalval; - long len; /* if this is a string, here is its length */ + struct { /* for strings */ + unsigned long hash; + int constindex; /* hint to reuse constants */ } s; - struct { + struct { /* for userdata */ int tag; - void *v; /* if this is a userdata, here is its value */ + void *value; } d; } u; - char str[1]; /* \0 byte already reserved */ -} TaggedString; - - + size_t len; + struct TString *nexthash; /* chain for hash table */ + int marked; + char str[TSPACK]; /* variable length string!! must be the last field! */ +} TString; /* ** Function Prototypes */ -typedef struct TProtoFunc { - GCnode head; - struct TObject *consts; - int nconsts; - Byte *code; /* ends with opcode ENDCODE */ +typedef struct Proto { + Number *knum; /* Number numbers used by the function */ + int nknum; /* size of `knum' */ + struct TString **kstr; /* strings used by the function */ + int nkstr; /* size of `kstr' */ + struct Proto **kproto; /* functions defined inside the function */ + int nkproto; /* size of `kproto' */ + Instruction *code; + int ncode; /* size of `code'; when 0 means an incomplete `Proto' */ + short numparams; + short is_vararg; + short maxstacksize; + short marked; + struct Proto *next; + /* debug information */ + int *lineinfo; /* map from opcodes to source lines */ + int nlineinfo; /* size of `lineinfo' */ + int nlocvars; + struct LocVar *locvars; /* information about local variables */ int lineDefined; - TaggedString *source; - struct LocVar *locvars; /* ends with line = -1 */ -} TProtoFunc; + TString *source; +} Proto; + typedef struct LocVar { - TaggedString *varname; /* NULL signals end of scope */ - int line; + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ } LocVar; - - - -/* Macros to access structure members */ -#define ttype(o) ((o)->ttype) -#define nvalue(o) ((o)->value.n) -#define svalue(o) ((o)->value.ts->str) -#define tsvalue(o) ((o)->value.ts) -#define clvalue(o) ((o)->value.cl) -#define avalue(o) ((o)->value.a) -#define fvalue(o) ((o)->value.f) -#define tfvalue(o) ((o)->value.tf) - -#define protovalue(o) ((o)->value.cl->consts) - - /* ** Closures */ typedef struct Closure { - GCnode head; - int nelems; /* not included the first one (always the prototype) */ - TObject consts[1]; /* at least one for prototype */ + union { + lua_CFunction c; /* C functions */ + struct Proto *l; /* Lua functions */ + } f; + struct Closure *next; + struct Closure *mark; /* marked closures (point to itself when not marked) */ + short isC; /* 0 for Lua functions, 1 for C functions */ + short nupvalues; + TObject upvalue[1]; } Closure; +#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->isC) + -typedef struct node { - TObject ref; +typedef struct Node { + TObject key; TObject val; + struct Node *next; /* for chaining */ } Node; typedef struct Hash { - GCnode head; Node *node; - int nhash; - int nuse; int htag; + int size; + Node *firstfree; /* this position is free; all positions after it are full */ + struct Hash *next; + struct Hash *mark; /* marked tables (point to itself when not marked) */ } Hash; -extern char *luaO_typenames[]; +/* unmarked tables and closures are represented by pointing `mark' to +** themselves +*/ +#define ismarked(x) ((x)->mark != (x)) + -#define luaO_typename(o) luaO_typenames[-ttype(o)] +/* +** informations about a call (for debugging) +*/ +typedef struct CallInfo { + struct Closure *func; /* function being called */ + const Instruction **pc; /* current pc of called function */ + int lastpc; /* last pc traced */ + int line; /* current line */ + int refi; /* current index in `lineinfo' */ +} CallInfo; -extern TObject luaO_nilobject; +extern const TObject luaO_nilobject; +extern const char *const luaO_typenames[]; -#define luaO_equalObj(t1,t2) ((ttype(t1) != ttype(t2)) ? 0 \ - : luaO_equalval(t1,t2)) -int luaO_equalval (TObject *t1, TObject *t2); -int luaO_redimension (int oldsize); -void luaO_insertlist (GCnode *root, GCnode *node); -double luaO_str2d (char *s); -#ifdef OLD_ANSI -void luaO_memup (void *dest, void *src, int size); -void luaO_memdown (void *dest, void *src, int size); -#else -#include -#define luaO_memup(d,s,n) memmove(d,s,n) -#define luaO_memdown(d,s,n) memmove(d,s,n) -#endif +#define luaO_typename(o) (luaO_typenames[ttype(o)]) + + +lint32 luaO_power2 (lint32 n); +char *luaO_openspace (lua_State *L, size_t n); + +int luaO_equalObj (const TObject *t1, const TObject *t2); +int luaO_str2d (const char *s, Number *result); + +void luaO_verror (lua_State *L, const char *fmt, ...); +void luaO_chunkid (char *out, const char *source, int len); + #endif diff --git a/src/lopcodes.h b/src/lopcodes.h index 6a59b39ef1..2df72ce7e8 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.33 1999/06/17 17:04:03 roberto Exp $ +** $Id: lopcodes.h,v 1.68 2000/10/24 16:05:59 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -7,132 +7,162 @@ #ifndef lopcodes_h #define lopcodes_h +#include "llimits.h" -/* -** NOTICE: variants of the same opcode must be consecutive: First, those -** with word parameter, then with byte parameter. -*/ +/*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. Moreover, + an instruction can have 0, 1, or 2 arguments. Instructions can + have the following types: + type 0: no arguments + type 1: 1 unsigned argument in the higher bits (called `U') + type 2: 1 signed argument in the higher bits (`S') + type 3: 1st unsigned argument in the higher bits (`A') + 2nd unsigned argument in the middle bits (`B') -typedef enum { -/* name parm before after side effect ------------------------------------------------------------------------------*/ -ENDCODE,/* - - (return) */ -RETCODE,/* b - (return) */ + A signed argument is represented in excess K; that is, the number + value is the unsigned value minus K. K is exactly the maximum value + for that argument (so that -max is represented by 0, and +max is + represented by 2*max), which is half the maximum for the corresponding + unsigned argument. -CALL,/* b c v_c...v_1 f r_b...r_1 f(v1,...,v_c) */ + The size of each argument is defined in `llimits.h'. The usual is an + instruction with 32 bits, U arguments with 26 bits (32-6), B arguments + with 9 bits, and A arguments with 17 bits (32-6-9). For small + installations, the instruction size can be 16, so U has 10 bits, + and A and B have 5 bits each. +===========================================================================*/ -TAILCALL,/* b c v_c...v_1 f (return) f(v1,...,v_c) */ -PUSHNIL,/* b - nil_0...nil_b */ -POP,/* b a_b...a_1 - */ -PUSHNUMBERW,/* w - (float)w */ -PUSHNUMBER,/* b - (float)b */ -PUSHNUMBERNEGW,/* w - (float)-w */ -PUSHNUMBERNEG,/* b - (float)-b */ +/* creates a mask with `n' 1 bits at position `p' */ +#define MASK1(n,p) ((~((~(Instruction)0)<>POS_U)) +#define SETARG_U(i,u) ((i) = (((i)&MASK0(SIZE_U,POS_U)) | \ + ((Instruction)(u)<>POS_A)) +#define SETARG_A(i,a) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ + ((Instruction)(a)<>POS_B) & MASK1(SIZE_B,0))) +#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ + ((Instruction)(b)<y)? 1 : nil */ -GEOP,/* - y x (x>=y)? 1 : nil */ -ADDOP,/* - y x x+y */ -SUBOP,/* - y x x-y */ -MULTOP,/* - y x x*y */ -DIVOP,/* - y x x/y */ -POWOP,/* - y x x^y */ -CONCOP,/* - y x x..y */ -MINUSOP,/* - x -x */ -NOTOP,/* - x (x==nil)? 1 : nil */ +OP_GETLOCAL,/* L - LOC[l] */ +OP_GETGLOBAL,/* K - VAR[KSTR[k]] */ -ONTJMPW,/* w x (x!=nil)? x : - (x!=nil)? PC+=w */ -ONTJMP,/* b x (x!=nil)? x : - (x!=nil)? PC+=b */ -ONFJMPW,/* w x (x==nil)? x : - (x==nil)? PC+=w */ -ONFJMP,/* b x (x==nil)? x : - (x==nil)? PC+=b */ -JMPW,/* w - - PC+=w */ -JMP,/* b - - PC+=b */ -IFFJMPW,/* w x - (x==nil)? PC+=w */ -IFFJMP,/* b x - (x==nil)? PC+=b */ -IFTUPJMPW,/* w x - (x!=nil)? PC-=w */ -IFTUPJMP,/* b x - (x!=nil)? PC-=b */ -IFFUPJMPW,/* w x - (x==nil)? PC-=w */ -IFFUPJMP,/* b x - (x==nil)? PC-=b */ +OP_GETTABLE,/* - i t t[i] */ +OP_GETDOTTED,/* K t t[KSTR[k]] */ +OP_GETINDEXED,/* L t t[LOC[l]] */ +OP_PUSHSELF,/* K t t t[KSTR[k]] */ -CLOSUREW,/* w c v_c...v_1 closure(CNST[w], v_c...v_1) */ -CLOSURE,/* b c v_c...v_1 closure(CNST[b], v_c...v_1) */ +OP_CREATETABLE,/* U - newarray(size = u) */ -SETLINEW,/* w - - LINE=w */ -SETLINE,/* b - - LINE=b */ +OP_SETLOCAL,/* L x - LOC[l]=x */ +OP_SETGLOBAL,/* K x - VAR[KSTR[k]]=x */ +OP_SETTABLE,/* A B v a_a-a_1 i t (pops b values) t[i]=v */ -LONGARGW,/* w (add w*(1<<16) to arg of next instruction) */ -LONGARG,/* b (add b*(1<<16) to arg of next instruction) */ +OP_SETLIST,/* A B v_b-v_1 t t t[i+a*FPF]=v_i */ +OP_SETMAP,/* U v_u k_u - v_1 k_1 t t t[k_i]=v_i */ -CHECKSTACK /* b (assert #temporaries == b; only for internal debuging!) */ +OP_ADD,/* - y x x+y */ +OP_ADDI,/* S x x+s */ +OP_SUB,/* - y x x-y */ +OP_MULT,/* - y x x*y */ +OP_DIV,/* - y x x/y */ +OP_POW,/* - y x x^y */ +OP_CONCAT,/* U v_u-v_1 v1..-..v_u */ +OP_MINUS,/* - x -x */ +OP_NOT,/* - x (x==nil)? 1 : nil */ -} OpCode; +OP_JMPNE,/* J y x - (x~=y)? PC+=s */ +OP_JMPEQ,/* J y x - (x==y)? PC+=s */ +OP_JMPLT,/* J y x - (xy)? PC+=s */ +OP_JMPGE,/* J y x - (x>=y)? PC+=s */ +OP_JMPT,/* J x - (x~=nil)? PC+=s */ +OP_JMPF,/* J x - (x==nil)? PC+=s */ +OP_JMPONT,/* J x (x~=nil)? x : - (x~=nil)? PC+=s */ +OP_JMPONF,/* J x (x==nil)? x : - (x==nil)? PC+=s */ +OP_JMP,/* J - - PC+=s */ -#define RFIELDS_PER_FLUSH 32 /* records (SETMAP) */ -#define LFIELDS_PER_FLUSH 64 /* FPF - lists (SETLIST) */ +OP_PUSHNILJMP,/* - - nil PC++; */ -#define ZEROVARARG 128 +OP_FORPREP,/* J */ +OP_FORLOOP,/* J */ +OP_LFORPREP,/* J */ +OP_LFORLOOP,/* J */ -/* maximum value of an arg of 3 bytes; must fit in an "int" */ -#if MAX_INT < (1<<24) -#define MAX_ARG MAX_INT -#else -#define MAX_ARG ((1<<24)-1) -#endif +OP_CLOSURE/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */ -/* maximum value of a word of 2 bytes; cannot be bigger than MAX_ARG */ -#if MAX_ARG < (1<<16) -#define MAX_WORD MAX_ARG -#else -#define MAX_WORD ((1<<16)-1) -#endif +} OpCode; + +#define NUM_OPCODES ((int)OP_CLOSURE+1) -/* maximum value of a byte */ -#define MAX_BYTE ((1<<8)-1) +#define ISJUMP(o) (OP_JMPNE <= (o) && (o) <= OP_JMP) + + + +/* special code to fit a LUA_MULTRET inside an argB */ +#define MULT_RET 255 /* (<=MAXARG_B) */ +#if MULT_RET>MAXARG_B +#undef MULT_RET +#define MULT_RET MAXARG_B +#endif #endif diff --git a/src/lparser.c b/src/lparser.c index b0aa13f5ac..b792c95685 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.37a 1999/06/17 17:04:03 roberto Exp $ +** $Id: lparser.c,v 1.116 2000/10/27 11:39:52 roberto Exp $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -8,1385 +8,1117 @@ #include #include -#include "lauxlib.h" -#include "ldo.h" +#include "lua.h" + +#include "lcode.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" +#include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" -#include "lua.h" -#include "luadebug.h" -#include "lzio.h" - - - -/* size of a "normal" jump instruction: OpCode + 1 byte */ -#define JMPSIZE 2 - -/* maximum number of local variables */ -#ifndef MAXLOCALS -#define MAXLOCALS 200 /* arbitrary limit (<256) */ -#endif - - -/* maximum number of upvalues */ -#ifndef MAXUPVALUES -#define MAXUPVALUES 32 /* arbitrary limit (<256) */ -#endif - - -/* maximum number of variables in the left side of an assignment */ -#ifndef MAXVARSLH -#define MAXVARSLH 100 /* arbitrary limit (<255) */ -#endif - - -/* maximum number of parameters in a function */ -#ifndef MAXPARAMS -#define MAXPARAMS 100 /* arbitrary limit (locvars (-1 if no debug information) */ - int lastsetline; /* line where last SETLINE was issued */ - vardesc upvalues[MAXUPVALUES]; /* upvalues */ - TaggedString *localvar[MAXLOCALS]; /* store local variable names */ -} FuncState; /* -** prototypes for non-terminal functions +** prototypes for recursive non-terminal functions */ -static int assignment (LexState *ls, vardesc *v, int nvars); -static int cond (LexState *ls); -static int funcname (LexState *ls, vardesc *v); -static int funcparams (LexState *ls, int slf); -static int listfields (LexState *ls); -static int localnamelist (LexState *ls); -static int optional (LexState *ls, int c); -static int recfields (LexState *ls); -static int stat (LexState *ls); -static void block (LexState *ls); static void body (LexState *ls, int needself, int line); static void chunk (LexState *ls); static void constructor (LexState *ls); -static void decinit (LexState *ls, listdesc *d); -static void exp0 (LexState *ls, vardesc *v); +static void expr (LexState *ls, expdesc *v); static void exp1 (LexState *ls); -static void exp2 (LexState *ls, vardesc *v); -static void explist (LexState *ls, listdesc *e); -static void explist1 (LexState *ls, listdesc *e); -static void ifpart (LexState *ls, int line); -static void parlist (LexState *ls); -static void part (LexState *ls, constdesc *cd); -static void recfield (LexState *ls); -static void ret (LexState *ls); -static void statlist (LexState *ls); -static void var_or_func (LexState *ls, vardesc *v); -static void var_or_func_tail (LexState *ls, vardesc *v); - - - -static void checklimit (LexState *ls, int val, int limit, char *msg) { - if (val > limit) { - char buff[100]; - sprintf(buff, "too many %s (limit=%d)", msg, limit); - luaX_error(ls, buff); - } -} - -static void check_pc (FuncState *fs, int n) { - luaM_growvector(fs->f->code, fs->pc, n, Byte, codeEM, MAX_INT); -} - - -static void code_byte (FuncState *fs, Byte c) { - check_pc(fs, 1); - fs->f->code[fs->pc++] = c; -} - - -static void deltastack (LexState *ls, int delta) { - FuncState *fs = ls->fs; - fs->stacksize += delta; - if (fs->stacksize > fs->maxstacksize) { - if (fs->stacksize > MAX_BYTE) - luaX_error(ls, "function/expression too complex"); - fs->maxstacksize = fs->stacksize; - } -} -static void code_oparg_at (LexState *ls, int pc, OpCode op, - int arg, int delta) { - Byte *code = ls->fs->f->code; - deltastack(ls, delta); - if (arg <= MAX_BYTE) { - code[pc] = (Byte)op; - code[pc+1] = (Byte)arg; - } - else if (arg > MAX_ARG) - luaX_error(ls, "code too long"); - else { /* MAX_BYTE < arg < MAX_ARG */ - if (arg > MAX_WORD) { - code[pc] = (Byte)LONGARG; - code[pc+1] = (Byte)(arg>>16); - pc += 2; - } - code[pc] = (Byte)(op-1); /* opcode for word argument */ - code[pc+1] = (Byte)((arg&0xFFFF)>>8); - code[pc+2] = (Byte)(arg&0xFF); +static void next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ } + else + ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */ } -static int codesize (int arg) { - if (arg <= MAX_BYTE) return 2; /* opcode + 1 byte */ - else if (arg <= MAX_WORD) return 3; /* opcode + 1 word (2 bytes) */ - else return 5; /* LONGARG + 1 byte + opcode + 1 word (2 bytes) */ +static void lookahead (LexState *ls) { + LUA_ASSERT(ls->lookahead.token == TK_EOS, "two look-aheads"); + ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo); } -static int fix_opcode (LexState *ls, int pc, OpCode op, int arg) { - int tomove = codesize(arg)-2; - if (tomove > 0) { /* need to open space? */ - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - check_pc(fs, tomove); - luaO_memup(f->code+pc+tomove, f->code+pc, fs->pc-pc); - fs->pc += tomove; - } - code_oparg_at(ls, pc, op, arg, 0); - return tomove; +static void error_expected (LexState *ls, int token) { + char buff[100], t[TOKEN_LEN]; + luaX_token2str(token, t); + sprintf(buff, "`%.20s' expected", t); + luaK_error(ls, buff); } -static void code_oparg (LexState *ls, OpCode op, int arg, int delta) { - int size = codesize(arg); - check_pc(ls->fs, size); - code_oparg_at(ls, ls->fs->pc, op, arg, delta); - ls->fs->pc += size; +static void check (LexState *ls, int c) { + if (ls->t.token != c) + error_expected(ls, c); + next(ls); } -static void code_opcode (LexState *ls, OpCode op, int delta) { - deltastack(ls, delta); - code_byte(ls->fs, (Byte)op); +static void check_condition (LexState *ls, int c, const char *msg) { + if (!c) luaK_error(ls, msg); } -static void code_constant (LexState *ls, int c) { - code_oparg(ls, PUSHCONSTANT, c, 1); +static int optional (LexState *ls, int c) { + if (ls->t.token == c) { + next(ls); + return 1; + } + else return 0; } -static int next_constant (FuncState *fs) { - TProtoFunc *f = fs->f; - luaM_growvector(f->consts, f->nconsts, 1, TObject, constantEM, MAX_ARG); - return f->nconsts++; +static void check_match (LexState *ls, int what, int who, int where) { + if (ls->t.token != what) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + char buff[100]; + char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; + luaX_token2str(what, t_what); + luaX_token2str(who, t_who); + sprintf(buff, "`%.20s' expected (to close `%.20s' at line %d)", + t_what, t_who, where); + luaK_error(ls, buff); + } + } + next(ls); } -static int string_constant (FuncState *fs, TaggedString *s) { - TProtoFunc *f = fs->f; - int c = s->constindex; - if (!(c < f->nconsts && - ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) { - c = next_constant(fs); - ttype(&f->consts[c]) = LUA_T_STRING; - tsvalue(&f->consts[c]) = s; - s->constindex = c; /* hint for next time */ +static int string_constant (FuncState *fs, TString *s) { + Proto *f = fs->f; + int c = s->u.s.constindex; + if (c >= f->nkstr || f->kstr[c] != s) { + luaM_growvector(fs->L, f->kstr, f->nkstr, 1, TString *, + "constant table overflow", MAXARG_U); + c = f->nkstr++; + f->kstr[c] = s; + s->u.s.constindex = c; /* hint for next time */ } return c; } -static void code_string (LexState *ls, TaggedString *s) { - code_constant(ls, string_constant(ls->fs, s)); -} - - -#define LIM 20 -static int real_constant (FuncState *fs, real r) { - /* check whether 'r' has appeared within the last LIM entries */ - TObject *cnt = fs->f->consts; - int c = fs->f->nconsts; - int lim = c < LIM ? 0 : c-LIM; - while (--c >= lim) { - if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) - return c; - } - /* not found; create a new entry */ - c = next_constant(fs); - cnt = fs->f->consts; /* 'next_constant' may have reallocated this vector */ - ttype(&cnt[c]) = LUA_T_NUMBER; - nvalue(&cnt[c]) = r; - return c; +static void code_string (LexState *ls, TString *s) { + luaK_kstr(ls, string_constant(ls->fs, s)); } -static void code_number (LexState *ls, real f) { - real af = (f<0) ? -f : f; - if (0 <= af && af <= (real)MAX_WORD && (int)af == af) { - /* abs(f) has a short integer value */ - code_oparg(ls, (f<0) ? PUSHNUMBERNEG : PUSHNUMBER, (int)af, 1); - } - else - code_constant(ls, real_constant(ls->fs, f)); +static TString *str_checkname (LexState *ls) { + TString *ts; + check_condition(ls, (ls->t.token == TK_NAME), " expected"); + ts = ls->t.seminfo.ts; + next(ls); + return ts; } -static void flush_record (LexState *ls, int n) { - if (n > 0) - code_oparg(ls, SETMAP, n-1, -2*n); +static int checkname (LexState *ls) { + return string_constant(ls->fs, str_checkname(ls)); } -static void flush_list (LexState *ls, int m, int n) { - if (n > 0) { - code_oparg(ls, SETLIST, m, -n); - code_byte(ls->fs, (Byte)n); - } +static int luaI_registerlocalvar (LexState *ls, TString *varname) { + Proto *f = ls->fs->f; + luaM_growvector(ls->L, f->locvars, f->nlocvars, 1, LocVar, "", MAX_INT); + f->locvars[f->nlocvars].varname = varname; + return f->nlocvars++; } -static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname, - int line) { - if (fs->nvars != -1) { /* debug information? */ - TProtoFunc *f = fs->f; - luaM_growvector(f->locvars, fs->nvars, 1, LocVar, "", MAX_INT); - f->locvars[fs->nvars].varname = varname; - f->locvars[fs->nvars].line = line; - fs->nvars++; - } +static void new_localvar (LexState *ls, TString *name, int n) { + FuncState *fs = ls->fs; + luaX_checklimit(ls, fs->nactloc+n+1, MAXLOCALS, "local variables"); + fs->actloc[fs->nactloc+n] = luaI_registerlocalvar(ls, name); } -static void luaI_unregisterlocalvar (FuncState *fs, int line) { - luaI_registerlocalvar(fs, NULL, line); +static void adjustlocalvars (LexState *ls, int nvars) { + FuncState *fs = ls->fs; + while (nvars--) + fs->f->locvars[fs->actloc[fs->nactloc++]].startpc = fs->pc; } -static void store_localvar (LexState *ls, TaggedString *name, int n) { +static void removelocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - checklimit(ls, fs->nlocalvar+n+1, MAXLOCALS, "local variables"); - fs->localvar[fs->nlocalvar+n] = name; - luaI_registerlocalvar(fs, name, ls->linenumber); + while (nvars--) + fs->f->locvars[fs->actloc[--fs->nactloc]].endpc = fs->pc; } -static void add_localvar (LexState *ls, TaggedString *name) { - store_localvar(ls, name, 0); - ls->fs->nlocalvar++; +static void new_localvarstr (LexState *ls, const char *name, int n) { + new_localvar(ls, luaS_newfixed(ls->L, name), n); } -static void correctvarlines (LexState *ls, int nvars) { - FuncState *fs = ls->fs; - if (fs->nvars != -1) { /* debug information? */ - for (; nvars; nvars--) { /* correct line information */ - fs->f->locvars[fs->nvars-nvars].line = fs->lastsetline; +static int search_local (LexState *ls, TString *n, expdesc *var) { + FuncState *fs; + int level = 0; + for (fs=ls->fs; fs; fs=fs->prev) { + int i; + for (i=fs->nactloc-1; i >= 0; i--) { + if (n == fs->f->locvars[fs->actloc[i]].varname) { + var->k = VLOCAL; + var->u.index = i; + return level; + } } + level++; /* `var' not found; check outer level */ } + var->k = VGLOBAL; /* not found in any level; must be global */ + return -1; } -static int aux_localname (FuncState *fs, TaggedString *n) { - int i; - for (i=fs->nlocalvar-1; i >= 0; i--) - if (n == fs->localvar[i]) return i; /* local var index */ - return -1; /* not found */ -} - - -static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) { - FuncState *fs = prev ? ls->fs->prev : ls->fs; - int i = aux_localname(fs, n); - if (i >= 0) { /* local value? */ - var->k = VLOCAL; - var->info = i; - } - else { - FuncState *level = fs; - while ((level = level->prev) != NULL) /* check shadowing */ - if (aux_localname(level, n) >= 0) - luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); - var->k = VGLOBAL; - var->info = string_constant(fs, n); - } +static void singlevar (LexState *ls, TString *n, expdesc *var) { + int level = search_local(ls, n, var); + if (level >= 1) /* neither local (0) nor global (-1)? */ + luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); + else if (level == -1) /* global? */ + var->u.index = string_constant(ls->fs, n); } -static int indexupvalue (LexState *ls, TaggedString *n) { +static int indexupvalue (LexState *ls, expdesc *v) { FuncState *fs = ls->fs; - vardesc v; int i; - singlevar(ls, n, &v, 1); for (i=0; inupvalues; i++) { - if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info) + if (fs->upvalues[i].k == v->k && fs->upvalues[i].u.index == v->u.index) return i; } /* new one */ - ++(fs->nupvalues); - checklimit(ls, fs->nupvalues, MAXUPVALUES, "upvalues"); - fs->upvalues[i] = v; /* i = fs->nupvalues - 1 */ - return i; -} - - -static void pushupvalue (LexState *ls, TaggedString *n) { - if (ls->fs->prev == NULL) - luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); - if (aux_localname(ls->fs, n) >= 0) - luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str); - code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1); -} - - - -static void check_debugline (LexState *ls) { - if (L->debug && ls->linenumber != ls->fs->lastsetline) { - code_oparg(ls, SETLINE, ls->linenumber, 0); - ls->fs->lastsetline = ls->linenumber; - } -} - - -static void adjuststack (LexState *ls, int n) { - if (n > 0) - code_oparg(ls, POP, n, -n); - else if (n < 0) - code_oparg(ls, PUSHNIL, (-n)-1, -n); + luaX_checklimit(ls, fs->nupvalues+1, MAXUPVALUES, "upvalues"); + fs->upvalues[fs->nupvalues] = *v; + return fs->nupvalues++; } -static void close_exp (LexState *ls, int pc, int nresults) { - if (pc > 0) { /* expression is an open function call? */ - Byte *code = ls->fs->f->code; - code[pc-1] = (Byte)nresults; /* set nresults */ - /* push results, pop params (at code[pc]) and function */ - deltastack(ls, nresults-(code[pc]+1)); +static void pushupvalue (LexState *ls, TString *n) { + FuncState *fs = ls->fs; + expdesc v; + int level = search_local(ls, n, &v); + if (level == -1) { /* global? */ + if (fs->prev == NULL) + luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); + v.u.index = string_constant(fs->prev, n); } -#ifdef DEBUG - code_oparg(ls, CHECKSTACK, ls->fs->stacksize, 0); -#endif + else if (level != 1) + luaX_syntaxerror(ls, + "upvalue must be global or local to immediately outer scope", n->str); + luaK_code1(fs, OP_PUSHUPVALUE, indexupvalue(ls, &v)); } -static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { - int diff = d->n - nvars; - if (d->pc == 0) { /* list is closed */ - /* push or pop eventual difference between list lengths */ - adjuststack(ls, diff); - } - else { /* must correct function call */ +static void adjust_mult_assign (LexState *ls, int nvars, int nexps) { + FuncState *fs = ls->fs; + int diff = nexps - nvars; + if (nexps > 0 && luaK_lastisopen(fs)) { /* list ends in a function call */ diff--; /* do not count function call itself */ if (diff <= 0) { /* more variables than values? */ - /* function call must provide extra values */ - close_exp(ls, d->pc, -diff); - } - else { /* more values than variables */ - close_exp(ls, d->pc, 0); /* call should provide no value */ - adjuststack(ls, diff); /* pop eventual extra values */ + luaK_setcallreturns(fs, -diff); /* function call provide extra values */ + diff = 0; /* no more difference */ } + else /* more values than variables */ + luaK_setcallreturns(fs, 0); /* call should provide no value */ } + /* push or pop eventual difference between list lengths */ + luaK_adjuststack(fs, diff); } -static void code_args (LexState *ls, int nparams, int dots) { +static void code_params (LexState *ls, int nparams, int dots) { FuncState *fs = ls->fs; - fs->nlocalvar += nparams; /* "self" may already be there */ - checklimit(ls, fs->nlocalvar, MAXPARAMS, "parameters"); - nparams = fs->nlocalvar; - if (!dots) { - fs->f->code[1] = (Byte)nparams; /* fill-in arg information */ - deltastack(ls, nparams); - } - else { - fs->f->code[1] = (Byte)(nparams+ZEROVARARG); - deltastack(ls, nparams+1); - add_localvar(ls, luaS_new("arg")); - } -} - - -static void unloaddot (LexState *ls, vardesc *v) { - /* dotted variables must be stored like regular indexed vars */ - if (v->k == VDOT) { - code_constant(ls, v->info); - v->k = VINDEXED; - } -} - - -static void lua_pushvar (LexState *ls, vardesc *var) { - switch (var->k) { - case VLOCAL: - code_oparg(ls, PUSHLOCAL, var->info, 1); - break; - case VGLOBAL: - code_oparg(ls, GETGLOBAL, var->info, 1); - break; - case VDOT: - code_oparg(ls, GETDOTTED, var->info, 0); - break; - case VINDEXED: - code_opcode(ls, GETTABLE, -1); - break; - case VEXP: - close_exp(ls, var->info, 1); /* function must return 1 value */ - break; - } - var->k = VEXP; - var->info = 0; /* now this is a closed expression */ -} - - -static void storevar (LexState *ls, vardesc *var) { - switch (var->k) { - case VLOCAL: - code_oparg(ls, SETLOCAL, var->info, -1); - break; - case VGLOBAL: - code_oparg(ls, SETGLOBAL, var->info, -1); - break; - case VINDEXED: - code_opcode(ls, SETTABLEPOP, -3); - break; - default: - LUA_INTERNALERROR("invalid var kind to store"); + adjustlocalvars(ls, nparams); + luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters"); + fs->f->numparams = fs->nactloc; /* `self' could be there already */ + fs->f->is_vararg = dots; + if (dots) { + new_localvarstr(ls, "arg", 0); + adjustlocalvars(ls, 1); } + luaK_deltastack(fs, fs->nactloc); /* count parameters in the stack */ } -static int fix_jump (LexState *ls, int pc, OpCode op, int n) { - /* jump is relative to position following jump instruction */ - return fix_opcode(ls, pc, op, n-(pc+JMPSIZE)); -} - - -static void fix_upjmp (LexState *ls, OpCode op, int pos) { - int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */ - code_oparg(ls, op, delta+(codesize(delta)-2), 0); +static void enterbreak (FuncState *fs, Breaklabel *bl) { + bl->stacklevel = fs->stacklevel; + bl->breaklist = NO_JUMP; + bl->previous = fs->bl; + fs->bl = bl; } -static void codeIf (LexState *ls, int thenAdd, int elseAdd) { - FuncState *fs = ls->fs; - int elseinit = elseAdd+JMPSIZE; - if (fs->pc == elseinit) { /* no else part? */ - fs->pc -= JMPSIZE; - elseinit = fs->pc; - } - else - elseinit += fix_jump(ls, elseAdd, JMP, fs->pc); - fix_jump(ls, thenAdd, IFFJMP, elseinit); +static void leavebreak (FuncState *fs, Breaklabel *bl) { + fs->bl = bl->previous; + LUA_ASSERT(bl->stacklevel == fs->stacklevel, "wrong levels"); + luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs)); } -static void func_onstack (LexState *ls, FuncState *func) { +static void pushclosure (LexState *ls, FuncState *func) { FuncState *fs = ls->fs; + Proto *f = fs->f; int i; - int c = next_constant(fs); - ttype(&fs->f->consts[c]) = LUA_T_PROTO; - fs->f->consts[c].value.tf = func->f; - if (func->nupvalues == 0) - code_constant(ls, c); - else { - for (i=0; inupvalues; i++) - lua_pushvar(ls, &func->upvalues[i]); - deltastack(ls, 1); /* CLOSURE puts one extra element (before poping) */ - code_oparg(ls, CLOSURE, c, -func->nupvalues); - code_byte(fs, (Byte)func->nupvalues); - } + for (i=0; inupvalues; i++) + luaK_tostack(ls, &func->upvalues[i], 1); + luaM_growvector(ls->L, f->kproto, f->nkproto, 1, Proto *, + "constant table overflow", MAXARG_A); + f->kproto[f->nkproto++] = func->f; + luaK_code2(fs, OP_CLOSURE, f->nkproto-1, func->nupvalues); } -static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { - TProtoFunc *f = luaF_newproto(); +static void open_func (LexState *ls, FuncState *fs) { + Proto *f = luaF_newproto(ls->L); fs->prev = ls->fs; /* linked list of funcstates */ + fs->ls = ls; + fs->L = ls->L; ls->fs = fs; - fs->stacksize = 0; - fs->maxstacksize = 0; - fs->nlocalvar = 0; + fs->stacklevel = 0; + fs->nactloc = 0; fs->nupvalues = 0; - fs->lastsetline = 0; + fs->bl = NULL; fs->f = f; - f->source = source; + f->source = ls->source; fs->pc = 0; + fs->lasttarget = 0; + fs->lastline = 0; + fs->jlt = NO_JUMP; f->code = NULL; - fs->nvars = (L->debug) ? 0 : -1; /* flag no debug information? */ - code_byte(fs, 0); /* to be filled with maxstacksize */ - code_byte(fs, 0); /* to be filled with arg information */ - /* push function (to avoid GC) */ - tfvalue(L->stack.top) = f; ttype(L->stack.top) = LUA_T_PROTO; - incr_top; + f->maxstacksize = 0; + f->numparams = 0; /* default for main chunk */ + f->is_vararg = 0; /* default for main chunk */ } static void close_func (LexState *ls) { + lua_State *L = ls->L; FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - code_opcode(ls, ENDCODE, 0); - f->code[0] = (Byte)fs->maxstacksize; - luaM_reallocvector(f->code, fs->pc, Byte); - luaM_reallocvector(f->consts, f->nconsts, TObject); - if (fs->nvars != -1) { /* debug information? */ - luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */ - luaM_reallocvector(f->locvars, fs->nvars, LocVar); - } + Proto *f = fs->f; + luaK_code0(fs, OP_END); + luaK_getlabel(fs); /* close eventual list of pending jumps */ + luaM_reallocvector(L, f->code, fs->pc, Instruction); + luaM_reallocvector(L, f->kstr, f->nkstr, TString *); + luaM_reallocvector(L, f->knum, f->nknum, Number); + luaM_reallocvector(L, f->kproto, f->nkproto, Proto *); + removelocalvars(ls, fs->nactloc); + luaM_reallocvector(L, f->locvars, f->nlocvars, LocVar); + luaM_reallocvector(L, f->lineinfo, f->nlineinfo+1, int); + f->lineinfo[f->nlineinfo++] = MAX_INT; /* end flag */ + luaF_protook(L, f, fs->pc); /* proto is ok now */ ls->fs = fs->prev; - L->stack.top--; /* pop function */ -} - - - -static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME, - LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',', 0}; - - -static int is_in (int tok, int *toks) { - int *t; - for (t=toks; *t; t++) - if (*t == tok) return t-toks; - return -1; -} - - -static void next (LexState *ls) { - ls->token = luaX_lex(ls); -} - - -static void error_expected (LexState *ls, int token) { - char buff[100], t[TOKEN_LEN]; - luaX_token2str(token, t); - sprintf(buff, "`%s' expected", t); - luaX_error(ls, buff); -} - - -static void error_unexpected (LexState *ls) { - luaX_error(ls, "unexpected token"); -} - - -static void error_unmatched (LexState *ls, int what, int who, int where) { - if (where == ls->linenumber) - error_expected(ls, what); - else { - char buff[100]; - char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; - luaX_token2str(what, t_what); - luaX_token2str(who, t_who); - sprintf(buff, "`%s' expected (to close `%s' at line %d)", - t_what, t_who, where); - luaX_error(ls, buff); - } -} - -static void check (LexState *ls, int c) { - if (ls->token != c) - error_expected(ls, c); - next(ls); -} - -static void check_match (LexState *ls, int what, int who, int where) { - if (ls->token != what) - error_unmatched(ls, what, who, where); - check_debugline(ls); /* to 'mark' the 'what' */ - next(ls); -} - -static int checkname (LexState *ls) { - int sc; - if (ls->token != NAME) - luaX_error(ls, "`NAME' expected"); - sc = string_constant(ls->fs, ls->seminfo.ts); - next(ls); - return sc; -} - - -static TaggedString *str_checkname (LexState *ls) { - int i = checkname(ls); /* this call may realloc `f->consts' */ - return tsvalue(&ls->fs->f->consts[i]); -} - - -static int optional (LexState *ls, int c) { - if (ls->token == c) { - next(ls); - return 1; - } - else return 0; + LUA_ASSERT(fs->bl == NULL, "wrong list end"); } -TProtoFunc *luaY_parser (ZIO *z) { +Proto *luaY_parser (lua_State *L, ZIO *z) { struct LexState lexstate; struct FuncState funcstate; - luaX_setinput(&lexstate, z); - init_state(&lexstate, &funcstate, luaS_new(zname(z))); + luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); + open_func(&lexstate, &funcstate); next(&lexstate); /* read first token */ chunk(&lexstate); - if (lexstate.token != EOS) - luaX_error(&lexstate, " expected"); + check_condition(&lexstate, (lexstate.t.token == TK_EOS), " expected"); close_func(&lexstate); + LUA_ASSERT(funcstate.prev == NULL, "wrong list end"); + LUA_ASSERT(funcstate.nupvalues == 0, "no upvalues in main"); return funcstate.f; } /*============================================================*/ -/* GRAMAR RULES */ +/* GRAMMAR RULES */ /*============================================================*/ -static void chunk (LexState *ls) { - /* chunk -> statlist ret */ - statlist(ls); - ret(ls); -} -static void statlist (LexState *ls) { - /* statlist -> { stat [;] } */ - while (stat(ls)) { - LUA_ASSERT(ls->fs->stacksize == ls->fs->nlocalvar, - "stack size != # local vars"); - optional(ls, ';'); +static int explist1 (LexState *ls) { + /* explist1 -> expr { ',' expr } */ + int n = 1; /* at least one expression */ + expdesc v; + expr(ls, &v); + while (ls->t.token == ',') { + luaK_tostack(ls, &v, 1); /* gets only 1 value from previous expression */ + next(ls); /* skip comma */ + expr(ls, &v); + n++; } + luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */ + return n; } -static int stat (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ - FuncState *fs = ls->fs; - switch (ls->token) { - case IF: /* stat -> IF ifpart END */ - ifpart(ls, line); - return 1; - case WHILE: { /* stat -> WHILE cond DO block END */ - TProtoFunc *f = fs->f; - int while_init = fs->pc; - int cond_end, cond_size; +static void funcargs (LexState *ls, int slf) { + FuncState *fs = ls->fs; + int slevel = fs->stacklevel - slf - 1; /* where is func in the stack */ + switch (ls->t.token) { + case '(': { /* funcargs -> '(' [ explist1 ] ')' */ + int line = ls->linenumber; + int nargs = 0; next(ls); - cond_end = cond(ls); - check(ls, DO); - block(ls); - check_match(ls, END, WHILE, line); - cond_size = cond_end-while_init; - check_pc(fs, cond_size); - memcpy(f->code+fs->pc, f->code+while_init, cond_size); - luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); - while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); - fix_upjmp(ls, IFTUPJMP, while_init); - return 1; + if (ls->t.token != ')') /* arg list not empty? */ + nargs = explist1(ls); + check_match(ls, ')', '(', line); +#ifdef LUA_COMPAT_ARGRET + if (nargs > 0) /* arg list is not empty? */ + luaK_setcallreturns(fs, 1); /* last call returns only 1 value */ +#else + UNUSED(nargs); /* to avoid warnings */ +#endif + break; } - - case DO: { /* stat -> DO block END */ - next(ls); - block(ls); - check_match(ls, END, DO, line); - return 1; + case '{': { /* funcargs -> constructor */ + constructor(ls); + break; } - - case REPEAT: { /* stat -> REPEAT block UNTIL exp1 */ - int repeat_init = fs->pc; + case TK_STRING: { /* funcargs -> STRING */ + code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */ next(ls); - block(ls); - check_match(ls, UNTIL, REPEAT, line); - exp1(ls); - fix_upjmp(ls, IFFUPJMP, repeat_init); - deltastack(ls, -1); /* pops condition */ - return 1; + break; } - - case FUNCTION: { /* stat -> FUNCTION funcname body */ - int needself; - vardesc v; - if (ls->fs->prev) /* inside other function? */ - return 0; - check_debugline(ls); - next(ls); - needself = funcname(ls, &v); - body(ls, needself, line); - storevar(ls, &v); - return 1; + default: { + luaK_error(ls, "function arguments expected"); + break; } + } + fs->stacklevel = slevel; /* call will remove function and arguments */ + luaK_code2(fs, OP_CALL, slevel, MULT_RET); +} - case LOCAL: { /* stat -> LOCAL localnamelist decinit */ - listdesc d; - int nvars; - check_debugline(ls); - next(ls); - nvars = localnamelist(ls); - decinit(ls, &d); - fs->nlocalvar += nvars; - correctvarlines(ls, nvars); /* vars will be alive only after decinit */ - adjust_mult_assign(ls, nvars, &d); - return 1; - } - case NAME: case '%': { /* stat -> func | ['%'] NAME assignment */ - vardesc v; - check_debugline(ls); - var_or_func(ls, &v); - if (v.k == VEXP) { /* stat -> func */ - if (v.info == 0) /* is just an upper value? */ - luaX_error(ls, "syntax error"); - close_exp(ls, v.info, 0); +static void var_or_func_tail (LexState *ls, expdesc *v) { + for (;;) { + switch (ls->t.token) { + case '.': { /* var_or_func_tail -> '.' NAME */ + next(ls); + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + luaK_kstr(ls, checkname(ls)); + v->k = VINDEXED; + break; } - else { /* stat -> ['%'] NAME assignment */ - int left = assignment(ls, &v, 1); - adjuststack(ls, left); /* remove eventual 'garbage' left on stack */ + case '[': { /* var_or_func_tail -> '[' exp1 ']' */ + next(ls); + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + v->k = VINDEXED; + exp1(ls); + check(ls, ']'); + break; } - return 1; + case ':': { /* var_or_func_tail -> ':' NAME funcargs */ + int name; + next(ls); + name = checkname(ls); + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + luaK_code1(ls->fs, OP_PUSHSELF, name); + funcargs(ls, 1); + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; + break; + } + case '(': case TK_STRING: case '{': { /* var_or_func_tail -> funcargs */ + luaK_tostack(ls, v, 1); /* `v' must be on stack */ + funcargs(ls, 0); + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; + break; + } + default: return; /* should be follow... */ } + } +} - case RETURN: case ';': case ELSE: case ELSEIF: - case END: case UNTIL: case EOS: /* 'stat' follow */ - return 0; - default: - error_unexpected(ls); - return 0; /* to avoid warnings */ +static void var_or_func (LexState *ls, expdesc *v) { + /* var_or_func -> ['%'] NAME var_or_func_tail */ + if (optional(ls, '%')) { /* upvalue? */ + pushupvalue(ls, str_checkname(ls)); + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; } + else /* variable name */ + singlevar(ls, str_checkname(ls), v); + var_or_func_tail(ls, v); } -static int SaveWord (LexState *ls) { - int res = ls->fs->pc; - check_pc(ls->fs, JMPSIZE); - ls->fs->pc += JMPSIZE; /* open space */ - return res; -} -static int SaveWordPop (LexState *ls) { - deltastack(ls, -1); /* pop condition */ - return SaveWord(ls); -} -static int cond (LexState *ls) { - /* cond -> exp1 */ - exp1(ls); - return SaveWordPop(ls); -} +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ -static void block (LexState *ls) { - /* block -> chunk */ - FuncState *fs = ls->fs; - int nlocalvar = fs->nlocalvar; - chunk(ls); - adjuststack(ls, fs->nlocalvar - nlocalvar); - for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) - luaI_unregisterlocalvar(fs, fs->lastsetline); -} -static int funcname (LexState *ls, vardesc *v) { - /* funcname -> NAME [':' NAME | '.' NAME] */ - int needself = 0; - singlevar(ls, str_checkname(ls), v, 0); - if (ls->token == ':' || ls->token == '.') { - needself = (ls->token == ':'); - next(ls); - lua_pushvar(ls, v); - code_constant(ls, checkname(ls)); - v->k = VINDEXED; +static void recfield (LexState *ls) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + switch (ls->t.token) { + case TK_NAME: { + luaK_kstr(ls, checkname(ls)); + break; + } + case '[': { + next(ls); + exp1(ls); + check(ls, ']'); + break; + } + default: luaK_error(ls, " or `[' expected"); } - return needself; -} - -static void body (LexState *ls, int needself, int line) { - /* body -> '(' parlist ')' chunk END */ - FuncState newfs; - init_state(ls, &newfs, ls->fs->f->source); - newfs.f->lineDefined = line; - check(ls, '('); - if (needself) - add_localvar(ls, luaS_new("self")); - parlist(ls); - check(ls, ')'); - chunk(ls); - check_match(ls, END, FUNCTION, line); - close_func(ls); - func_onstack(ls, &newfs); + check(ls, '='); + exp1(ls); } -static void ifpart (LexState *ls, int line) { - /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ - int c; - int e; - next(ls); /* skip IF or ELSEIF */ - c = cond(ls); - check(ls, THEN); - block(ls); - e = SaveWord(ls); - if (ls->token == ELSEIF) - ifpart(ls, line); - else { - if (optional(ls, ELSE)) - block(ls); - check_match(ls, END, IF, line); +static int recfields (LexState *ls) { + /* recfields -> recfield { ',' recfield } [','] */ + FuncState *fs = ls->fs; + int n = 1; /* at least one element */ + recfield(ls); + while (ls->t.token == ',') { + next(ls); + if (ls->t.token == ';' || ls->t.token == '}') + break; + recfield(ls); + n++; + if (n%RFIELDS_PER_FLUSH == 0) + luaK_code1(fs, OP_SETMAP, RFIELDS_PER_FLUSH); } - codeIf(ls, c, e); + luaK_code1(fs, OP_SETMAP, n%RFIELDS_PER_FLUSH); + return n; } -static void ret (LexState *ls) { - /* ret -> [RETURN explist sc] */ - if (optional(ls, RETURN)) { - listdesc e; - check_debugline(ls); - explist(ls, &e); - if (e.pc > 0) { /* expression is an open function call? */ - Byte *code = ls->fs->f->code; - code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ - code[e.pc-1] = (Byte)ls->fs->nlocalvar; - } - else - code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); - ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ - optional(ls, ';'); +static int listfields (LexState *ls) { + /* listfields -> exp1 { ',' exp1 } [','] */ + FuncState *fs = ls->fs; + int n = 1; /* at least one element */ + exp1(ls); + while (ls->t.token == ',') { + next(ls); + if (ls->t.token == ';' || ls->t.token == '}') + break; + exp1(ls); + n++; + luaX_checklimit(ls, n/LFIELDS_PER_FLUSH, MAXARG_A, + "`item groups' in a list initializer"); + if (n%LFIELDS_PER_FLUSH == 0) + luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); } + luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); + return n; } -/* -** For parsing expressions, we use a classic stack with priorities. -** Each binary operator is represented by its index in "binop" + FIRSTBIN -** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. -*/ - -#define INDNOT 0 -#define INDMINUS 1 - -/* code of first binary operator */ -#define FIRSTBIN 2 - -/* code for power operator (last operator) -** '^' needs special treatment because it is right associative -*/ -#define POW 13 - -static int binop [] = {EQ, NE, '>', '<', LE, GE, CONC, - '+', '-', '*', '/', '^', 0}; - -static int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; - -static OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, LTOP, - LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP}; - -#define MAXOPS 20 /* op's stack size (arbitrary limit) */ -typedef struct stack_op { - int ops[MAXOPS]; - int top; -} stack_op; - - -static void exp1 (LexState *ls) { - vardesc v; - exp0(ls, &v); - lua_pushvar(ls, &v); - if (is_in(ls->token, expfollow) < 0) - luaX_error(ls, "ill-formed expression"); +static void constructor_part (LexState *ls, Constdesc *cd) { + switch (ls->t.token) { + case ';': case '}': { /* constructor_part -> empty */ + cd->n = 0; + cd->k = ls->t.token; + break; + } + case TK_NAME: { /* may be listfields or recfields */ + lookahead(ls); + if (ls->lookahead.token != '=') /* expression? */ + goto case_default; + /* else go through to recfields */ + } + case '[': { /* constructor_part -> recfields */ + cd->n = recfields(ls); + cd->k = 1; /* record */ + break; + } + default: { /* constructor_part -> listfields */ + case_default: + cd->n = listfields(ls); + cd->k = 0; /* list */ + break; + } + } } -static void exp0 (LexState *ls, vardesc *v) { - /* exp0 -> exp2 {(AND | OR) exp2} */ - exp2(ls, v); - while (ls->token == AND || ls->token == OR) { - int op = (ls->token == AND) ? ONFJMP : ONTJMP; - int pc; - lua_pushvar(ls, v); - next(ls); - pc = SaveWordPop(ls); - exp2(ls, v); - lua_pushvar(ls, v); - fix_jump(ls, pc, op, ls->fs->pc); +static void constructor (LexState *ls) { + /* constructor -> '{' constructor_part [';' constructor_part] '}' */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_code1(fs, OP_CREATETABLE, 0); + int nelems; + Constdesc cd; + check(ls, '{'); + constructor_part(ls, &cd); + nelems = cd.n; + if (optional(ls, ';')) { + Constdesc other_cd; + constructor_part(ls, &other_cd); + check_condition(ls, (cd.k != other_cd.k), "invalid constructor syntax"); + nelems += other_cd.n; } + check_match(ls, '}', '{', line); + luaX_checklimit(ls, nelems, MAXARG_U, "elements in a table constructor"); + SETARG_U(fs->f->code[pc], nelems); /* set initial table size */ } +/* }====================================================================== */ -static void push (LexState *ls, stack_op *s, int op) { - if (s->top >= MAXOPS) - luaX_error(ls, "expression too complex"); - s->ops[s->top++] = op; -} -static void pop_to (LexState *ls, stack_op *s, int prio) { - int op; - while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { - code_opcode(ls, opcodes[op], optop--; - } -} -static void simpleexp (LexState *ls, vardesc *v, stack_op *s) { - check_debugline(ls); - switch (ls->token) { - case NUMBER: { /* simpleexp -> NUMBER */ - real r = ls->seminfo.r; +/* +** {====================================================================== +** Expression parsing +** ======================================================================= +*/ + + +static void simpleexp (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs; + switch (ls->t.token) { + case TK_NUMBER: { /* simpleexp -> NUMBER */ + Number r = ls->t.seminfo.r; next(ls); - /* dirty trick: check whether it is a -NUMBER not followed by '^' */ - /* (because the priority of '^' is closer than '-'...) */ - if (s->top > 0 && s->ops[s->top-1] == INDMINUS && ls->token != '^') { - s->top--; /* remove '-' from stack */ - r = -r; - } - code_number(ls, r); + luaK_number(fs, r); break; } - - case STRING: /* simpleexp -> STRING */ - code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ + case TK_STRING: { /* simpleexp -> STRING */ + code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */ next(ls); break; - - case NIL: /* simpleexp -> NIL */ - adjuststack(ls, -1); + } + case TK_NIL: { /* simpleexp -> NIL */ + luaK_adjuststack(fs, -1); next(ls); break; - - case '{': /* simpleexp -> constructor */ + } + case '{': { /* simpleexp -> constructor */ constructor(ls); break; - - case FUNCTION: /* simpleexp -> FUNCTION body */ + } + case TK_FUNCTION: { /* simpleexp -> FUNCTION body */ next(ls); body(ls, 0, ls->linenumber); break; - - case '(': /* simpleexp -> '(' exp0 ')' */ + } + case '(': { /* simpleexp -> '(' expr ')' */ next(ls); - exp0(ls, v); + expr(ls, v); check(ls, ')'); return; - - case NAME: case '%': + } + case TK_NAME: case '%': { var_or_func(ls, v); return; - - default: - luaX_error(ls, " expected"); + } + default: { + luaK_error(ls, " expected"); return; + } } - v->k = VEXP; v->info = 0; + v->k = VEXP; + v->u.l.t = v->u.l.f = NO_JUMP; } -static void prefixexp (LexState *ls, vardesc *v, stack_op *s) { - /* prefixexp -> {NOT | '-'} simpleexp */ - while (ls->token == NOT || ls->token == '-') { - push(ls, s, (ls->token==NOT)?INDNOT:INDMINUS); - next(ls); - } - simpleexp(ls, v, s); +static void exp1 (LexState *ls) { + expdesc v; + expr(ls, &v); + luaK_tostack(ls, &v, 1); } -static void exp2 (LexState *ls, vardesc *v) { - stack_op s; - int op; - s.top = 0; - prefixexp(ls, v, &s); - while ((op = is_in(ls->token, binop)) >= 0) { - op += FIRSTBIN; - lua_pushvar(ls, v); - /* '^' is right associative, so must 'simulate' a higher priority */ - pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); - push(ls, &s, op); - next(ls); - prefixexp(ls, v, &s); - lua_pushvar(ls, v); - } - if (s.top > 0) { - lua_pushvar(ls, v); - pop_to(ls, &s, 0); +static UnOpr getunopr (int op) { + switch (op) { + case TK_NOT: return OPR_NOT; + case '-': return OPR_MINUS; + default: return OPR_NOUNOPR; } } -static void var_or_func (LexState *ls, vardesc *v) { - /* var_or_func -> ['%'] NAME var_or_func_tail */ - if (optional(ls, '%')) { /* upvalue? */ - pushupvalue(ls, str_checkname(ls)); - v->k = VEXP; - v->info = 0; /* closed expression */ +static BinOpr getbinopr (int op) { + switch (op) { + case '+': return OPR_ADD; + case '-': return OPR_SUB; + case '*': return OPR_MULT; + case '/': return OPR_DIV; + case '^': return OPR_POW; + case TK_CONCAT: return OPR_CONCAT; + case TK_NE: return OPR_NE; + case TK_EQ: return OPR_EQ; + case '<': return OPR_LT; + case TK_LE: return OPR_LE; + case '>': return OPR_GT; + case TK_GE: return OPR_GE; + case TK_AND: return OPR_AND; + case TK_OR: return OPR_OR; + default: return OPR_NOBINOPR; } - else /* variable name */ - singlevar(ls, str_checkname(ls), v, 0); - var_or_func_tail(ls, v); } -static void var_or_func_tail (LexState *ls, vardesc *v) { - for (;;) { - switch (ls->token) { - case '.': /* var_or_func_tail -> '.' NAME */ - next(ls); - lua_pushvar(ls, v); /* 'v' must be on stack */ - v->k = VDOT; - v->info = checkname(ls); - break; - - case '[': /* var_or_func_tail -> '[' exp1 ']' */ - next(ls); - lua_pushvar(ls, v); /* 'v' must be on stack */ - exp1(ls); - check(ls, ']'); - v->k = VINDEXED; - break; +static const struct { + char left; /* left priority for each binary operator */ + char right; /* right priority */ +} priority[] = { /* ORDER OPR */ + {5, 5}, {5, 5}, {6, 6}, {6, 6}, /* arithmetic */ + {9, 8}, {4, 3}, /* power and concat (right associative) */ + {2, 2}, {2, 2}, /* equality */ + {2, 2}, {2, 2}, {2, 2}, {2, 2}, /* order */ + {1, 1}, {1, 1} /* logical */ +}; - case ':': /* var_or_func_tail -> ':' NAME funcparams */ - next(ls); - lua_pushvar(ls, v); /* 'v' must be on stack */ - code_oparg(ls, PUSHSELF, checkname(ls), 1); - v->k = VEXP; - v->info = funcparams(ls, 1); - break; +#define UNARY_PRIORITY 7 /* priority for unary operators */ - case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ - lua_pushvar(ls, v); /* 'v' must be on stack */ - v->k = VEXP; - v->info = funcparams(ls, 0); - break; - default: return; /* should be follow... */ - } +/* +** subexpr -> (simplexep | unop subexpr) { binop subexpr } +** where `binop' is any binary operator with a priority higher than `limit' +*/ +static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { + BinOpr op; + UnOpr uop = getunopr(ls->t.token); + if (uop != OPR_NOUNOPR) { + next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls, uop, v); } + else simpleexp(ls, v); + /* expand while operators have priorities higher than `limit' */ + op = getbinopr(ls->t.token); + while (op != OPR_NOBINOPR && priority[op].left > limit) { + expdesc v2; + BinOpr nextop; + next(ls); + luaK_infix(ls, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, &v2, priority[op].right); + luaK_posfix(ls, op, v, &v2); + op = nextop; + } + return op; /* return first untreated operator */ } -static int funcparams (LexState *ls, int slf) { - FuncState *fs = ls->fs; - int nparams = 1; /* in cases STRING and constructor */ - switch (ls->token) { - case '(': { /* funcparams -> '(' explist ')' */ - int line = ls->linenumber; - listdesc e; - next(ls); - explist(ls, &e); - check_match(ls, ')', '(', line); - close_exp(ls, e.pc, 1); - nparams = e.n; - break; - } - case '{': /* funcparams -> constructor */ - constructor(ls); - break; +static void expr (LexState *ls, expdesc *v) { + subexpr(ls, v, -1); +} - case STRING: /* funcparams -> STRING */ - code_string(ls, ls->seminfo.ts); /* must use 'seminfo' before "next" */ - next(ls); - break; +/* }==================================================================== */ + + +/* +** {====================================================================== +** Rules for Statements +** ======================================================================= +*/ - default: - luaX_error(ls, "function arguments expected"); - break; - } - code_byte(fs, CALL); - code_byte(fs, 0); /* save space for nresult */ - code_byte(fs, (Byte)(nparams+slf)); - return fs->pc-1; -} - -static void explist (LexState *ls, listdesc *d) { - switch (ls->token) { - case ELSE: case ELSEIF: case END: case UNTIL: - case EOS: case ';': case ')': - d->pc = 0; - d->n = 0; - break; - default: - explist1(ls, d); +static int block_follow (int token) { + switch (token) { + case TK_ELSE: case TK_ELSEIF: case TK_END: + case TK_UNTIL: case TK_EOS: + return 1; + default: return 0; } } -static void explist1 (LexState *ls, listdesc *d) { - vardesc v; - exp0(ls, &v); - d->n = 1; - while (ls->token == ',') { - d->n++; - lua_pushvar(ls, &v); + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + int nactloc = fs->nactloc; + chunk(ls); + luaK_adjuststack(fs, fs->nactloc - nactloc); /* remove local variables */ + removelocalvars(ls, fs->nactloc - nactloc); +} + + +static int assignment (LexState *ls, expdesc *v, int nvars) { + int left = 0; /* number of values left in the stack after assignment */ + luaX_checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); + if (ls->t.token == ',') { /* assignment -> ',' NAME assignment */ + expdesc nv; next(ls); - exp0(ls, &v); + var_or_func(ls, &nv); + check_condition(ls, (nv.k != VEXP), "syntax error"); + left = assignment(ls, &nv, nvars+1); + } + else { /* assignment -> '=' explist1 */ + int nexps; + check(ls, '='); + nexps = explist1(ls); + adjust_mult_assign(ls, nvars, nexps); } - if (v.k == VEXP) - d->pc = v.info; - else { - lua_pushvar(ls, &v); - d->pc = 0; + if (v->k != VINDEXED) + luaK_storevar(ls, v); + else { /* there may be garbage between table-index and value */ + luaK_code2(ls->fs, OP_SETTABLE, left+nvars+2, 1); + left += 2; } + return left; } -static void parlist (LexState *ls) { - int nparams = 0; - int dots = 0; - switch (ls->token) { - case DOTS: /* parlist -> DOTS */ - next(ls); - dots = 1; - break; - case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ - init: - store_localvar(ls, str_checkname(ls), nparams++); - if (ls->token == ',') { - next(ls); - switch (ls->token) { - case DOTS: /* tailparlist -> DOTS */ - next(ls); - dots = 1; - break; +static void cond (LexState *ls, expdesc *v) { + /* cond -> exp */ + expr(ls, v); /* read condition */ + luaK_goiftrue(ls->fs, v, 0); +} - case NAME: /* tailparlist -> NAME [',' tailparlist] */ - goto init; - default: luaX_error(ls, "NAME or `...' expected"); - } - } - break; +static void whilestat (LexState *ls, int line) { + /* whilestat -> WHILE cond DO block END */ + FuncState *fs = ls->fs; + int while_init = luaK_getlabel(fs); + expdesc v; + Breaklabel bl; + enterbreak(fs, &bl); + next(ls); + cond(ls, &v); + check(ls, TK_DO); + block(ls); + luaK_patchlist(fs, luaK_jump(fs), while_init); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + check_match(ls, TK_END, TK_WHILE, line); + leavebreak(fs, &bl); +} - case ')': break; /* parlist -> empty */ - default: luaX_error(ls, "NAME or `...' expected"); - } - code_args(ls, nparams, dots); +static void repeatstat (LexState *ls, int line) { + /* repeatstat -> REPEAT block UNTIL cond */ + FuncState *fs = ls->fs; + int repeat_init = luaK_getlabel(fs); + expdesc v; + Breaklabel bl; + enterbreak(fs, &bl); + next(ls); + block(ls); + check_match(ls, TK_UNTIL, TK_REPEAT, line); + cond(ls, &v); + luaK_patchlist(fs, v.u.l.f, repeat_init); + leavebreak(fs, &bl); } -static int localnamelist (LexState *ls) { - /* localnamelist -> NAME {',' NAME} */ - int i = 1; - store_localvar(ls, str_checkname(ls), 0); - while (ls->token == ',') { - next(ls); - store_localvar(ls, str_checkname(ls), i++); + +static void forbody (LexState *ls, int nvar, OpCode prepfor, OpCode loopfor) { + /* forbody -> DO block END */ + FuncState *fs = ls->fs; + int prep = luaK_code1(fs, prepfor, NO_JUMP); + int blockinit = luaK_getlabel(fs); + check(ls, TK_DO); + adjustlocalvars(ls, nvar); /* scope for control variables */ + block(ls); + luaK_patchlist(fs, luaK_code1(fs, loopfor, NO_JUMP), blockinit); + luaK_patchlist(fs, prep, luaK_getlabel(fs)); + removelocalvars(ls, nvar); +} + + +static void fornum (LexState *ls, TString *varname) { + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + FuncState *fs = ls->fs; + check(ls, '='); + exp1(ls); /* initial value */ + check(ls, ','); + exp1(ls); /* limit */ + if (optional(ls, ',')) + exp1(ls); /* optional step */ + else + luaK_code1(fs, OP_PUSHINT, 1); /* default step */ + new_localvar(ls, varname, 0); + new_localvarstr(ls, "(limit)", 1); + new_localvarstr(ls, "(step)", 2); + forbody(ls, 3, OP_FORPREP, OP_FORLOOP); +} + + +static void forlist (LexState *ls, TString *indexname) { + /* forlist -> NAME,NAME IN exp1 forbody */ + TString *valname; + check(ls, ','); + valname = str_checkname(ls); + /* next test is dirty, but avoids `in' being a reserved word */ + check_condition(ls, + (ls->t.token == TK_NAME && ls->t.seminfo.ts == luaS_new(ls->L, "in")), + "`in' expected"); + next(ls); /* skip `in' */ + exp1(ls); /* table */ + new_localvarstr(ls, "(table)", 0); + new_localvar(ls, indexname, 1); + new_localvar(ls, valname, 2); + forbody(ls, 3, OP_LFORPREP, OP_LFORLOOP); +} + + +static void forstat (LexState *ls, int line) { + /* forstat -> fornum | forlist */ + FuncState *fs = ls->fs; + TString *varname; + Breaklabel bl; + enterbreak(fs, &bl); + next(ls); /* skip `for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls->t.token) { + case '=': fornum(ls, varname); break; + case ',': forlist(ls, varname); break; + default: luaK_error(ls, "`=' or `,' expected"); } - return i; + check_match(ls, TK_END, TK_FOR, line); + leavebreak(fs, &bl); } -static void decinit (LexState *ls, listdesc *d) { - /* decinit -> ['=' explist1] */ - if (ls->token == '=') { - next(ls); - explist1(ls, d); + +static void test_then_block (LexState *ls, expdesc *v) { + /* test_then_block -> [IF | ELSEIF] cond THEN block */ + next(ls); /* skip IF or ELSEIF */ + cond(ls, v); + check(ls, TK_THEN); + block(ls); /* `then' part */ +} + + +static void ifstat (LexState *ls, int line) { + /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState *fs = ls->fs; + expdesc v; + int escapelist = NO_JUMP; + test_then_block(ls, &v); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + test_then_block(ls, &v); /* ELSEIF cond THEN block */ } - else { - d->n = 0; - d->pc = 0; + if (ls->t.token == TK_ELSE) { + luaK_concat(fs, &escapelist, luaK_jump(fs)); + luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + next(ls); /* skip ELSE */ + block(ls); /* `else' part */ } + else + luaK_concat(fs, &escapelist, v.u.l.f); + luaK_patchlist(fs, escapelist, luaK_getlabel(fs)); + check_match(ls, TK_END, TK_IF, line); +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL NAME {',' NAME} ['=' explist1] */ + int nvars = 0; + int nexps; + do { + next(ls); /* skip LOCAL or ',' */ + new_localvar(ls, str_checkname(ls), nvars++); + } while (ls->t.token == ','); + if (optional(ls, '=')) + nexps = explist1(ls); + else + nexps = 0; + adjust_mult_assign(ls, nvars, nexps); + adjustlocalvars(ls, nvars); } -static int assignment (LexState *ls, vardesc *v, int nvars) { - int left = 0; - checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); - unloaddot(ls, v); - if (ls->token == ',') { /* assignment -> ',' NAME assignment */ - vardesc nv; +static int funcname (LexState *ls, expdesc *v) { + /* funcname -> NAME [':' NAME | '.' NAME] */ + int needself = 0; + singlevar(ls, str_checkname(ls), v); + if (ls->t.token == ':' || ls->t.token == '.') { + needself = (ls->t.token == ':'); next(ls); - var_or_func(ls, &nv); - if (nv.k == VEXP) - luaX_error(ls, "syntax error"); - left = assignment(ls, &nv, nvars+1); - } - else { /* assignment -> '=' explist1 */ - listdesc d; - check(ls, '='); - explist1(ls, &d); - adjust_mult_assign(ls, nvars, &d); + luaK_tostack(ls, v, 1); + luaK_kstr(ls, checkname(ls)); + v->k = VINDEXED; } - if (v->k != VINDEXED || left+(nvars-1) == 0) { - /* global/local var or indexed var without values in between */ - storevar(ls, v); + return needself; +} + + +static void funcstat (LexState *ls, int line) { + /* funcstat -> FUNCTION funcname body */ + int needself; + expdesc v; + next(ls); /* skip FUNCTION */ + needself = funcname(ls, &v); + body(ls, needself, line); + luaK_storevar(ls, &v); +} + + +static void namestat (LexState *ls) { + /* stat -> func | ['%'] NAME assignment */ + FuncState *fs = ls->fs; + expdesc v; + var_or_func(ls, &v); + if (v.k == VEXP) { /* stat -> func */ + check_condition(ls, luaK_lastisopen(fs), "syntax error"); /* an upvalue? */ + luaK_setcallreturns(fs, 0); /* call statement uses no results */ } - else { /* indexed var with values in between*/ - code_oparg(ls, SETTABLE, left+(nvars-1), -1); - left += 2; /* table&index are not popped, because they aren't on top */ + else { /* stat -> ['%'] NAME assignment */ + int left = assignment(ls, &v, 1); + luaK_adjuststack(fs, left); /* remove eventual garbage left on stack */ } - return left; } -static void constructor (LexState *ls) { - /* constructor -> '{' part [';' part] '}' */ - int line = ls->linenumber; - int pc = SaveWord(ls); - int nelems; - constdesc cd; - deltastack(ls, 1); - check(ls, '{'); - part(ls, &cd); - nelems = cd.n; - if (ls->token == ';') { - constdesc other_cd; - next(ls); - part(ls, &other_cd); - if (cd.k == other_cd.k) /* repeated parts? */ - luaX_error(ls, "invalid constructor syntax"); - nelems += other_cd.n; - } - check_match(ls, '}', '{', line); - fix_opcode(ls, pc, CREATEARRAY, nelems); +static void retstat (LexState *ls) { + /* stat -> RETURN explist */ + FuncState *fs = ls->fs; + next(ls); /* skip RETURN */ + if (!block_follow(ls->t.token)) + explist1(ls); /* optional return values */ + luaK_code1(fs, OP_RETURN, ls->fs->nactloc); + fs->stacklevel = fs->nactloc; /* removes all temp values */ } -static void part (LexState *ls, constdesc *cd) { - switch (ls->token) { - case ';': case '}': /* part -> empty */ - cd->n = 0; - cd->k = ls->token; - return; - case NAME: { - vardesc v; - exp0(ls, &v); - if (ls->token == '=') { - switch (v.k) { - case VGLOBAL: - code_constant(ls, v.info); - break; - case VLOCAL: - code_string(ls, ls->fs->localvar[v.info]); - break; - default: - error_unexpected(ls); - } - next(ls); - exp1(ls); - cd->n = recfields(ls); - cd->k = 1; /* record */ - } - else { - lua_pushvar(ls, &v); - cd->n = listfields(ls); - cd->k = 0; /* list */ - } - break; - } +static void breakstat (LexState *ls) { + /* stat -> BREAK [NAME] */ + FuncState *fs = ls->fs; + int currentlevel = fs->stacklevel; + Breaklabel *bl = fs->bl; + if (!bl) + luaK_error(ls, "no loop to break"); + next(ls); /* skip BREAK */ + luaK_adjuststack(fs, currentlevel - bl->stacklevel); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); + /* correct stack for compiler and symbolic execution */ + luaK_adjuststack(fs, bl->stacklevel - currentlevel); +} - case '[': /* part -> recfield recfields */ - recfield(ls); - cd->n = recfields(ls); - cd->k = 1; /* record */ - break; - default: /* part -> exp1 listfields */ - exp1(ls); - cd->n = listfields(ls); - cd->k = 0; /* list */ - break; +static int stat (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + switch (ls->t.token) { + case TK_IF: { /* stat -> ifstat */ + ifstat(ls, line); + return 0; + } + case TK_WHILE: { /* stat -> whilestat */ + whilestat(ls, line); + return 0; + } + case TK_DO: { /* stat -> DO block END */ + next(ls); /* skip DO */ + block(ls); + check_match(ls, TK_END, TK_DO, line); + return 0; + } + case TK_FOR: { /* stat -> forstat */ + forstat(ls, line); + return 0; + } + case TK_REPEAT: { /* stat -> repeatstat */ + repeatstat(ls, line); + return 0; + } + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); + return 0; + } + case TK_LOCAL: { /* stat -> localstat */ + localstat(ls); + return 0; + } + case TK_NAME: case '%': { /* stat -> namestat */ + namestat(ls); + return 0; + } + case TK_RETURN: { /* stat -> retstat */ + retstat(ls); + return 1; /* must be last statement */ + } + case TK_BREAK: { /* stat -> breakstat */ + breakstat(ls); + return 1; /* must be last statement */ + } + default: { + luaK_error(ls, " expected"); + return 0; /* to avoid warnings */ + } } } -static int recfields (LexState *ls) { - /* recfields -> { ',' recfield } [','] */ - int n = 1; /* one has been read before */ - while (ls->token == ',') { - next(ls); - if (ls->token == ';' || ls->token == '}') - break; - recfield(ls); - n++; - if (n%RFIELDS_PER_FLUSH == 0) - flush_record(ls, RFIELDS_PER_FLUSH); + +static void parlist (LexState *ls) { + /* parlist -> [ param { ',' param } ] */ + int nparams = 0; + int dots = 0; + if (ls->t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_DOTS: next(ls); dots = 1; break; + case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; + default: luaK_error(ls, " or `...' expected"); + } + } while (!dots && optional(ls, ',')); } - flush_record(ls, n%RFIELDS_PER_FLUSH); - return n; + code_params(ls, nparams, dots); } -static int listfields (LexState *ls) { - /* listfields -> { ',' exp1 } [','] */ - int n = 1; /* one has been read before */ - while (ls->token == ',') { - next(ls); - if (ls->token == ';' || ls->token == '}') - break; - exp1(ls); - n++; - if (n%LFIELDS_PER_FLUSH == 0) - flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); + +static void body (LexState *ls, int needself, int line) { + /* body -> '(' parlist ')' chunk END */ + FuncState new_fs; + open_func(ls, &new_fs); + new_fs.f->lineDefined = line; + check(ls, '('); + if (needself) { + new_localvarstr(ls, "self", 0); + adjustlocalvars(ls, 1); } - flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); - return n; + parlist(ls); + check(ls, ')'); + chunk(ls); + check_match(ls, TK_END, TK_FUNCTION, line); + close_func(ls); + pushclosure(ls, &new_fs); } -static void recfield (LexState *ls) { - /* recfield -> (NAME | '['exp1']') = exp1 */ - switch (ls->token) { - case NAME: - code_constant(ls, checkname(ls)); - break; - case '[': - next(ls); - exp1(ls); - check(ls, ']'); - break; +/* }====================================================================== */ - default: luaX_error(ls, "NAME or `[' expected"); + +static void chunk (LexState *ls) { + /* chunk -> { stat [';'] } */ + int islast = 0; + while (!islast && !block_follow(ls->t.token)) { + islast = stat(ls); + optional(ls, ';'); + LUA_ASSERT(ls->fs->stacklevel == ls->fs->nactloc, + "stack size != # local vars"); } - check(ls, '='); - exp1(ls); } diff --git a/src/lparser.h b/src/lparser.h index 9825ec57fc..445acea63f 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.3 1999/02/25 19:13:56 roberto Exp $ +** $Id: lparser.h,v 1.26 2000/10/09 13:47:46 roberto Exp $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -11,10 +11,50 @@ #include "lzio.h" -void luaY_codedebugline (int line); -TProtoFunc *luaY_parser (ZIO *z); -void luaY_error (char *s); -void luaY_syntaxerror (char *s, char *token); +/* +** Expression descriptor +*/ + +typedef enum { + VGLOBAL, + VLOCAL, + VINDEXED, + VEXP +} expkind; + +typedef struct expdesc { + expkind k; + union { + int index; /* VGLOBAL: `kstr' index of global name; VLOCAL: stack index */ + struct { + int t; /* patch list of `exit when true' */ + int f; /* patch list of `exit when false' */ + } l; + } u; +} expdesc; + + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + Proto *f; /* current function header */ + struct FuncState *prev; /* enclosing function */ + struct LexState *ls; /* lexical state */ + struct lua_State *L; /* copy of the Lua state */ + int pc; /* next position to code */ + int lasttarget; /* `pc' of last `jump target' */ + int jlt; /* list of jumps to `lasttarget' */ + short stacklevel; /* number of values on activation register */ + short nactloc; /* number of active local variables */ + short nupvalues; /* number of upvalues */ + int lastline; /* line where last `lineinfo' was generated */ + struct Breaklabel *bl; /* chain of breakable blocks */ + expdesc upvalues[MAXUPVALUES]; /* upvalues */ + int actloc[MAXLOCALS]; /* local-variable stack (indices to locvars) */ +} FuncState; + + +Proto *luaY_parser (lua_State *L, ZIO *z); #endif diff --git a/src/lstate.c b/src/lstate.c index 3b98d72976..586c108586 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,13 +1,15 @@ /* -** $Id: lstate.c,v 1.12 1999/05/11 20:08:20 roberto Exp $ +** $Id: lstate.c,v 1.48 2000/10/30 16:29:59 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ -#include "lbuiltin.h" +#include + +#include "lua.h" + #include "ldo.h" -#include "lfunc.h" #include "lgc.h" #include "llex.h" #include "lmem.h" @@ -17,70 +19,103 @@ #include "ltm.h" -lua_State *lua_state = NULL; +#ifdef LUA_DEBUG +static lua_State *lua_state = NULL; +void luaB_opentests (lua_State *L); +#endif -void lua_open (void) -{ - if (lua_state) return; - lua_state = luaM_new(lua_State); - L->Cstack.base = 0; - L->Cstack.lua2C = 0; - L->Cstack.num = 0; - L->errorJmp = NULL; +/* +** built-in implementation for ERRORMESSAGE. In a "correct" environment +** ERRORMESSAGE should have an external definition, and so this function +** would not be used. +*/ +static int errormessage (lua_State *L) { + const char *s = lua_tostring(L, 1); + if (s == NULL) s = "(no message)"; + fprintf(stderr, "error: %s\n", s); + return 0; +} + + +/* +** open parts that may cause memory-allocation errors +*/ +static void f_luaopen (lua_State *L, void *ud) { + int stacksize = *(int *)ud; + if (stacksize == 0) + stacksize = DEFAULT_STACK_SIZE; + else + stacksize += LUA_MINSTACK; + L->gt = luaH_new(L, 10); /* table of globals */ + luaD_init(L, stacksize); + luaS_init(L); + luaX_init(L); + luaT_init(L); + lua_newtable(L); + lua_ref(L, 1); /* create registry */ + lua_register(L, LUA_ERRORMESSAGE, errormessage); +#ifdef LUA_DEBUG + luaB_opentests(L); + if (lua_state == NULL) lua_state = L; /* keep first state to be opened */ +#endif + LUA_ASSERT(lua_gettop(L) == 0, "wrong API stack"); +} + + +LUA_API lua_State *lua_open (int stacksize) { + lua_State *L = luaM_new(NULL, lua_State); + if (L == NULL) return NULL; /* memory allocation error */ + L->stack = NULL; + L->strt.size = L->udt.size = 0; + L->strt.nuse = L->udt.nuse = 0; + L->strt.hash = NULL; + L->udt.hash = NULL; L->Mbuffer = NULL; - L->Mbuffbase = 0; L->Mbuffsize = 0; - L->Mbuffnext = 0; - L->Cblocks = NULL; - L->numCblocks = 0; - L->debug = 0; - L->callhook = NULL; - L->linehook = NULL; - L->rootproto.next = NULL; - L->rootproto.marked = 0; - L->rootcl.next = NULL; - L->rootcl.marked = 0; - L->rootglobal.next = NULL; - L->rootglobal.marked = 0; - L->roottable.next = NULL; - L->roottable.marked = 0; - L->IMtable = NULL; + L->rootproto = NULL; + L->rootcl = NULL; + L->roottable = NULL; + L->TMtable = NULL; + L->last_tag = -1; L->refArray = NULL; L->refSize = 0; - L->GCthreshold = GARBAGE_BLOCK; - L->nblocks = 0; - luaD_init(); - luaS_init(); - luaX_init(); - luaT_init(); - luaB_predefine(); + L->refFree = NONEXT; + L->nblocks = sizeof(lua_State); + L->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */ + L->callhook = NULL; + L->linehook = NULL; + L->allowhooks = 1; + L->errorJmp = NULL; + if (luaD_runprotected(L, f_luaopen, &stacksize) != 0) { + /* memory allocation error: free partial state */ + lua_close(L); + return NULL; + } + L->GCthreshold = 2*L->nblocks; + return L; } -void lua_close (void) -{ - TaggedString *alludata = luaS_collectudata(); - L->GCthreshold = MAX_INT; /* to avoid GC during GC */ - luaC_hashcallIM((Hash *)L->roottable.next); /* GC t.methods for tables */ - luaC_strcallIM(alludata); /* GC tag methods for userdata */ - luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */ - luaH_free((Hash *)L->roottable.next); - luaF_freeproto((TProtoFunc *)L->rootproto.next); - luaF_freeclosure((Closure *)L->rootcl.next); - luaS_free(alludata); - luaS_freeall(); - luaM_free(L->stack.stack); - luaM_free(L->IMtable); - luaM_free(L->refArray); - luaM_free(L->Mbuffer); - luaM_free(L->Cblocks); - luaM_free(L); - L = NULL; -#ifdef DEBUG - printf("total de blocos: %ld\n", numblocks); - printf("total de memoria: %ld\n", totalmem); -#endif +LUA_API void lua_close (lua_State *L) { + LUA_ASSERT(L != lua_state || lua_gettop(L) == 0, "garbage in C stack"); + luaC_collect(L, 1); /* collect all elements */ + LUA_ASSERT(L->rootproto == NULL, "list should be empty"); + LUA_ASSERT(L->rootcl == NULL, "list should be empty"); + LUA_ASSERT(L->roottable == NULL, "list should be empty"); + luaS_freeall(L); + if (L->stack) + L->nblocks -= (L->stack_last - L->stack + 1)*sizeof(TObject); + luaM_free(L, L->stack); + L->nblocks -= (L->last_tag+1)*sizeof(struct TM); + luaM_free(L, L->TMtable); + L->nblocks -= (L->refSize)*sizeof(struct Ref); + luaM_free(L, L->refArray); + L->nblocks -= (L->Mbuffsize)*sizeof(char); + luaM_free(L, L->Mbuffer); + LUA_ASSERT(L->nblocks == sizeof(lua_State), "wrong count for nblocks"); + luaM_free(L, L); + LUA_ASSERT(L != lua_state || memdebug_numblocks == 0, "memory leak!"); + LUA_ASSERT(L != lua_state || memdebug_total == 0,"memory leak!"); } - diff --git a/src/lstate.h b/src/lstate.h index 168257dd6c..0c8f552156 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.19 1999/05/11 20:08:20 roberto Exp $ +** $Id: lstate.h,v 1.41 2000/10/05 13:00:17 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -7,88 +7,71 @@ #ifndef lstate_h #define lstate_h -#include - #include "lobject.h" #include "lua.h" #include "luadebug.h" -#define GARBAGE_BLOCK 150 - -typedef int StkId; /* index to stack elements */ +typedef TObject *StkId; /* index to stack elements */ /* -** "jmp_buf" may be an array, so it is better to make sure it has an -** address (and not that it *is* an address...) +** marks for Reference array */ -struct lua_longjmp { - jmp_buf b; -}; +#define NONEXT -1 /* to end the free list */ +#define HOLD -2 +#define COLLECTED -3 +#define LOCK -4 -struct Stack { - TObject *top; - TObject *stack; - TObject *last; +struct Ref { + TObject o; + int st; /* can be LOCK, HOLD, COLLECTED, or next (for free list) */ }; -struct C_Lua_Stack { - StkId base; /* when Lua calls C or C calls Lua, points to */ - /* the first slot after the last parameter. */ - StkId lua2C; /* points to first element of "array" lua2C */ - int num; /* size of "array" lua2C */ -}; + +struct lua_longjmp; /* defined in ldo.c */ +struct TM; /* defined in ltm.h */ typedef struct stringtable { int size; - int nuse; /* number of elements (including EMPTYs) */ - TaggedString **hash; + lint32 nuse; /* number of elements */ + TString **hash; } stringtable; -enum Status {LOCK, HOLD, FREE, COLLECTED}; - -struct ref { - TObject o; - enum Status status; -}; - struct lua_State { /* thread-specific state */ - struct Stack stack; /* Lua stack */ - struct C_Lua_Stack Cstack; /* C2lua struct */ + StkId top; /* first free slot in the stack */ + StkId stack; /* stack base */ + StkId stack_last; /* last free slot in the stack */ + int stacksize; + StkId Cbase; /* base for current C function */ struct lua_longjmp *errorJmp; /* current error recover point */ char *Mbuffer; /* global buffer */ - int Mbuffbase; /* current first position of Mbuffer */ - int Mbuffsize; /* size of Mbuffer */ - int Mbuffnext; /* next position to fill in Mbuffer */ - struct C_Lua_Stack *Cblocks; - int numCblocks; /* number of nested Cblocks */ - int debug; - lua_CHFunction callhook; - lua_LHFunction linehook; + size_t Mbuffsize; /* size of Mbuffer */ /* global state */ - GCnode rootproto; /* list of all prototypes */ - GCnode rootcl; /* list of all closures */ - GCnode roottable; /* list of all tables */ - GCnode rootglobal; /* list of strings with global values */ - stringtable *string_root; /* array of hash tables for strings and udata */ - struct IM *IMtable; /* table for tag methods */ - int last_tag; /* last used tag in IMtable */ - struct ref *refArray; /* locked objects */ + Proto *rootproto; /* list of all prototypes */ + Closure *rootcl; /* list of all closures */ + Hash *roottable; /* list of all tables */ + stringtable strt; /* hash table for strings */ + stringtable udt; /* hash table for udata */ + Hash *gt; /* table for globals */ + struct TM *TMtable; /* table for tag methods */ + int last_tag; /* last used tag in TMtable */ + struct Ref *refArray; /* locked objects */ int refSize; /* size of refArray */ + int refFree; /* list of free positions in refArray */ unsigned long GCthreshold; - unsigned long nblocks; /* number of 'blocks' currently allocated */ + unsigned long nblocks; /* number of `bytes' currently allocated */ + lua_Hook callhook; + lua_Hook linehook; + int allowhooks; }; -#define L lua_state - - #endif diff --git a/src/lstring.c b/src/lstring.c index fa974ae983..e4c7e26ca9 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.19 1999/02/26 15:49:53 roberto Exp $ +** $Id: lstring.c,v 1.45 2000/10/30 17:49:19 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -7,292 +7,149 @@ #include +#include "lua.h" + #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" -#include "lua.h" - - -#define NUM_HASHSTR 31 -#define NUM_HASHUDATA 31 -#define NUM_HASHS (NUM_HASHSTR+NUM_HASHUDATA) -#define gcsizestring(l) (1+(l/64)) /* "weight" for a string with length 'l' */ +/* +** type equivalent to TString, but with maximum alignment requirements +*/ +union L_UTString { + TString ts; + union L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ +}; -static TaggedString EMPTY = {{NULL, 2}, 0L, 0, - {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; +void luaS_init (lua_State *L) { + L->strt.hash = luaM_newvector(L, 1, TString *); + L->udt.hash = luaM_newvector(L, 1, TString *); + L->nblocks += 2*sizeof(TString *); + L->strt.size = L->udt.size = 1; + L->strt.nuse = L->udt.nuse = 0; + L->strt.hash[0] = L->udt.hash[0] = NULL; +} -void luaS_init (void) { - int i; - L->string_root = luaM_newvector(NUM_HASHS, stringtable); - for (i=0; istring_root[i].size = 0; - L->string_root[i].nuse = 0; - L->string_root[i].hash = NULL; - } +void luaS_freeall (lua_State *L) { + LUA_ASSERT(L->strt.nuse==0, "non-empty string table"); + L->nblocks -= (L->strt.size + L->udt.size)*sizeof(TString *); + luaM_free(L, L->strt.hash); + LUA_ASSERT(L->udt.nuse==0, "non-empty udata table"); + luaM_free(L, L->udt.hash); } -static unsigned long hash_s (char *s, long l) { - unsigned long h = 0; /* seed */ - while (l--) - h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++)); +static unsigned long hash_s (const char *s, size_t l) { + unsigned long h = l; /* seed */ + size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ + for (; l>=step; l-=step) + h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++)); return h; } -static int newsize (stringtable *tb) { - int size = tb->size; - int realuse = 0; - int i; - /* count how many entries are really in use */ - for (i=0; ihash[i] != NULL && tb->hash[i] != &EMPTY) - realuse++; - return luaO_redimension((realuse+1)*2); /* +1 is the new element */ -} - -static void grow (stringtable *tb) { - int ns = newsize(tb); - TaggedString **newhash = luaM_newvector(ns, TaggedString *); +void luaS_resize (lua_State *L, stringtable *tb, int newsize) { + TString **newhash = luaM_newvector(L, newsize, TString *); int i; - for (i=0; inuse = 0; for (i=0; isize; i++) { - if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) { - unsigned long h = tb->hash[i]->hash; - int h1 = h%ns; - while (newhash[h1]) { - h1 += (h&(ns-2)) + 1; /* double hashing */ - if (h1 >= ns) h1 -= ns; - } - newhash[h1] = tb->hash[i]; - tb->nuse++; + TString *p = tb->hash[i]; + while (p) { /* for each node in the list */ + TString *next = p->nexthash; /* save next */ + unsigned long h = (tb == &L->strt) ? p->u.s.hash : IntPoint(p->u.d.value); + int h1 = h&(newsize-1); /* new position */ + LUA_ASSERT(h%newsize == (h&(newsize-1)), + "a&(x-1) == a%x, for x power of 2"); + p->nexthash = newhash[h1]; /* chain it in new position */ + newhash[h1] = p; + p = next; } } - luaM_free(tb->hash); - tb->size = ns; + luaM_free(L, tb->hash); + L->nblocks += (newsize - tb->size)*sizeof(TString *); + tb->size = newsize; tb->hash = newhash; } -static TaggedString *newone_s (char *str, long l, unsigned long h) { - TaggedString *ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l); - memcpy(ts->str, str, l); - ts->str[l] = 0; /* ending 0 */ - ts->u.s.globalval.ttype = LUA_T_NIL; /* initialize global value */ - ts->u.s.len = l; - ts->constindex = 0; - L->nblocks += gcsizestring(l); - ts->head.marked = 0; - ts->head.next = (GCnode *)ts; /* signal it is in no list */ - ts->hash = h; - return ts; +static void newentry (lua_State *L, stringtable *tb, TString *ts, int h) { + ts->nexthash = tb->hash[h]; /* chain new entry */ + tb->hash[h] = ts; + tb->nuse++; + if (tb->nuse > (lint32)tb->size && tb->size < MAX_INT/2) /* too crowded? */ + luaS_resize(L, tb, tb->size*2); } -static TaggedString *newone_u (char *buff, int tag, unsigned long h) { - TaggedString *ts = luaM_new(TaggedString); - ts->u.d.v = buff; - ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; - ts->constindex = -1; /* tag -> this is a userdata */ - L->nblocks++; - ts->head.marked = 0; - ts->head.next = (GCnode *)ts; /* signal it is in no list */ - ts->hash = h; - return ts; -} -static TaggedString *insert_s (char *str, long l, stringtable *tb) { - TaggedString *ts; + +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { unsigned long h = hash_s(str, l); - int size = tb->size; - int j = -1; - int h1; - if ((long)tb->nuse*3 >= (long)size*2) { - grow(tb); - size = tb->size; - } - h1 = h%size; - while ((ts = tb->hash[h1]) != NULL) { - if (ts == &EMPTY) - j = h1; - else if (ts->u.s.len == l && (memcmp(str, ts->str, l) == 0)) + int h1 = h & (L->strt.size-1); + TString *ts; + for (ts = L->strt.hash[h1]; ts; ts = ts->nexthash) { + if (ts->len == l && (memcmp(str, ts->str, l) == 0)) return ts; - h1 += (h&(size-2)) + 1; /* double hashing */ - if (h1 >= size) h1 -= size; } /* not found */ - if (j != -1) /* is there an EMPTY space? */ - h1 = j; - else - tb->nuse++; - ts = tb->hash[h1] = newone_s(str, l, h); + ts = (TString *)luaM_malloc(L, sizestring(l)); + ts->marked = 0; + ts->nexthash = NULL; + ts->len = l; + ts->u.s.hash = h; + ts->u.s.constindex = 0; + memcpy(ts->str, str, l); + ts->str[l] = 0; /* ending 0 */ + L->nblocks += sizestring(l); + newentry(L, &L->strt, ts, h1); /* insert it on table */ return ts; } -static TaggedString *insert_u (void *buff, int tag, stringtable *tb) { - TaggedString *ts; - unsigned long h = (unsigned long)buff; - int size = tb->size; - int j = -1; - int h1; - if ((long)tb->nuse*3 >= (long)size*2) { - grow(tb); - size = tb->size; - } - h1 = h%size; - while ((ts = tb->hash[h1]) != NULL) { - if (ts == &EMPTY) - j = h1; - else if ((tag == ts->u.d.tag || tag == LUA_ANYTAG) && buff == ts->u.d.v) - return ts; - h1 += (h&(size-2)) + 1; /* double hashing */ - if (h1 >= size) h1 -= size; - } - /* not found */ - if (j != -1) /* is there an EMPTY space? */ - h1 = j; - else - tb->nuse++; - ts = tb->hash[h1] = newone_u(buff, tag, h); +TString *luaS_newudata (lua_State *L, size_t s, void *udata) { + union L_UTString *uts = (union L_UTString *)luaM_malloc(L, + (lint32)sizeof(union L_UTString)+s); + TString *ts = &uts->ts; + ts->marked = 0; + ts->nexthash = NULL; + ts->len = s; + ts->u.d.tag = 0; + ts->u.d.value = (udata == NULL) ? uts+1 : udata; + L->nblocks += sizestring(s); + /* insert it on table */ + newentry(L, &L->udt, ts, IntPoint(ts->u.d.value) & (L->udt.size-1)); return ts; } -TaggedString *luaS_createudata (void *udata, int tag) { - int t = ((unsigned)udata%NUM_HASHUDATA)+NUM_HASHSTR; - return insert_u(udata, tag, &L->string_root[t]); -} - -TaggedString *luaS_newlstr (char *str, long l) { - int t = (l==0) ? 0 : ((int)((unsigned char)str[0]*l))%NUM_HASHSTR; - return insert_s(str, l, &L->string_root[t]); -} - -TaggedString *luaS_new (char *str) { - return luaS_newlstr(str, strlen(str)); -} - -TaggedString *luaS_newfixedstring (char *str) { - TaggedString *ts = luaS_new(str); - if (ts->head.marked == 0) - ts->head.marked = 2; /* avoid GC */ - return ts; -} - - -void luaS_free (TaggedString *l) { - while (l) { - TaggedString *next = (TaggedString *)l->head.next; - L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len); - luaM_free(l); - l = next; - } -} - - -/* -** Garbage collection functions. -*/ - -static void remove_from_list (GCnode *l) { - while (l) { - GCnode *next = l->next; - while (next && !next->marked) - next = l->next = next->next; - l = next; - } -} - - -TaggedString *luaS_collector (void) { - TaggedString *frees = NULL; - int i; - remove_from_list(&(L->rootglobal)); - for (i=0; istring_root[i]; - int j; - for (j=0; jsize; j++) { - TaggedString *t = tb->hash[j]; - if (t == NULL) continue; - if (t->head.marked == 1) - t->head.marked = 0; - else if (!t->head.marked) { - t->head.next = (GCnode *)frees; - frees = t; - tb->hash[j] = &EMPTY; - } - } - } - return frees; -} - - -TaggedString *luaS_collectudata (void) { - TaggedString *frees = NULL; - int i; - L->rootglobal.next = NULL; /* empty list of globals */ - for (i=NUM_HASHSTR; istring_root[i]; - int j; - for (j=0; jsize; j++) { - TaggedString *t = tb->hash[j]; - if (t == NULL || t == &EMPTY) - continue; - LUA_ASSERT(t->constindex == -1, "must be userdata"); - t->head.next = (GCnode *)frees; - frees = t; - tb->hash[j] = &EMPTY; - } - } - return frees; -} - - -void luaS_freeall (void) { - int i; - for (i=0; istring_root[i]; - int j; - for (j=0; jsize; j++) { - TaggedString *t = tb->hash[j]; - if (t == &EMPTY) continue; - luaM_free(t); - } - luaM_free(tb->hash); - } - luaM_free(L->string_root); -} - - -void luaS_rawsetglobal (TaggedString *ts, TObject *newval) { - ts->u.s.globalval = *newval; - if (ts->head.next == (GCnode *)ts) { /* is not in list? */ - ts->head.next = L->rootglobal.next; - L->rootglobal.next = (GCnode *)ts; +TString *luaS_createudata (lua_State *L, void *udata, int tag) { + int h1 = IntPoint(udata) & (L->udt.size-1); + TString *ts; + for (ts = L->udt.hash[h1]; ts; ts = ts->nexthash) { + if (udata == ts->u.d.value && (tag == ts->u.d.tag || tag == LUA_ANYTAG)) + return ts; } + /* not found */ + ts = luaS_newudata(L, 0, udata); + if (tag != LUA_ANYTAG) + ts->u.d.tag = tag; + return ts; } -char *luaS_travsymbol (int (*fn)(TObject *)) { - TaggedString *g; - for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next) - if (fn(&g->u.s.globalval)) - return g->str; - return NULL; +TString *luaS_new (lua_State *L, const char *str) { + return luaS_newlstr(L, str, strlen(str)); } -int luaS_globaldefined (char *name) { - TaggedString *ts = luaS_new(name); - return ts->u.s.globalval.ttype != LUA_T_NIL; +TString *luaS_newfixed (lua_State *L, const char *str) { + TString *ts = luaS_new(L, str); + if (ts->marked == 0) ts->marked = FIXMARK; /* avoid GC */ + return ts; } diff --git a/src/lstring.h b/src/lstring.h index 6b214a212b..67ede68d5a 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.7 1998/03/06 16:54:42 roberto Exp $ +** $Id: lstring.h,v 1.24 2000/10/30 17:49:19 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -9,20 +9,29 @@ #include "lobject.h" +#include "lstate.h" -void luaS_init (void); -TaggedString *luaS_createudata (void *udata, int tag); -TaggedString *luaS_collector (void); -void luaS_free (TaggedString *l); -TaggedString *luaS_newlstr (char *str, long l); -TaggedString *luaS_new (char *str); -TaggedString *luaS_newfixedstring (char *str); -void luaS_rawsetglobal (TaggedString *ts, TObject *newval); -char *luaS_travsymbol (int (*fn)(TObject *)); -int luaS_globaldefined (char *name); -TaggedString *luaS_collectudata (void); -void luaS_freeall (void); +/* +** any TString with mark>=FIXMARK is never collected. +** Marks>=RESERVEDMARK are used to identify reserved words. +*/ +#define FIXMARK 2 +#define RESERVEDMARK 3 + + +#define sizestring(l) ((long)sizeof(TString) + \ + ((long)(l+1)-TSPACK)*(long)sizeof(char)) + + +void luaS_init (lua_State *L); +void luaS_resize (lua_State *L, stringtable *tb, int newsize); +TString *luaS_newudata (lua_State *L, size_t s, void *udata); +TString *luaS_createudata (lua_State *L, void *udata, int tag); +void luaS_freeall (lua_State *L); +TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +TString *luaS_new (lua_State *L, const char *str); +TString *luaS_newfixed (lua_State *L, const char *str); #endif diff --git a/src/ltable.c b/src/ltable.c index d768ba0bbb..b28712d90d 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,177 +1,303 @@ /* -** $Id: ltable.c,v 1.22 1999/05/21 19:41:49 roberto Exp $ +** $Id: ltable.c,v 1.58 2000/10/26 12:47:05 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ -#include -#include "lauxlib.h" +/* +** Implementation of tables (aka arrays, objects, or hash tables); +** uses a mix of chained scatter table with Brent's variation. +** A main invariant of these tables is that, if an element is not +** in its main position (i.e. the `original' position that its hash gives +** to it), then the colliding element is in its own main position. +** In other words, there are collisions only when two elements have the +** same main position (i.e. the same hash values for that table size). +** Because of that, the load factor of these tables can be 100% without +** performance penalties. +*/ + + +#include "lua.h" + #include "lmem.h" #include "lobject.h" #include "lstate.h" +#include "lstring.h" #include "ltable.h" -#include "lua.h" -#define gcsize(n) (1+(n/16)) +#define gcsize(L, n) (sizeof(Hash)+(n)*sizeof(Node)) -#define nuse(t) ((t)->nuse) -#define nodevector(t) ((t)->node) -#define TagDefault LUA_T_ARRAY; +#define TagDefault LUA_TTABLE -static long int hashindex (TObject *ref) { - long int h; - switch (ttype(ref)) { - case LUA_T_NUMBER: - h = (long int)nvalue(ref); - break; - case LUA_T_STRING: case LUA_T_USERDATA: - h = (IntPoint)tsvalue(ref); +/* +** returns the `main' position of an element in a table (that is, the index +** of its hash value) +*/ +Node *luaH_mainposition (const Hash *t, const TObject *key) { + unsigned long h; + switch (ttype(key)) { + case LUA_TNUMBER: + h = (unsigned long)(long)nvalue(key); break; - case LUA_T_ARRAY: - h = (IntPoint)avalue(ref); + case LUA_TSTRING: + h = tsvalue(key)->u.s.hash; break; - case LUA_T_PROTO: - h = (IntPoint)tfvalue(ref); + case LUA_TUSERDATA: + h = IntPoint(tsvalue(key)); break; - case LUA_T_CPROTO: - h = (IntPoint)fvalue(ref); + case LUA_TTABLE: + h = IntPoint(hvalue(key)); break; - case LUA_T_CLOSURE: - h = (IntPoint)clvalue(ref); + case LUA_TFUNCTION: + h = IntPoint(clvalue(key)); break; default: - lua_error("unexpected type to index table"); - h = 0; /* to avoid warnings */ + return NULL; /* invalid key */ } - return (h >= 0 ? h : -(h+1)); + LUA_ASSERT(h%(unsigned int)t->size == (h&((unsigned int)t->size-1)), + "a&(x-1) == a%x, for x power of 2"); + return &t->node[h&(t->size-1)]; +} + + +static const TObject *luaH_getany (lua_State *L, const Hash *t, + const TObject *key) { + Node *n = luaH_mainposition(t, key); + if (!n) + lua_error(L, "table index is nil"); + else do { + if (luaO_equalObj(key, &n->key)) + return &n->val; + n = n->next; + } while (n); + return &luaO_nilobject; /* key not found */ +} + + +/* specialized version for numbers */ +const TObject *luaH_getnum (const Hash *t, Number key) { + Node *n = &t->node[(unsigned long)(long)key&(t->size-1)]; + do { + if (ttype(&n->key) == LUA_TNUMBER && nvalue(&n->key) == key) + return &n->val; + n = n->next; + } while (n); + return &luaO_nilobject; /* key not found */ } -Node *luaH_present (Hash *t, TObject *key) { - int tsize = nhash(t); - long int h = hashindex(key); - int h1 = h%tsize; - Node *n = node(t, h1); - /* keep looking until an entry with "ref" equal to key or nil */ - while ((ttype(ref(n)) == ttype(key)) ? !luaO_equalval(key, ref(n)) - : ttype(ref(n)) != LUA_T_NIL) { - h1 += (h&(tsize-2)) + 1; /* double hashing */ - if (h1 >= tsize) h1 -= tsize; - n = node(t, h1); +/* specialized version for strings */ +const TObject *luaH_getstr (const Hash *t, TString *key) { + Node *n = &t->node[key->u.s.hash&(t->size-1)]; + do { + if (ttype(&n->key) == LUA_TSTRING && tsvalue(&n->key) == key) + return &n->val; + n = n->next; + } while (n); + return &luaO_nilobject; /* key not found */ +} + + +const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key) { + switch (ttype(key)) { + case LUA_TNUMBER: return luaH_getnum(t, nvalue(key)); + case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); + default: return luaH_getany(L, t, key); } - return n; } -void luaH_free (Hash *frees) { - while (frees) { - Hash *next = (Hash *)frees->head.next; - L->nblocks -= gcsize(frees->nhash); - luaM_free(nodevector(frees)); - luaM_free(frees); - frees = next; +Node *luaH_next (lua_State *L, const Hash *t, const TObject *key) { + int i; + if (ttype(key) == LUA_TNIL) + i = 0; /* first iteration */ + else { + const TObject *v = luaH_get(L, t, key); + if (v == &luaO_nilobject) + lua_error(L, "invalid key for `next'"); + i = (int)(((const char *)v - + (const char *)(&t->node[0].val)) / sizeof(Node)) + 1; + } + for (; isize; i++) { + Node *n = node(t, i); + if (ttype(val(n)) != LUA_TNIL) + return n; } + return NULL; /* no more elements */ } -static Node *hashnodecreate (int nhash) { - Node *v = luaM_newvector(nhash, Node); +/* +** try to remove a key without value from a table. To avoid problems with +** hash, change `key' for a number with the same hash. +*/ +void luaH_remove (Hash *t, TObject *key) { + if (ttype(key) == LUA_TNUMBER || + (ttype(key) == LUA_TSTRING && tsvalue(key)->len <= 30)) + return; /* do not remove numbers nor small strings */ + else { + /* try to find a number `n' with the same hash as `key' */ + Node *mp = luaH_mainposition(t, key); + int n = mp - &t->node[0]; + /* make sure `n' is not in `t' */ + while (luaH_getnum(t, n) != &luaO_nilobject) { + if (n >= MAX_INT - t->size) + return; /* give up; (to avoid overflow) */ + n += t->size; + } + ttype(key) = LUA_TNUMBER; + nvalue(key) = n; + LUA_ASSERT(luaH_mainposition(t, key) == mp, "cannot change hash"); + } +} + + +static void setnodevector (lua_State *L, Hash *t, lint32 size) { int i; - for (i=0; i MAX_INT) + lua_error(L, "table overflow"); + t->node = luaM_newvector(L, size, Node); + for (i=0; i<(int)size; i++) { + ttype(&t->node[i].key) = ttype(&t->node[i].val) = LUA_TNIL; + t->node[i].next = NULL; + } + L->nblocks += gcsize(L, size) - gcsize(L, t->size); + t->size = size; + t->firstfree = &t->node[size-1]; /* first free position to be used */ } -Hash *luaH_new (int nhash) { - Hash *t = luaM_new(Hash); - nhash = luaO_redimension(nhash*3/2); - nodevector(t) = hashnodecreate(nhash); - nhash(t) = nhash; - nuse(t) = 0; +Hash *luaH_new (lua_State *L, int size) { + Hash *t = luaM_new(L, Hash); t->htag = TagDefault; - luaO_insertlist(&(L->roottable), (GCnode *)t); - L->nblocks += gcsize(nhash); + t->next = L->roottable; + L->roottable = t; + t->mark = t; + t->size = 0; + L->nblocks += gcsize(L, 0); + t->node = NULL; + setnodevector(L, t, luaO_power2(size)); return t; } -static int newsize (Hash *t) { +void luaH_free (lua_State *L, Hash *t) { + L->nblocks -= gcsize(L, t->size); + luaM_free(L, t->node); + luaM_free(L, t); +} + + +static int numuse (const Hash *t) { Node *v = t->node; - int size = nhash(t); + int size = t->size; int realuse = 0; int i; for (i=0; isize; + Node *nold = t->node; + int nelems = numuse(t); int i; - nodevector(t) = hashnodecreate(nnew); - nhash(t) = nnew; - nuse(t) = 0; - for (i=0; i= oldsize-oldsize/4) /* using more than 3/4? */ + setnodevector(L, t, (lint32)oldsize*2); + else if (nelems <= oldsize/4 && /* less than 1/4? */ + oldsize > MINPOWER2) + setnodevector(L, t, oldsize/2); + else + setnodevector(L, t, oldsize); + for (i=0; ival) != LUA_TNIL) + *luaH_set(L, t, &old->key) = old->val; } - L->nblocks += gcsize(nnew)-gcsize(nold); - luaM_free(vold); + luaM_free(L, nold); /* free old array */ } -void luaH_set (Hash *t, TObject *ref, TObject *val) { - Node *n = luaH_present(t, ref); - if (ttype(ref(n)) != LUA_T_NIL) - *val(n) = *val; - else { - TObject buff; - buff = *val; /* rehash may invalidate this address */ - if ((long)nuse(t)*3L > (long)nhash(t)*2L) { - rehash(t); - n = luaH_present(t, ref); +/* +** inserts a key into a hash table; first, check whether key is +** already present; if not, check whether key's main position is free; +** if not, check whether colliding node is in its main position or not; +** if it is not, move colliding node to an empty place and put new key +** in its main position; otherwise (colliding node is in its main position), +** new key goes to an empty position. +*/ +TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) { + Node *mp = luaH_mainposition(t, key); + Node *n = mp; + if (!mp) + lua_error(L, "table index is nil"); + do { /* check whether `key' is somewhere in the chain */ + if (luaO_equalObj(key, &n->key)) + return &n->val; /* that's all */ + else n = n->next; + } while (n); + /* `key' not found; must insert it */ + if (ttype(&mp->key) != LUA_TNIL) { /* main position is not free? */ + Node *othern; /* main position of colliding node */ + n = t->firstfree; /* get a free place */ + /* is colliding node out of its main position? (can only happens if + its position is after "firstfree") */ + if (mp > n && (othern=luaH_mainposition(t, &mp->key)) != mp) { + /* yes; move colliding node into free position */ + while (othern->next != mp) othern = othern->next; /* find previous */ + othern->next = n; /* redo the chain with `n' in place of `mp' */ + *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + mp->next = NULL; /* now `mp' is free */ } - nuse(t)++; - *ref(n) = *ref; - *val(n) = buff; + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + n->next = mp->next; /* chain new position */ + mp->next = n; + mp = n; + } + } + mp->key = *key; + for (;;) { /* correct `firstfree' */ + if (ttype(&t->firstfree->key) == LUA_TNIL) + return &mp->val; /* OK; table still has a free place */ + else if (t->firstfree == t->node) break; /* cannot decrement from here */ + else (t->firstfree)--; } + rehash(L, t); /* no more free places */ + return luaH_set(L, t, key); /* `rehash' invalidates this insertion */ } -int luaH_pos (Hash *t, TObject *r) { - Node *n = luaH_present(t, r); - luaL_arg_check(ttype(val(n)) != LUA_T_NIL, 2, "key not found"); - return n-(t->node); +TObject *luaH_setint (lua_State *L, Hash *t, int key) { + TObject index; + ttype(&index) = LUA_TNUMBER; + nvalue(&index) = key; + return luaH_set(L, t, &index); } -void luaH_setint (Hash *t, int ref, TObject *val) { - TObject index; - ttype(&index) = LUA_T_NUMBER; - nvalue(&index) = ref; - luaH_set(t, &index, val); +void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val) { + TObject *value, index; + ttype(&index) = LUA_TSTRING; + tsvalue(&index) = key; + value = luaH_set(L, t, &index); + ttype(value) = LUA_TNUMBER; + nvalue(value) = val; } -TObject *luaH_getint (Hash *t, int ref) { - TObject index; - ttype(&index) = LUA_T_NUMBER; - nvalue(&index) = ref; - return luaH_get(t, &index); +const TObject *luaH_getglobal (lua_State *L, const char *name) { + return luaH_getstr(L->gt, luaS_new(L, name)); } diff --git a/src/ltable.h b/src/ltable.h index 49b485f2d3..8ee41a81af 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 1.11 1999/02/23 14:57:28 roberto Exp $ +** $Id: ltable.h,v 1.24 2000/08/31 14:08:27 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -10,21 +10,25 @@ #include "lobject.h" -#define node(t,i) (&(t)->node[i]) -#define ref(n) (&(n)->ref) +#define node(t,i) (&(t)->node[i]) +#define key(n) (&(n)->key) #define val(n) (&(n)->val) -#define nhash(t) ((t)->nhash) - -#define luaH_get(t,ref) (val(luaH_present((t), (ref)))) -#define luaH_move(t,from,to) (luaH_setint(t, to, luaH_getint(t, from))) - -Hash *luaH_new (int nhash); -void luaH_free (Hash *frees); -Node *luaH_present (Hash *t, TObject *key); -void luaH_set (Hash *t, TObject *ref, TObject *val); -int luaH_pos (Hash *t, TObject *r); -void luaH_setint (Hash *t, int ref, TObject *val); -TObject *luaH_getint (Hash *t, int ref); + +Hash *luaH_new (lua_State *L, int nhash); +void luaH_free (lua_State *L, Hash *t); +const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key); +const TObject *luaH_getnum (const Hash *t, Number key); +const TObject *luaH_getstr (const Hash *t, TString *key); +void luaH_remove (Hash *t, TObject *key); +TObject *luaH_set (lua_State *L, Hash *t, const TObject *key); +Node * luaH_next (lua_State *L, const Hash *t, const TObject *r); +TObject *luaH_setint (lua_State *L, Hash *t, int key); +void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val); +unsigned long luaH_hash (lua_State *L, const TObject *key); +const TObject *luaH_getglobal (lua_State *L, const char *name); + +/* exported only for debugging */ +Node *luaH_mainposition (const Hash *t, const TObject *key); #endif diff --git a/src/ltests.c b/src/ltests.c new file mode 100644 index 0000000000..c27c7c8172 --- /dev/null +++ b/src/ltests.c @@ -0,0 +1,543 @@ +/* +** $Id: ltests.c,v 1.54 2000/10/31 13:10:24 roberto Exp $ +** Internal Module for Debugging of the Lua Implementation +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + + +#include "lua.h" + +#include "lapi.h" +#include "lauxlib.h" +#include "lcode.h" +#include "ldebug.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "luadebug.h" +#include "lualib.h" + + +void luaB_opentests (lua_State *L); + + +/* +** The whole module only makes sense with LUA_DEBUG on +*/ +#ifdef LUA_DEBUG + + + +static void setnameval (lua_State *L, const char *name, int val) { + lua_pushstring(L, name); + lua_pushnumber(L, val); + lua_settable(L, -3); +} + + +/* +** {====================================================== +** Disassembler +** ======================================================= +*/ + + +static const char *const instrname[NUM_OPCODES] = { + "END", "RETURN", "CALL", "TAILCALL", "PUSHNIL", "POP", "PUSHINT", + "PUSHSTRING", "PUSHNUM", "PUSHNEGNUM", "PUSHUPVALUE", "GETLOCAL", + "GETGLOBAL", "GETTABLE", "GETDOTTED", "GETINDEXED", "PUSHSELF", + "CREATETABLE", "SETLOCAL", "SETGLOBAL", "SETTABLE", "SETLIST", "SETMAP", + "ADD", "ADDI", "SUB", "MULT", "DIV", "POW", "CONCAT", "MINUS", "NOT", + "JMPNE", "JMPEQ", "JMPLT", "JMPLE", "JMPGT", "JMPGE", "JMPT", "JMPF", + "JMPONT", "JMPONF", "JMP", "PUSHNILJMP", "FORPREP", "FORLOOP", "LFORPREP", + "LFORLOOP", "CLOSURE" +}; + + +static int pushop (lua_State *L, Proto *p, int pc) { + char buff[100]; + Instruction i = p->code[pc]; + OpCode o = GET_OPCODE(i); + const char *name = instrname[o]; + sprintf(buff, "%5d - ", luaG_getline(p->lineinfo, pc, 1, NULL)); + switch ((enum Mode)luaK_opproperties[o].mode) { + case iO: + sprintf(buff+8, "%-12s", name); + break; + case iU: + sprintf(buff+8, "%-12s%4u", name, GETARG_U(i)); + break; + case iS: + sprintf(buff+8, "%-12s%4d", name, GETARG_S(i)); + break; + case iAB: + sprintf(buff+8, "%-12s%4d %4d", name, GETARG_A(i), GETARG_B(i)); + break; + } + lua_pushstring(L, buff); + return (o != OP_END); +} + + +static int listcode (lua_State *L) { + int pc; + Proto *p; + int res; + luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), + 1, "Lua function expected"); + p = clvalue(luaA_index(L, 1))->f.l; + lua_newtable(L); + setnameval(L, "maxstack", p->maxstacksize); + setnameval(L, "numparams", p->numparams); + pc = 0; + do { + lua_pushnumber(L, pc+1); + res = pushop(L, p, pc++); + lua_settable(L, -3); + } while (res); + return 1; +} + + +static int liststrings (lua_State *L) { + Proto *p; + int i; + luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), + 1, "Lua function expected"); + p = clvalue(luaA_index(L, 1))->f.l; + lua_newtable(L); + for (i=0; inkstr; i++) { + lua_pushnumber(L, i+1); + lua_pushstring(L, p->kstr[i]->str); + lua_settable(L, -3); + } + return 1; +} + + +static int listlocals (lua_State *L) { + Proto *p; + int pc = luaL_check_int(L, 2) - 1; + int i = 0; + const char *name; + luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), + 1, "Lua function expected"); + p = clvalue(luaA_index(L, 1))->f.l; + while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) + lua_pushstring(L, name); + return i-1; +} + +/* }====================================================== */ + + + +static int get_limits (lua_State *L) { + lua_newtable(L); + setnameval(L, "BITS_INT", BITS_INT); + setnameval(L, "LFPF", LFIELDS_PER_FLUSH); + setnameval(L, "MAXARG_A", MAXARG_A); + setnameval(L, "MAXARG_B", MAXARG_B); + setnameval(L, "MAXARG_S", MAXARG_S); + setnameval(L, "MAXARG_U", MAXARG_U); + setnameval(L, "MAXLOCALS", MAXLOCALS); + setnameval(L, "MAXPARAMS", MAXPARAMS); + setnameval(L, "MAXSTACK", MAXSTACK); + setnameval(L, "MAXUPVALUES", MAXUPVALUES); + setnameval(L, "MAXVARSLH", MAXVARSLH); + setnameval(L, "RFPF", RFIELDS_PER_FLUSH); + setnameval(L, "SIZE_A", SIZE_A); + setnameval(L, "SIZE_B", SIZE_B); + setnameval(L, "SIZE_OP", SIZE_OP); + setnameval(L, "SIZE_U", SIZE_U); + return 1; +} + + +static int mem_query (lua_State *L) { + if (lua_isnull(L, 1)) { + lua_pushnumber(L, memdebug_total); + lua_pushnumber(L, memdebug_numblocks); + lua_pushnumber(L, memdebug_maxmem); + return 3; + } + else { + memdebug_memlimit = luaL_check_int(L, 1); + return 0; + } +} + + +static int hash_query (lua_State *L) { + if (lua_isnull(L, 2)) { + luaL_arg_check(L, lua_tag(L, 1) == LUA_TSTRING, 1, "string expected"); + lua_pushnumber(L, tsvalue(luaA_index(L, 1))->u.s.hash); + } + else { + Hash *t; + luaL_checktype(L, 2, LUA_TTABLE); + t = hvalue(luaA_index(L, 2)); + lua_pushnumber(L, luaH_mainposition(t, luaA_index(L, 1)) - t->node); + } + return 1; +} + + +static int table_query (lua_State *L) { + const Hash *t; + int i = luaL_opt_int(L, 2, -1); + luaL_checktype(L, 1, LUA_TTABLE); + t = hvalue(luaA_index(L, 1)); + if (i == -1) { + lua_pushnumber(L, t->size); + lua_pushnumber(L, t->firstfree - t->node); + return 2; + } + else if (i < t->size) { + luaA_pushobject(L, &t->node[i].key); + luaA_pushobject(L, &t->node[i].val); + if (t->node[i].next) { + lua_pushnumber(L, t->node[i].next - t->node); + return 3; + } + else + return 2; + } + return 0; +} + + +static int string_query (lua_State *L) { + stringtable *tb = (*luaL_check_string(L, 1) == 's') ? &L->strt : &L->udt; + int s = luaL_opt_int(L, 2, 0) - 1; + if (s==-1) { + lua_pushnumber(L ,tb->nuse); + lua_pushnumber(L ,tb->size); + return 2; + } + else if (s < tb->size) { + TString *ts; + int n = 0; + for (ts = tb->hash[s]; ts; ts = ts->nexthash) { + ttype(L->top) = LUA_TSTRING; + tsvalue(L->top) = ts; + incr_top; + n++; + } + return n; + } + return 0; +} + + +static int tref (lua_State *L) { + luaL_checkany(L, 1); + lua_pushvalue(L, 1); + lua_pushnumber(L, lua_ref(L, luaL_opt_int(L, 2, 1))); + return 1; +} + +static int getref (lua_State *L) { + if (lua_getref(L, luaL_check_int(L, 1))) + return 1; + else + return 0; +} + +static int unref (lua_State *L) { + lua_unref(L, luaL_check_int(L, 1)); + return 0; +} + +static int newuserdata (lua_State *L) { + if (lua_isnumber(L, 2)) + lua_pushusertag(L, (void *)luaL_check_int(L, 1), luaL_check_int(L, 2)); + else + lua_newuserdata(L, luaL_check_int(L, 1)); + return 1; +} + +static int udataval (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + lua_pushnumber(L, (int)lua_touserdata(L, 1)); + return 1; +} + +static int newstate (lua_State *L) { + lua_State *L1 = lua_open(luaL_check_int(L, 1)); + if (L1) + lua_pushuserdata(L, L1); + else + lua_pushnil(L); + return 1; +} + +static int loadlib (lua_State *L) { + lua_State *L1 = (lua_State *)lua_touserdata(L, 1); + switch (*luaL_check_string(L, 2)) { + case 'm': lua_mathlibopen(L1); break; + case 's': lua_strlibopen(L1); break; + case 'i': lua_iolibopen(L1); break; + case 'd': lua_dblibopen(L1); break; + case 'b': lua_baselibopen(L1); break; + default: luaL_argerror(L, 2, "invalid option"); + } + return 0; +} + +static int closestate (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + lua_close((lua_State *)lua_touserdata(L, 1)); + return 0; +} + +static int doremote (lua_State *L) { + lua_State *L1; + const char *code = luaL_check_string(L, 2); + int status; + luaL_checktype(L, 1, LUA_TUSERDATA); + L1 = (lua_State *)lua_touserdata(L, 1); + status = lua_dostring(L1, code); + if (status != 0) { + lua_pushnil(L); + lua_pushnumber(L, status); + return 2; + } + else { + int i = 0; + while (!lua_isnull(L1, ++i)) + lua_pushstring(L, lua_tostring(L1, i)); + return i-1; + } +} + +static int settagmethod (lua_State *L) { + int tag = luaL_check_int(L, 1); + const char *event = luaL_check_string(L, 2); + luaL_checkany(L, 3); + lua_gettagmethod(L, tag, event); + lua_pushvalue(L, 3); + lua_settagmethod(L, tag, event); + return 1; +} + +static int pushbool (lua_State *L, int b) { + if (b) lua_pushnumber(L, 1); + else lua_pushnil(L); + return 1; +} + +static int equal (lua_State *L) { + return pushbool(L, lua_equal(L, 1, 2)); +} + + + +/* +** {====================================================== +** function to test the API with C. It interprets a kind of "assembler" +** language with calls to the API, so the test can be driven by Lua code +** ======================================================= +*/ + +static const char *const delimits = " \t\n,;"; + +static void skip (const char **pc) { + while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; +} + +static int getnum (lua_State *L, const char **pc) { + int res = 0; + int sig = 1; + skip(pc); + if (**pc == '.') { + res = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + (*pc)++; + return res; + } + else if (**pc == '-') { + sig = -1; + (*pc)++; + } + while (isdigit(**pc)) res = res*10 + (*(*pc)++) - '0'; + return sig*res; +} + +static const char *getname (char *buff, const char **pc) { + int i = 0; + skip(pc); + while (**pc != '\0' && !strchr(delimits, **pc)) + buff[i++] = *(*pc)++; + buff[i] = '\0'; + return buff; +} + + +#define EQ(s1) (strcmp(s1, inst) == 0) + +#define getnum ((getnum)(L, &pc)) +#define getname ((getname)(buff, &pc)) + + +static int testC (lua_State *L) { + char buff[30]; + const char *pc = luaL_check_string(L, 1); + for (;;) { + const char *inst = getname; + if EQ("") return 0; + else if EQ("isnumber") { + lua_pushnumber(L, lua_isnumber(L, getnum)); + } + else if EQ("isstring") { + lua_pushnumber(L, lua_isstring(L, getnum)); + } + else if EQ("istable") { + lua_pushnumber(L, lua_istable(L, getnum)); + } + else if EQ("iscfunction") { + lua_pushnumber(L, lua_iscfunction(L, getnum)); + } + else if EQ("isfunction") { + lua_pushnumber(L, lua_isfunction(L, getnum)); + } + else if EQ("isuserdata") { + lua_pushnumber(L, lua_isuserdata(L, getnum)); + } + else if EQ("isnil") { + lua_pushnumber(L, lua_isnil(L, getnum)); + } + else if EQ("isnull") { + lua_pushnumber(L, lua_isnull(L, getnum)); + } + else if EQ("tonumber") { + lua_pushnumber(L, lua_tonumber(L, getnum)); + } + else if EQ("tostring") { + lua_pushstring(L, lua_tostring(L, getnum)); + } + else if EQ("tonumber") { + lua_pushnumber(L, lua_tonumber(L, getnum)); + } + else if EQ("strlen") { + lua_pushnumber(L, lua_strlen(L, getnum)); + } + else if EQ("tocfunction") { + lua_pushcfunction(L, lua_tocfunction(L, getnum)); + } + else if EQ("return") { + return getnum; + } + else if EQ("gettop") { + lua_pushnumber(L, lua_gettop(L)); + } + else if EQ("settop") { + lua_settop(L, getnum); + } + else if EQ("pop") { + lua_pop(L, getnum); + } + else if EQ("pushnum") { + lua_pushnumber(L, getnum); + } + else if EQ("pushvalue") { + lua_pushvalue(L, getnum); + } + else if EQ("remove") { + lua_remove(L, getnum); + } + else if EQ("insert") { + lua_insert(L, getnum); + } + else if EQ("gettable") { + lua_gettable(L, getnum); + } + else if EQ("settable") { + lua_settable(L, getnum); + } + else if EQ("next") { + lua_next(L, -2); + } + else if EQ("concat") { + lua_concat(L, getnum); + } + else if EQ("rawcall") { + int narg = getnum; + int nres = getnum; + lua_rawcall(L, narg, nres); + } + else if EQ("call") { + int narg = getnum; + int nres = getnum; + lua_call(L, narg, nres); + } + else if EQ("dostring") { + lua_dostring(L, luaL_check_string(L, getnum)); + } + else if EQ("settagmethod") { + int tag = getnum; + const char *event = getname; + lua_settagmethod(L, tag, event); + } + else if EQ("gettagmethod") { + int tag = getnum; + const char *event = getname; + lua_gettagmethod(L, tag, event); + } + else if EQ("type") { + lua_pushstring(L, lua_typename(L, lua_type(L, getnum))); + } + else luaL_verror(L, "unknown instruction %.30s", buff); + } + return 0; +} + +/* }====================================================== */ + + + +static const struct luaL_reg tests_funcs[] = { + {"hash", hash_query}, + {"limits", get_limits}, + {"listcode", listcode}, + {"liststrings", liststrings}, + {"listlocals", listlocals}, + {"loadlib", loadlib}, + {"querystr", string_query}, + {"querytab", table_query}, + {"testC", testC}, + {"ref", tref}, + {"getref", getref}, + {"unref", unref}, + {"newuserdata", newuserdata}, + {"udataval", udataval}, + {"newstate", newstate}, + {"closestate", closestate}, + {"doremote", doremote}, + {"settagmethod", settagmethod}, + {"equal", equal}, + {"totalmem", mem_query} +}; + + +void luaB_opentests (lua_State *L) { + lua_newtable(L); + lua_getglobals(L); + lua_pushvalue(L, -2); + lua_setglobals(L); + luaL_openl(L, tests_funcs); /* open functions inside new table */ + lua_setglobals(L); /* restore old table of globals */ + lua_setglobal(L, "T"); /* set new table as global T */ +} + +#endif diff --git a/src/ltm.c b/src/ltm.c index 709d5e5f25..a20909a1b3 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 1.25 1999/05/21 19:41:49 roberto Exp $ +** $Id: ltm.c,v 1.56 2000/10/31 13:10:24 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -8,241 +8,156 @@ #include #include -#include "lauxlib.h" +#include "lua.h" + +#include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "ltm.h" -char *luaT_eventname[] = { /* ORDER IM */ - "gettable", "settable", "index", "getglobal", "setglobal", "add", - "sub", "mul", "div", "pow", "unm", "lt", "le", "gt", "ge", - "concat", "gc", "function", NULL +const char *const luaT_eventname[] = { /* ORDER TM */ + "gettable", "settable", "index", "getglobal", "setglobal", "add", "sub", + "mul", "div", "pow", "unm", "lt", "concat", "gc", "function", + "le", "gt", "ge", /* deprecated options!! */ + NULL }; -static int luaI_checkevent (char *name, char *list[]) { - int e = luaL_findstring(name, list); +static int findevent (const char *name) { + int i; + for (i=0; luaT_eventname[i]; i++) + if (strcmp(luaT_eventname[i], name) == 0) + return i; + return -1; /* name not found */ +} + + +static int luaI_checkevent (lua_State *L, const char *name, int t) { + int e = findevent(name); + if (e >= TM_N) + luaO_verror(L, "event `%.50s' is deprecated", name); + if (e == TM_GC && t == LUA_TTABLE) + luaO_verror(L, "event `gc' for tables is deprecated"); if (e < 0) - luaL_verror("`%.50s' is not a valid event name", name); + luaO_verror(L, "`%.50s' is not a valid event name", name); return e; } -/* events in LUA_T_NIL are all allowed, since this is used as a +/* events in LUA_TNIL are all allowed, since this is used as a * 'placeholder' for "default" fallbacks */ -static char luaT_validevents[NUM_TAGS][IM_N] = { /* ORDER LUA_T, ORDER IM */ -{1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_T_USERDATA */ -{1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_NUMBER */ -{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_STRING */ -{0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_ARRAY */ -{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_PROTO */ -{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_CPROTO */ -{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} /* LUA_T_NIL */ +/* ORDER LUA_T, ORDER TM */ +static const char luaT_validevents[NUM_TAGS][TM_N] = { + {1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TUSERDATA */ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_TNIL */ + {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, /* LUA_TNUMBER */ + {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_TSTRING */ + {0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TTABLE */ + {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0} /* LUA_TFUNCTION */ }; -static int luaT_validevent (int t, int e) { /* ORDER LUA_T */ - return (t < LUA_T_NIL) ? 1 : luaT_validevents[-t][e]; +int luaT_validevent (int t, int e) { /* ORDER LUA_T */ + return (t >= NUM_TAGS) ? 1 : luaT_validevents[t][e]; } -static void init_entry (int tag) { +static void init_entry (lua_State *L, int tag) { int i; - for (i=0; iTMtable[tag].collected = NULL; } -void luaT_init (void) { +void luaT_init (lua_State *L) { int t; - L->last_tag = -(NUM_TAGS-1); - luaM_growvector(L->IMtable, 0, NUM_TAGS, struct IM, arrEM, MAX_INT); - for (t=L->last_tag; t<=0; t++) - init_entry(t); + luaM_growvector(L, L->TMtable, 0, NUM_TAGS, struct TM, "", MAX_INT); + L->nblocks += NUM_TAGS*sizeof(struct TM); + L->last_tag = NUM_TAGS-1; + for (t=0; t<=L->last_tag; t++) + init_entry(L, t); } -int lua_newtag (void) { - --L->last_tag; - luaM_growvector(L->IMtable, -(L->last_tag), 1, struct IM, arrEM, MAX_INT); - init_entry(L->last_tag); +LUA_API int lua_newtag (lua_State *L) { + luaM_growvector(L, L->TMtable, L->last_tag, 1, struct TM, + "tag table overflow", MAX_INT); + L->nblocks += sizeof(struct TM); + L->last_tag++; + init_entry(L, L->last_tag); return L->last_tag; } -static void checktag (int tag) { - if (!(L->last_tag <= tag && tag <= 0)) - luaL_verror("%d is not a valid tag", tag); +static void checktag (lua_State *L, int tag) { + if (!(0 <= tag && tag <= L->last_tag)) + luaO_verror(L, "%d is not a valid tag", tag); } -void luaT_realtag (int tag) { - if (!(L->last_tag <= tag && tag < LUA_T_NIL)) - luaL_verror("tag %d was not created by `newtag'", tag); +void luaT_realtag (lua_State *L, int tag) { + if (!validtag(tag)) + luaO_verror(L, "tag %d was not created by `newtag'", tag); } -int lua_copytagmethods (int tagto, int tagfrom) { +LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom) { int e; - checktag(tagto); - checktag(tagfrom); - for (e=0; evalue.a->htag; - case LUA_T_USERDATA: { - int tag = o->value.ts->u.d.tag; - return (tag >= 0) ? LUA_T_USERDATA : tag; - } - case LUA_T_CLOSURE: - return o->value.cl->consts[0].ttype; -#ifdef DEBUG - case LUA_T_PMARK: case LUA_T_CMARK: - case LUA_T_CLMARK: case LUA_T_LINE: - LUA_INTERNALERROR("invalid type"); -#endif - default: - return t; +int luaT_tag (const TObject *o) { + int t = ttype(o); + switch (t) { + case LUA_TUSERDATA: return tsvalue(o)->u.d.tag; + case LUA_TTABLE: return hvalue(o)->htag; + default: return t; } } -TObject *luaT_gettagmethod (int t, char *event) { - int e = luaI_checkevent(event, luaT_eventname); - checktag(t); - if (luaT_validevent(t, e)) - return luaT_getim(t,e); - else - return &luaO_nilobject; -} - - -void luaT_settagmethod (int t, char *event, TObject *func) { - TObject temp; - int e = luaI_checkevent(event, luaT_eventname); - checktag(t); - if (!luaT_validevent(t, e)) - luaL_verror("cannot change tag method `%.20s' for type `%.20s'%.20s", - luaT_eventname[e], luaO_typenames[-t], - (t == LUA_T_ARRAY || t == LUA_T_USERDATA) ? " with default tag" - : ""); - temp = *func; - *func = *luaT_getim(t,e); - *luaT_getim(t, e) = temp; -} - - -char *luaT_travtagmethods (int (*fn)(TObject *)) { /* ORDER IM */ +LUA_API void lua_gettagmethod (lua_State *L, int t, const char *event) { int e; - for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { - int t; - for (t=0; t>=L->last_tag; t--) - if (fn(luaT_getim(t,e))) - return luaT_eventname[e]; + e = luaI_checkevent(L, event, t); + checktag(L, t); + if (luaT_validevent(t, e) && luaT_gettm(L, t, e)) { + clvalue(L->top) = luaT_gettm(L, t, e); + ttype(L->top) = LUA_TFUNCTION; } - return NULL; -} - - -/* -* =================================================================== -* compatibility with old fallback system -*/ -#ifdef LUA_COMPAT2_5 - -#include "lapi.h" -#include "lstring.h" - -static void errorFB (void) -{ - lua_Object o = lua_getparam(1); - if (lua_isstring(o)) - fprintf(stderr, "lua: %s\n", lua_getstring(o)); else - fprintf(stderr, "lua: unknown error\n"); -} - - -static void nilFB (void) { } - - -static void typeFB (void) { - lua_error("unexpected type"); + ttype(L->top) = LUA_TNIL; + incr_top; } -static void fillvalids (IMS e, TObject *func) { - int t; - for (t=LUA_T_NIL; t<=LUA_T_USERDATA; t++) - if (luaT_validevent(t, e)) - *luaT_getim(t, e) = *func; -} - - -void luaT_setfallback (void) { - static char *oldnames [] = {"error", "getglobal", "arith", "order", NULL}; - TObject oldfunc; - lua_CFunction replace; - char *name = luaL_check_string(1); - lua_Object func = lua_getparam(2); - luaL_arg_check(lua_isfunction(func), 2, "function expected"); - switch (luaL_findstring(name, oldnames)) { - case 0: { /* old error fallback */ - TObject *em = &(luaS_new("_ERRORMESSAGE")->u.s.globalval); - oldfunc = *em; - *em = *luaA_Address(func); - replace = errorFB; - break; - } - case 1: /* old getglobal fallback */ - oldfunc = *luaT_getim(LUA_T_NIL, IM_GETGLOBAL); - *luaT_getim(LUA_T_NIL, IM_GETGLOBAL) = *luaA_Address(func); - replace = nilFB; - break; - case 2: { /* old arith fallback */ - int i; - oldfunc = *luaT_getim(LUA_T_NUMBER, IM_POW); - for (i=IM_ADD; i<=IM_UNM; i++) /* ORDER IM */ - fillvalids(i, luaA_Address(func)); - replace = typeFB; +LUA_API void lua_settagmethod (lua_State *L, int t, const char *event) { + int e = luaI_checkevent(L, event, t); + checktag(L, t); + if (!luaT_validevent(t, e)) + luaO_verror(L, "cannot change `%.20s' tag method for type `%.20s'%.20s", + luaT_eventname[e], luaO_typenames[t], + (t == LUA_TTABLE || t == LUA_TUSERDATA) ? + " with default tag" : ""); + switch (ttype(L->top - 1)) { + case LUA_TNIL: + luaT_gettm(L, t, e) = NULL; break; - } - case 3: { /* old order fallback */ - int i; - oldfunc = *luaT_getim(LUA_T_NIL, IM_LT); - for (i=IM_LT; i<=IM_GE; i++) /* ORDER IM */ - fillvalids(i, luaA_Address(func)); - replace = typeFB; + case LUA_TFUNCTION: + luaT_gettm(L, t, e) = clvalue(L->top - 1); break; - } - default: { - int e; - if ((e = luaL_findstring(name, luaT_eventname)) >= 0) { - oldfunc = *luaT_getim(LUA_T_NIL, e); - fillvalids(e, luaA_Address(func)); - replace = (e == IM_GC || e == IM_INDEX) ? nilFB : typeFB; - } - else { - luaL_verror("`%.50s' is not a valid fallback name", name); - replace = NULL; /* to avoid warnings */ - } - } + default: + lua_error(L, "tag method must be a function (or nil)"); } - if (oldfunc.ttype != LUA_T_NIL) - luaA_pushobject(&oldfunc); - else - lua_pushcfunction(replace); + L->top--; } -#endif diff --git a/src/ltm.h b/src/ltm.h index 845ea15317..3bd8e82751 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 1.5 1999/01/15 13:11:57 roberto Exp $ +** $Id: ltm.h,v 1.18 2000/10/05 13:00:17 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -13,50 +13,47 @@ /* * WARNING: if you change the order of this enumeration, -* grep "ORDER IM" +* grep "ORDER TM" */ typedef enum { - IM_GETTABLE = 0, - IM_SETTABLE, - IM_INDEX, - IM_GETGLOBAL, - IM_SETGLOBAL, - IM_ADD, - IM_SUB, - IM_MUL, - IM_DIV, - IM_POW, - IM_UNM, - IM_LT, - IM_LE, - IM_GT, - IM_GE, - IM_CONCAT, - IM_GC, - IM_FUNCTION -} IMS; - -#define IM_N 18 - - -struct IM { - TObject int_method[IM_N]; + TM_GETTABLE = 0, + TM_SETTABLE, + TM_INDEX, + TM_GETGLOBAL, + TM_SETGLOBAL, + TM_ADD, + TM_SUB, + TM_MUL, + TM_DIV, + TM_POW, + TM_UNM, + TM_LT, + TM_CONCAT, + TM_GC, + TM_FUNCTION, + TM_N /* number of elements in the enum */ +} TMS; + + +struct TM { + Closure *method[TM_N]; + TString *collected; /* list of garbage-collected udata with this tag */ }; -#define luaT_getim(tag,event) (&L->IMtable[-(tag)].int_method[event]) -#define luaT_getimbyObj(o,e) (luaT_getim(luaT_effectivetag(o),(e))) +#define luaT_gettm(L,tag,event) (L->TMtable[tag].method[event]) +#define luaT_gettmbyObj(L,o,e) (luaT_gettm((L),luaT_tag(o),(e))) -extern char *luaT_eventname[]; +#define validtag(t) (NUM_TAGS <= (t) && (t) <= L->last_tag) -void luaT_init (void); -void luaT_realtag (int tag); -int luaT_effectivetag (TObject *o); -void luaT_settagmethod (int t, char *event, TObject *func); -TObject *luaT_gettagmethod (int t, char *event); -char *luaT_travtagmethods (int (*fn)(TObject *)); +extern const char *const luaT_eventname[]; + + +void luaT_init (lua_State *L); +void luaT_realtag (lua_State *L, int tag); +int luaT_tag (const TObject *o); +int luaT_validevent (int t, int e); /* used by compatibility module */ -void luaT_setfallback (void); /* only if LUA_COMPAT2_5 */ #endif diff --git a/src/lua/Makefile b/src/lua/Makefile index cf5d31b64c..5b47161f22 100644 --- a/src/lua/Makefile +++ b/src/lua/Makefile @@ -1,4 +1,4 @@ -# makefile for lua interpreter +# makefile for Lua interpreter LUA= ../.. @@ -14,7 +14,7 @@ T= $(BIN)/lua all: $T $T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib -lm + $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(LIB)/liblua.a: cd ..; $(MAKE) diff --git a/src/lua/README b/src/lua/README index db2eafb7e5..832fb5bf78 100644 --- a/src/lua/README +++ b/src/lua/README @@ -1,38 +1,40 @@ -This client is a sample lua interpreter. +This is lua, a sample Lua interpreter. It can be used as a batch interpreter and also interactively. - -Here are the options it understands: - +There are man pages for it in both nroff and html in ../../doc. + +Here are the options that it understands: + - execute stdin as a file + -c close Lua when exiting + -e stat execute string `stat' + -f name execute file `name' with remaining arguments in table `arg' + -i enter interactive mode with prompt + -q enter interactive mode without prompt + -sNUM set stack size to NUM (must be the first option) -v print version information - -d turn debug on - -e stat dostring `stat' - -q interactive mode without prompt - -i interactive mode with prompt - - executes stdin as a file - a=b sets global `a' with string `b' (no need to quote b) - name dofile `name' + a=b set global `a' to string `b' + name execute file `name' If no options are given, then it reads lines from stdin and executes them -as they are read. So, each line must contain a complete statement. +as they are read -- so, each line must contain a complete statement. To span a statement across several lines, end each line with a backslash '\'. To change the prompt, set the global variable _PROMPT to whatever you want. -You can do after calling the interpreter or on the command line with - _PROMPT="lua: " -for example. +You can do this after calling the interpreter or on the command line with + lua _PROMPT="lua: " -i +for example. Note that you need "-i" in this case. You must be careful when using quotes on the command line because they are usually handled by the shell. This interpreter is good for using Lua as a standalone language. -For a minimal interpreter, see etc/min.c. +For a minimal interpreter, see ../../etc/min.c. If your application simply exports new functions to Lua (which is common), -then you can use this interpreter unmodified: just define a function - - void lua_userinit (void) - -in your code. In this function, you should do whatever initializations are -need, typically exporting your functions to Lua. -If you use this scheme, you must explicily open any standard libraries you need. -See ../lib/linit.c +then you can use this interpreter (almost) unmodified, as follows: +First, define a function + void myinit (lua_State *L) +in your own code. In this function, you should do whatever initializations +are needed by your application, typically exporting your functions to Lua. +Then, add a call "myinit(L)" in lua.c after the place marked + "add your libraries here" +Of course, you can use any name instead of "myinit". diff --git a/src/lua/lua.c b/src/lua/lua.c index 5acd61733d..2da857e1cb 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.21 1999/07/02 18:22:38 roberto Exp $ +** $Id: lua.c,v 1.55 2000/10/20 16:36:32 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -11,24 +11,51 @@ #include #include "lua.h" + #include "luadebug.h" #include "lualib.h" +static lua_State *L = NULL; + + +#ifndef PROMPT +#define PROMPT "> " +#endif + #ifdef _POSIX_SOURCE #include #else -#define isatty(x) (x==0) /* assume stdin is a tty */ +static int isatty (int x) { return x==0; } /* assume stdin is a tty */ #endif +/* +** global options +*/ +struct Options { + int toclose; + int stacksize; +}; + + typedef void (*handler)(int); /* type for signal actions */ static void laction (int i); -static lua_LHFunction old_linehook = NULL; -static lua_CHFunction old_callhook = NULL; +static lua_Hook old_linehook = NULL; +static lua_Hook old_callhook = NULL; + + +static void userinit (void) { + lua_baselibopen(L); + lua_iolibopen(L); + lua_strlibopen(L); + lua_mathlibopen(L); + lua_dblibopen(L); + /* add your libraries here */ +} static handler lreset (void) { @@ -37,66 +64,125 @@ static handler lreset (void) { static void lstop (void) { - lua_setlinehook(old_linehook); - lua_setcallhook(old_callhook); + lua_setlinehook(L, old_linehook); + lua_setcallhook(L, old_callhook); lreset(); - lua_error("interrupted!"); + lua_error(L, "interrupted!"); } static void laction (int i) { + (void)i; /* to avoid warnings */ signal(SIGINT, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ - old_linehook = lua_setlinehook((lua_LHFunction)lstop); - old_callhook = lua_setcallhook((lua_CHFunction)lstop); + old_linehook = lua_setlinehook(L, (lua_Hook)lstop); + old_callhook = lua_setcallhook(L, (lua_Hook)lstop); } -static int ldo (int (*f)(char *), char *name) { +static int ldo (int (*f)(lua_State *l, const char *), const char *name) { int res; handler h = lreset(); - res = f(name); /* dostring | dofile */ + int top = lua_gettop(L); + res = f(L, name); /* dostring | dofile */ + lua_settop(L, top); /* remove eventual results */ signal(SIGINT, h); /* restore old action */ + /* Lua gives no message in such cases, so lua.c provides one */ + if (res == LUA_ERRMEM) { + fprintf(stderr, "lua: memory allocation error\n"); + } + else if (res == LUA_ERRERR) + fprintf(stderr, "lua: error in error message\n"); return res; } static void print_message (void) { fprintf(stderr, -"Lua: command line options:\n" -" -v print version information\n" -" -d turn debug on\n" -" -e stat dostring `stat'\n" -" -q interactive mode without prompt\n" -" -i interactive mode with prompt\n" -" - executes stdin as a file\n" -" a=b sets global `a' with string `b'\n" -" name dofile `name'\n\n"); + "usage: lua [options]. Available options are:\n" + " - execute stdin as a file\n" + " -c close Lua when exiting\n" + " -e stat execute string `stat'\n" + " -f name execute file `name' with remaining arguments in table `arg'\n" + " -i enter interactive mode with prompt\n" + " -q enter interactive mode without prompt\n" + " -sNUM set stack size to NUM (must be the first option)\n" + " -v print version information\n" + " a=b set global `a' to string `b'\n" + " name execute file `name'\n" +); +} + + +static void print_version (void) { + printf("%.80s %.80s\n", LUA_VERSION, LUA_COPYRIGHT); } static void assign (char *arg) { - if (strlen(arg) >= 500) - fprintf(stderr, "lua: shell argument too long"); - else { - char buffer[500]; - char *eq = strchr(arg, '='); - lua_pushstring(eq+1); - strncpy(buffer, arg, eq-arg); - buffer[eq-arg] = 0; - lua_setglobal(buffer); + char *eq = strchr(arg, '='); + *eq = '\0'; /* spilt `arg' in two strings (name & value) */ + lua_pushstring(L, eq+1); + lua_setglobal(L, arg); +} + + +static void getargs (char *argv[]) { + int i; + lua_newtable(L); + for (i=0; argv[i]; i++) { + /* arg[i] = argv[i] */ + lua_pushnumber(L, i); + lua_pushstring(L, argv[i]); + lua_settable(L, -3); + } + /* arg.n = maximum index in table `arg' */ + lua_pushstring(L, "n"); + lua_pushnumber(L, i-1); + lua_settable(L, -3); +} + + +static int l_getargs (lua_State *l) { + char **argv = (char **)lua_touserdata(l, -1); + getargs(argv); + return 1; +} + + +static int file_input (const char *argv) { + int result = ldo(lua_dofile, argv); + if (result) { + if (result == LUA_ERRFILE) { + fprintf(stderr, "lua: cannot execute file "); + perror(argv); + } + return EXIT_FAILURE; } + else + return EXIT_SUCCESS; } -static void manual_input (int prompt) { +/* maximum length of an input string */ +#ifndef MAXINPUT +#define MAXINPUT BUFSIZ +#endif + +static void manual_input (int version, int prompt) { int cont = 1; + if (version) print_version(); while (cont) { - char buffer[BUFSIZ]; + char buffer[MAXINPUT]; int i = 0; - lua_beginblock(); - if (prompt) - printf("%s", lua_getstring(lua_getglobal("_PROMPT"))); + if (prompt) { + const char *s; + lua_getglobal(L, "_PROMPT"); + s = lua_tostring(L, -1); + if (!s) s = PROMPT; + fputs(s, stdout); + lua_pop(L, 1); /* remove global */ + } for(;;) { int c = getchar(); if (c == EOF) { @@ -108,81 +194,129 @@ static void manual_input (int prompt) { buffer[i-1] = '\n'; else break; } - else if (i >= BUFSIZ-1) { - fprintf(stderr, "lua: argument line too long\n"); + else if (i >= MAXINPUT-1) { + fprintf(stderr, "lua: input line too long\n"); break; } else buffer[i++] = (char)c; } buffer[i] = '\0'; ldo(lua_dostring, buffer); - lua_endblock(); + lua_settop(L, 0); /* remove eventual results */ } printf("\n"); } -int main (int argc, char *argv[]) -{ - int i; - lua_open(); - lua_pushstring("> "); lua_setglobal("_PROMPT"); - lua_userinit(); - if (argc < 2) { /* no arguments? */ +static int handle_argv (char *argv[], struct Options *opt) { + if (opt->stacksize > 0) argv++; /* skip option `-s' (if present) */ + if (*argv == NULL) { /* no more arguments? */ if (isatty(0)) { - printf("%s %s\n", LUA_VERSION, LUA_COPYRIGHT); - manual_input(1); + manual_input(1, 1); } else ldo(lua_dofile, NULL); /* executes stdin as a file */ } - else for (i=1; itoclose = 1; + break; + } + case 'v': { + print_version(); + break; + } + case 'e': { + i++; + if (argv[i] == NULL) { + print_message(); + return EXIT_FAILURE; + } + if (ldo(lua_dostring, argv[i]) != 0) { + fprintf(stderr, "lua: error running argument `%.99s'\n", argv[i]); + return EXIT_FAILURE; + } + break; + } + case 'f': { + i++; + if (argv[i] == NULL) { + print_message(); + return EXIT_FAILURE; + } + getargs(argv+i); /* collect remaining arguments */ + lua_setglobal(L, "arg"); + return file_input(argv[i]); /* stop scanning arguments */ + } + case 's': { + fprintf(stderr, "lua: stack size (`-s') must be the first option\n"); + return EXIT_FAILURE; + } + default: { + print_message(); + return EXIT_FAILURE; } - break; - default: - print_message(); - exit(1); - } - } - else if (strchr(argv[i], '=')) - assign(argv[i]); - else { - int result = ldo(lua_dofile, argv[i]); - if (result) { - if (result == 2) { - fprintf(stderr, "lua: cannot execute file "); - perror(argv[i]); } - exit(1); - } } } -#ifdef DEBUG - lua_close(); -#endif - return 0; + return EXIT_SUCCESS; +} + + +static void getstacksize (int argc, char *argv[], struct Options *opt) { + if (argc >= 2 && argv[1][0] == '-' && argv[1][1] == 's') { + int stacksize = atoi(&argv[1][2]); + if (stacksize <= 0) { + fprintf(stderr, "lua: invalid stack size ('%.20s')\n", &argv[1][2]); + exit(EXIT_FAILURE); + } + opt->stacksize = stacksize; + } + else + opt->stacksize = 0; /* no stack size */ +} + + +static void register_getargs (char *argv[]) { + lua_pushuserdata(L, argv); + lua_pushcclosure(L, l_getargs, 1); + lua_setglobal(L, "getargs"); +} + + +int main (int argc, char *argv[]) { + struct Options opt; + int status; + opt.toclose = 0; + getstacksize(argc, argv, &opt); /* handle option `-s' */ + L = lua_open(opt.stacksize); /* create state */ + userinit(); /* open libraries */ + register_getargs(argv); /* create `getargs' function */ + status = handle_argv(argv+1, &opt); + if (opt.toclose) + lua_close(L); + return status; } diff --git a/src/luac/Makefile b/src/luac/Makefile index e2950e6087..4517d82b4b 100644 --- a/src/luac/Makefile +++ b/src/luac/Makefile @@ -1,12 +1,12 @@ -# makefile for lua compiler +# makefile for Lua compiler LUA= ../.. include $(LUA)/config INCS= -I$(INC) $(EXTRA_INCS) -I.. -OBJS= dump.o luac.o opcode.o opt.o print.o stubs.o test.o -SRCS= dump.c luac.c opcode.c opt.c print.c stubs.c test.c luac.h opcode.h +OBJS= dump.o luac.o opt.o print.o stubs.o +SRCS= dump.c luac.c opt.c print.c stubs.c luac.h print.h T= $(BIN)/luac diff --git a/src/luac/README b/src/luac/README index 9fba74bbe2..8d8bb491d1 100644 --- a/src/luac/README +++ b/src/luac/README @@ -1,28 +1,22 @@ +This is luac, the Lua compiler. +There are man pages for it in both nroff and html in ../../doc. + luac translates Lua programs into binary files that can be loaded and executed with lua_dofile in C or with dofile in Lua. -The main advantages of pre-compiling chunks are: faster loading, -protecting source code from user changes, off-line syntax error detection. +The main advantages of pre-compiling chunks are: faster loading, protecting +source code from user changes, and off-line syntax error detection. luac can also be used to learn about the Lua virtual machine. Here are the options that luac understands: - -c compile (default) - -d generate debugging information - -D name predefine 'name' for conditional compilation - -l list (default for -u) - -n save numbers in native format (file may not be portable) - -o file output file for -c (default is "luac.out") - -O optimize - -p parse only - -q quiet (default for -c) - -t test code integrity - -u undump - -U name undefine 'name' for conditional compilation - -v show version information - -V verbose - - compile "stdin" + - process stdin + -l list + -o file output file (default is "luac.out") + -p parse only + -s strip debug information + -t test code integrity + -v show version information -Finally, luac is an example of how to use the internals of Lua (politely). -Also, luac does not need the runtime code and stubs.c makes sure it is not +luac is also an example of how to use the internals of Lua (politely). +Finally, luac does not need the runtime code, and stubs.c makes sure it is not linked into luac. This file also shows how to avoid linking the parser. - diff --git a/src/luac/dump.c b/src/luac/dump.c index 479ce5d416..149469ba11 100644 --- a/src/luac/dump.c +++ b/src/luac/dump.c @@ -1,154 +1,121 @@ /* -** $Id: dump.c,v 1.20 1999/07/02 19:34:26 lhf Exp $ +** $Id: dump.c,v 1.30 2000/10/31 16:57:23 lhf Exp $ ** save bytecodes to file ** See Copyright Notice in lua.h */ -#include #include #include -#include "luac.h" +#include -#ifdef OLD_ANSI -#define strerror(e) "(no error message provided by operating system)" -#endif +#include "luac.h" +#define DumpVector(b,n,size,D) fwrite(b,size,n,D) #define DumpBlock(b,size,D) fwrite(b,size,1,D) -#define DumpInt DumpLong +#define DumpByte fputc -static void DumpWord(int i, FILE* D) +static void DumpInt(int x, FILE* D) { - int hi= 0x0000FF & (i>>8); - int lo= 0x0000FF & i; - fputc(hi,D); - fputc(lo,D); + DumpBlock(&x,sizeof(x),D); } -static void DumpLong(long i, FILE* D) +static void DumpSize(size_t x, FILE* D) { - int hi= 0x00FFFF & (i>>16); - int lo= 0x00FFFF & i; - DumpWord(hi,D); - DumpWord(lo,D); + DumpBlock(&x,sizeof(x),D); } -static void DumpNumber(real x, FILE* D, int native, TProtoFunc* tf) +static void DumpNumber(Number x, FILE* D) { - if (native) - DumpBlock(&x,sizeof(x),D); - else - { - char b[256]; - int n; - sprintf(b,NUMBER_FMT"%n",x,&n); - luaU_str2d(b,tf->source->str); /* help lundump not to fail */ - fputc(n,D); - DumpBlock(b,n,D); - } + DumpBlock(&x,sizeof(x),D); } -static void DumpCode(TProtoFunc* tf, FILE* D) +static void DumpString(const TString* s, FILE* D) { - int size=luaU_codesize(tf); - DumpLong(size,D); - DumpBlock(tf->code,size,D); -} - -static void DumpString(char* s, int size, FILE* D) -{ - if (s==NULL) - DumpLong(0,D); + if (s==NULL || s->str==NULL) + DumpSize(0,D); else { - DumpLong(size,D); - DumpBlock(s,size,D); + size_t size=s->len+1; /* include trailing '\0' */ + DumpSize(size,D); + DumpBlock(s->str,size,D); } } -static void DumpTString(TaggedString* s, FILE* D) +static void DumpCode(const Proto* tf, FILE* D) { - if (s==NULL) - DumpString(NULL,0,D); - else - DumpString(s->str,s->u.s.len+1,D); + DumpInt(tf->ncode,D); + DumpVector(tf->code,tf->ncode,sizeof(*tf->code),D); } -static void DumpLocals(TProtoFunc* tf, FILE* D) +static void DumpLocals(const Proto* tf, FILE* D) { - if (tf->locvars==NULL) - DumpInt(0,D); - else + int i,n=tf->nlocvars; + DumpInt(n,D); + for (i=0; ilocvars; v->line>=0; v++) - ++n; - DumpInt(n,D); - for (v=tf->locvars; v->line>=0; v++) - { - DumpInt(v->line,D); - DumpTString(v->varname,D); - } + DumpString(tf->locvars[i].varname,D); + DumpInt(tf->locvars[i].startpc,D); + DumpInt(tf->locvars[i].endpc,D); } } -static void DumpFunction(TProtoFunc* tf, FILE* D, int native); +static void DumpLines(const Proto* tf, FILE* D) +{ + DumpInt(tf->nlineinfo,D); + DumpVector(tf->lineinfo,tf->nlineinfo,sizeof(*tf->lineinfo),D); +} + +static void DumpFunction(const Proto* tf, FILE* D); -static void DumpConstants(TProtoFunc* tf, FILE* D, int native) +static void DumpConstants(const Proto* tf, FILE* D) { - int i,n=tf->nconsts; - DumpInt(n,D); + int i,n; + DumpInt(n=tf->nkstr,D); for (i=0; iconsts+i; - fputc(-ttype(o),D); /* ttype(o) is negative - ORDER LUA_T */ - switch (ttype(o)) - { - case LUA_T_NUMBER: - DumpNumber(nvalue(o),D,native,tf); - break; - case LUA_T_STRING: - DumpTString(tsvalue(o),D); - break; - case LUA_T_PROTO: - DumpFunction(tfvalue(o),D,native); - break; - case LUA_T_NIL: - break; - default: /* cannot happen */ - luaU_badconstant("dump",i,o,tf); - break; - } - } + DumpString(tf->kstr[i],D); + DumpInt(tf->nknum,D); + DumpVector(tf->knum,tf->nknum,sizeof(*tf->knum),D); + DumpInt(n=tf->nkproto,D); + for (i=0; ikproto[i],D); } -static void DumpFunction(TProtoFunc* tf, FILE* D, int native) +static void DumpFunction(const Proto* tf, FILE* D) { + DumpString(tf->source,D); DumpInt(tf->lineDefined,D); - DumpTString(tf->source,D); - DumpCode(tf,D); + DumpInt(tf->numparams,D); + DumpByte(tf->is_vararg,D); + DumpInt(tf->maxstacksize,D); DumpLocals(tf,D); - DumpConstants(tf,D,native); + DumpLines(tf,D); + DumpConstants(tf,D); + DumpCode(tf,D); if (ferror(D)) - luaL_verror("write error" IN ": %s (errno=%d)",INLOC,strerror(errno),errno); + { + perror("luac: write error"); + exit(1); + } } -static void DumpHeader(TProtoFunc* Main, FILE* D, int native) +static void DumpHeader(FILE* D) { - fputc(ID_CHUNK,D); + DumpByte(ID_CHUNK,D); fputs(SIGNATURE,D); - fputc(VERSION,D); - if (native) - { - fputc(sizeof(real),D); - DumpNumber(TEST_NUMBER,D,native,Main); - } - else - fputc(0,D); + DumpByte(VERSION,D); + DumpByte(luaU_endianess(),D); + DumpByte(sizeof(int),D); + DumpByte(sizeof(size_t),D); + DumpByte(sizeof(Instruction),D); + DumpByte(SIZE_INSTRUCTION,D); + DumpByte(SIZE_OP,D); + DumpByte(SIZE_B,D); + DumpByte(sizeof(Number),D); + DumpNumber(TEST_NUMBER,D); } -void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native) +void luaU_dumpchunk(const Proto* Main, FILE* D) { - DumpHeader(Main,D,native); - DumpFunction(Main,D,native); + DumpHeader(D); + DumpFunction(Main,D); } diff --git a/src/luac/luac.c b/src/luac/luac.c index 68af1c7628..8832de62d4 100644 --- a/src/luac/luac.c +++ b/src/luac/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.17 1999/07/02 19:34:26 lhf Exp $ +** $Id: luac.c,v 1.28 2000/11/06 20:06:27 lhf Exp $ ** lua compiler (saves bytecodes to files; also list binary files) ** See Copyright Notice in lua.h */ @@ -7,181 +7,197 @@ #include #include #include -#include "luac.h" + #include "lparser.h" #include "lstate.h" #include "lzio.h" +#include "luac.h" #define OUTPUT "luac.out" /* default output file */ -static FILE* efopen(char* name, char* mode); -static void doit(int undump, char* filename); +static void usage(const char* message, const char* arg); +static int doargs(int argc, const char* argv[]); +static Proto* load(const char* filename); +static FILE* efopen(const char* name, const char* mode); +static void strip(Proto* tf); +static Proto* combine(Proto** P, int n); + +lua_State* lua_state=NULL; /* lazy! */ static int listing=0; /* list bytecodes? */ -static int debugging=0; /* emit debug information? */ static int dumping=1; /* dump bytecodes? */ -static int undumping=0; /* undump bytecodes? */ -static int optimizing=0; /* optimize? */ -static int parsing=0; /* parse only? */ +static int stripping=0; /* strip debug information? */ static int testing=0; /* test integrity? */ -static int verbose=0; /* tell user what is done */ -static int native=0; /* save numbers in native format? */ -static FILE* D; /* output file */ +static const char* output=OUTPUT; /* output file name */ -static void usage(char* op) +#define IS(s) (strcmp(argv[i],s)==0) + +int main(int argc, const char* argv[]) { - if (op) fprintf(stderr,"luac: unrecognized option '%s'\n",op); + Proto** P,*tf; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given",NULL); + L=lua_open(0); + P=luaM_newvector(L,argc,Proto*); + for (i=0; iu.s.globalval.ttype=LUA_T_NUMBER; - s->u.s.globalval.value.n=1; - } - else if (IS("-d")) /* debug */ - debugging=1; + return i; else if (IS("-l")) /* list */ listing=1; - else if (IS("-n")) /* native */ - native=1; else if (IS("-o")) /* output file */ - d=argv[++i]; - else if (IS("-O")) /* optimize */ - optimizing=1; - else if (IS("-p")) /* parse only */ { - dumping=0; - parsing=1; + output=argv[++i]; + if (output==NULL) usage(NULL,NULL); } - else if (IS("-q")) /* quiet */ - listing=0; + else if (IS("-p")) /* parse only */ + dumping=0; + else if (IS("-s")) /* strip debug information */ + stripping=1; else if (IS("-t")) /* test */ - testing=1; - else if (IS("-u")) /* undump */ { + testing=1; dumping=0; - undumping=1; - listing=1; - } - else if (IS("-U")) /* undefine */ - { - TaggedString* s=luaS_new(argv[++i]); - s->u.s.globalval.ttype=LUA_T_NIL; } else if (IS("-v")) /* show version */ - printf("%s %s\n(written by %s)\n\n",LUA_VERSION,LUA_COPYRIGHT,LUA_AUTHORS); - else if (IS("-V")) /* verbose */ - verbose=1; - else /* unknown option */ - usage(argv[i]); - } - --i; /* fake new argv[0] */ - argc-=i; - argv+=i; - if (dumping || parsing) - { - if (argc<2) usage(NULL); - if (dumping) { - for (i=1; idebug=0; - if (debugging) L->debug=1; - Main=luaY_parser(z); - if (optimizing) luaU_optchunk(Main); - if (listing) luaU_printchunk(Main); - if (testing) luaU_testchunk(Main); - if (dumping) luaU_dumpchunk(Main,D,native); + Proto* tf; + ZIO z; + char source[512]; + FILE* f; + int c,undump; + if (filename==NULL) + { + f=stdin; + filename="(stdin)"; + } + else + f=efopen(filename,"r"); + c=ungetc(fgetc(f),f); + if (ferror(f)) + { + fprintf(stderr,"luac: cannot read from "); + perror(filename); + exit(1); + } + undump=(c==ID_CHUNK); + if (undump && f!=stdin) + { + fclose(f); + f=efopen(filename,"rb"); + } + sprintf(source,"@%.*s",Sizeof(source)-2,filename); + luaZ_Fopen(&z,f,source); + tf = undump ? luaU_undump(L,&z) : luaY_parser(L,&z); + if (f!=stdin) fclose(f); + return tf; } -static void do_undump(ZIO* z) +static Proto* combine(Proto** P, int n) { - for (;;) + if (n==1) + return P[0]; + else { - TProtoFunc* Main=luaU_undump1(z); - if (Main==NULL) break; - if (optimizing) luaU_optchunk(Main); - if (listing) luaU_printchunk(Main); - if (testing) luaU_testchunk(Main); + int i,pc=0; + Proto* tf=luaF_newproto(L); + tf->source=luaS_new(L,"=(luac)"); + tf->maxstacksize=1; + tf->kproto=P; + tf->nkproto=n; + tf->ncode=2*n+1; + tf->code=luaM_newvector(L,tf->ncode,Instruction); + for (i=0; icode[pc++]=CREATE_AB(OP_CLOSURE,i,0); + tf->code[pc++]=CREATE_AB(OP_CALL,0,0); + } + tf->code[pc++]=OP_END; + return tf; } } -static void doit(int undump, char* filename) +static void strip(Proto* tf) { - FILE* f= (filename==NULL) ? stdin : efopen(filename, undump ? "rb" : "r"); - ZIO z; - char source[255+2]; /* +2 for '@' and '\0' */ - luaL_filesource(source,filename,sizeof(source)); - zFopen(&z,f,source); - if (verbose) fprintf(stderr,"%s\n",source+1); - if (undump) do_undump(&z); else do_compile(&z); - if (f!=stdin) fclose(f); + int i,n=tf->nkproto; + tf->lineinfo=NULL; + tf->nlineinfo=0; + tf->source=luaS_new(L,"=(none)"); + tf->locvars=NULL; + tf->nlocvars=0; + for (i=0; ikproto[i]); } -static FILE* efopen(char* name, char* mode) +static FILE* efopen(const char* name, const char* mode) { FILE* f=fopen(name,mode); if (f==NULL) { - fprintf(stderr,"luac: cannot open %sput file ",mode[0]=='r' ? "in" : "out"); + fprintf(stderr,"luac: cannot open %sput file ",*mode=='r' ? "in" : "out"); perror(name); exit(1); } return f; } + +void luaU_testchunk(const Proto* Main) +{ + UNUSED(Main); + fprintf(stderr,"luac: -t not operational in this version\n"); + exit(1); +} diff --git a/src/luac/luac.h b/src/luac/luac.h index 1ae5267bfe..f8987cf2e2 100644 --- a/src/luac/luac.h +++ b/src/luac/luac.h @@ -1,48 +1,31 @@ /* -** $Id: luac.h,v 1.11 1999/07/02 19:34:26 lhf Exp $ +** $Id: luac.h,v 1.18 2000/10/31 16:57:23 lhf Exp $ ** definitions for luac ** See Copyright Notice in lua.h */ -#include "lauxlib.h" +#include "ldebug.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lstring.h" +#include "ltable.h" #include "lundump.h" -typedef struct -{ - char* name; /* name of opcode */ - int op; /* value of opcode */ - int class; /* class of opcode (byte variant) */ - int args; /* types of arguments (operands) */ - int arg; /* arg #1 */ - int arg2; /* arg #2 */ -} Opcode; +extern lua_State *lua_state; +#define L lua_state /* lazy! */ /* from dump.c */ -void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native); - -/* from opcode.c */ -int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE); -int luaU_codesize(TProtoFunc* tf); +void luaU_dumpchunk(const Proto* Main, FILE* D); /* from opt.c */ -void luaU_optchunk(TProtoFunc* Main); +void luaU_optchunk(Proto* Main); /* from print.c */ -void luaU_printchunk(TProtoFunc* Main); +void luaU_printchunk(const Proto* Main); /* from test.c */ -void luaU_testchunk(TProtoFunc* Main); -TObject* luaU_getconstant(TProtoFunc* tf, int i, int at); - -#define INFO(tf,p,I) luaU_opcodeinfo(tf,p,I,__FILE__,__LINE__) +void luaU_testchunk(const Proto* Main); -/* fake (but convenient) opcodes */ -#define NOP 255 -#define STACK (-1) -#define ARGS (-2) -#define VARARGS (-3) +#define Sizeof(x) ((int)sizeof(x)) diff --git a/src/luac/opcode.c b/src/luac/opcode.c deleted file mode 100644 index c2d4ae7dfc..0000000000 --- a/src/luac/opcode.c +++ /dev/null @@ -1,102 +0,0 @@ -/* -** $Id: opcode.c,v 1.9 1999/05/25 19:58:55 lhf Exp $ -** opcode information -** See Copyright Notice in lua.h -*/ - -#include "luac.h" - -enum { /* for Opcode.args */ - ARGS_NONE, - ARGS_B, - ARGS_W, - ARGS_BB, - ARGS_WB -}; - -static Opcode Info[]= /* ORDER lopcodes.h */ -{ -#include "opcode.h" -}; - -static Opcode Fake[]= /* ORDER luac.h */ -{ -{ "NOP", NOP, NOP, ARGS_NONE, -1, -1 }, -{ "STACK", STACK, STACK, ARGS_B, -1, -1 }, -{ "ARGS", ARGS, ARGS, ARGS_B, -1, -1 }, -{ "VARARGS", VARARGS, VARARGS, ARGS_B, -1, -1 }, -}; - -#define NOPCODES (sizeof(Info)/sizeof(Info[0])) - -int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE) -{ - Opcode OP; - Byte* code=tf->code; - int op=*p; - int size=1; - if (p==code) /* first byte is STACK */ - { - OP=Fake[-STACK]; - OP.arg=op; - } - else if (p==code+1) /* second byte is ARGS or VARARGS */ - { - if (op=NOPCODES) /* cannot happen */ - { - luaL_verror("[%s:%d] bad opcode %d at pc=%d" IN, - xFILE,xLINE,op,(int)(p-code),INLOC); - return 0; - } - else /* ordinary opcode */ - { - OP=Info[op]; - switch (OP.args) - { - case ARGS_NONE: size=1; - break; - case ARGS_B: size=2; OP.arg=p[1]; - break; - case ARGS_W: size=3; OP.arg=(p[1]<<8)+p[2]; - break; - case ARGS_BB: size=3; OP.arg=p[1]; OP.arg2=p[2]; - break; - case ARGS_WB: size=4; OP.arg=(p[1]<<8)+p[2]; OP.arg2=p[3]; - break; - default: /* cannot happen */ - luaL_verror("[%s:%d] bad args %d for %s at pc=%d" IN, - __FILE__,__LINE__,OP.args,OP.name,(int)(p-code),INLOC); - break; - } - } - *I=OP; - return size; -} - -int luaU_codesize(TProtoFunc* tf) -{ - Byte* code=tf->code; - Byte* p=code; - for (;;) - { - Opcode OP; - p+=INFO(tf,p,&OP); - if (OP.op==ENDCODE) break; - } - return p-code; -} diff --git a/src/luac/opcode.h b/src/luac/opcode.h deleted file mode 100644 index 4ae910f5c8..0000000000 --- a/src/luac/opcode.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -** $Id: opcode.h,v 1.1 1999/03/25 13:43:05 lhf Exp $ -** opcode info to be #included into opcode.c -** extracted automatically from lopcodes.h by mkopcodeh -- DO NOT EDIT -** See Copyright Notice in lua.h -*/ -{ "ENDCODE", ENDCODE, ENDCODE, ARGS_NONE, -1, -1 }, -{ "RETCODE", RETCODE, RETCODE, ARGS_B, -1, -1 }, -{ "CALL", CALL, CALL, ARGS_BB, -1, -1 }, -{ "TAILCALL", TAILCALL, TAILCALL, ARGS_BB, -1, -1 }, -{ "PUSHNIL", PUSHNIL, PUSHNIL, ARGS_B, -1, -1 }, -{ "POP", POP, POP, ARGS_B, -1, -1 }, -{ "PUSHNUMBERW", PUSHNUMBERW, PUSHNUMBER, ARGS_W, -1, -1 }, -{ "PUSHNUMBER", PUSHNUMBER, PUSHNUMBER, ARGS_B, -1, -1 }, -{ "PUSHNUMBERNEGW", PUSHNUMBERNEGW, PUSHNUMBERNEG, ARGS_W, -1, -1 }, -{ "PUSHNUMBERNEG", PUSHNUMBERNEG, PUSHNUMBERNEG, ARGS_B, -1, -1 }, -{ "PUSHCONSTANTW", PUSHCONSTANTW, PUSHCONSTANT, ARGS_W, -1, -1 }, -{ "PUSHCONSTANT", PUSHCONSTANT, PUSHCONSTANT, ARGS_B, -1, -1 }, -{ "PUSHUPVALUE", PUSHUPVALUE, PUSHUPVALUE, ARGS_B, -1, -1 }, -{ "PUSHLOCAL", PUSHLOCAL, PUSHLOCAL, ARGS_B, -1, -1 }, -{ "GETGLOBALW", GETGLOBALW, GETGLOBAL, ARGS_W, -1, -1 }, -{ "GETGLOBAL", GETGLOBAL, GETGLOBAL, ARGS_B, -1, -1 }, -{ "GETTABLE", GETTABLE, GETTABLE, ARGS_NONE, -1, -1 }, -{ "GETDOTTEDW", GETDOTTEDW, GETDOTTED, ARGS_W, -1, -1 }, -{ "GETDOTTED", GETDOTTED, GETDOTTED, ARGS_B, -1, -1 }, -{ "PUSHSELFW", PUSHSELFW, PUSHSELF, ARGS_W, -1, -1 }, -{ "PUSHSELF", PUSHSELF, PUSHSELF, ARGS_B, -1, -1 }, -{ "CREATEARRAYW", CREATEARRAYW, CREATEARRAY, ARGS_W, -1, -1 }, -{ "CREATEARRAY", CREATEARRAY, CREATEARRAY, ARGS_B, -1, -1 }, -{ "SETLOCAL", SETLOCAL, SETLOCAL, ARGS_B, -1, -1 }, -{ "SETGLOBALW", SETGLOBALW, SETGLOBAL, ARGS_W, -1, -1 }, -{ "SETGLOBAL", SETGLOBAL, SETGLOBAL, ARGS_B, -1, -1 }, -{ "SETTABLEPOP", SETTABLEPOP, SETTABLEPOP, ARGS_NONE, -1, -1 }, -{ "SETTABLE", SETTABLE, SETTABLE, ARGS_B, -1, -1 }, -{ "SETLISTW", SETLISTW, SETLIST, ARGS_WB, -1, -1 }, -{ "SETLIST", SETLIST, SETLIST, ARGS_BB, -1, -1 }, -{ "SETMAP", SETMAP, SETMAP, ARGS_B, -1, -1 }, -{ "NEQOP", NEQOP, NEQOP, ARGS_NONE, -1, -1 }, -{ "EQOP", EQOP, EQOP, ARGS_NONE, -1, -1 }, -{ "LTOP", LTOP, LTOP, ARGS_NONE, -1, -1 }, -{ "LEOP", LEOP, LEOP, ARGS_NONE, -1, -1 }, -{ "GTOP", GTOP, GTOP, ARGS_NONE, -1, -1 }, -{ "GEOP", GEOP, GEOP, ARGS_NONE, -1, -1 }, -{ "ADDOP", ADDOP, ADDOP, ARGS_NONE, -1, -1 }, -{ "SUBOP", SUBOP, SUBOP, ARGS_NONE, -1, -1 }, -{ "MULTOP", MULTOP, MULTOP, ARGS_NONE, -1, -1 }, -{ "DIVOP", DIVOP, DIVOP, ARGS_NONE, -1, -1 }, -{ "POWOP", POWOP, POWOP, ARGS_NONE, -1, -1 }, -{ "CONCOP", CONCOP, CONCOP, ARGS_NONE, -1, -1 }, -{ "MINUSOP", MINUSOP, MINUSOP, ARGS_NONE, -1, -1 }, -{ "NOTOP", NOTOP, NOTOP, ARGS_NONE, -1, -1 }, -{ "ONTJMPW", ONTJMPW, ONTJMP, ARGS_W, -1, -1 }, -{ "ONTJMP", ONTJMP, ONTJMP, ARGS_B, -1, -1 }, -{ "ONFJMPW", ONFJMPW, ONFJMP, ARGS_W, -1, -1 }, -{ "ONFJMP", ONFJMP, ONFJMP, ARGS_B, -1, -1 }, -{ "JMPW", JMPW, JMP, ARGS_W, -1, -1 }, -{ "JMP", JMP, JMP, ARGS_B, -1, -1 }, -{ "IFFJMPW", IFFJMPW, IFFJMP, ARGS_W, -1, -1 }, -{ "IFFJMP", IFFJMP, IFFJMP, ARGS_B, -1, -1 }, -{ "IFTUPJMPW", IFTUPJMPW, IFTUPJMP, ARGS_W, -1, -1 }, -{ "IFTUPJMP", IFTUPJMP, IFTUPJMP, ARGS_B, -1, -1 }, -{ "IFFUPJMPW", IFFUPJMPW, IFFUPJMP, ARGS_W, -1, -1 }, -{ "IFFUPJMP", IFFUPJMP, IFFUPJMP, ARGS_B, -1, -1 }, -{ "CLOSUREW", CLOSUREW, CLOSURE, ARGS_WB, -1, -1 }, -{ "CLOSURE", CLOSURE, CLOSURE, ARGS_BB, -1, -1 }, -{ "SETLINEW", SETLINEW, SETLINE, ARGS_W, -1, -1 }, -{ "SETLINE", SETLINE, SETLINE, ARGS_B, -1, -1 }, -{ "LONGARGW", LONGARGW, LONGARG, ARGS_W, -1, -1 }, -{ "LONGARG", LONGARG, LONGARG, ARGS_B, -1, -1 }, -{ "CHECKSTACK", CHECKSTACK, CHECKSTACK, ARGS_B, -1, -1 }, diff --git a/src/luac/opt.c b/src/luac/opt.c index e2becc2ab8..e51a086852 100644 --- a/src/luac/opt.c +++ b/src/luac/opt.c @@ -1,5 +1,5 @@ /* -** $Id: opt.c,v 1.12 1999/07/02 19:34:26 lhf Exp $ +** $Id: opt.c,v 1.22 2000/10/31 16:57:23 lhf Exp $ ** optimize bytecodes ** See Copyright Notice in lua.h */ @@ -7,275 +7,121 @@ #include #include #include -#include "luac.h" -static void FixArg(Byte* p, int i, int j, int isconst) -{ - if (j==i) - ; - else if (i<=MAX_BYTE) /* j>8; - p[2]=j; - } - } - else /* previous instruction must've been LONGARG */ - { - if (isconst && j<=MAX_WORD) p[-2]=p[-1]=NOP; else p[-1]=j>>16; - p[1]=j>>8; - p[2]=j; - } -} +#include "luac.h" -static void FixConstants(TProtoFunc* tf, int* C) +static int MapConstant(Hash* t, int j, const TObject* key) { - Byte* code=tf->code; - Byte* p=code; - int longarg=0; - for (;;) + const TObject* o=luaH_get(L,t,key); + if (ttype(o)==LUA_TNUMBER) + return (int) nvalue(o); + else { - Opcode OP; - int n=INFO(tf,p,&OP); - int op=OP.class; - int i=OP.arg+longarg; - longarg=0; - if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED || - op==PUSHSELF || op==SETGLOBAL || op==CLOSURE) - FixArg(p,i,C[i],1); - else if (op==LONGARG) longarg=i<<16; - else if (op==ENDCODE) break; - p+=n; + TObject val; + ttype(&val)=LUA_TNUMBER; + nvalue(&val)=j; + *luaH_set(L,t,key)=val; + LUA_ASSERT(j>=0,"MapConstant returns negative!"); + return j; } } -#define UNREF 1 /* "type" of unused constants */ -#define BIAS 128 /* mark for used constants */ - -static void NoUnrefs(TProtoFunc* tf) +static int MapConstants(Proto* tf, Hash* map) { - int i,n=tf->nconsts; - Byte* code=tf->code; - Byte* p=code; - int longarg=0; - for (;;) /* mark all used constants */ - { - Opcode OP; - int n=INFO(tf,p,&OP); - int op=OP.class; - int i=OP.arg+longarg; - longarg=0; - if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED || - op==PUSHSELF || op==SETGLOBAL || op==CLOSURE) - { - TObject* o=tf->consts+i; - if (ttype(o)<=0) ttype(o)+=BIAS; /* mark as used */ - } - else if (op==LONGARG) longarg=i<<16; - else if (op==ENDCODE) break; - p+=n; - } - for (i=0; inknum; ttype(&o)=LUA_TNUMBER; + for (i=0; iconsts+i; - if (ttype(o)<=0) - ttype(o)=UNREF; /* mark as unused */ - else - ttype(o)-=BIAS; /* unmark used constant */ + nvalue(&o)=tf->knum[i]; + k=MapConstant(map,j,&o); + if (k==j) j++; } -} - -#define CMP(oa,ob,f) memcmp(&f(oa),&f(ob),sizeof(f(oa))) - -static int compare(TProtoFunc* tf, int ia, int ib) -{ - TObject* oa=tf->consts+ia; - TObject* ob=tf->consts+ib; - int t=ttype(oa)-ttype(ob); - if (t) return t; - switch (ttype(oa)) + m=j; + j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING; + for (i=0; ikstr[i]; + k=MapConstant(map,j,&o); + if (k==j) j++; } + return m+j; } -static TProtoFunc* TF; /* for sort */ - -static int compare1(const void* a, const void* b) -{ - int ia=*(int*)a; - int ib=*(int*)b; - int t=compare(TF,ia,ib); - return (t) ? t : ia-ib; -} - -static void OptConstants(TProtoFunc* tf) +static void PackConstants(Proto* tf, Hash* map) { - static int* C=NULL; - static int* D=NULL; - int i,k; - int n=tf->nconsts; - if (n==0) return; - luaM_reallocvector(C,n,int); - luaM_reallocvector(D,n,int); - NoUnrefs(tf); - for (i=0; inknum,tf->nkstr); +#endif + j=0; n=tf->nknum; ttype(&o)=LUA_TNUMBER; for (i=0; iconsts+i; - if (ttype(o)!=UNREF) - { - tf->consts[k]=tf->consts[i]; - C[i]=k++; - } - } - else C[i]=C[D[i]]; + nvalue(&o)=tf->knum[i]; + k=MapConstant(map,-1,&o); + if (k==j) tf->knum[j++]=tf->knum[i]; } - if (knknum=j; + j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING; + for (i=0; isource->str,tf->lineDefined,n,k); - FixConstants(tf,C); - tf->nconsts=k; + tsvalue(&o)=tf->kstr[i]; + k=MapConstant(map,-1,&o); + if (k==j) tf->kstr[j++]=tf->kstr[i]; } + tf->nkstr=j; +#ifdef DEBUG + printf("%p after pack nknum=%d nkstr=%d\n",tf,tf->nknum,tf->nkstr); +#endif } -static int NoDebug(TProtoFunc* tf) +static void OptConstants(Proto* tf) { - Byte* code=tf->code; - Byte* p=code; - int lop=NOP; /* last opcode */ - int nop=0; - for (;;) /* change SETLINE to NOP */ + Instruction* p; + int n=tf->nknum+tf->nkstr; + Hash* map=luaH_new(L,n); + int m=MapConstants(tf,map); +#ifdef DEBUG + printf("%p n=%d m=%d %s\n",tf,n,m,(m==n)?"nothing to optimize":"yes!"); +#endif + if (m==n) return; + for (p=tf->code;; p++) { - Opcode OP; - int n=INFO(tf,p,&OP); - int op=OP.class; - if (op==NOP) ++nop; - else if (op==SETLINE) + Instruction i=*p; + int op=GET_OPCODE(i); + switch (op) { - int m; - if (lop==LONGARG) m=2; else if (lop==LONGARGW) m=3; else m=0; - nop+=n+m; memset(p-m,NOP,n+m); + TObject o; + int j,k; + case OP_PUSHNUM: case OP_PUSHNEGNUM: + j=GETARG_U(i); + ttype(&o)=LUA_TNUMBER; nvalue(&o)=tf->knum[j]; + k=MapConstant(map,-1,&o); + if (k!=j) *p=CREATE_U(op,k); + break; + case OP_PUSHSTRING: case OP_GETGLOBAL: case OP_GETDOTTED: + case OP_PUSHSELF: case OP_SETGLOBAL: + j=GETARG_U(i); + ttype(&o)=LUA_TSTRING; tsvalue(&o)=tf->kstr[j]; + k=MapConstant(map,-1,&o); + if (k!=j) *p=CREATE_U(op,k); + break; + case OP_END: + PackConstants(tf,map); + luaH_free(L,map); + return; + default: + break; } - else if (op==ENDCODE) break; - lop=OP.op; - p+=n; } - return nop; } -static int FixJump(TProtoFunc* tf, Byte* a, Byte* b) -{ - Byte* p; - int nop=0; - for (p=a; pcode; - Byte* p=code; - int longarg=0; - for (;;) - { - Opcode OP; - int n=INFO(tf,p,&OP); - int op=OP.class; - int i=OP.arg+longarg; - int nop=0; - longarg=0; - if (op==ENDCODE) break; - else if (op==IFTUPJMP || op==IFFUPJMP) - nop=FixJump(tf,p-i+n,p); - else if (op==ONTJMP || op==ONFJMP || op==JMP || op==IFFJMP) - nop=FixJump(tf,p,p+i+n); - else if (op==LONGARG) longarg=i<<16; - if (nop>0) FixArg(p,i,i-nop,0); - p+=n; - } -} - -static void PackCode(TProtoFunc* tf) -{ - Byte* code=tf->code; - Byte* p=code; - Byte* q=code; - for (;;) - { - Opcode OP; - int n=INFO(tf,p,&OP); - int op=OP.class; - if (op!=NOP) { memcpy(q,p,n); q+=n; } - p+=n; - if (op==ENDCODE) break; - } -printf("\t" SOURCE " reduced code from %d to %d\n", - tf->source->str,tf->lineDefined,(int)(p-code),(int)(q-code)); -} - -static void OptCode(TProtoFunc* tf) -{ - if (NoDebug(tf)==0) return; /* cannot improve code */ - FixJumps(tf); - PackCode(tf); -} - -static void OptFunction(TProtoFunc* tf); - -static void OptFunctions(TProtoFunc* tf) -{ - int i,n=tf->nconsts; - for (i=0; iconsts+i; - if (ttype(o)==LUA_T_PROTO) OptFunction(tfvalue(o)); - } -} - -static void OptFunction(TProtoFunc* tf) +void OptFunction(Proto* tf) { + int i,n=tf->nkproto; OptConstants(tf); - OptCode(tf); - OptFunctions(tf); - tf->source=luaS_new(""); - tf->locvars=NULL; -} - -void luaU_optchunk(TProtoFunc* Main) -{ - OptFunction(Main); + for (i=0; ikproto[i]); } diff --git a/src/luac/print.c b/src/luac/print.c index b1ee8934b9..4ffc8b3d16 100644 --- a/src/luac/print.c +++ b/src/luac/print.c @@ -1,223 +1,99 @@ /* -** $Id: print.c,v 1.21 1999/05/25 19:58:55 lhf Exp $ +** $Id: print.c,v 1.32 2000/11/06 20:04:36 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ #include #include + #include "luac.h" -#ifdef DEBUG -static void PrintConstants(TProtoFunc* tf) +/* macros used in print.h, included in PrintCode */ +#define P_OP(x) printf("%-11s\t",x) +#define P_NONE +#define P_AB printf("%d %d",GETARG_A(i),GETARG_B(i)) +#define P_F printf("%d %d\t; %p",GETARG_A(i),GETARG_B(i),tf->kproto[GETARG_A(i)]) +#define P_J printf("%d\t; to %d",GETARG_S(i),GETARG_S(i)+at+1) +#define P_Q PrintString(tf,GETARG_U(i)) +#define P_K printf("%d\t; %s",GETARG_U(i),tf->kstr[GETARG_U(i)]->str) +#define P_L PrintLocal(tf,GETARG_U(i),at-1) +#define P_N printf("%d\t; " NUMBER_FMT,GETARG_U(i),tf->knum[GETARG_U(i)]) +#define P_S printf("%d",GETARG_S(i)) +#define P_U printf("%u",GETARG_U(i)) + +static void PrintString(const Proto* tf, int n) { - int i,n=tf->nconsts; - printf("constants (%d) for %p:\n",n,tf); - for (i=0; ikstr[n]->str; + printf("%d\t; ",n); + putchar('"'); + for (; *s; s++) { - TObject* o=tf->consts+i; - printf("%6d ",i); - switch (ttype(o)) + switch (*s) { - case LUA_T_NUMBER: - printf("N " NUMBER_FMT "\n",(double)nvalue(o)); - break; - case LUA_T_STRING: - printf("S %p\t\"%s\"\n",tsvalue(o),svalue(o)); - break; - case LUA_T_PROTO: - printf("F %p\n",tfvalue(o)); - break; - case LUA_T_NIL: - printf("nil\n"); - break; - default: /* cannot happen */ - printf("? type=%d\n",ttype(o)); - break; + case '"': printf("\\\""); break; + case '\a': printf("\\a"); break; + case '\b': printf("\\b"); break; + case '\f': printf("\\f"); break; + case '\n': printf("\\n"); break; + case '\r': printf("\\r"); break; + case '\t': printf("\\t"); break; + case '\v': printf("\\v"); break; + default: putchar(*s); break; } } + putchar('"'); } -#endif -static void PrintConstant(TProtoFunc* tf, int i, int at) +static void PrintLocal(const Proto* tf, int n, int pc) { - TObject* o=luaU_getconstant(tf,i,at); - switch (ttype(o)) - { - case LUA_T_NUMBER: - printf(NUMBER_FMT,(double)nvalue(o)); - break; - case LUA_T_STRING: - printf("\"%s\"",svalue(o)); - break; - case LUA_T_PROTO: - printf("function at %p",(void*)tfvalue(o)); - break; - case LUA_T_NIL: - printf("(nil)"); - break; - default: /* cannot happen */ - luaU_badconstant("print",i,o,tf); - break; - } + const char* s=luaF_getlocalname(tf,n+1,pc); + printf("%u",n); + if (s!=NULL) printf("\t; %s",s); } -static void PrintCode(TProtoFunc* tf) +static void PrintCode(const Proto* tf) { - Byte* code=tf->code; - Byte* p=code; - int line=0; - int longarg=0; + const Instruction* code=tf->code; + const Instruction* p=code; for (;;) { - Opcode OP; - int n=INFO(tf,p,&OP); - int i=OP.arg+longarg; - int at=p-code; - longarg=0; - printf("%6d ",at); - { - Byte* q=p; - int j=n; - while (j--) printf("%02X",*q++); - } - printf("%*s%-14s ",2*(5-n),"",OP.name); - if (OP.arg >=0) printf("%d",i); - if (OP.arg2>=0) printf(" %d",OP.arg2); - - switch (OP.class) - { - - case ENDCODE: - printf("\n"); - return; - - case PUSHCONSTANT: - case GETGLOBAL: - case SETGLOBAL: - case GETDOTTED: - case PUSHSELF: - case CLOSURE: - printf("\t; "); - PrintConstant(tf,i,at); - break; - - case PUSHLOCAL: - case SETLOCAL: - { - char* s=luaF_getlocalname(tf,i+1,line); - if (s) printf("\t; %s",s); - break; - } - - case SETLINE: - printf("\t; " SOURCE,tf->source->str,line=i); - break; - - case LONGARG: - longarg=i<<16; - break; - -/* suggested by Norman Ramsey */ - case ONTJMP: - case ONFJMP: - case JMP: - case IFFJMP: - printf("\t; to %d",at+i+n); - break; - case IFTUPJMP: - case IFFUPJMP: - printf("\t; to %d",at-i+n); - break; - - } - printf("\n"); - p+=n; - } -} - -static void PrintLocals(TProtoFunc* tf) -{ - LocVar* v=tf->locvars; - int n,i; - if (v==NULL || v->line<0) return; - n=tf->code[1]; if (n>=ZEROVARARG) n-=ZEROVARARG; - printf("locals:"); - for (i=0; ivarname->str); - for (; v->line>=0; v++) - { - if (v->varname==NULL) - { - --i; if (i<0) luaL_verror("bad locvars[%d]",v-tf->locvars); else printf(")"); - } - else - { - ++i; printf(" (%s",v->varname->str); + int at=p-code+1; + Instruction i=*p; + int line=luaG_getline(tf->lineinfo,at-1,1,NULL); + printf("%6d\t",at); + if (line>=0) printf("[%d]\t",line); else printf("[-]\t"); + switch (GET_OPCODE(i)) { +#include "print.h" } + printf("\n"); + if (i==OP_END) break; + p++; } - i-=n; - while (i--) printf(")"); - printf("\n"); } #define IsMain(tf) (tf->lineDefined==0) -static void PrintHeader(TProtoFunc* tf, TProtoFunc* Main, int at) -{ - int size=luaU_codesize(tf); - if (IsMain(tf)) - printf("\nmain " SOURCE " (%d bytes at %p)\n", - tf->source->str,tf->lineDefined,size,tf); - else - { - printf("\nfunction " SOURCE " (%d bytes at %p); used at ", - tf->source->str,tf->lineDefined,size,tf); - if (Main && IsMain(Main)) - printf("main"); - else - printf("%p",Main); - printf("+%d\n",at); - } -} - -static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at); +#define SS(x) (x==1)?"":"s" +#define S(x) x,SS(x) -static void PrintFunctions(TProtoFunc* Main) +static void PrintHeader(const Proto* tf) { - Byte* code=Main->code; - Byte* p=code; - int longarg=0; - for (;;) - { - Opcode OP; - int n=INFO(Main,p,&OP); - int op=OP.class; - int i=OP.arg+longarg; - longarg=0; - if (op==PUSHCONSTANT || op==CLOSURE) - { - TObject* o=Main->consts+i; - if (ttype(o)==LUA_T_PROTO) PrintFunction(tfvalue(o),Main,(int)(p-code)); - } - else if (op==LONGARG) longarg=i<<16; - else if (op==ENDCODE) break; - p+=n; - } + printf("\n%s " SOURCE_FMT " (%d instruction%s/%d bytes at %p)\n", + IsMain(tf)?"main":"function",SOURCE, + S(tf->ncode),tf->ncode*Sizeof(Instruction),tf); + printf("%d%s param%s, %d stack%s, ", + tf->numparams,tf->is_vararg?"+":"",SS(tf->numparams),S(tf->maxstacksize)); + printf("%d local%s, %d string%s, %d number%s, %d function%s, %d line%s\n", + S(tf->nlocvars),S(tf->nkstr),S(tf->nknum),S(tf->nkproto),S(tf->nlineinfo)); } -static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at) -{ - PrintHeader(tf,Main,at); - PrintLocals(tf); - PrintCode(tf); -#ifdef DEBUG - PrintConstants(tf); -#endif - PrintFunctions(tf); -} +#define PrintFunction luaU_printchunk -void luaU_printchunk(TProtoFunc* Main) +void PrintFunction(const Proto* tf) { - PrintFunction(Main,0,0); + int i,n=tf->nkproto; + PrintHeader(tf); + PrintCode(tf); + for (i=0; ikproto[i]); } diff --git a/src/luac/print.h b/src/luac/print.h new file mode 100644 index 0000000000..5f74e14959 --- /dev/null +++ b/src/luac/print.h @@ -0,0 +1,55 @@ +/* +** $Id: print.h,v 1.1 2000/11/06 20:03:12 lhf Exp $ +** extracted automatically from lopcodes.h by mkprint.lua -- DO NOT EDIT +** See Copyright Notice in lua.h +*/ + + case OP_END: P_OP("END"); P_NONE; break; + case OP_RETURN: P_OP("RETURN"); P_U; break; + case OP_CALL: P_OP("CALL"); P_AB; break; + case OP_TAILCALL: P_OP("TAILCALL"); P_AB; break; + case OP_PUSHNIL: P_OP("PUSHNIL"); P_U; break; + case OP_POP: P_OP("POP"); P_U; break; + case OP_PUSHINT: P_OP("PUSHINT"); P_S; break; + case OP_PUSHSTRING: P_OP("PUSHSTRING"); P_Q; break; + case OP_PUSHNUM: P_OP("PUSHNUM"); P_N; break; + case OP_PUSHNEGNUM: P_OP("PUSHNEGNUM"); P_N; break; + case OP_PUSHUPVALUE: P_OP("PUSHUPVALUE"); P_U; break; + case OP_GETLOCAL: P_OP("GETLOCAL"); P_L; break; + case OP_GETGLOBAL: P_OP("GETGLOBAL"); P_K; break; + case OP_GETTABLE: P_OP("GETTABLE"); P_NONE; break; + case OP_GETDOTTED: P_OP("GETDOTTED"); P_K; break; + case OP_GETINDEXED: P_OP("GETINDEXED"); P_L; break; + case OP_PUSHSELF: P_OP("PUSHSELF"); P_K; break; + case OP_CREATETABLE: P_OP("CREATETABLE"); P_U; break; + case OP_SETLOCAL: P_OP("SETLOCAL"); P_L; break; + case OP_SETGLOBAL: P_OP("SETGLOBAL"); P_K; break; + case OP_SETTABLE: P_OP("SETTABLE"); P_AB; break; + case OP_SETLIST: P_OP("SETLIST"); P_AB; break; + case OP_SETMAP: P_OP("SETMAP"); P_U; break; + case OP_ADD: P_OP("ADD"); P_NONE; break; + case OP_ADDI: P_OP("ADDI"); P_S; break; + case OP_SUB: P_OP("SUB"); P_NONE; break; + case OP_MULT: P_OP("MULT"); P_NONE; break; + case OP_DIV: P_OP("DIV"); P_NONE; break; + case OP_POW: P_OP("POW"); P_NONE; break; + case OP_CONCAT: P_OP("CONCAT"); P_U; break; + case OP_MINUS: P_OP("MINUS"); P_NONE; break; + case OP_NOT: P_OP("NOT"); P_NONE; break; + case OP_JMPNE: P_OP("JMPNE"); P_J; break; + case OP_JMPEQ: P_OP("JMPEQ"); P_J; break; + case OP_JMPLT: P_OP("JMPLT"); P_J; break; + case OP_JMPLE: P_OP("JMPLE"); P_J; break; + case OP_JMPGT: P_OP("JMPGT"); P_J; break; + case OP_JMPGE: P_OP("JMPGE"); P_J; break; + case OP_JMPT: P_OP("JMPT"); P_J; break; + case OP_JMPF: P_OP("JMPF"); P_J; break; + case OP_JMPONT: P_OP("JMPONT"); P_J; break; + case OP_JMPONF: P_OP("JMPONF"); P_J; break; + case OP_JMP: P_OP("JMP"); P_J; break; + case OP_PUSHNILJMP: P_OP("PUSHNILJMP"); P_NONE; break; + case OP_FORPREP: P_OP("FORPREP"); P_J; break; + case OP_FORLOOP: P_OP("FORLOOP"); P_J; break; + case OP_LFORPREP: P_OP("LFORPREP"); P_J; break; + case OP_LFORLOOP: P_OP("LFORLOOP"); P_J; break; + case OP_CLOSURE: P_OP("CLOSURE"); P_F; break; diff --git a/src/luac/stubs.c b/src/luac/stubs.c index 5f38940ed8..74f509eb26 100644 --- a/src/luac/stubs.c +++ b/src/luac/stubs.c @@ -1,68 +1,109 @@ /* -** $Id: stubs.c,v 1.11 1999/03/11 17:09:10 lhf Exp $ +** $Id: stubs.c,v 1.20 2000/10/31 16:57:23 lhf Exp $ ** avoid runtime modules in luac ** See Copyright Notice in lua.h */ -#ifdef NOSTUBS - -/* according to gcc, ANSI C forbids an empty source file */ -void luaU_dummy(void); -void luaU_dummy(void){} - -#else - -#include #include #include + +#include "ldo.h" +#include "llex.h" #include "luac.h" +#undef L + +#ifndef NOSTUBS + +const char luac_ident[] = "$luac: " LUA_VERSION " " LUA_COPYRIGHT " $\n" + "$Authors: " LUA_AUTHORS " $"; /* -* avoid lapi lauxlib lbuiltin ldo lgc ltable ltm lvm -* use only lbuffer lfunc llex lmem lobject lparser lstate lstring lzio +* avoid lapi ldebug ldo lgc lstate ltm lvm +* use only lcode lfunc llex lmem lobject lparser lstring ltable lzio */ /* simplified from ldo.c */ -void lua_error(char* s) -{ - if (s) fprintf(stderr,"luac: %s\n",s); - exit(1); +void lua_error (lua_State* L, const char* s) { + UNUSED(L); + if (s) fprintf(stderr,"luac: %s\n",s); + exit(1); } -/* copied from lauxlib.c */ -void luaL_verror (char *fmt, ...) -{ - char buff[500]; - va_list argp; - va_start(argp, fmt); - vsprintf(buff, fmt, argp); - va_end(argp); - lua_error(buff); +/* simplified from ldo.c */ +void luaD_breakrun (lua_State *L, int errcode) { + UNUSED(errcode); + lua_error(L,"memory allocation error"); } -/* copied from lauxlib.c */ -void luaL_filesource (char *out, char *filename, int len) { - if (filename == NULL) filename = "(stdin)"; - sprintf(out, "@%.*s", len-2, filename); /* -2 for '@' and '\0' */ +/* simplified from lstate.c */ +lua_State *lua_open (int stacksize) { + lua_State *L = luaM_new(NULL, lua_State); + if (L == NULL) return NULL; /* memory allocation error */ + L->stack = NULL; + L->strt.size = L->udt.size = 0; + L->strt.nuse = L->udt.nuse = 0; + L->strt.hash = NULL; + L->udt.hash = NULL; + L->Mbuffer = NULL; + L->Mbuffsize = 0; + L->rootproto = NULL; + L->rootcl = NULL; + L->roottable = NULL; + L->TMtable = NULL; + L->last_tag = -1; + L->refArray = NULL; + L->refSize = 0; + L->refFree = NONEXT; + L->nblocks = sizeof(lua_State); + L->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */ + L->callhook = NULL; + L->linehook = NULL; + L->allowhooks = 1; + L->errorJmp = NULL; + if (stacksize == 0) + stacksize = DEFAULT_STACK_SIZE; + else + stacksize += LUA_MINSTACK; + L->gt = luaH_new(L, 10); /* table of globals */ + luaS_init(L); + luaX_init(L); + L->GCthreshold = 2*L->nblocks; + return L; } -/* avoid runtime modules in lstate.c */ - -#include "lbuiltin.h" -#include "ldo.h" -#include "lgc.h" -#include "ltable.h" -#include "ltm.h" - -void luaB_predefine(void){} -void luaC_hashcallIM(Hash *l){} -void luaC_strcallIM(TaggedString *l){} -void luaD_gcIM(TObject *o){} -void luaH_free(Hash *frees){} -void luaT_init(void){} +/* copied from ldebug.c */ +int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) { + int refi; + if (lineinfo == NULL || pc == -1) + return -1; /* no line info or function is not active */ + refi = prefi ? *prefi : 0; + if (lineinfo[refi] < 0) + refline += -lineinfo[refi++]; + LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); + while (lineinfo[refi] > pc) { + refline--; + refi--; + if (lineinfo[refi] < 0) + refline -= -lineinfo[refi--]; + LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); + } + for (;;) { + int nextline = refline + 1; + int nextref = refi + 1; + if (lineinfo[nextref] < 0) + nextline += -lineinfo[nextref++]; + LUA_ASSERT(lineinfo[nextref] >= 0, "invalid line info"); + if (lineinfo[nextref] > pc) + break; + refline = nextline; + refi = nextref; + } + if (prefi) *prefi = refi; + return refline; +} /* -* the code below avoids the lexer and the parser (llex lparser). +* the code below avoids the lexer and the parser (llex lparser lcode). * it is useful if you only want to load binary files. * this works for interpreters like lua.c too. */ @@ -72,49 +113,14 @@ void luaT_init(void){} #include "llex.h" #include "lparser.h" -void luaX_init(void){} -void luaD_init(void){} - -TProtoFunc* luaY_parser(ZIO *z) { - lua_error("parser not loaded"); - return NULL; -} - -#else - -/* copied from lauxlib.c */ -int luaL_findstring (char *name, char *list[]) { - int i; - for (i=0; list[i]; i++) - if (strcmp(list[i], name) == 0) - return i; - return -1; /* name not found */ -} - -/* copied from lauxlib.c */ -void luaL_chunkid (char *out, char *source, int len) { - len -= 13; /* 13 = strlen("string ''...\0") */ - if (*source == '@') - sprintf(out, "file `%.*s'", len, source+1); - else if (*source == '(') - strcpy(out, "(C code)"); - else { - char *b = strchr(source , '\n'); /* stop string at first new line */ - int lim = (b && (b-source)stack.stack = luaM_newvector(STACK_UNIT, TObject); - L->stack.top = L->stack.stack; - L->stack.last = L->stack.stack+(STACK_UNIT-1); +Proto *luaY_parser(lua_State *L, ZIO *z) { + UNUSED(z); + lua_error(L,"parser not loaded"); + return NULL; } #endif diff --git a/src/luac/test.c b/src/luac/test.c deleted file mode 100644 index 78ba4556d7..0000000000 --- a/src/luac/test.c +++ /dev/null @@ -1,253 +0,0 @@ -/* -** $Id: test.c,v 1.10 1999/07/02 19:34:26 lhf Exp $ -** test integrity -** See Copyright Notice in lua.h -*/ - -#include -#include -#include -#include "luac.h" - -#define AT "pc=%d" -#define ATLOC 0) -#define UNSAFE(s) \ - luaL_verror("unsafe code at " AT IN "\n " s,at,INLOC - -TObject* luaU_getconstant(TProtoFunc* tf, int i, int at) -{ - if (i>=tf->nconsts) UNSAFE("bad constant #%d (max=%d)"),i,tf->nconsts-1,ATLOC; - return tf->consts+i; -} - -static int check(int n, TProtoFunc* tf, int at, int sp, int ss) -{ - if (n==0) return sp; - sp+=n; - if (sp<00) UNSAFE("stack underflow (sp=%d)"),sp,ATLOC; - if (sp>ss) UNSAFE("stack overflow (sp=%d ss=%d)"),sp,ss,ATLOC; - return sp; -} - -#define CHECK(before,after) \ - sp=check(-(before),tf,at,sp,ss), sp=check(after,tf,at,sp,ss) - -static int jmpok(TProtoFunc* tf, int size, int at, int d) -{ - int to=at+d; - if (to<2 || to>=size) - UNSAFE("invalid jump to %d (valid range is 2..%d)"),to,size-1,ATLOC; - return to; -} - -static void TestStack(TProtoFunc* tf, int size, int* SP, int* JP) -{ - Byte* code=tf->code; - Byte* p=code; - int longarg=0; - int ss=0; - int sp=0; - for (;;) - { - Opcode OP; - int n=INFO(tf,p,&OP); - int op=OP.class; - int i=OP.arg+longarg; - int at=p-code; - longarg=0; - switch (op) /* test sanity of operands */ - { - case PUSHCONSTANT: - case GETGLOBAL: - case GETDOTTED: - case PUSHSELF: - case SETGLOBAL: - case CLOSURE: - { - TObject* o=luaU_getconstant(tf,i,at); - if ((op==CLOSURE && ttype(o)!=LUA_T_PROTO) - || (op==GETGLOBAL && ttype(o)!=LUA_T_STRING) - || (op==SETGLOBAL && ttype(o)!=LUA_T_STRING)) - UNSAFE("bad operand to %s"),OP.name,ATLOC; - break; - } - case PUSHLOCAL: - if (i>=sp) UNSAFE("bad local #%d (max=%d)"),i,sp-1,ATLOC; - break; - case SETLOCAL: - if (i>=(sp-1)) UNSAFE("bad local #%d (max=%d)"),i,sp-2,ATLOC; - break; - case ONTJMP: - case ONFJMP: /* negate to remember ON?JMP */ - JP[at]=-jmpok(tf,size,at,i+n); - break; - case JMP: /* remember JMP targets */ - case IFFJMP: - JP[at]= jmpok(tf,size,at,i+n); - break; - case IFTUPJMP: - case IFFUPJMP: - JP[at]= jmpok(tf,size,at,-i+n); - break; - } - - SP[at]=sp; /* remember depth before instruction */ - - switch (op) - { - case STACK: ss=i; break; - case ARGS: CHECK(0,i); break; - case VARARGS: break; - case ENDCODE: return; - case RETCODE: CHECK(i,0); sp=i; break; - case CALL: CHECK(OP.arg2+1,i); break; - case TAILCALL: CHECK(OP.arg2,0); sp=i; break; - case PUSHNIL: CHECK(0,i+1); break; - case POP: CHECK(0,-i); break; - case PUSHNUMBER: - case PUSHNUMBERNEG: - case PUSHCONSTANT: - case PUSHUPVALUE: - case PUSHLOCAL: - case GETGLOBAL: CHECK(0,1); break; - case GETTABLE: CHECK(2,1); break; - case GETDOTTED: CHECK(1,1); break; - case PUSHSELF: CHECK(1,2); break; - case CREATEARRAY: CHECK(0,1); break; - case SETLOCAL: CHECK(1,0); break; - case SETGLOBAL: CHECK(1,0); break; - case SETTABLEPOP: CHECK(3,0); break; - case SETTABLE: CHECK(i+3,i+2); break; - case SETLIST: CHECK(OP.arg2+1,1); break; - case SETMAP: CHECK(2*(i+1)+1,1); break; - case NEQOP: - case EQOP: - case LTOP: - case LEOP: - case GTOP: - case GEOP: - case ADDOP: - case SUBOP: - case MULTOP: - case DIVOP: - case POWOP: - case CONCOP: CHECK(2,1); break; - case MINUSOP: - case NOTOP: CHECK(1,1); break; - case ONTJMP: - case ONFJMP: - case IFFJMP: - case IFTUPJMP: - case IFFUPJMP: CHECK(1,0); break; - case JMP: break; - case CLOSURE: CHECK(OP.arg2,1); break; - case SETLINE: break; - case LONGARG: - longarg=i<<16; - if (longarg<0) UNSAFE("longarg overflow"),ATLOC; - break; - case CHECKSTACK: break; - default: /* cannot happen */ - UNSAFE("cannot test opcode %d [%s]"),OP.op,OP.name,ATLOC; - break; - } - p+=n; - } -} - -static void TestJumps(TProtoFunc* tf, int size, int* SP, int* JP) -{ - int i; - for (i=0; ilocvars==NULL) return; - for (v=tf->locvars; v->line>=0; v++) - { - int at=v-tf->locvars; /* for ATLOC */ - if (l>v->line) - UNSAFE("bad line number %d; expected at least %d"),v->line,l,ATLOC; - l=v->line; - if (v->varname==NULL) - { - if (--d<0) UNSAFE("no scope to close"),ATLOC; - } - else - ++d; - } -} - -static void TestFunction(TProtoFunc* tf); - -static void TestConstants(TProtoFunc* tf) -{ - int i,n=tf->nconsts; - for (i=0; iconsts+i; - switch (ttype(o)) - { - case LUA_T_NUMBER: - break; - case LUA_T_STRING: - break; - case LUA_T_PROTO: - TestFunction(tfvalue(o)); - break; - case LUA_T_NIL: - break; - default: /* cannot happen */ - luaU_badconstant("print",i,o,tf); - break; - } - } -} - -static void TestFunction(TProtoFunc* tf) -{ - TestCode(tf); - TestLocals(tf); - TestConstants(tf); -} - -void luaU_testchunk(TProtoFunc* Main) -{ - TestFunction(Main); -} diff --git a/src/lundump.c b/src/lundump.c index 0c3b5fd711..a8d0610675 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,239 +1,244 @@ /* -** $Id: lundump.c,v 1.21 1999/07/02 19:34:26 lhf Exp $ +** $Id: lundump.c,v 1.33 2000/10/31 16:57:23 lhf Exp $ ** load bytecodes from files ** See Copyright Notice in lua.h */ #include #include -#include "lauxlib.h" + #include "lfunc.h" #include "lmem.h" #include "lopcodes.h" #include "lstring.h" #include "lundump.h" -#define LoadBlock(b,size,Z) ezread(Z,b,size) +#define LoadByte ezgetc -static void unexpectedEOZ (ZIO* Z) +static const char* ZNAME (ZIO* Z) { - luaL_verror("unexpected end of file in %s",zname(Z)); + const char* s=zname(Z); + return (*s=='@') ? s+1 : s; } -static int ezgetc (ZIO* Z) +static void unexpectedEOZ (lua_State* L, ZIO* Z) { - int c=zgetc(Z); - if (c==EOZ) unexpectedEOZ(Z); - return c; + luaO_verror(L,"unexpected end of file in `%.99s'",ZNAME(Z)); } -static void ezread (ZIO* Z, void* b, int n) +static int ezgetc (lua_State* L, ZIO* Z) { - int r=zread(Z,b,n); - if (r!=0) unexpectedEOZ(Z); + int c=zgetc(Z); + if (c==EOZ) unexpectedEOZ(L,Z); + return c; } -static unsigned int LoadWord (ZIO* Z) +static void ezread (lua_State* L, ZIO* Z, void* b, int n) { - unsigned int hi=ezgetc(Z); - unsigned int lo=ezgetc(Z); - return (hi<<8)|lo; + int r=zread(Z,b,n); + if (r!=0) unexpectedEOZ(L,Z); } -static unsigned long LoadLong (ZIO* Z) +static void LoadBlock (lua_State* L, void* b, size_t size, ZIO* Z, int swap) { - unsigned long hi=LoadWord(Z); - unsigned long lo=LoadWord(Z); - return (hi<<16)|lo; -} - -/* -* convert number from text -*/ -double luaU_str2d (char* b, char* where) -{ - int negative=(b[0]=='-'); - double x=luaO_str2d(b+negative); - if (x<0) luaL_verror("cannot convert number '%s' in %s",b,where); - return negative ? -x : x; + if (swap) + { + char *p=(char *) b+size-1; + int n=size; + while (n--) *p--=(char)ezgetc(L,Z); + } + else + ezread(L,Z,b,size); } -static real LoadNumber (ZIO* Z, int native) +static void LoadVector (lua_State* L, void* b, int m, size_t size, ZIO* Z, int swap) { - real x; - if (native) + if (swap) { - LoadBlock(&x,sizeof(x),Z); - return x; + char *q=(char *) b; + while (m--) + { + char *p=q+size-1; + int n=size; + while (n--) *p--=(char)ezgetc(L,Z); + q+=size; + } } else - { - char b[256]; - int size=ezgetc(Z); - LoadBlock(b,size,Z); - b[size]=0; - return luaU_str2d(b,zname(Z)); - } + ezread(L,Z,b,m*size); } -static int LoadInt (ZIO* Z, char* message) +static int LoadInt (lua_State* L, ZIO* Z, int swap) { - unsigned long l=LoadLong(Z); - unsigned int i=l; - if (i!=l) luaL_verror(message,l,zname(Z)); - return i; + int x; + LoadBlock(L,&x,sizeof(x),Z,swap); + return x; } -#define PAD 5 /* two word operands plus opcode */ +static size_t LoadSize (lua_State* L, ZIO* Z, int swap) +{ + size_t x; + LoadBlock(L,&x,sizeof(x),Z,swap); + return x; +} -static Byte* LoadCode (ZIO* Z) +static Number LoadNumber (lua_State* L, ZIO* Z, int swap) { - int size=LoadInt(Z,"code too long (%ld bytes) in %s"); - Byte* b=luaM_malloc(size+PAD); - LoadBlock(b,size,Z); - if (b[size-1]!=ENDCODE) luaL_verror("bad code in %s",zname(Z)); - memset(b+size,ENDCODE,PAD); /* pad code for safety */ - return b; + Number x; + LoadBlock(L,&x,sizeof(x),Z,swap); + return x; } -static TaggedString* LoadTString (ZIO* Z) +static TString* LoadString (lua_State* L, ZIO* Z, int swap) { - long size=LoadLong(Z); + size_t size=LoadSize(L,Z,swap); if (size==0) return NULL; else { - char* s=luaL_openspace(size); - LoadBlock(s,size,Z); - return luaS_newlstr(s,size-1); + char* s=luaO_openspace(L,size); + LoadBlock(L,s,size,Z,0); + return luaS_newlstr(L,s,size-1); /* remove trailing '\0' */ } } -static void LoadLocals (TProtoFunc* tf, ZIO* Z) +static void LoadCode (lua_State* L, Proto* tf, ZIO* Z, int swap) { - int i,n=LoadInt(Z,"too many locals (%ld) in %s"); - if (n==0) return; - tf->locvars=luaM_newvector(n+1,LocVar); + int size=LoadInt(L,Z,swap); + tf->code=luaM_newvector(L,size,Instruction); + LoadVector(L,tf->code,size,sizeof(*tf->code),Z,swap); + if (tf->code[size-1]!=OP_END) luaO_verror(L,"bad code in `%.99s'",ZNAME(Z)); + luaF_protook(L,tf,size); +} + +static void LoadLocals (lua_State* L, Proto* tf, ZIO* Z, int swap) +{ + int i,n; + tf->nlocvars=n=LoadInt(L,Z,swap); + tf->locvars=luaM_newvector(L,n,LocVar); for (i=0; ilocvars[i].line=LoadInt(Z,"too many lines (%ld) in %s"); - tf->locvars[i].varname=LoadTString(Z); + tf->locvars[i].varname=LoadString(L,Z,swap); + tf->locvars[i].startpc=LoadInt(L,Z,swap); + tf->locvars[i].endpc=LoadInt(L,Z,swap); } - tf->locvars[i].line=-1; /* flag end of vector */ - tf->locvars[i].varname=NULL; } -static TProtoFunc* LoadFunction (ZIO* Z, int native); +static void LoadLines (lua_State* L, Proto* tf, ZIO* Z, int swap) +{ + int n; + tf->nlineinfo=n=LoadInt(L,Z,swap); + tf->lineinfo=luaM_newvector(L,n,int); + LoadVector(L,tf->lineinfo,n,sizeof(*tf->lineinfo),Z,swap); +} + +static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap); -static void LoadConstants (TProtoFunc* tf, ZIO* Z, int native) +static void LoadConstants (lua_State* L, Proto* tf, ZIO* Z, int swap) { - int i,n=LoadInt(Z,"too many constants (%ld) in %s"); - tf->nconsts=n; - if (n==0) return; - tf->consts=luaM_newvector(n,TObject); + int i,n; + tf->nkstr=n=LoadInt(L,Z,swap); + tf->kstr=luaM_newvector(L,n,TString*); for (i=0; iconsts+i; - ttype(o)=-ezgetc(Z); /* ttype(o) is negative - ORDER LUA_T */ - switch (ttype(o)) - { - case LUA_T_NUMBER: - nvalue(o)=LoadNumber(Z,native); - break; - case LUA_T_STRING: - tsvalue(o)=LoadTString(Z); - break; - case LUA_T_PROTO: - tfvalue(o)=LoadFunction(Z,native); - break; - case LUA_T_NIL: - break; - default: /* cannot happen */ - luaU_badconstant("load",i,o,tf); - break; - } - } + tf->kstr[i]=LoadString(L,Z,swap); + tf->nknum=n=LoadInt(L,Z,swap); + tf->knum=luaM_newvector(L,n,Number); + LoadVector(L,tf->knum,n,sizeof(*tf->knum),Z,swap); + tf->nkproto=n=LoadInt(L,Z,swap); + tf->kproto=luaM_newvector(L,n,Proto*); + for (i=0; ikproto[i]=LoadFunction(L,Z,swap); } -static TProtoFunc* LoadFunction (ZIO* Z, int native) +static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap) { - TProtoFunc* tf=luaF_newproto(); - tf->lineDefined=LoadInt(Z,"lineDefined too large (%ld) in %s"); - tf->source=LoadTString(Z); - if (tf->source==NULL) tf->source=luaS_new(zname(Z)); - tf->code=LoadCode(Z); - LoadLocals(tf,Z); - LoadConstants(tf,Z,native); + Proto* tf=luaF_newproto(L); + tf->source=LoadString(L,Z,swap); + tf->lineDefined=LoadInt(L,Z,swap); + tf->numparams=LoadInt(L,Z,swap); + tf->is_vararg=LoadByte(L,Z); + tf->maxstacksize=LoadInt(L,Z,swap); + LoadLocals(L,tf,Z,swap); + LoadLines(L,tf,Z,swap); + LoadConstants(L,tf,Z,swap); + LoadCode(L,tf,Z,swap); return tf; } -static void LoadSignature (ZIO* Z) +static void LoadSignature (lua_State* L, ZIO* Z) { - char* s=SIGNATURE; - while (*s!=0 && ezgetc(Z)==*s) + const char* s=SIGNATURE; + while (*s!=0 && ezgetc(L,Z)==*s) ++s; - if (*s!=0) luaL_verror("bad signature in %s",zname(Z)); + if (*s!=0) luaO_verror(L,"bad signature in `%.99s'",ZNAME(Z)); } -static int LoadHeader (ZIO* Z) +static void TestSize (lua_State* L, int s, const char* what, ZIO* Z) +{ + int r=ezgetc(L,Z); + if (r!=s) + luaO_verror(L,"virtual machine mismatch in `%.99s':\n" + " %.20s is %d but read %d",ZNAME(Z),what,s,r); +} + +#define TESTSIZE(s) TestSize(L,s,#s,Z) +#define V(v) v/16,v%16 + +static int LoadHeader (lua_State* L, ZIO* Z) { - int version,sizeofR; - int native; - LoadSignature(Z); - version=ezgetc(Z); + int version,swap; + Number f=0,tf=TEST_NUMBER; + LoadSignature(L,Z); + version=ezgetc(L,Z); if (version>VERSION) - luaL_verror( - "%s too new: version=0x%02x; expected at most 0x%02x", - zname(Z),version,VERSION); + luaO_verror(L,"`%.99s' too new:\n" + " read version %d.%d; expected at most %d.%d", + ZNAME(Z),V(version),V(VERSION)); if (version0 || t" -#define IN " in %p " SOURCE -#define INLOC tf,tf->source->str,tf->lineDefined - -/* format for numbers in listings and error messages */ -#ifndef NUMBER_FMT -#define NUMBER_FMT "%.16g" /* LUA_NUMBER */ -#endif +#define SOURCE_FMT "<%d:%.99s>" +#define SOURCE tf->lineDefined,tf->source->str +#define IN_FMT " in %p " SOURCE_FMT +#define IN tf,SOURCE /* a multiple of PI for testing native format */ /* multiplying by 1E8 gives non-trivial integer values */ diff --git a/src/lvm.c b/src/lvm.c index 670642b9cf..63e42efb2d 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,28 +1,27 @@ /* -** $Id: lvm.c,v 1.58 1999/06/22 20:37:23 roberto Exp $ +** $Id: lvm.c,v 1.146 2000/10/26 12:47:05 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ -#include -#include #include #include #include -#include "lauxlib.h" +#include "lua.h" + +#include "lapi.h" +#include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" -#include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" -#include "luadebug.h" #include "lvm.h" @@ -31,605 +30,681 @@ #endif -#define highbyte(x) ((x)<<8) - - -/* Extra stack size to run a function: LUA_T_LINE(1), TM calls(2), ... */ -#define EXTRA_STACK 5 - +/* +** Extra stack size to run a function: +** TAG_LINE(1), NAME(1), TM calls(3) (plus some extra...) +*/ +#define EXTRA_STACK 8 -static TaggedString *strconc (TaggedString *l, TaggedString *r) { - long nl = l->u.s.len; - long nr = r->u.s.len; - char *buffer = luaL_openspace(nl+nr); - memcpy(buffer, l->str, nl); - memcpy(buffer+nl, r->str, nr); - return luaS_newlstr(buffer, nl+nr); -} -int luaV_tonumber (TObject *obj) { /* LUA_NUMBER */ - if (ttype(obj) != LUA_T_STRING) +int luaV_tonumber (TObject *obj) { + if (ttype(obj) != LUA_TSTRING) return 1; else { - double t; - char *e = svalue(obj); - int sig = 1; - while (isspace((unsigned char)*e)) e++; - if (*e == '-') { - e++; - sig = -1; - } - else if (*e == '+') e++; - /* no digit before or after decimal point? */ - if (!isdigit((unsigned char)*e) && !isdigit((unsigned char)*(e+1))) + if (!luaO_str2d(svalue(obj), &nvalue(obj))) return 2; - t = luaO_str2d(e); - if (t<0) return 2; - nvalue(obj) = (real)t*sig; - ttype(obj) = LUA_T_NUMBER; + ttype(obj) = LUA_TNUMBER; return 0; } } -int luaV_tostring (TObject *obj) { /* LUA_NUMBER */ - if (ttype(obj) != LUA_T_NUMBER) +int luaV_tostring (lua_State *L, TObject *obj) { /* LUA_NUMBER */ + if (ttype(obj) != LUA_TNUMBER) return 1; else { - char s[32]; /* 16 digits, signal, point and \0 (+ some extra...) */ - sprintf(s, "%.16g", (double)nvalue(obj)); - tsvalue(obj) = luaS_new(s); - ttype(obj) = LUA_T_STRING; + char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ + lua_number2str(s, nvalue(obj)); /* convert `s' to number */ + tsvalue(obj) = luaS_new(L, s); + ttype(obj) = LUA_TSTRING; return 0; } } -void luaV_setn (Hash *t, int val) { - TObject index, value; - ttype(&index) = LUA_T_STRING; tsvalue(&index) = luaS_new("n"); - ttype(&value) = LUA_T_NUMBER; nvalue(&value) = val; - luaH_set(t, &index, &value); +static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) { + CallInfo *ci = infovalue(base-1); + int *lineinfo = ci->func->f.l->lineinfo; + int pc = (*ci->pc - ci->func->f.l->code) - 1; + int newline; + if (pc == 0) { /* may be first time? */ + ci->line = 1; + ci->refi = 0; + ci->lastpc = pc+1; /* make sure it will call linehook */ + } + newline = luaG_getline(lineinfo, pc, ci->line, &ci->refi); + /* calls linehook when enters a new line or jumps back (loop) */ + if (newline != ci->line || pc <= ci->lastpc) { + ci->line = newline; + L->top = top; + luaD_lineHook(L, base-2, newline, linehook); + } + ci->lastpc = pc; +} + + +static Closure *luaV_closure (lua_State *L, int nelems) { + Closure *c = luaF_newclosure(L, nelems); + L->top -= nelems; + while (nelems--) + c->upvalue[nelems] = *(L->top+nelems); + clvalue(L->top) = c; + ttype(L->top) = LUA_TFUNCTION; + incr_top; + return c; } -void luaV_closure (int nelems) { - if (nelems > 0) { - struct Stack *S = &L->stack; - Closure *c = luaF_newclosure(nelems); - c->consts[0] = *(S->top-1); - memcpy(&c->consts[1], S->top-(nelems+1), nelems*sizeof(TObject)); - S->top -= nelems; - ttype(S->top-1) = LUA_T_CLOSURE; - (S->top-1)->value.cl = c; - } +void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems) { + Closure *cl = luaV_closure(L, nelems); + cl->f.c = c; + cl->isC = 1; +} + + +void luaV_Lclosure (lua_State *L, Proto *l, int nelems) { + Closure *cl = luaV_closure(L, nelems); + cl->f.l = l; + cl->isC = 0; } /* ** Function to index a table. -** Receives the table at top-2 and the index at top-1. +** Receives the table at `t' and the key at top. */ -void luaV_gettable (void) { - TObject *table = L->stack.top-2; - TObject *im; - if (ttype(table) != LUA_T_ARRAY) { /* not a table, get gettable method */ - im = luaT_getimbyObj(table, IM_GETTABLE); - if (ttype(im) == LUA_T_NIL) - lua_error("indexed expression not a table"); +const TObject *luaV_gettable (lua_State *L, StkId t) { + Closure *tm; + int tg; + if (ttype(t) == LUA_TTABLE && /* `t' is a table? */ + ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */ + luaT_gettm(L, tg, TM_GETTABLE) == NULL)) { /* or no TM? */ + /* do a primitive get */ + const TObject *h = luaH_get(L, hvalue(t), L->top-1); + /* result is no nil or there is no `index' tag method? */ + if (ttype(h) != LUA_TNIL || ((tm=luaT_gettm(L, tg, TM_INDEX)) == NULL)) + return h; /* return result */ + /* else call `index' tag method */ } - else { /* object is a table... */ - int tg = table->value.a->htag; - im = luaT_getim(tg, IM_GETTABLE); - if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */ - TObject *h = luaH_get(avalue(table), table+1); - if (ttype(h) == LUA_T_NIL && - (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL)) { - /* result is nil and there is an "index" tag method */ - luaD_callTM(im, 2, 1); /* calls it */ - } - else { - L->stack.top--; - *table = *h; /* "push" result into table position */ - } - return; - } - /* else it has a "gettable" method, go through to next command */ + else { /* try a `gettable' tag method */ + tm = luaT_gettmbyObj(L, t, TM_GETTABLE); + } + if (tm != NULL) { /* is there a tag method? */ + luaD_checkstack(L, 2); + *(L->top+1) = *(L->top-1); /* key */ + *L->top = *t; /* table */ + clvalue(L->top-1) = tm; /* tag method */ + ttype(L->top-1) = LUA_TFUNCTION; + L->top += 2; + luaD_call(L, L->top - 3, 1); + return L->top - 1; /* call result */ + } + else { /* no tag method */ + luaG_typeerror(L, t, "index"); + return NULL; /* to avoid warnings */ } - /* object is not a table, or it has a "gettable" method */ - luaD_callTM(im, 2, 1); } /* -** Receives table at *t, index at *(t+1) and value at top. +** Receives table at `t', key at `key' and value at top. */ -void luaV_settable (TObject *t) { - struct Stack *S = &L->stack; - TObject *im; - if (ttype(t) != LUA_T_ARRAY) { /* not a table, get "settable" method */ - im = luaT_getimbyObj(t, IM_SETTABLE); - if (ttype(im) == LUA_T_NIL) - lua_error("indexed expression not a table"); - } - else { /* object is a table... */ - im = luaT_getim(avalue(t)->htag, IM_SETTABLE); - if (ttype(im) == LUA_T_NIL) { /* and does not have a "settable" method */ - luaH_set(avalue(t), t+1, S->top-1); - S->top--; /* pop value */ - return; +void luaV_settable (lua_State *L, StkId t, StkId key) { + int tg; + if (ttype(t) == LUA_TTABLE && /* `t' is a table? */ + ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */ + luaT_gettm(L, tg, TM_SETTABLE) == NULL)) /* or no TM? */ + *luaH_set(L, hvalue(t), key) = *(L->top-1); /* do a primitive set */ + else { /* try a `settable' tag method */ + Closure *tm = luaT_gettmbyObj(L, t, TM_SETTABLE); + if (tm != NULL) { + luaD_checkstack(L, 3); + *(L->top+2) = *(L->top-1); + *(L->top+1) = *key; + *(L->top) = *t; + clvalue(L->top-1) = tm; + ttype(L->top-1) = LUA_TFUNCTION; + L->top += 3; + luaD_call(L, L->top - 4, 0); /* call `settable' tag method */ } - /* else it has a "settable" method, go through to next command */ + else /* no tag method... */ + luaG_typeerror(L, t, "index"); } - /* object is not a table, or it has a "settable" method */ - /* prepare arguments and call the tag method */ - *(S->top+1) = *(L->stack.top-1); - *(S->top) = *(t+1); - *(S->top-1) = *t; - S->top += 2; /* WARNING: caller must assure stack space */ - luaD_callTM(im, 3, 0); } -void luaV_rawsettable (TObject *t) { - if (ttype(t) != LUA_T_ARRAY) - lua_error("indexed expression not a table"); - else { - struct Stack *S = &L->stack; - luaH_set(avalue(t), t+1, S->top-1); - S->top -= 3; +const TObject *luaV_getglobal (lua_State *L, TString *s) { + const TObject *value = luaH_getstr(L->gt, s); + Closure *tm = luaT_gettmbyObj(L, value, TM_GETGLOBAL); + if (tm == NULL) /* is there a tag method? */ + return value; /* default behavior */ + else { /* tag method */ + luaD_checkstack(L, 3); + clvalue(L->top) = tm; + ttype(L->top) = LUA_TFUNCTION; + tsvalue(L->top+1) = s; /* global name */ + ttype(L->top+1) = LUA_TSTRING; + *(L->top+2) = *value; + L->top += 3; + luaD_call(L, L->top - 3, 1); + return L->top - 1; } } -void luaV_getglobal (TaggedString *ts) { - /* WARNING: caller must assure stack space */ - /* only userdata, tables and nil can have getglobal tag methods */ - static char valid_getglobals[] = {1, 0, 0, 1, 0, 0, 1, 0}; /* ORDER LUA_T */ - TObject *value = &ts->u.s.globalval; - if (valid_getglobals[-ttype(value)]) { - TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL); - if (ttype(im) != LUA_T_NIL) { /* is there a tag method? */ - struct Stack *S = &L->stack; - ttype(S->top) = LUA_T_STRING; - tsvalue(S->top) = ts; - S->top++; - *S->top++ = *value; - luaD_callTM(im, 2, 1); - return; +void luaV_setglobal (lua_State *L, TString *s) { + const TObject *oldvalue = luaH_getstr(L->gt, s); + Closure *tm = luaT_gettmbyObj(L, oldvalue, TM_SETGLOBAL); + if (tm == NULL) { /* is there a tag method? */ + if (oldvalue != &luaO_nilobject) { + /* cast to remove `const' is OK, because `oldvalue' != luaO_nilobject */ + *(TObject *)oldvalue = *(L->top - 1); + } + else { + TObject key; + ttype(&key) = LUA_TSTRING; + tsvalue(&key) = s; + *luaH_set(L, L->gt, &key) = *(L->top - 1); } - /* else no tag method: go through to default behavior */ } - *L->stack.top++ = *value; /* default behavior */ -} - - -void luaV_setglobal (TaggedString *ts) { - TObject *oldvalue = &ts->u.s.globalval; - TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL); - if (ttype(im) == LUA_T_NIL) /* is there a tag method? */ - luaS_rawsetglobal(ts, --L->stack.top); else { - /* WARNING: caller must assure stack space */ - struct Stack *S = &L->stack; - TObject newvalue; - newvalue = *(S->top-1); - ttype(S->top-1) = LUA_T_STRING; - tsvalue(S->top-1) = ts; - *S->top++ = *oldvalue; - *S->top++ = newvalue; - luaD_callTM(im, 3, 0); + luaD_checkstack(L, 3); + *(L->top+2) = *(L->top-1); /* new value */ + *(L->top+1) = *oldvalue; + ttype(L->top) = LUA_TSTRING; + tsvalue(L->top) = s; + clvalue(L->top-1) = tm; + ttype(L->top-1) = LUA_TFUNCTION; + L->top += 3; + luaD_call(L, L->top - 4, 0); } } -static void call_binTM (IMS event, char *msg) -{ - TObject *im = luaT_getimbyObj(L->stack.top-2, event);/* try first operand */ - if (ttype(im) == LUA_T_NIL) { - im = luaT_getimbyObj(L->stack.top-1, event); /* try second operand */ - if (ttype(im) == LUA_T_NIL) { - im = luaT_getim(0, event); /* try a 'global' i.m. */ - if (ttype(im) == LUA_T_NIL) - lua_error(msg); +static int call_binTM (lua_State *L, StkId top, TMS event) { + /* try first operand */ + Closure *tm = luaT_gettmbyObj(L, top-2, event); + L->top = top; + if (tm == NULL) { + tm = luaT_gettmbyObj(L, top-1, event); /* try second operand */ + if (tm == NULL) { + tm = luaT_gettm(L, 0, event); /* try a `global' method */ + if (tm == NULL) + return 0; /* error */ } } - lua_pushstring(luaT_eventname[event]); - luaD_callTM(im, 3, 1); + lua_pushstring(L, luaT_eventname[event]); + luaD_callTM(L, tm, 3, 1); + return 1; } -static void call_arith (IMS event) -{ - call_binTM(event, "unexpected type in arithmetic operation"); +static void call_arith (lua_State *L, StkId top, TMS event) { + if (!call_binTM(L, top, event)) + luaG_binerror(L, top-2, LUA_TNUMBER, "perform arithmetic on"); } -static int luaV_strcomp (char *l, long ll, char *r, long lr) -{ +static int luaV_strcomp (const TString *ls, const TString *rs) { + const char *l = ls->str; + size_t ll = ls->len; + const char *r = rs->str; + size_t lr = rs->len; for (;;) { - long temp = strcoll(l, r); + int temp = strcoll(l, r); if (temp != 0) return temp; - /* strings are equal up to a '\0' */ - temp = strlen(l); /* index of first '\0' in both strings */ - if (temp == ll) /* l is finished? */ - return (temp == lr) ? 0 : -1; /* l is equal or smaller than r */ - else if (temp == lr) /* r is finished? */ - return 1; /* l is greater than r (because l is not finished) */ - /* both strings longer than temp; go on comparing (after the '\0') */ - temp++; - l += temp; ll -= temp; r += temp; lr -= temp; + else { /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == ll) /* l is finished? */ + return (len == lr) ? 0 : -1; /* l is equal or smaller than r */ + else if (len == lr) /* r is finished? */ + return 1; /* l is greater than r (because l is not finished) */ + /* both strings longer than `len'; go on comparing (after the '\0') */ + len++; + l += len; ll -= len; r += len; lr -= len; + } } } -void luaV_comparison (lua_Type ttype_less, lua_Type ttype_equal, - lua_Type ttype_great, IMS op) { - struct Stack *S = &L->stack; - TObject *l = S->top-2; - TObject *r = S->top-1; - real result; - if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER) - result = nvalue(l)-nvalue(r); - else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING) - result = luaV_strcomp(svalue(l), tsvalue(l)->u.s.len, - svalue(r), tsvalue(r)->u.s.len); - else { - call_binTM(op, "unexpected type in comparison"); - return; + +int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top) { + if (ttype(l) == LUA_TNUMBER && ttype(r) == LUA_TNUMBER) + return (nvalue(l) < nvalue(r)); + else if (ttype(l) == LUA_TSTRING && ttype(r) == LUA_TSTRING) + return (luaV_strcomp(tsvalue(l), tsvalue(r)) < 0); + else { /* call TM */ + luaD_checkstack(L, 2); + *top++ = *l; + *top++ = *r; + if (!call_binTM(L, top, TM_LT)) + luaG_ordererror(L, top-2); + L->top--; + return (ttype(L->top) != LUA_TNIL); } - S->top--; - nvalue(S->top-1) = 1; - ttype(S->top-1) = (result < 0) ? ttype_less : - (result == 0) ? ttype_equal : ttype_great; } -void luaV_pack (StkId firstel, int nvararg, TObject *tab) { - TObject *firstelem = L->stack.stack+firstel; +void luaV_strconc (lua_State *L, int total, StkId top) { + do { + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (tostring(L, top-2) || tostring(L, top-1)) { + if (!call_binTM(L, top, TM_CONCAT)) + luaG_binerror(L, top-2, LUA_TSTRING, "concat"); + } + else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ + /* at least two string values; get as many as possible */ + lint32 tl = (lint32)tsvalue(top-1)->len + + (lint32)tsvalue(top-2)->len; + char *buffer; + int i; + while (n < total && !tostring(L, top-n-1)) { /* collect total length */ + tl += tsvalue(top-n-1)->len; + n++; + } + if (tl > MAX_SIZET) lua_error(L, "string size overflow"); + buffer = luaO_openspace(L, tl); + tl = 0; + for (i=n; i>0; i--) { /* concat all strings */ + size_t l = tsvalue(top-i)->len; + memcpy(buffer+tl, tsvalue(top-i)->str, l); + tl += l; + } + tsvalue(top-n) = luaS_newlstr(L, buffer, tl); + } + total -= n-1; /* got `n' strings to create 1 new */ + top -= n-1; + } while (total > 1); /* repeat until only 1 result left */ +} + + +static void luaV_pack (lua_State *L, StkId firstelem) { int i; - Hash *htab; - if (nvararg < 0) nvararg = 0; - htab = avalue(tab) = luaH_new(nvararg+1); /* +1 for field 'n' */ - ttype(tab) = LUA_T_ARRAY; - for (i=0; itop; i++) + *luaH_setint(L, htab, i+1) = *(firstelem+i); + /* store counter in field `n' */ + luaH_setstrnum(L, htab, luaS_new(L, "n"), i); + L->top = firstelem; /* remove elements from the stack */ + ttype(L->top) = LUA_TTABLE; + hvalue(L->top) = htab; + incr_top; } -static void adjust_varargs (StkId first_extra_arg) -{ - TObject arg; - luaV_pack(first_extra_arg, - (L->stack.top-L->stack.stack)-first_extra_arg, &arg); - luaD_adjusttop(first_extra_arg); - *L->stack.top++ = arg; +static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { + int nvararg = (L->top-base) - nfixargs; + if (nvararg < 0) + luaD_adjusttop(L, base, nfixargs); + luaV_pack(L, base+nfixargs); } +#define dojump(pc, i) { int d = GETARG_S(i); pc += d; } + /* -** Execute the given opcode, until a RET. Parameters are between -** [stack+base,top). Returns n such that the the results are between -** [stack+n,top). +** Executes the given Lua function. Parameters are between [base,top). +** Returns n such that the the results are between [n,top). */ -StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base) { - struct Stack *S = &L->stack; /* to optimize */ - register Byte *pc = tf->code; - TObject *consts = tf->consts; - if (L->callhook) - luaD_callHook(base, tf, 0); - luaD_checkstack((*pc++)+EXTRA_STACK); - if (*pc < ZEROVARARG) - luaD_adjusttop(base+*(pc++)); - else { /* varargs */ - luaC_checkGC(); - adjust_varargs(base+(*pc++)-ZEROVARARG); - } +StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { + const Proto *const tf = cl->f.l; + StkId top; /* keep top local, for performance */ + const Instruction *pc = tf->code; + TString **const kstr = tf->kstr; + const 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); + else + luaD_adjusttop(L, base, tf->numparams); + top = L->top; + /* main loop of interpreter */ for (;;) { - register int aux = 0; - switchentry: - switch ((OpCode)*pc++) { - - case ENDCODE: - S->top = S->stack + base; - goto ret; - - case RETCODE: - base += *pc++; - goto ret; - - case CALL: aux = *pc++; - luaD_calln(*pc++, aux); + const Instruction i = *pc++; + if (linehook) + traceexec(L, base, top, linehook); + switch (GET_OPCODE(i)) { + case OP_END: { + L->top = top; + return top; + } + case OP_RETURN: { + L->top = top; + return base+GETARG_U(i); + } + case OP_CALL: { + int nres = GETARG_B(i); + if (nres == MULT_RET) nres = LUA_MULTRET; + L->top = top; + luaD_call(L, base+GETARG_A(i), nres); + top = L->top; break; - - case TAILCALL: aux = *pc++; - luaD_calln(*pc++, MULT_RET); - base += aux; - goto ret; - - case PUSHNIL: aux = *pc++; + } + case OP_TAILCALL: { + L->top = top; + luaD_call(L, base+GETARG_A(i), LUA_MULTRET); + return base+GETARG_B(i); + } + case OP_PUSHNIL: { + int n = GETARG_U(i); + LUA_ASSERT(n>0, "invalid argument"); do { - ttype(S->top++) = LUA_T_NIL; - } while (aux--); + ttype(top++) = LUA_TNIL; + } while (--n > 0); break; - - case POP: aux = *pc++; - S->top -= aux; + } + case OP_POP: { + top -= GETARG_U(i); break; - - case PUSHNUMBERW: aux += highbyte(*pc++); - case PUSHNUMBER: aux += *pc++; - ttype(S->top) = LUA_T_NUMBER; - nvalue(S->top) = aux; - S->top++; + } + case OP_PUSHINT: { + ttype(top) = LUA_TNUMBER; + nvalue(top) = (Number)GETARG_S(i); + top++; break; - - case PUSHNUMBERNEGW: aux += highbyte(*pc++); - case PUSHNUMBERNEG: aux += *pc++; - ttype(S->top) = LUA_T_NUMBER; - nvalue(S->top) = -aux; - S->top++; + } + case OP_PUSHSTRING: { + ttype(top) = LUA_TSTRING; + tsvalue(top) = kstr[GETARG_U(i)]; + top++; break; - - case PUSHCONSTANTW: aux += highbyte(*pc++); - case PUSHCONSTANT: aux += *pc++; - *S->top++ = consts[aux]; + } + case OP_PUSHNUM: { + ttype(top) = LUA_TNUMBER; + nvalue(top) = tf->knum[GETARG_U(i)]; + top++; break; - - case PUSHUPVALUE: aux = *pc++; - *S->top++ = cl->consts[aux+1]; + } + case OP_PUSHNEGNUM: { + ttype(top) = LUA_TNUMBER; + nvalue(top) = -tf->knum[GETARG_U(i)]; + top++; break; - - case PUSHLOCAL: aux = *pc++; - *S->top++ = *((S->stack+base) + aux); + } + case OP_PUSHUPVALUE: { + *top++ = cl->upvalue[GETARG_U(i)]; break; - - case GETGLOBALW: aux += highbyte(*pc++); - case GETGLOBAL: aux += *pc++; - luaV_getglobal(tsvalue(&consts[aux])); + } + case OP_GETLOCAL: { + *top++ = *(base+GETARG_U(i)); break; - - case GETTABLE: - luaV_gettable(); + } + case OP_GETGLOBAL: { + L->top = top; + *top = *luaV_getglobal(L, kstr[GETARG_U(i)]); + top++; break; - - case GETDOTTEDW: aux += highbyte(*pc++); - case GETDOTTED: aux += *pc++; - *S->top++ = consts[aux]; - luaV_gettable(); + } + case OP_GETTABLE: { + L->top = top; + top--; + *(top-1) = *luaV_gettable(L, top-1); break; - - case PUSHSELFW: aux += highbyte(*pc++); - case PUSHSELF: aux += *pc++; { - TObject receiver; - receiver = *(S->top-1); - *S->top++ = consts[aux]; - luaV_gettable(); - *S->top++ = receiver; + } + case OP_GETDOTTED: { + ttype(top) = LUA_TSTRING; + tsvalue(top) = kstr[GETARG_U(i)]; + L->top = top+1; + *(top-1) = *luaV_gettable(L, top-1); break; } - - case CREATEARRAYW: aux += highbyte(*pc++); - case CREATEARRAY: aux += *pc++; - luaC_checkGC(); - avalue(S->top) = luaH_new(aux); - ttype(S->top) = LUA_T_ARRAY; - S->top++; + case OP_GETINDEXED: { + *top = *(base+GETARG_U(i)); + L->top = top+1; + *(top-1) = *luaV_gettable(L, top-1); break; - - case SETLOCAL: aux = *pc++; - *((S->stack+base) + aux) = *(--S->top); + } + case OP_PUSHSELF: { + TObject receiver; + receiver = *(top-1); + ttype(top) = LUA_TSTRING; + tsvalue(top++) = kstr[GETARG_U(i)]; + L->top = top; + *(top-2) = *luaV_gettable(L, top-2); + *(top-1) = receiver; break; - - case SETGLOBALW: aux += highbyte(*pc++); - case SETGLOBAL: aux += *pc++; - luaV_setglobal(tsvalue(&consts[aux])); + } + case OP_CREATETABLE: { + L->top = top; + luaC_checkGC(L); + hvalue(top) = luaH_new(L, GETARG_U(i)); + ttype(top) = LUA_TTABLE; + top++; break; - - case SETTABLEPOP: - luaV_settable(S->top-3); - S->top -= 2; /* pop table and index */ + } + case OP_SETLOCAL: { + *(base+GETARG_U(i)) = *(--top); break; - - case SETTABLE: - luaV_settable(S->top-3-(*pc++)); + } + case OP_SETGLOBAL: { + L->top = top; + luaV_setglobal(L, kstr[GETARG_U(i)]); + top--; break; - - case SETLISTW: aux += highbyte(*pc++); - case SETLIST: aux += *pc++; { - int n = *(pc++); - Hash *arr = avalue(S->top-n-1); - aux *= LFIELDS_PER_FLUSH; + } + case OP_SETTABLE: { + StkId t = top-GETARG_A(i); + L->top = top; + luaV_settable(L, t, t+1); + top -= GETARG_B(i); /* pop values */ + break; + } + case OP_SETLIST: { + int aux = GETARG_A(i) * LFIELDS_PER_FLUSH; + int n = GETARG_B(i); + Hash *arr = hvalue(top-n-1); + L->top = top-n; /* final value of `top' (in case of errors) */ for (; n; n--) - luaH_setint(arr, n+aux, --S->top); + *luaH_setint(L, arr, n+aux) = *(--top); break; } - - case SETMAP: aux = *pc++; { - Hash *arr = avalue(S->top-(2*aux)-3); - do { - luaH_set(arr, S->top-2, S->top-1); - S->top-=2; - } while (aux--); + case OP_SETMAP: { + int n = GETARG_U(i); + StkId finaltop = top-2*n; + Hash *arr = hvalue(finaltop-1); + L->top = finaltop; /* final value of `top' (in case of errors) */ + for (; n; n--) { + top-=2; + *luaH_set(L, arr, top) = *(top+1); + } break; } - - case NEQOP: aux = 1; - case EQOP: { - int res = luaO_equalObj(S->top-2, S->top-1); - if (aux) res = !res; - S->top--; - ttype(S->top-1) = res ? LUA_T_NUMBER : LUA_T_NIL; - nvalue(S->top-1) = 1; + case OP_ADD: { + if (tonumber(top-2) || tonumber(top-1)) + call_arith(L, top, TM_ADD); + else + nvalue(top-2) += nvalue(top-1); + top--; break; } - - case LTOP: - luaV_comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); - break; - - case LEOP: - luaV_comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); + case OP_ADDI: { + if (tonumber(top-1)) { + ttype(top) = LUA_TNUMBER; + nvalue(top) = (Number)GETARG_S(i); + call_arith(L, top+1, TM_ADD); + } + else + nvalue(top-1) += (Number)GETARG_S(i); break; - - case GTOP: - luaV_comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); + } + case OP_SUB: { + if (tonumber(top-2) || tonumber(top-1)) + call_arith(L, top, TM_SUB); + else + nvalue(top-2) -= nvalue(top-1); + top--; break; - - case GEOP: - luaV_comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); + } + case OP_MULT: { + if (tonumber(top-2) || tonumber(top-1)) + call_arith(L, top, TM_MUL); + else + nvalue(top-2) *= nvalue(top-1); + top--; break; - - case ADDOP: { - TObject *l = S->top-2; - TObject *r = S->top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_ADD); - else { - nvalue(l) += nvalue(r); - --S->top; - } + } + case OP_DIV: { + if (tonumber(top-2) || tonumber(top-1)) + call_arith(L, top, TM_DIV); + else + nvalue(top-2) /= nvalue(top-1); + top--; break; } - - case SUBOP: { - TObject *l = S->top-2; - TObject *r = S->top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_SUB); - else { - nvalue(l) -= nvalue(r); - --S->top; - } + case OP_POW: { + if (!call_binTM(L, top, TM_POW)) + lua_error(L, "undefined operation"); + top--; break; } - - case MULTOP: { - TObject *l = S->top-2; - TObject *r = S->top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_MUL); - else { - nvalue(l) *= nvalue(r); - --S->top; - } + case OP_CONCAT: { + int n = GETARG_U(i); + luaV_strconc(L, n, top); + top -= n-1; + L->top = top; + luaC_checkGC(L); break; } - - case DIVOP: { - TObject *l = S->top-2; - TObject *r = S->top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_DIV); - else { - nvalue(l) /= nvalue(r); - --S->top; + case OP_MINUS: { + if (tonumber(top-1)) { + ttype(top) = LUA_TNIL; + call_arith(L, top+1, TM_UNM); } + else + nvalue(top-1) = -nvalue(top-1); break; } - - case POWOP: - call_binTM(IM_POW, "undefined operation"); + case OP_NOT: { + ttype(top-1) = + (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL; + nvalue(top-1) = 1; break; - - case CONCOP: { - TObject *l = S->top-2; - TObject *r = S->top-1; - if (tostring(l) || tostring(r)) - call_binTM(IM_CONCAT, "unexpected type for concatenation"); - else { - tsvalue(l) = strconc(tsvalue(l), tsvalue(r)); - --S->top; - } - luaC_checkGC(); + } + case OP_JMPNE: { + top -= 2; + if (!luaO_equalObj(top, top+1)) dojump(pc, i); break; } - - case MINUSOP: - if (tonumber(S->top-1)) { - ttype(S->top) = LUA_T_NIL; - S->top++; - call_arith(IM_UNM); - } - else - nvalue(S->top-1) = - nvalue(S->top-1); + case OP_JMPEQ: { + top -= 2; + if (luaO_equalObj(top, top+1)) dojump(pc, i); break; - - case NOTOP: - ttype(S->top-1) = - (ttype(S->top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL; - nvalue(S->top-1) = 1; + } + case OP_JMPLT: { + top -= 2; + if (luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i); break; - - case ONTJMPW: aux += highbyte(*pc++); - case ONTJMP: aux += *pc++; - if (ttype(S->top-1) != LUA_T_NIL) pc += aux; - else S->top--; + } + case OP_JMPLE: { /* a <= b === !(btop-1) == LUA_T_NIL) pc += aux; - else S->top--; + } + case OP_JMPGT: { /* a > b === (b= b === !(atop) == LUA_T_NIL) pc += aux; + } + case OP_JMPT: { + if (ttype(--top) != LUA_TNIL) dojump(pc, i); break; - - case IFTUPJMPW: aux += highbyte(*pc++); - case IFTUPJMP: aux += *pc++; - if (ttype(--S->top) != LUA_T_NIL) pc -= aux; + } + case OP_JMPF: { + if (ttype(--top) == LUA_TNIL) dojump(pc, i); break; - - case IFFUPJMPW: aux += highbyte(*pc++); - case IFFUPJMP: aux += *pc++; - if (ttype(--S->top) == LUA_T_NIL) pc -= aux; + } + case OP_JMPONT: { + if (ttype(top-1) == LUA_TNIL) top--; + else dojump(pc, i); break; - - case CLOSUREW: aux += highbyte(*pc++); - case CLOSURE: aux += *pc++; - *S->top++ = consts[aux]; - luaV_closure(*pc++); - luaC_checkGC(); + } + case OP_JMPONF: { + if (ttype(top-1) != LUA_TNIL) top--; + else dojump(pc, i); break; - - case SETLINEW: aux += highbyte(*pc++); - case SETLINE: aux += *pc++; - if ((S->stack+base-1)->ttype != LUA_T_LINE) { - /* open space for LINE value */ - luaD_openstack((S->top-S->stack)-base); - base++; - (S->stack+base-1)->ttype = LUA_T_LINE; + } + case OP_JMP: { + dojump(pc, i); + break; + } + case OP_PUSHNILJMP: { + ttype(top++) = LUA_TNIL; + pc++; + break; + } + case OP_FORPREP: { + if (tonumber(top-1)) + lua_error(L, "`for' step must be a number"); + if (tonumber(top-2)) + lua_error(L, "`for' limit must be a number"); + if (tonumber(top-3)) + lua_error(L, "`for' initial value must be a number"); + if (nvalue(top-1) > 0 ? + nvalue(top-3) > nvalue(top-2) : + nvalue(top-3) < nvalue(top-2)) { /* `empty' loop? */ + top -= 3; /* remove control variables */ + dojump(pc, i); /* jump to loop end */ } - (S->stack+base-1)->value.i = aux; - if (L->linehook) - luaD_lineHook(aux); break; - - case LONGARGW: aux += highbyte(*pc++); - case LONGARG: aux += *pc++; - aux = highbyte(highbyte(aux)); - goto switchentry; /* do not reset "aux" */ - - case CHECKSTACK: aux = *pc++; - LUA_ASSERT((S->top-S->stack)-base == aux && S->last >= S->top, - "wrong stack size"); + } + case OP_FORLOOP: { + LUA_ASSERT(ttype(top-1) == LUA_TNUMBER, "invalid step"); + LUA_ASSERT(ttype(top-2) == LUA_TNUMBER, "invalid limit"); + if (ttype(top-3) != LUA_TNUMBER) + lua_error(L, "`for' index must be a number"); + nvalue(top-3) += nvalue(top-1); /* increment index */ + if (nvalue(top-1) > 0 ? + nvalue(top-3) > nvalue(top-2) : + nvalue(top-3) < nvalue(top-2)) + top -= 3; /* end loop: remove control variables */ + else + dojump(pc, i); /* repeat loop */ break; - + } + case OP_LFORPREP: { + Node *node; + if (ttype(top-1) != LUA_TTABLE) + lua_error(L, "`for' table must be a table"); + node = luaH_next(L, hvalue(top-1), &luaO_nilobject); + if (node == NULL) { /* `empty' loop? */ + top--; /* remove table */ + dojump(pc, i); /* jump to loop end */ + } + else { + top += 2; /* index,value */ + *(top-2) = *key(node); + *(top-1) = *val(node); + } + break; + } + case OP_LFORLOOP: { + Node *node; + LUA_ASSERT(ttype(top-3) == LUA_TTABLE, "invalid table"); + node = luaH_next(L, hvalue(top-3), top-2); + if (node == NULL) /* end loop? */ + top -= 3; /* remove table, key, and value */ + else { + *(top-2) = *key(node); + *(top-1) = *val(node); + dojump(pc, i); /* repeat loop */ + } + break; + } + case OP_CLOSURE: { + L->top = top; + luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i)); + top = L->top; + luaC_checkGC(L); + break; + } } - } ret: - if (L->callhook) - luaD_callHook(0, NULL, 1); - return base; + } } - diff --git a/src/lvm.h b/src/lvm.h index d6a639e2c9..ace07c82e1 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 1.8 1999/02/08 17:07:59 roberto Exp $ +** $Id: lvm.h,v 1.27 2000/10/05 12:14:08 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -13,22 +13,20 @@ #include "ltm.h" -#define tonumber(o) ((ttype(o) != LUA_T_NUMBER) && (luaV_tonumber(o) != 0)) -#define tostring(o) ((ttype(o) != LUA_T_STRING) && (luaV_tostring(o) != 0)) +#define tonumber(o) ((ttype(o) != LUA_TNUMBER) && (luaV_tonumber(o) != 0)) +#define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0)) -void luaV_pack (StkId firstel, int nvararg, TObject *tab); int luaV_tonumber (TObject *obj); -int luaV_tostring (TObject *obj); -void luaV_setn (Hash *t, int val); -void luaV_gettable (void); -void luaV_settable (TObject *t); -void luaV_rawsettable (TObject *t); -void luaV_getglobal (TaggedString *ts); -void luaV_setglobal (TaggedString *ts); -StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base); -void luaV_closure (int nelems); -void luaV_comparison (lua_Type ttype_less, lua_Type ttype_equal, - lua_Type ttype_great, IMS op); +int luaV_tostring (lua_State *L, TObject *obj); +const TObject *luaV_gettable (lua_State *L, StkId t); +void luaV_settable (lua_State *L, StkId t, StkId key); +const TObject *luaV_getglobal (lua_State *L, TString *s); +void luaV_setglobal (lua_State *L, TString *s); +StkId luaV_execute (lua_State *L, const Closure *cl, StkId base); +void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems); +void luaV_Lclosure (lua_State *L, Proto *l, int nelems); +int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top); +void luaV_strconc (lua_State *L, int total, StkId top); #endif diff --git a/src/lzio.c b/src/lzio.c index 865d9c5eb6..c958fe4642 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.7 1999/03/05 13:15:50 roberto Exp $ +** $Id: lzio.c,v 1.13 2000/06/12 13:52:05 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -9,6 +9,8 @@ #include #include +#include "lua.h" + #include "lzio.h" @@ -16,62 +18,60 @@ /* ----------------------------------------------------- memory buffers --- */ static int zmfilbuf (ZIO* z) { - return EOZ; + (void)z; /* to avoid warnings */ + return EOZ; } -ZIO* zmopen (ZIO* z, char* b, int size, char *name) -{ - if (b==NULL) return NULL; - z->n=size; - z->p= (unsigned char *)b; - z->filbuf=zmfilbuf; - z->u=NULL; - z->name=name; - return z; +ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name) { + if (b==NULL) return NULL; + z->n = size; + z->p = (const unsigned char *)b; + z->filbuf = zmfilbuf; + z->u = NULL; + z->name = name; + return z; } /* ------------------------------------------------------------ strings --- */ -ZIO* zsopen (ZIO* z, char* s, char *name) -{ - if (s==NULL) return NULL; - return zmopen(z,s,strlen(s),name); +ZIO* zsopen (ZIO* z, const char* s, const char *name) { + if (s==NULL) return NULL; + return zmopen(z, s, strlen(s), name); } /* -------------------------------------------------------------- FILEs --- */ static int zffilbuf (ZIO* z) { - int n; - if (feof((FILE *)z->u)) return EOZ; - n=fread(z->buffer,1,ZBSIZE,z->u); - if (n==0) return EOZ; - z->n=n-1; - z->p=z->buffer; - return *(z->p++); + size_t n; + if (feof((FILE *)z->u)) return EOZ; + n = fread(z->buffer, 1, ZBSIZE, (FILE *)z->u); + if (n==0) return EOZ; + z->n = n-1; + z->p = z->buffer; + return *(z->p++); } -ZIO* zFopen (ZIO* z, FILE* f, char *name) -{ - if (f==NULL) return NULL; - z->n=0; - z->p=z->buffer; - z->filbuf=zffilbuf; - z->u=f; - z->name=name; - return z; +ZIO* zFopen (ZIO* z, FILE* f, const char *name) { + if (f==NULL) return NULL; + z->n = 0; + z->p = z->buffer; + z->filbuf = zffilbuf; + z->u = f; + z->name = name; + return z; } /* --------------------------------------------------------------- read --- */ -int zread (ZIO *z, void *b, int n) { +size_t zread (ZIO *z, void *b, size_t n) { while (n) { - int m; + size_t m; if (z->n == 0) { if (z->filbuf(z) == EOZ) return n; /* return number of missing bytes */ - zungetc(z); /* put result from 'filbuf' in the buffer */ + zungetc(z); /* put result from `filbuf' in the buffer */ } m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); diff --git a/src/lzio.h b/src/lzio.h index d7edd26317..5f4b43de04 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.4 1998/01/09 14:57:43 roberto Exp $ +** $Id: lzio.h,v 1.7 2000/10/20 16:36:32 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -22,28 +22,31 @@ typedef struct zio ZIO; -ZIO* zFopen (ZIO* z, FILE* f, char *name); /* open FILEs */ -ZIO* zsopen (ZIO* z, char* s, char *name); /* string */ -ZIO* zmopen (ZIO* z, char* b, int size, char *name); /* memory */ +ZIO* zFopen (ZIO* z, FILE* f, const char *name); /* open FILEs */ +ZIO* zsopen (ZIO* z, const char* s, const char *name); /* string */ +ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name); /* memory */ -int zread (ZIO* z, void* b, int n); /* read next n bytes */ +size_t zread (ZIO* z, void* b, size_t n); /* read next n bytes */ -#define zgetc(z) (--(z)->n>=0 ? ((int)*(z)->p++): (z)->filbuf(z)) +#define zgetc(z) (((z)->n--)>0 ? ((int)*(z)->p++): (z)->filbuf(z)) #define zungetc(z) (++(z)->n,--(z)->p) #define zname(z) ((z)->name) + /* --------- Private Part ------------------ */ +#ifndef ZBSIZE #define ZBSIZE 256 /* buffer size */ +#endif struct zio { - int n; /* bytes still unread */ - unsigned char* p; /* current position in buffer */ - int (*filbuf)(ZIO* z); - void* u; /* additional data */ - char *name; - unsigned char buffer[ZBSIZE]; /* buffer */ + size_t n; /* bytes still unread */ + const unsigned char* p; /* current position in buffer */ + int (*filbuf)(ZIO* z); + void* u; /* additional data */ + const char *name; + unsigned char buffer[ZBSIZE]; /* buffer */ }; diff --git a/test/array.lua b/test/array.lua deleted file mode 100644 index 728a0b279f..0000000000 --- a/test/array.lua +++ /dev/null @@ -1,13 +0,0 @@ -a = {} - -local i=0 -while i<10 do - a[i] = i*i - i=i+1 -end - -local r,v = next(a,nil) -while r ~= nil do - write ("array[",r,"] = ",v,"\n") - r,v = next(a,r) -end diff --git a/test/bisect.lua b/test/bisect.lua index 4de9e99b8d..9e1d8f707f 100644 --- a/test/bisect.lua +++ b/test/bisect.lua @@ -18,9 +18,12 @@ function solve(f,a,b) write(format("after %d steps, root is %.10g, f=%g\n",n,z,f(z))) end +-- an example + -- our function function f(x) return x*x*x-x-1 end +-- find zero in [1,2] solve(f,1,2) diff --git a/test/cf-for.lua b/test/cf-for.lua new file mode 100644 index 0000000000..1bd0ab27fc --- /dev/null +++ b/test/cf-for.lua @@ -0,0 +1,19 @@ +-- temperature conversion table +-- now using the new "for" statement + +-- celsius to farenheit + +for c0=-20,50-1,10 do + write("C ") + for c=c0,c0+10-1 do + write(format("%3.0f ",c)) + end + write("\n") + + write("F ") + for c=c0,c0+10-1 do + f=(9/5)*c+32 + write(format("%3.0f ",f)) + end + write("\n\n") +end diff --git a/test/examples/ps/hilbert.lua b/test/examples/ps/hilbert.lua index b1042b572f..dbcec96381 100644 --- a/test/examples/ps/hilbert.lua +++ b/test/examples/ps/hilbert.lua @@ -3,8 +3,6 @@ -- Luiz Henrique de Figueiredo (lhf@csg.uwaterloo.ca) -- 10 Nov 95 -$debug - dofile("ps.lua") function p() diff --git a/test/examples/www/staff.lua b/test/examples/www/staff.lua index 7fa5b810c8..f36df4ad62 100644 --- a/test/examples/www/staff.lua +++ b/test/examples/www/staff.lua @@ -1,7 +1,5 @@ -$debug - readfrom("template.html") -TEMPLATE=read(".*") +TEMPLATE=read("*a") readfrom() PAT="|(%a%a*)|" @@ -17,10 +15,8 @@ function get(i) end function global(t) - local i,v=next(t,nil) - while i do + for i,v in t do GLOBAL[i]=v - i,v=next(t,i) end end diff --git a/test/fib.lua b/test/fib.lua index 881cbdc3ca..d946946a44 100644 --- a/test/fib.lua +++ b/test/fib.lua @@ -1,6 +1,7 @@ -- very inefficient fibonacci function function fib(n) + N=N+1 if n<2 then return n else @@ -8,4 +9,31 @@ function fib(n) end end -print(fib(20)) +-- a much faster cached version + +function cache(f) + local c={} + return function (x) + local y=%c[x] + if not y then + y=%f(x) + %c[x]=y + end + return y + end +end + +function test(s) + N=0 + local c=clock() + local v=fib(n) + local t=clock()-c + print(s,n,v,t,N) +end + +n=n or 24 -- for other values, do lua -e n=XX fib.lua +n=tonumber(n) +print("","n","value","time","evals") +test("plain") +fib=cache(fib) +test("cached") diff --git a/test/globals.lua b/test/globals.lua index 03b977c3be..baa7504934 100644 --- a/test/globals.lua +++ b/test/globals.lua @@ -1,20 +1,19 @@ --- globals.lua -- reads the output of luac -d -l -p and reports global variable usage --- typical usage: luac -p -l -d file.lua | lua globals.lua | sort +-- lines where a global is written to are marked with "*" +-- typical usage: luac -p -l file.lua | lua globals.lua | sort local P="^.*; " -- pattern to extract comments -local l="" -- last line seen while 1 do local s=read() if s==nil then return end - if strfind(s,"%sSETLINE") then - l=gsub(s,P,"") - elseif strfind(s,"%sGETGLOBAL") then + if strfind(s,"%sGETGLOBAL") then local g=gsub(s,P,"") + local _,_,l=strfind(s,"(%d+)") write(g,"\t",l,"\n") elseif strfind(s,"%sSETGLOBAL") then local g=gsub(s,P,"") - write(g,"*\t",l,"\n") + local _,_,l=strfind(s,"(%d+)") + write(g,"\t",l,"*\n") end end diff --git a/test/life.lua b/test/life.lua new file mode 100644 index 0000000000..7c817a044a --- /dev/null +++ b/test/life.lua @@ -0,0 +1,121 @@ +-- life.lua +-- original by Dave Bollinger posted to lua-l +-- modified to use ANSI terminal escape sequences + +ALIVE="O" +DEAD="-" + +function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary + local i=10000 + while i>0 do i=i-1 end + -- local i=clock()+1 while(clock()0 do + t[h] = {} + local x=w + while x>0 do + t[h][x]=0 + x=x-1 + end + h=h-1 + end + return t +end + +_CELLS = {} + +-- give birth to a "shape" within the cell array +function _CELLS:spawn(shape,left,top) + local y=0 + while y 0 do + local xm1,x,xp1,xi=self.w-1,self.w,1,self.w + while xi > 0 do + local sum = self[ym1][xm1] + self[ym1][x] + self[ym1][xp1] + + self[y][xm1] + self[y][xp1] + + self[yp1][xm1] + self[yp1][x] + self[yp1][xp1] + next[y][x] = ((sum==2) and self[y][x]) or ((sum==3) and 1) or 0 + xm1,x,xp1,xi = x,xp1,xp1+1,xi-1 + end + ym1,y,yp1,yi = y,yp1,yp1+1,yi-1 + end +end + +-- output the array to screen +function _CELLS:draw() + local out="" -- accumulate to reduce flicker + local y=1 + while y <= self.h do + local x=1 + while x <= self.w do + out=out..(((self[y][x]>0) and ALIVE) or DEAD) + x=x+1 + end + out=out.."\n" + y=y+1 + end + write(out) +end + +-- constructor +function CELLS(w,h) + local c = ARRAY2D(w,h) + c.spawn = _CELLS.spawn + c.evolve = _CELLS.evolve + c.draw = _CELLS.draw + return c +end + +-- +-- shapes suitable for use with spawn() above +-- +HEART = { 1,0,1,1,0,1,1,1,1; w=3,h=3 } +GLIDER = { 0,0,1,1,0,1,0,1,1; w=3,h=3 } +EXPLODE = { 0,1,0,1,1,1,1,0,1,0,1,0; w=3,h=4 } +FISH = { 0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0; w=5,h=4 } +BUTTERFLY = { 1,0,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1; w=5,h=5 } + +-- the main routine +function LIFE(w,h) + -- create two arrays + local thisgen = CELLS(w,h) + local nextgen = CELLS(w,h) + + -- create some life + -- about 1000 generations of fun, then a glider steady-state + thisgen:spawn(GLIDER,5,4) + thisgen:spawn(EXPLODE,25,10) + thisgen:spawn(FISH,4,12) + + -- run until break + local gen=1 + write("\027[2J") -- ANSI clear screen + while 1 do + thisgen:evolve(nextgen) + thisgen,nextgen = nextgen,thisgen + write("\027[H") -- ANSI home cursor + thisgen:draw() + write("Generation: "..gen.."\n") + gen=gen+1 + --delay() -- no delay + end +end + +LIFE(40,20) diff --git a/test/lisp.lua b/test/lisp.lua new file mode 100644 index 0000000000..e6bcd08424 --- /dev/null +++ b/test/lisp.lua @@ -0,0 +1,22 @@ +-- a simple LISP evaluator + +function eval(x) + if type(x)=="table" then + return eval(x[1])(eval(x[2]),eval(x[3])) + else + return x + end +end + +function add(x,y) return x+y end +function sub(x,y) return x-y end +function mul(x,y) return x*y end +function div(x,y) return x/y end +function pow(x,y) return x^y end + +-- an example + +function E(x) print(eval(x)) end + +E{add,1,{mul,2,3}} +E{sin,60} diff --git a/test/old.lua b/test/old.lua new file mode 100644 index 0000000000..ebb4e70b1f --- /dev/null +++ b/test/old.lua @@ -0,0 +1,42 @@ +-- implementation of old functions + +function foreach(t,f) + for i,v in t do + local r=f(i,v) + if r then return r end + end +end + +function foreachi(t,f) + for i=1,getn(t) do + local r=f(i,t[i]) + if r then return r end + end +end + +function foreachvar(f) + return foreach(globals(),f) +end + +function nextvar(n) + return next(globals(),n) +end + +function rawgetglobal(n) + return rawget(globals(),n) +end + +function rawsetglobal(n,v) + return rawset(globals(),n,v) +end + +rawsettable=rawset +rawgettable=rawget + +function getglobal(n) + return globals()[n] +end + +function setglobal(n,v) + globals()[n]=v +end diff --git a/test/qp.lua b/test/qp.lua new file mode 100644 index 0000000000..eb6b3205ba --- /dev/null +++ b/test/qp.lua @@ -0,0 +1,6 @@ +-- decode quoted-printable text + +T=read"*a" +T=gsub(T,"=\n","") +T=gsub(T,"=(%x%x)",function (x) return strchar(tonumber(x,16)) end) +write(T) diff --git a/test/save.lua b/test/save.lua index ce2e5b345c..855e4c192b 100644 --- a/test/save.lua +++ b/test/save.lua @@ -12,9 +12,7 @@ function savevar (n,v) else write("{}\n") v.__visited__ = n - local r,f - r,f = next(v,nil) - while r ~= nil do + for r,f in v do if r ~= "__visited__" then if type(r) == 'string' then savevar(n.."."..r,f) @@ -22,7 +20,6 @@ function savevar (n,v) savevar(n.."["..r.."]",f) end end - r,f = next(v,r) end end else write(tostring(v)) end @@ -31,14 +28,10 @@ end function save () write("\n-- global environment\n") - local n,v = nextvar(nil) - while n ~= nil do - savevar(n,v) - n,v = nextvar(n) - end + foreach(globals(),savevar) end --- ow some examples +-- an example a = 3 x = {a = 4, b = "name", l={4,5,67}} diff --git a/test/sort.lua b/test/sort.lua index 41473f4ace..1d50ad4721 100644 --- a/test/sort.lua +++ b/test/sort.lua @@ -1,3 +1,6 @@ +-- two implementations of a sort function +-- this is an example only. Lua has now a built-in function "sort" + -- extracted from Programming Pearls, page 110 function qsort(x,l,u,f) if l>> ") +--foreach(t,print) + if t.what=="main" then + if func=="call" then + write("begin ",t.source) + else + write("end ",t.source) + end + elseif t.what=="Lua" then + write(func," ",t.name," <",t.linedefined,":",t.source,">") + else + write(func," ",t.name," [",t.what,"] ") + end + if t.currentline>=0 then write(":",t.currentline) end + write("\n") +end + +setcallhook(callhook) diff --git a/test/trace-globals.lua b/test/trace-globals.lua new file mode 100644 index 0000000000..566e1106b7 --- /dev/null +++ b/test/trace-globals.lua @@ -0,0 +1,75 @@ +-- shows how to trace assigments to global variables + +-- a tostring that quotes strings. note the use of the original tostring. +local tostring=function(a) + if tag(a)==tag("") then + return format("%q",a) + else + return %tostring(a) + end +end + +local T=newtag() + +local Tlog=function (name,old,new) + local t=getinfo(3,"Sl") + local line=t.currentline + write(t.source) + if line>=0 then write(":",line) end + write(" -- ",name," is now ",%tostring(new)," (was ",%tostring(old),")","\n") +end + +local Tgetnew=function (name) + local t=settag({},%T) + rawset(globals(),name,t) + return nil +end + +local Tsetnew=function (name,old,new) + %Tlog(name,old,new) + local t=settag({value=new},%T) + rawset(globals(),name,t) + return t +end + +local Tsetglobal=function (name,old,new) + %Tlog(name,old.value,new) + old.value=new +end + +local Tgetglobal=function (x,value) + return value.value +end + +settagmethod(T,"getglobal",Tgetglobal) +settagmethod(T,"setglobal",Tsetglobal) + +-- to trace only selected variables, use the following function +-- and comment the next two calls to settagmethod + +function trace(name) + local t=settag({value=rawget(globals(),name)},%T) + rawset(globals(),name,t) +end + +settagmethod(tag(nil),"getglobal",Tgetnew) +settagmethod(tag(nil),"setglobal",Tsetnew) + +-- an example + +trace"a" +print(a) +a=1 +b=2 +c=3 +a=10 +b=20 +c=30 +trace"b" +b="lua" +c={} +a=print +c=nil +c=100 + +print(a,b,c,d) diff --git a/test/trace.lua b/test/trace.lua deleted file mode 100644 index 5f32a8f9bb..0000000000 --- a/test/trace.lua +++ /dev/null @@ -1,33 +0,0 @@ --- shows how to trace assigments to global variables - -T=newtag() -- tag for tracing - -function Ttrace(name) -- trace a global variable - local t={} - settag(t,T) - rawsetglobal(name,t) -end - -function Tsetglobal(name,old,new) - write("tracing: ",name," now is ",new,"\n") - old.value=new -end - -function Tgetglobal(x,value) -- get the actual value - return value.value -end - -settagmethod(T,"getglobal",Tgetglobal) -settagmethod(T,"setglobal",Tsetglobal) - --- now show it working - -Ttrace("a") -Ttrace("c") - -a=1 -b=2 -c=3 -a=10 -b=20 -c=30 diff --git a/test/undefined.lua b/test/undefined.lua new file mode 100644 index 0000000000..bbecffe33f --- /dev/null +++ b/test/undefined.lua @@ -0,0 +1,20 @@ +-- catch "undefined" global variables. see FAQ. + +do + local f=function(name) + local v=rawget(globals(),name) + if v then + return v + else + error("undefined global variable `"..name.."'") + end + end + + settagmethod(tag(nil),"getglobal",f) +end + +-- an example + +a=1 +c=3 +print(a,b,c) -- 'b' is undefined diff --git a/test/webform.lua b/test/webform.lua new file mode 100644 index 0000000000..3e4c3ce46b --- /dev/null +++ b/test/webform.lua @@ -0,0 +1,8 @@ +-- convert POST data to Lua table + +T=read"*a" -- for GET, use T=getenv"QUERY_STRING" +T=gsub(T,"=","=[[") +T=gsub(T,"&","]],\n") +T=gsub(T,"+"," ") +T=gsub(T,"%%(%x%x)",function (x) return strchar(tonumber(x,16)) end) +write("form{\n",T,"]]}\n") From 1981b7c90eb09e956e969cda5c473be4560af573 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Thu, 4 Jul 2002 12:00:00 +0000 Subject: [PATCH 13/97] Lua 4.0.1 --- DIFFS | 97 ++++++++++++++++++++++++++++++++++++++++++++++ UPDATE | 19 +++++++++ include/lua.h | 4 +- src/lapi.c | 4 +- src/ldo.c | 11 ++++-- src/lgc.c | 4 +- src/lgc.h | 3 +- src/lib/lbaselib.c | 8 ++-- src/lparser.c | 4 +- src/lstring.c | 4 +- src/lvm.c | 4 +- 11 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 DIFFS create mode 100644 UPDATE diff --git a/DIFFS b/DIFFS new file mode 100644 index 0000000000..b7c8638869 --- /dev/null +++ b/DIFFS @@ -0,0 +1,97 @@ +diff -r lua-4.0/include/lua.h lua/include/lua.h +2c2 +< ** $Id: lua.h,v 1.79 2000/10/31 12:44:07 roberto Exp $ +--- +> ** $Id: lua.h,v 1.79a 2000/10/31 12:44:07 roberto Exp $ +25c25 +< #define LUA_VERSION "Lua 4.0" +--- +> #define LUA_VERSION "Lua 4.0.1" +diff -r lua-4.0/src/lapi.c lua/src/lapi.c +2c2 +< ** $Id: lapi.c,v 1.110 2000/10/30 12:50:09 roberto Exp $ +--- +> ** $Id: lapi.c,v 1.110a 2000/10/30 12:50:09 roberto Exp $ +488c488 +< TString *ts = luaS_newudata(L, size, NULL); +--- +> TString *ts = luaS_newudata(L, (size==0) ? 1 : size, NULL); +diff -r lua-4.0/src/ldo.c lua/src/ldo.c +2c2 +< ** $Id: ldo.c,v 1.109 2000/10/30 12:38:50 roberto Exp $ +--- +> ** $Id: ldo.c,v 1.109a 2000/10/30 12:38:50 roberto Exp $ +247c247,249 +< luaC_checkGC(L); +--- +> /* before parsing, give a (good) chance to GC */ +> if (L->nblocks/8 >= L->GCthreshold/10) +> luaC_collectgarbage(L); +277,278c279,280 +< filename = lua_tostring(L, -1); /* filename = '@'..filename */ +< lua_pop(L, 1); /* OK: there is no GC during parser */ +--- +> c = lua_gettop(L); +> filename = lua_tostring(L, c); /* filename = '@'..filename */ +280a283 +> lua_remove(L, c); /* remove `filename' from the stack */ +diff -r lua-4.0/src/lgc.c lua/src/lgc.c +2c2 +< ** $Id: lgc.c,v 1.72 2000/10/26 12:47:05 roberto Exp $ +--- +> ** $Id: lgc.c,v 1.72+ 2000/10/26 12:47:05 roberto Exp $ +339c339 +< static void luaC_collectgarbage (lua_State *L) { +--- +> void luaC_collectgarbage (lua_State *L) { +diff -r lua-4.0/src/lgc.h lua/src/lgc.h +2c2 +< ** $Id: lgc.h,v 1.8 2000/10/02 14:47:43 roberto Exp $ +--- +> ** $Id: lgc.h,v 1.9 2001/02/02 16:23:20 roberto Exp $ +14a15 +> void luaC_collectgarbage (lua_State *L); +diff -r lua-4.0/src/lib/lbaselib.c lua/src/lib/lbaselib.c +2c2 +< ** $Id: lbaselib.c,v 1.17 2000/11/06 13:45:18 roberto Exp $ +--- +> ** $Id: lbaselib.c,v 1.17a 2000/11/06 13:45:18 roberto Exp $ +168c168 +< lua_rawget(L, -2); +--- +> lua_rawget(L, 1); +176c176 +< lua_rawset(L, -3); +--- +> lua_rawset(L, 1); +260c260 +< if (*s == '\27') /* binary files start with ESC... */ +--- +> if (*s == '\33') /* binary files start with ESC... */ +diff -r lua-4.0/src/lparser.c lua/src/lparser.c +2c2 +< ** $Id: lparser.c,v 1.116 2000/10/27 11:39:52 roberto Exp $ +--- +> ** $Id: lparser.c,v 1.117 2000/11/29 11:57:42 roberto Exp $ +1000c1000 +< if (!block_follow(ls->t.token)) +--- +> if (!block_follow(ls->t.token) && ls->t.token != ';') +diff -r lua-4.0/src/lstring.c lua/src/lstring.c +2c2 +< ** $Id: lstring.c,v 1.45 2000/10/30 17:49:19 roberto Exp $ +--- +> ** $Id: lstring.c,v 1.45a 2000/10/30 17:49:19 roberto Exp $ +122c122 +< ts->u.d.value = (udata == NULL) ? uts+1 : udata; +--- +> ts->u.d.value = (s > 0) ? uts+1 : udata; +diff -r lua-4.0/src/lvm.c lua/src/lvm.c +2c2 +< ** $Id: lvm.c,v 1.146 2000/10/26 12:47:05 roberto Exp $ +--- +> ** $Id: lvm.c,v 1.146a 2000/10/26 12:47:05 roberto Exp $ +82c82 +< luaD_lineHook(L, base-2, newline, linehook); +--- +> luaD_lineHook(L, base-1, newline, linehook); diff --git a/UPDATE b/UPDATE new file mode 100644 index 0000000000..1be0709df7 --- /dev/null +++ b/UPDATE @@ -0,0 +1,19 @@ +This is an update of Lua 4.0 that includes the following bug fixes and +improvements: + +lua/src/lapi.c +lua/src/lstring.c + Fixed a bug in lua_pushuserdata(L, NULL) +lua/src/ldo.c +lua/src/lgc.c +lua/src/lgc.h + Give a good chance for GC before parsing +lua/src/lparser.c + Fixed a bug (did not accept `;' after a `return') +lua/src/lvm.c + Fixed a bug (linehook off by 1) +lua/src/lib/lbaselib.c + Fixed a bug in rawget and rawset (seg. fault if given extra arguments) + Fixed a bug in dostring (identification of precompiled chunks) + +To use simply open this tarball over the original Lua 4.0 source. diff --git a/include/lua.h b/include/lua.h index 1b2715341b..660ecd80a1 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.79 2000/10/31 12:44:07 roberto Exp $ +** $Id: lua.h,v 1.79a 2000/10/31 12:44:07 roberto Exp $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -22,7 +22,7 @@ #endif -#define LUA_VERSION "Lua 4.0" +#define LUA_VERSION "Lua 4.0.1" #define LUA_COPYRIGHT "Copyright (C) 1994-2000 TeCGraf, PUC-Rio" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" diff --git a/src/lapi.c b/src/lapi.c index e80023428e..54c2cba411 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.110 2000/10/30 12:50:09 roberto Exp $ +** $Id: lapi.c,v 1.110a 2000/10/30 12:50:09 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -485,7 +485,7 @@ LUA_API void lua_concat (lua_State *L, int n) { LUA_API void *lua_newuserdata (lua_State *L, size_t size) { - TString *ts = luaS_newudata(L, size, NULL); + TString *ts = luaS_newudata(L, (size==0) ? 1 : size, NULL); tsvalue(L->top) = ts; ttype(L->top) = LUA_TUSERDATA; api_incr_top(L); diff --git a/src/ldo.c b/src/ldo.c index fbb892a5a0..8a779bbe03 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.109 2000/10/30 12:38:50 roberto Exp $ +** $Id: ldo.c,v 1.109a 2000/10/30 12:38:50 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -244,7 +244,9 @@ static int protectedparser (lua_State *L, ZIO *z, int bin) { unsigned long old_blocks; int status; p.z = z; p.bin = bin; - luaC_checkGC(L); + /* before parsing, give a (good) chance to GC */ + if (L->nblocks/8 >= L->GCthreshold/10) + luaC_collectgarbage(L); old_blocks = L->nblocks; status = luaD_runprotected(L, f_parser, &p); if (status == 0) { @@ -274,10 +276,11 @@ static int parse_file (lua_State *L, const char *filename) { lua_pushstring(L, "@"); lua_pushstring(L, (filename == NULL) ? "(stdin)" : filename); lua_concat(L, 2); - filename = lua_tostring(L, -1); /* filename = '@'..filename */ - lua_pop(L, 1); /* OK: there is no GC during parser */ + c = lua_gettop(L); + filename = lua_tostring(L, c); /* filename = '@'..filename */ luaZ_Fopen(&z, f, filename); status = protectedparser(L, &z, bin); + lua_remove(L, c); /* remove `filename' from the stack */ if (f != stdin) fclose(f); return status; diff --git a/src/lgc.c b/src/lgc.c index 6b916a8b23..f1eee9ab09 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.72 2000/10/26 12:47:05 roberto Exp $ +** $Id: lgc.c,v 1.72+ 2000/10/26 12:47:05 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -336,7 +336,7 @@ void luaC_collect (lua_State *L, int all) { } -static void luaC_collectgarbage (lua_State *L) { +void luaC_collectgarbage (lua_State *L) { markall(L); invalidaterefs(L); /* check unlocked references */ luaC_collect(L, 0); diff --git a/src/lgc.h b/src/lgc.h index 87a14d1695..09b66a2bd3 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 1.8 2000/10/02 14:47:43 roberto Exp $ +** $Id: lgc.h,v 1.9 2001/02/02 16:23:20 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ void luaC_collect (lua_State *L, int all); +void luaC_collectgarbage (lua_State *L); void luaC_checkGC (lua_State *L); diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index 1ff475f9f7..29bad6a8f2 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.17 2000/11/06 13:45:18 roberto Exp $ +** $Id: lbaselib.c,v 1.17a 2000/11/06 13:45:18 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -165,7 +165,7 @@ static int luaB_globals (lua_State *L) { static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); - lua_rawget(L, -2); + lua_rawget(L, 1); return 1; } @@ -173,7 +173,7 @@ static int luaB_rawset (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); luaL_checkany(L, 3); - lua_rawset(L, -3); + lua_rawset(L, 1); return 1; } @@ -257,7 +257,7 @@ static int luaB_dostring (lua_State *L) { int oldtop = lua_gettop(L); size_t l; const char *s = luaL_check_lstr(L, 1, &l); - if (*s == '\27') /* binary files start with ESC... */ + if (*s == '\33') /* binary files start with ESC... */ lua_error(L, "`dostring' cannot run pre-compiled code"); return passresults(L, lua_dobuffer(L, s, l, luaL_opt_string(L, 2, s)), oldtop); } diff --git a/src/lparser.c b/src/lparser.c index b792c95685..67161c868e 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.116 2000/10/27 11:39:52 roberto Exp $ +** $Id: lparser.c,v 1.117 2000/11/29 11:57:42 roberto Exp $ ** LL(1) Parser and code generator for Lua ** See Copyright Notice in lua.h */ @@ -997,7 +997,7 @@ static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = ls->fs; next(ls); /* skip RETURN */ - if (!block_follow(ls->t.token)) + if (!block_follow(ls->t.token) && ls->t.token != ';') explist1(ls); /* optional return values */ luaK_code1(fs, OP_RETURN, ls->fs->nactloc); fs->stacklevel = fs->nactloc; /* removes all temp values */ diff --git a/src/lstring.c b/src/lstring.c index e4c7e26ca9..a415a7d3fd 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.45 2000/10/30 17:49:19 roberto Exp $ +** $Id: lstring.c,v 1.45a 2000/10/30 17:49:19 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -119,7 +119,7 @@ TString *luaS_newudata (lua_State *L, size_t s, void *udata) { ts->nexthash = NULL; ts->len = s; ts->u.d.tag = 0; - ts->u.d.value = (udata == NULL) ? uts+1 : udata; + ts->u.d.value = (s > 0) ? uts+1 : udata; L->nblocks += sizestring(s); /* insert it on table */ newentry(L, &L->udt, ts, IntPoint(ts->u.d.value) & (L->udt.size-1)); diff --git a/src/lvm.c b/src/lvm.c index 63e42efb2d..2a00b6a532 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.146 2000/10/26 12:47:05 roberto Exp $ +** $Id: lvm.c,v 1.146a 2000/10/26 12:47:05 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -79,7 +79,7 @@ static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) { if (newline != ci->line || pc <= ci->lastpc) { ci->line = newline; L->top = top; - luaD_lineHook(L, base-2, newline, linehook); + luaD_lineHook(L, base-1, newline, linehook); } ci->lastpc = pc; } From f0e4e22f5c119865eb5a8d3844a40df2d5980b3b Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 11 Apr 2003 12:00:00 +0000 Subject: [PATCH 14/97] Lua 5.0 --- COPYRIGHT | 70 +- DIFFS | 97 - HISTORY | 52 +- INSTALL | 52 +- MANIFEST | 261 +- Makefile | 74 +- README | 70 +- UPDATE | 19 - build | 33 + config | 182 +- configure | 9 + doc/idx.html | 411 -- doc/index.html | 93 - doc/logo.gif | Bin 2750 -> 4232 bytes doc/lua.1 | 202 +- doc/lua.html | 202 +- doc/luac.1 | 63 +- doc/luac.html | 63 +- doc/manual.html | 7554 +++++++++++++++++-------------- doc/readme.html | 11 +- etc/.exrc | 1 + etc/Makefile | 34 +- etc/README | 59 +- etc/bin2c.c | 24 +- etc/compat.lua | 192 + etc/def.lua | 9 - etc/doall.lua | 6 + etc/lua.magic | 6 +- etc/luser_number.h | 34 + etc/luser_tests.h | 68 + etc/min.c | 26 +- etc/noparser.c | 26 + etc/saconfig.c | 87 + etc/setfallback.lua | 55 - etc/stdcall.lua | 10 - etc/trace.c | 49 +- include/Makefile | 2 +- include/lauxlib.h | 95 +- include/lua.h | 397 +- include/luadebug.h | 46 - include/lualib.h | 44 +- src/Makefile | 8 +- src/README | 5 + src/lapi.c | 900 +++- src/lapi.h | 3 +- src/lcode.c | 1047 ++--- src/lcode.h | 58 +- src/ldebug.c | 699 +-- src/ldebug.h | 22 +- src/ldo.c | 624 +-- src/ldo.h | 53 +- src/ldump.c | 170 + src/lfunc.c | 130 +- src/lfunc.h | 9 +- src/lgc.c | 614 ++- src/lgc.h | 12 +- src/lib/Makefile | 11 +- src/lib/README | 10 +- src/lib/lauxlib.c | 491 +- src/lib/lbaselib.c | 867 ++-- src/lib/ldblib.c | 241 +- src/lib/liolib.c | 986 ++-- src/lib/lmathlib.c | 152 +- src/lib/loadlib.c | 205 + src/lib/lstrlib.c | 599 ++- src/lib/ltablib.c | 250 + src/llex.c | 365 +- src/llex.h | 31 +- src/llimits.h | 185 +- src/lmem.c | 163 +- src/lmem.h | 40 +- src/lobject.c | 180 +- src/lobject.h | 360 +- src/lopcodes.c | 102 + src/lopcodes.h | 260 +- src/lparser.c | 1369 +++--- src/lparser.h | 55 +- src/lstate.c | 249 +- src/lstate.h | 198 +- src/lstring.c | 163 +- src/lstring.h | 26 +- src/ltable.c | 580 ++- src/ltable.h | 31 +- src/ltests.c | 691 ++- src/ltm.c | 169 +- src/ltm.h | 36 +- src/lua/Makefile | 9 +- src/lua/README | 50 +- src/lua/lua.c | 548 ++- src/luac/Makefile | 19 +- src/luac/README | 12 +- src/luac/dump.c | 121 - src/luac/luac.c | 224 +- src/luac/luac.h | 31 - src/luac/opt.c | 127 - src/luac/print.c | 224 +- src/luac/print.h | 55 - src/luac/stubs.c | 127 - src/lundump.c | 310 +- src/lundump.h | 33 +- src/lvm.c | 1080 ++--- src/lvm.h | 31 +- src/lzio.c | 89 +- src/lzio.h | 63 +- test/README | 29 +- test/bisect.lua | 16 +- test/cf-for.lua | 19 - test/cf.lua | 31 +- test/compat.lua | 192 + test/echo.lua | 5 + test/env.lua | 7 + test/examples/ps/hilbert.lua | 42 - test/examples/ps/ps.lua | 181 - test/examples/www/README | 10 - test/examples/www/db.lua | 46 - test/examples/www/staff.lua | 33 - test/examples/www/template.html | 29 - test/factorial.lua | 19 +- test/fib.lua | 27 +- test/fibfor.lua | 13 + test/globals.lua | 24 +- test/hello.lua | 2 +- test/life.lua | 46 +- test/lisp.lua | 22 - test/luac.lua | 7 + test/old.lua | 42 - test/printf.lua | 7 + test/qp.lua | 6 - test/readonly.lua | 12 + test/save.lua | 42 - test/sieve.lua | 29 + test/sort.lua | 10 +- test/table.lua | 13 +- test/trace-calls.lua | 35 +- test/trace-globals.lua | 91 +- test/undefined.lua | 19 +- test/webform.lua | 8 - test/xd.lua | 14 + 138 files changed, 16187 insertions(+), 12301 deletions(-) delete mode 100644 DIFFS delete mode 100644 UPDATE create mode 100755 build create mode 100755 configure delete mode 100644 doc/idx.html delete mode 100644 doc/index.html create mode 120000 etc/.exrc create mode 100644 etc/compat.lua delete mode 100644 etc/def.lua create mode 100644 etc/doall.lua create mode 100644 etc/luser_number.h create mode 100644 etc/luser_tests.h create mode 100644 etc/noparser.c create mode 100644 etc/saconfig.c delete mode 100644 etc/setfallback.lua delete mode 100644 etc/stdcall.lua delete mode 100644 include/luadebug.h create mode 100644 src/README create mode 100644 src/ldump.c create mode 100644 src/lib/loadlib.c create mode 100644 src/lib/ltablib.c create mode 100644 src/lopcodes.c delete mode 100644 src/luac/dump.c delete mode 100644 src/luac/luac.h delete mode 100644 src/luac/opt.c delete mode 100644 src/luac/print.h delete mode 100644 src/luac/stubs.c delete mode 100644 test/cf-for.lua create mode 100644 test/compat.lua create mode 100644 test/echo.lua create mode 100644 test/env.lua delete mode 100644 test/examples/ps/hilbert.lua delete mode 100644 test/examples/ps/ps.lua delete mode 100644 test/examples/www/README delete mode 100644 test/examples/www/db.lua delete mode 100644 test/examples/www/staff.lua delete mode 100644 test/examples/www/template.html create mode 100644 test/fibfor.lua delete mode 100644 test/lisp.lua create mode 100644 test/luac.lua delete mode 100644 test/old.lua create mode 100644 test/printf.lua delete mode 100644 test/qp.lua create mode 100644 test/readonly.lua delete mode 100644 test/save.lua create mode 100644 test/sieve.lua delete mode 100644 test/webform.lua create mode 100644 test/xd.lua diff --git a/COPYRIGHT b/COPYRIGHT index eef88b050c..fd3cdf9b3e 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,53 +1,33 @@ -Lua Copyright Notice --------------------- +Lua License +----------- -Lua is free and non-proprietary. -It can be used for both academic and commercial purposes at absolutely no cost. -There are no royalties or GNU-like "copyleft" restrictions. -Lua (probably) qualifies as Open Source software. -Nevertheless, Lua is not in the public domain and TeCGraf keeps its copyright. +Lua is licensed under the terms of the MIT license reproduced below. +This means that Lua is free software and can be used for both academic +and commercial purposes at absolutely no cost. -If you use Lua, please give us credit (a nice way to do this is to include a -Lua logo in a web page for your product), but we would appreciate *not* -receiving lengthy legal documents to sign. - -The legal details are below. +For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 1994-2000 TeCGraf, PUC-Rio. All rights reserved. - -Permission is hereby granted, without written agreement and without license -or royalty fees, to use, copy, modify, translate, and distribute -this software and its documentation (hereby called the "package") -for any purpose, including commercial applications, subject to -the following conditions: - - * The above copyright notice and this permission notice shall appear in all - copies or substantial portions of this package. - - * The origin of this package must not be misrepresented; you must not - claim that you wrote the original package. If you use this package in a - product, an acknowledgment in the product documentation would be greatly - appreciated (but it is not required). - - * Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original package. - -The authors specifically disclaim any warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a particular -purpose. The package provided hereunder is on an "as is" basis, and the -authors have no obligation to provide maintenance, support, updates, -enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the -authors be held liable to any party for direct, indirect, special, -incidental, or consequential damages arising out of the use of this package -and its documentation. - -The Lua language and this implementation have been entirely designed and written -by Waldemar Celes, Roberto Ierusalimschy, and Luiz Henrique de Figueiredo -at TeCGraf, PUC-Rio in Brazil. - -This implementation contains no third-party code. +Copyright (C) 2003 Tecgraf, PUC-Rio. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. =============================================================================== diff --git a/DIFFS b/DIFFS deleted file mode 100644 index b7c8638869..0000000000 --- a/DIFFS +++ /dev/null @@ -1,97 +0,0 @@ -diff -r lua-4.0/include/lua.h lua/include/lua.h -2c2 -< ** $Id: lua.h,v 1.79 2000/10/31 12:44:07 roberto Exp $ ---- -> ** $Id: lua.h,v 1.79a 2000/10/31 12:44:07 roberto Exp $ -25c25 -< #define LUA_VERSION "Lua 4.0" ---- -> #define LUA_VERSION "Lua 4.0.1" -diff -r lua-4.0/src/lapi.c lua/src/lapi.c -2c2 -< ** $Id: lapi.c,v 1.110 2000/10/30 12:50:09 roberto Exp $ ---- -> ** $Id: lapi.c,v 1.110a 2000/10/30 12:50:09 roberto Exp $ -488c488 -< TString *ts = luaS_newudata(L, size, NULL); ---- -> TString *ts = luaS_newudata(L, (size==0) ? 1 : size, NULL); -diff -r lua-4.0/src/ldo.c lua/src/ldo.c -2c2 -< ** $Id: ldo.c,v 1.109 2000/10/30 12:38:50 roberto Exp $ ---- -> ** $Id: ldo.c,v 1.109a 2000/10/30 12:38:50 roberto Exp $ -247c247,249 -< luaC_checkGC(L); ---- -> /* before parsing, give a (good) chance to GC */ -> if (L->nblocks/8 >= L->GCthreshold/10) -> luaC_collectgarbage(L); -277,278c279,280 -< filename = lua_tostring(L, -1); /* filename = '@'..filename */ -< lua_pop(L, 1); /* OK: there is no GC during parser */ ---- -> c = lua_gettop(L); -> filename = lua_tostring(L, c); /* filename = '@'..filename */ -280a283 -> lua_remove(L, c); /* remove `filename' from the stack */ -diff -r lua-4.0/src/lgc.c lua/src/lgc.c -2c2 -< ** $Id: lgc.c,v 1.72 2000/10/26 12:47:05 roberto Exp $ ---- -> ** $Id: lgc.c,v 1.72+ 2000/10/26 12:47:05 roberto Exp $ -339c339 -< static void luaC_collectgarbage (lua_State *L) { ---- -> void luaC_collectgarbage (lua_State *L) { -diff -r lua-4.0/src/lgc.h lua/src/lgc.h -2c2 -< ** $Id: lgc.h,v 1.8 2000/10/02 14:47:43 roberto Exp $ ---- -> ** $Id: lgc.h,v 1.9 2001/02/02 16:23:20 roberto Exp $ -14a15 -> void luaC_collectgarbage (lua_State *L); -diff -r lua-4.0/src/lib/lbaselib.c lua/src/lib/lbaselib.c -2c2 -< ** $Id: lbaselib.c,v 1.17 2000/11/06 13:45:18 roberto Exp $ ---- -> ** $Id: lbaselib.c,v 1.17a 2000/11/06 13:45:18 roberto Exp $ -168c168 -< lua_rawget(L, -2); ---- -> lua_rawget(L, 1); -176c176 -< lua_rawset(L, -3); ---- -> lua_rawset(L, 1); -260c260 -< if (*s == '\27') /* binary files start with ESC... */ ---- -> if (*s == '\33') /* binary files start with ESC... */ -diff -r lua-4.0/src/lparser.c lua/src/lparser.c -2c2 -< ** $Id: lparser.c,v 1.116 2000/10/27 11:39:52 roberto Exp $ ---- -> ** $Id: lparser.c,v 1.117 2000/11/29 11:57:42 roberto Exp $ -1000c1000 -< if (!block_follow(ls->t.token)) ---- -> if (!block_follow(ls->t.token) && ls->t.token != ';') -diff -r lua-4.0/src/lstring.c lua/src/lstring.c -2c2 -< ** $Id: lstring.c,v 1.45 2000/10/30 17:49:19 roberto Exp $ ---- -> ** $Id: lstring.c,v 1.45a 2000/10/30 17:49:19 roberto Exp $ -122c122 -< ts->u.d.value = (udata == NULL) ? uts+1 : udata; ---- -> ts->u.d.value = (s > 0) ? uts+1 : udata; -diff -r lua-4.0/src/lvm.c lua/src/lvm.c -2c2 -< ** $Id: lvm.c,v 1.146 2000/10/26 12:47:05 roberto Exp $ ---- -> ** $Id: lvm.c,v 1.146a 2000/10/26 12:47:05 roberto Exp $ -82c82 -< luaD_lineHook(L, base-2, newline, linehook); ---- -> luaD_lineHook(L, base-1, newline, linehook); diff --git a/HISTORY b/HISTORY index 10b033ae3d..cf6e1c019d 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,52 @@ -This is Lua 4.0. +This is Lua 5.0. + +* Changes from version 4.0 to 5.0 + ------------------------------- + Language: + + lexical scoping. + + Lua coroutines. + + standard libraries now packaged in tables. + + tags replaced by metatables and tag methods replaced by metamethods, + stored in metatables. + + proper tail calls. + + each function can have its own global table, which can be shared. + + new __newindex metamethod, called when we insert a new key into a table. + + new block comments: --[[ ... ]]. + + new generic for. + + new weak tables. + + new boolean type. + + new syntax "local function". + + (f()) returns the first value returned by f. + + {f()} fills a table with all values returned by f. + + \n ignored in [[\n . + + fixed and-or priorities. + + more general syntax for function definition (e.g. function a.x.y:f()...end). + + more general syntax for function calls (e.g. (print or write)(9)). + + new functions (time/date, tmpfile, unpack, require, load*, etc.). + API: + + chunks are loaded by using lua_load; new luaL_loadfile and luaL_loadbuffer. + + introduced lightweight userdata, a simple "void*" without a metatable. + + new error handling protocol: the core no longer prints error messages; + all errors are reported to the caller on the stack. + + new lua_atpanic for host cleanup. + + new, signal-safe, hook scheme. + Implementation: + + new license: MIT. + + new, faster, register-based virtual machine. + + support for external multithreading and coroutines. + + new and consistent error message format. + + the core no longer needs "stdio.h" for anything (except for a single + use of sprintf to convert numbers to strings). + + lua.c now runs the environment variable LUA_INIT, if present. It can + be "@filename", to run a file, or the chunk itself. + + support for user extensions in lua.c. + sample implementation given for command line editing. + + new dynamic loading library, active by default on several platforms. + + safe garbage-collector metamethods. + + precompiled bytecodes checked for integrity (secure binary dostring). + + strings are fully aligned. + + position capture in string.find. + + read('*l') can read lines with embedded zeros. * Changes from version 3.2 to 4.0 ------------------------------- @@ -18,7 +66,7 @@ This is Lua 4.0. + New API: fully re-entrant, simpler, and more efficient. + New debug API. Implementation: - + cleaner virtual machine -- at least 20% faster. + + faster than ever: cleaner virtual machine and new hashing algorithm. + non-recursive garbage-collector algorithm. + reduced memory usage for programs with many strings. + improved treatment for memory allocation errors. diff --git a/INSTALL b/INSTALL index e31eefad29..748c6861d0 100644 --- a/INSTALL +++ b/INSTALL @@ -1,16 +1,18 @@ -This is Lua 4.0. +This is Lua 5.0. * Installation ------------ Building Lua on a Unix system should be very easy: - 1. Edit "config" to suit your platform, if at all necessary. + 1. Read "config" and edit it to suit your platform and needs. + We strongly recommend that you enable support for dynamic loading, + if your platform allows it. 2. Do "make". 3. If you want to install Lua in an "official" place in your system, then do "make install". The official place and the way to install files are defined in "config". You may have to be root to do this. - See below for instructions for Windows and Macintosh. + See below for instructions for Windows and other systems. * What you get ------------ @@ -20,7 +22,7 @@ This is Lua 4.0. * include files in ./include. These are the only directories you need for development. - There man pages for lua and luac in both nroff and html, and a reference + There are man pages for lua and luac, in both nroff and html; a reference manual in html in ./doc, some sample code in ./test, and some useful stuff in ./etc. You don't need these directories for development. @@ -35,38 +37,44 @@ This is Lua 4.0. * Shared libraries ---------------- If you are running Linux, do "make so" after "make" succeeds. - This will create shared libraries in ./lib. It's probably better to - build shared libraries before "make install". + This will create shared libraries in ./lib. + To install those shared libraries in an official place, do "make soinstall". If you want the interpreter and the compiler to use shared libraries, - then do "make sobin" too. + then do "make sobin" too. You may want to do this before "make install". - You may need to include lib/ in the LD_LIBRAY_PATH environment variable - to link programs that use the shared libraries if you don't put them in - the "official" places with "make install". + If you only want the shared libraries, you may want to add -fPIC to MYCFLAGS + in "config". Also, you may need to run "ldconfig" as root. + + You may need to include ./lib in the LD_LIBRARY_PATH environment variable + to link programs that use the shared libraries if you don't put them in the + official places with "make install". (You may need to use the full path.) Building shared libraries in other systems is similar but details differ; you may need to fix a few details in the top-level Makefile. -* Installation on Windows or Macintosh - ------------------------------------ - The instructions for building Lua on a Mac or Windows machine depend on - the particular compiler you are using. - The simplest way is to create a folder with all .c and .h files. - Then create projects for the core library, the standard library, - the interpreter, and the compiler, as follows: +* Installation on Windows and other systems + ----------------------------------------------------- + The instructions for building Lua on other systems machine depend on the + particular compiler you are using. The simplest way is to create a folder + with all .c and .h files, and then create projects for the core library, + the standard library, the interpreter, and the compiler, as follows: - core lib: lapi.c lcode.c ldebug.c ldo.c lfunc.c lgc.c llex.c lmem.c - lobject.c lparser.c lstate.c lstring.c ltable.c ltests.c - ltm.c lundump.c lvm.c lzio.c + core lib: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c + lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c + ltable.c ltests.c ltm.c lundump.c lvm.c lzio.c - standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c + standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c ltablib.c + lstrlib.c loadlib.c interpreter: core lib, standard lib, lua.c - compiler: core lib, dump.c luac.c opt.c print.c stubs.c + compiler: core lib, standard lib, luac.c print.c + and also lopcodes.c (with LUA_OPNAMES defined) from core. Of course, to use Lua as a library, you'll have to know how to create and use libraries with your compiler. + Also, read "config" to see what can be customized at compilation time. + (end of INSTALL) diff --git a/MANIFEST b/MANIFEST index d7dfbc5473..e26c9de27b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,133 +1,130 @@ -MANIFEST contents of Lua 4.0 distribution on Mon Nov 6 19:15:16 EDT 2000 -lua -lua/COPYRIGHT -lua/HISTORY -lua/INSTALL -lua/MANIFEST -lua/Makefile -lua/README -lua/bin -lua/config -lua/doc -lua/doc/idx.html -lua/doc/index.html -lua/doc/logo.gif -lua/doc/lua.1 -lua/doc/lua.html -lua/doc/luac.1 -lua/doc/luac.html -lua/doc/manual.html -lua/doc/readme.html -lua/etc -lua/etc/Makefile -lua/etc/README -lua/etc/bin2c.c -lua/etc/def.lua -lua/etc/lua.ico -lua/etc/lua.magic -lua/etc/lua.xpm -lua/etc/min.c -lua/etc/setfallback.lua -lua/etc/stdcall.lua -lua/etc/trace.c -lua/include -lua/include/Makefile -lua/include/lauxlib.h -lua/include/lua.h -lua/include/luadebug.h -lua/include/lualib.h -lua/lib -lua/src -lua/src/Makefile -lua/src/lapi.c -lua/src/lapi.h -lua/src/lcode.c -lua/src/lcode.h -lua/src/ldebug.c -lua/src/ldebug.h -lua/src/ldo.c -lua/src/ldo.h -lua/src/lfunc.c -lua/src/lfunc.h -lua/src/lgc.c -lua/src/lgc.h -lua/src/lib -lua/src/lib/Makefile -lua/src/lib/README -lua/src/lib/lauxlib.c -lua/src/lib/lbaselib.c -lua/src/lib/ldblib.c -lua/src/lib/liolib.c -lua/src/lib/lmathlib.c -lua/src/lib/lstrlib.c -lua/src/llex.c -lua/src/llex.h -lua/src/llimits.h -lua/src/lmem.c -lua/src/lmem.h -lua/src/lobject.c -lua/src/lobject.h -lua/src/lopcodes.h -lua/src/lparser.c -lua/src/lparser.h -lua/src/lstate.c -lua/src/lstate.h -lua/src/lstring.c -lua/src/lstring.h -lua/src/ltable.c -lua/src/ltable.h -lua/src/ltests.c -lua/src/ltm.c -lua/src/ltm.h -lua/src/lua -lua/src/lua/Makefile -lua/src/lua/README -lua/src/lua/lua.c -lua/src/luac -lua/src/luac/Makefile -lua/src/luac/README -lua/src/luac/dump.c -lua/src/luac/luac.c -lua/src/luac/luac.h -lua/src/luac/opt.c -lua/src/luac/print.c -lua/src/luac/print.h -lua/src/luac/stubs.c -lua/src/lundump.c -lua/src/lundump.h -lua/src/lvm.c -lua/src/lvm.h -lua/src/lzio.c -lua/src/lzio.h -lua/test -lua/test/README -lua/test/bisect.lua -lua/test/cf-for.lua -lua/test/cf.lua -lua/test/examples -lua/test/examples/ps -lua/test/examples/ps/hilbert.lua -lua/test/examples/ps/ps.lua -lua/test/examples/www -lua/test/examples/www/README -lua/test/examples/www/db.lua -lua/test/examples/www/staff.lua -lua/test/examples/www/template.html -lua/test/factorial.lua -lua/test/fib.lua -lua/test/globals.lua -lua/test/hello.lua -lua/test/life.lua -lua/test/lisp.lua -lua/test/lua -lua/test/luac -lua/test/old.lua -lua/test/qp.lua -lua/test/save.lua -lua/test/sort.lua -lua/test/table.lua -lua/test/trace-calls.lua -lua/test/trace-globals.lua -lua/test/undefined.lua -lua/test/webform.lua +MANIFEST contents of Lua 5.0 distribution on Fri Apr 11 11:01:08 BRT 2003 +lua-5.0 +lua-5.0/COPYRIGHT +lua-5.0/HISTORY +lua-5.0/INSTALL +lua-5.0/MANIFEST +lua-5.0/Makefile +lua-5.0/README +lua-5.0/bin +lua-5.0/build +lua-5.0/config +lua-5.0/configure +lua-5.0/doc +lua-5.0/doc/logo.gif +lua-5.0/doc/lua.1 +lua-5.0/doc/lua.html +lua-5.0/doc/luac.1 +lua-5.0/doc/luac.html +lua-5.0/doc/manual.html +lua-5.0/doc/readme.html +lua-5.0/etc +lua-5.0/etc/.exrc +lua-5.0/etc/Makefile +lua-5.0/etc/README +lua-5.0/etc/bin2c.c +lua-5.0/etc/compat.lua +lua-5.0/etc/doall.lua +lua-5.0/etc/lua.ico +lua-5.0/etc/lua.magic +lua-5.0/etc/lua.xpm +lua-5.0/etc/luser_number.h +lua-5.0/etc/luser_tests.h +lua-5.0/etc/min.c +lua-5.0/etc/noparser.c +lua-5.0/etc/saconfig.c +lua-5.0/etc/trace.c +lua-5.0/include +lua-5.0/include/Makefile +lua-5.0/include/lauxlib.h +lua-5.0/include/lua.h +lua-5.0/include/lualib.h +lua-5.0/lib +lua-5.0/src +lua-5.0/src/Makefile +lua-5.0/src/README +lua-5.0/src/lapi.c +lua-5.0/src/lapi.h +lua-5.0/src/lcode.c +lua-5.0/src/lcode.h +lua-5.0/src/ldebug.c +lua-5.0/src/ldebug.h +lua-5.0/src/ldo.c +lua-5.0/src/ldo.h +lua-5.0/src/ldump.c +lua-5.0/src/lfunc.c +lua-5.0/src/lfunc.h +lua-5.0/src/lgc.c +lua-5.0/src/lgc.h +lua-5.0/src/lib +lua-5.0/src/lib/Makefile +lua-5.0/src/lib/README +lua-5.0/src/lib/lauxlib.c +lua-5.0/src/lib/lbaselib.c +lua-5.0/src/lib/ldblib.c +lua-5.0/src/lib/liolib.c +lua-5.0/src/lib/lmathlib.c +lua-5.0/src/lib/loadlib.c +lua-5.0/src/lib/lstrlib.c +lua-5.0/src/lib/ltablib.c +lua-5.0/src/llex.c +lua-5.0/src/llex.h +lua-5.0/src/llimits.h +lua-5.0/src/lmem.c +lua-5.0/src/lmem.h +lua-5.0/src/lobject.c +lua-5.0/src/lobject.h +lua-5.0/src/lopcodes.c +lua-5.0/src/lopcodes.h +lua-5.0/src/lparser.c +lua-5.0/src/lparser.h +lua-5.0/src/lstate.c +lua-5.0/src/lstate.h +lua-5.0/src/lstring.c +lua-5.0/src/lstring.h +lua-5.0/src/ltable.c +lua-5.0/src/ltable.h +lua-5.0/src/ltests.c +lua-5.0/src/ltm.c +lua-5.0/src/ltm.h +lua-5.0/src/lua +lua-5.0/src/lua/Makefile +lua-5.0/src/lua/README +lua-5.0/src/lua/lua.c +lua-5.0/src/luac +lua-5.0/src/luac/Makefile +lua-5.0/src/luac/README +lua-5.0/src/luac/luac.c +lua-5.0/src/luac/print.c +lua-5.0/src/lundump.c +lua-5.0/src/lundump.h +lua-5.0/src/lvm.c +lua-5.0/src/lvm.h +lua-5.0/src/lzio.c +lua-5.0/src/lzio.h +lua-5.0/test +lua-5.0/test/README +lua-5.0/test/bisect.lua +lua-5.0/test/cf.lua +lua-5.0/test/compat.lua +lua-5.0/test/echo.lua +lua-5.0/test/env.lua +lua-5.0/test/factorial.lua +lua-5.0/test/fib.lua +lua-5.0/test/fibfor.lua +lua-5.0/test/globals.lua +lua-5.0/test/hello.lua +lua-5.0/test/life.lua +lua-5.0/test/lua +lua-5.0/test/luac +lua-5.0/test/luac.lua +lua-5.0/test/printf.lua +lua-5.0/test/readonly.lua +lua-5.0/test/sieve.lua +lua-5.0/test/sort.lua +lua-5.0/test/table.lua +lua-5.0/test/trace-calls.lua +lua-5.0/test/trace-globals.lua +lua-5.0/test/undefined.lua +lua-5.0/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index adf018f2cb..007b72d0a9 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,99 @@ # makefile for Lua hierarchy # see INSTALL for installation instructions -# see file "config" for customization instructions +# see config for customization instructions LUA= . include $(LUA)/config -# primary targets (only "all" and "clean" are useful after distribution) -all clean co klean: +# primary targets ("co" and "klean" are used for making the distribution) +all clean co klean: dirs cd include; $(MAKE) $@ cd src; $(MAKE) $@ - cd src/luac; $(MAKE) $@ cd src/lib; $(MAKE) $@ + cd src/luac; $(MAKE) $@ cd src/lua; $(MAKE) $@ +# in case they were not created during unpacking +dirs: bin lib + +bin lib: + mkdir -p $@ + +# simple test to see Lua working +test: all + bin/lua test/hello.lua + # remove debug information from binaries strip: - strip bin/lua bin/luac + $(STRIP) bin/* # official installation install: all strip mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_EXEC) bin/* $(INSTALL_BIN) $(INSTALL_DATA) include/*.h $(INSTALL_INC) - $(INSTALL_DATA) lib/lib* $(INSTALL_LIB) + $(INSTALL_DATA) lib/*.a $(INSTALL_LIB) $(INSTALL_DATA) doc/*.1 $(INSTALL_MAN) # shared libraries (for Linux) so: ld -o lib/liblua.so.$V -shared src/*.o ld -o lib/liblualib.so.$V -shared src/lib/*.o - cd lib; ln -s liblua.so.$V liblua.so; ln -s liblualib.so.$V liblualib.so + cd lib; ln -fs liblua.so.$V liblua.so; ln -fs liblualib.so.$V liblualib.so # binaries using shared libraries sobin: - rm -f bin/lua bin/luac + rm -f bin/* cd src/lua; $(MAKE) cd src/luac; $(MAKE) +# install shared libraries +soinstall: + $(INSTALL_EXEC) lib/*.so.* $(INSTALL_LIB) + cd $(INSTALL_LIB); ln -fs liblua.so.$V liblua.so; ln -fs liblualib.so.$V liblualib.so + +# clean shared libraries +soclean: + rm -f lib/*.so* bin/* + +# echo config parameters +echo: + @echo "" + @echo "These are the parameters currently set in $(LUA)/config to build Lua $V:" + @echo "" + @echo "LOADLIB = $(LOADLIB)" + @echo "DLLIB = $(DLLIB)" + @echo "NUMBER = $(NUMBER)" + @echo "POPEN = $(POPEN)" + @echo "TMPNAM = $(TMPNAM)" + @echo "DEGREES = $(DEGREES)" + @echo "USERCONF = $(USERCONF)" + @echo "CC = $(CC)" + @echo "WARN = $(WARN)" + @echo "MYCFLAGS = $(MYCFLAGS)" + @echo "MYLDFLAGS = $(MYLDFLAGS)" + @echo "EXTRA_LIBS = $(EXTRA_LIBS)" + @echo "AR = $(AR)" + @echo "RANLIB = $(RANLIB)" + @echo "STRIP = $(STRIP)" + @echo "INSTALL_ROOT = $(INSTALL_ROOT)" + @echo "INSTALL_BIN = $(INSTALL_BIN)" + @echo "INSTALL_INC = $(INSTALL_INC)" + @echo "INSTALL_LIB = $(INSTALL_LIB)" + @echo "INSTALL_MAN = $(INSTALL_MAN)" + @echo "INSTALL_EXEC = $(INSTALL_EXEC)" + @echo "INSTALL_DATA = $(INSTALL_DATA)" + @echo "" + @echo "Edit $(LUA)/config if needed to suit your platform and then run make." + @echo "" + +# turn config into Lua code +# uncomment the last sed expression if you want nil instead of empty strings +lecho: + @echo "-- $(LUA)/config for Lua $V" + @echo "VERSION = '$(V)'" + @make echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' + @echo "-- EOF" + # (end of Makefile) diff --git a/README b/README index 81f767aee8..4aaaba5286 100644 --- a/README +++ b/README @@ -1,72 +1,44 @@ -This is Lua 4.0. -See HISTORY for a summary of changes since the last version. +This is Lua 5.0. +See HISTORY for a summary of changes since the last released version. * What is Lua? ------------ Lua is a powerful, light-weight programming language designed for extending applications. Lua is also frequently used as a general-purpose, stand-alone - language. + language. Lua is free software. - Lua combines simple procedural syntax (similar to Pascal) with powerful - data description constructs based on associative arrays and extensible - semantics. Lua is dynamically typed, interpreted from bytecodes, and has - automatic memory management, making it ideal for configuration, scripting, - and rapid prototyping. - - Lua is a language engine that you can embed into your application. - This means that, besides syntax and semantics, Lua has an API that - allows the application to exchange data with Lua programs and also to - extend Lua with C functions. In this sense, Lua can be regarded as a - language framework for building domain-specific languages. - - Lua is implemented as a small library of C functions, written in ANSI C, - and compiles unmodified in all known platforms. The implementation goals - are simplicity, efficiency, portability, and low embedding cost. - The result is a fast language engine with small footprint, making it - ideal in embedded systems too. - - Lua was awarded the first prize (technological category) in the - Second Compaq Award for Research and Development in Computer Science in 1997. - This award was a joint venture of Compaq Computer in Brazil, the Brazilian - Ministry of Science and Technology, and the Brazilian Academy of Sciences. + For complete information, visit Lua's web site at http://www.lua.org/ . + For an executive summary, see http://www.lua.org/about.html . Lua has been used in many different projects around the world. - For a short list, see http://www.tecgraf.puc-rio.br/lua/uses.html . + For a short list, see http://www.lua.org/uses.html . * Availability ------------ - Lua is freely available for both academic and commercial purposes and - can be downloaded from the sites below. See COPYRIGHT for details. - - Home page: http://www.tecgraf.puc-rio.br/lua/ - http://csg.uwaterloo.ca/~lhf/lua/ - In Brazil: ftp://ftp.tecgraf.puc-rio.br/pub/lua/ - In Canada: ftp://csg.uwaterloo.ca/pub/lhf/lua/ - In the US: ftp://ftp.freesoftware.com/pub/languages/lua/ - In Germany: ftp://ftp.uni-trier.de/pub/languages/lua/ - In Germany: ftp://ftp.gwdg.de/pub/languages/lua/ - In Greece: ftp://ftp.ntua.gr/pub/lang/lua/ - In Japan: ftp://ftp.u-aizu.ac.jp/pub/lang/lua/ - In Denmark: ftp://ftp.ucore.com/lua/dist + Lua is freely available for both academic and commercial purposes. + See COPYRIGHT and http://www.lua.org/license.html for details. + Lua can be downloaded from its official site http://www.lua.org/ and + several other sites aroung the world. For a complete list of mirror sites, + see http://www.lua.org/mirrors.html . * Installation ------------ - See INSTALL. + Lua is implemented in pure ANSI C, and compiles unmodified in all known + platforms that have an ANSI C compiler. Under Unix, simply typing "make" + should work. See INSTALL for detailed instructions. * Contacting the authors ---------------------- - Lua was designed and implemented by Waldemar Celes, Roberto Ierusalimschy - and Luiz Henrique de Figueiredo. - They can be contacted by email at lua@tecgraf.puc-rio.br. - Send your comments, questions, and bug reports to lua@tecgraf.puc-rio.br. + For more information about the authors, see http://www.lua.org/authors.html . For reporting bugs, try also the mailing list: lua-l@tecgraf.puc-rio.br. For more information about this list, including instructions on how to - subscribe, see http://www.tecgraf.puc-rio.br/lua/lua-l.html . + subscribe and access the archives, see http://www.lua.org/lua-l.html . - Lua is developed at TeCGraf, the Computer Graphics Technology Group - of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). - TeCGraf is a laboratory of the Department of Computer Science. - Dozens of industrial products developed by TeCGraf use Lua. +* Origin + ------ + Lua is developed at Tecgraf, the Computer Graphics Technology Group + of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). + Tecgraf is a laboratory of the Department of Computer Science. (end of README) diff --git a/UPDATE b/UPDATE deleted file mode 100644 index 1be0709df7..0000000000 --- a/UPDATE +++ /dev/null @@ -1,19 +0,0 @@ -This is an update of Lua 4.0 that includes the following bug fixes and -improvements: - -lua/src/lapi.c -lua/src/lstring.c - Fixed a bug in lua_pushuserdata(L, NULL) -lua/src/ldo.c -lua/src/lgc.c -lua/src/lgc.h - Give a good chance for GC before parsing -lua/src/lparser.c - Fixed a bug (did not accept `;' after a `return') -lua/src/lvm.c - Fixed a bug (linehook off by 1) -lua/src/lib/lbaselib.c - Fixed a bug in rawget and rawset (seg. fault if given extra arguments) - Fixed a bug in dostring (identification of precompiled chunks) - -To use simply open this tarball over the original Lua 4.0 source. diff --git a/build b/build new file mode 100755 index 0000000000..6faed3710c --- /dev/null +++ b/build @@ -0,0 +1,33 @@ +# If you don't want to use make, run this script. +# But make sure you read config to see what can be customized. + + +# Easiest way to build bin/lua: +# cc -O2 -o bin/lua -Iinclude -Isrc src/*.c src/lib/*.c src/lua/*.c -lm -ldl + + +# Easiest way to build Lua libraries and executables: +echo -n 'building core library... ' +cd src +cc -O2 -c -I../include *.c +ar rc ../lib/liblua.a *.o +rm -f *.o + +echo -n 'standard library... ' +cd lib +cc -O2 -c -I../../include *.c +ar rc ../../lib/liblualib.a *.o +rm -f *.o + +echo -n 'lua... ' +cd ../lua +cc -O2 -o ../../bin/lua -I../../include *.c ../../lib/*.a -lm -ldl + +echo -n 'luac... ' +cd ../luac +cc -O2 -o ../../bin/luac -I../../include -I.. *.c -DLUA_OPNAMES ../lopcodes.c ../../lib/*.a + +echo 'done' + +cd ../.. +bin/lua test/hello.lua diff --git a/config b/config index 6a271eaf87..34c77ea372 100644 --- a/config +++ b/config @@ -1,100 +1,178 @@ -# configuration file for making Lua +# configuration file for making Lua 5.0 # see INSTALL for installation instructions -# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= +# These are default values. Skip this section and see the explanations below. + +LOADLIB= +DLLIB= +NUMBER= +POPEN= +TMPNAM= +DEGREES= +USERCONF= -# ------------------------------------------------------------------ Lua +# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= -# Lua uses double for numbers. To change this, uncomment one of the lines below. -#NUMBER= -DLUA_NUM_TYPE=double -#NUMBER= -DLUA_NUM_TYPE=float -#NUMBER= -DLUA_NUM_TYPE=long -# Optionally, you may also want change how numbers are converted to strings, -# and vice-versa. Look for LUA_NUMBER in llimits.h and in the rest of the code. +# --------------------------------------------------------------- Lua libraries + +# Support for dynamically loading C libraries for Lua is a very important +# feature, which we strongly recommend be enabled. By default, this support is +# enabled on Windows systems (see below) but disabled on other systems because +# it relies on system-dependent code that is not part of ANSI C. For more +# information on dynamic loading, read the comments in src/lib/liolib.c . +# +# To enable support for dynamic loading on Unix systems that support the dlfcn +# interface (e.g., Linux, Solaris, IRIX, BSD, AIX, HPUX, and probably others), +# uncomment the next two lines. +# +#LOADLIB= -DUSE_DLOPEN=1 +#DLLIB= -ldl +# +# In Linux with gcc, you should also uncomment the next definition for +# MYLDFLAGS, which passes -E (= -export-dynamic) to the linker. This option +# allows dynamic libraries to link back to the `lua' program, so that they do +# not need the Lua libraries. (Other systems may have an equivalent facility.) +# +#MYLDFLAGS= -Wl,-E +# +# On Windows systems. support for dynamic loading is enabled by default. +# To disable this support, uncomment the next line. +# +#LOADLIB= -DUSE_DLL=0 + +# The Lua IO library (src/lib/liolib.c) has support for pipes using popen and +# pclose. This support is enabled by default on POSIX systems. +# If your system is not POSIX but has popen and pclose, define USE_POPEN=1. +# If you don't want to support pipes, define USE_POPEN=0. +# +#POPEN= -DUSE_POPEN=1 +#POPEN= -DUSE_POPEN=0 +# +# The form below will probably work in (some) Windows systems. +# +#POPEN= -DUSE_POPEN=1 -Dpopen=_popen -Dpclose=_pclose + +# The Lua OS library (src/lib/liolib.c) exports an interface to the C function +# tmpnam, which gcc now thinks is `dangerous'. So, support for tmpnam is +# disabled by default when compiling with gcc. +# If you still want to use tmpnam, define USE_TMPNAME=1. If you don't want to +# use tmpnam even if you're not compiling with gcc, define USE_TMPNAME=0. +# +#TMPNAM= -DUSE_TMPNAME=1 +#TMPNAM= -DUSE_TMPNAME=0 + +# The Lua math library (src/lib/lmathlib.c) now operates in radians, unlike +# previous versions of Lua, which used degrees. To use degrees instead of +# radians, define USE_DEGREES. +# +#DEGREES= -DUSE_DEGREES + +# ------------------------------------------------------------------ Lua core + +# Lua uses double for numbers. To change this, uncomment and edit the following +# line, changing USE_XXX to one of USE_DOUBLE, USE_FLOAT, USE_LONG, USE_INT. +# +#NUMBER= -DLUA_USER_H='"../etc/luser_number.h"' -DUSE_XXX + +# When compiling Lua with gcc on a Pentium machine, using a fast rounding +# method for the conversion of doubles to ints can give around 20% speed +# improvement. To use this rounding method, uncomment the following line. +#NUMBER= -DLUA_USER_H='"../etc/luser_number.h"' -DUSE_FASTROUND + +# For partial compatibility with old upvalue syntax, define LUA_COMPATUPSYNTAX. +# For partial compatibility with old upvalue behavior in C functions, define +# LUA_COMPATUPVALUES. Add these definitions to MYCFLAGS. +# +# -DLUA_COMPATUPSYNTAX -DLUA_COMPATUPVALUES + +# ------------------------------------------------------------- Lua interpreter -# If you want support for pipes, uncomment the following line. -# You need popen in your C library. -#POPEN= -DPOPEN +# The stand-alone Lua interpreter needs the math functions, which are usually +# in libm.a (-lm). If your C library already includes the math functions, +# or if you are using a modified interpreter that does not need them, +# then comment the following line or add the appropriates libraries. +# +EXTRA_LIBS= -lm -# If you need compatibility with previous versions, edit and uncomment the -# definition of COMPAT below. -# Use -DLUA_COMPAT_READPATTERN if you need complex read patterns. -# Use -DLUA_COMPAT_ARGRET if you need the old semantics that used only the -# first value returned by a function when it is called as the last parameter. -# Use -DLUA_DEPRECATEDFUNCS if you need the obsolete functions in the standard -# Lua library (not recommended). -#COMPAT= -DLUA_COMPAT_READPATTERN -DLUA_COMPAT_ARGRET -DLUA_DEPRECATEDFUNCS +# If you want to customize the stand-alone Lua interpreter, uncomment and +# edit the following two lines; also edit etc/saconfig.c to suit your needs. +# -DUSE_READLINE adds line editing and history to the interpreter. You need +# to add -lreadline (and perhaps also -lhistory and -lcurses or -lncurses) +# to EXTRA_LIBS. +# +#USERCONF=-DLUA_USERCONFIG='"$(LUA)/etc/saconfig.c"' -DUSE_READLINE +#EXTRA_LIBS= -lm -ldl -lreadline # -lhistory -lcurses -lncurses # ------------------------------------------------------------------ C compiler -# You need an ANSI C compiler. gcc is a popular one. +# You need an ANSI C compiler. gcc is a popular one. We do not use -ansi in +# WARN because it disables POSIX features used in the libraries. +# CC= gcc -WARN= -ansi -pedantic -Wall - -# On IRIX, cc is a good ANSI compiler. -#CC= cc -#WARN= -ansi -fullwarn - -# On Solaris, cc is optional. You may have to add -Dsparc if you use -Xc. -#CC= cc -#WARN= -Xc # -Dsparc - -# ------------------------------------------------------------------ C library +WARN= -Wall -# If your C library is not POSIX compliant, comment the following line. -POSIX= -D_POSIX_SOURCE +# ------------------------------------------------------------------ C options -# If your C library does not have the newer ANSI functions strerror, strcoll, -# and locale support, uncomment the following line. SunOs 4.1.x is one example. -#OLD_ANSI= -DOLD_ANSI +# Write here any options you may need for your C compiler. +# If you are using gcc, -O3 will get you a faster but larger code. You can +# also add -fomit-frame-pointer to get even faster code at the cost of losing +# debug information. If you only want the shared libraries, you may want to +# add -fPIC to MYCFLAGS. +# +MYCFLAGS= -O2 +#MYCFLAGS= -O3 -fomit-frame-pointer # -fPIC -# In SunOs 4.1.x, standard headers in /usr/include are not ANSI, -# so uncomment the following line to avoid prototypes warnings. -#EXTRA_INCS= -I/usr/5include - -# The stand-alone Lua interpreter needs the math functions, which are usually -# in libm.a (-lm). If your C library already includes the math functions, -# or if you are using a modified interpreter that does not need them, -# then comment the following line. -EXTRA_LIBS= -lm +# Write here any options you may need for your C linker. +#MYLDFLAGS= # ------------------------------------------------------------------ librarian # This should work in all Unix systems. +# AR= ar rcu # If your system doesn't have (or need) ranlib, use RANLIB=true. # On some systems, "ar s" does what ranlib would do. +# RANLIB= ranlib #RANLIB= ar s #RANLIB= true +# ------------------------------------------------------------------ stripper + +# This should work in all Unix systems, but you may want to add options. +# +STRIP= strip + # ------------------------------------------------------------------ install # Locations for "make install". You may need to be root do "make install". +# INSTALL_ROOT= /usr/local INSTALL_BIN= $(INSTALL_ROOT)/bin INSTALL_INC= $(INSTALL_ROOT)/include INSTALL_LIB= $(INSTALL_ROOT)/lib INSTALL_MAN= $(INSTALL_ROOT)/man/man1 -# You might prefer to use "install" if you have it. +# You may prefer to use "install" instead of "cp" if you have it. +# If you use "install", you may also want to change the permissions after -m. +# INSTALL_EXEC= cp INSTALL_DATA= cp #INSTALL_EXEC= install -m 0755 #INSTALL_DATA= install -m 0644 -# == END OF USER SETTINGS. DO NOT CHANGE ANYTHING BELOW THIS LINE ============= +# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= + +V=5.0 BIN= $(LUA)/bin INC= $(LUA)/include LIB= $(LUA)/lib INCS= -I$(INC) $(EXTRA_INCS) -DEFS= $(COMPAT) $(NUMBER) $(OLD_ANSI) $(EXTRA_DEFS) - -CFLAGS= -O2 $(WARN) $(INCS) $(DEFS) +DEFS= $(NUMBER) $(EXTRA_DEFS) -V=4.0 +CFLAGS= $(MYCFLAGS) $(WARN) $(INCS) $(DEFS) # (end of config) diff --git a/configure b/configure new file mode 100755 index 0000000000..0aa89712fb --- /dev/null +++ b/configure @@ -0,0 +1,9 @@ +#!/bin/sh + +# Lua does not use GNU autoconf; just edit ./config if needed to suit your +# platform and then run make. + +# This shows the parameters currently set in ./config: +make echo + +# If you want config as a Lua program, run "make lecho". diff --git a/doc/idx.html b/doc/idx.html deleted file mode 100644 index 74693a564c..0000000000 --- a/doc/idx.html +++ /dev/null @@ -1,411 +0,0 @@ - - -Lua 4.0 Reference Manual - Word Index - - - - -
    -

    -Lua -Reference manual -- word index -

    - -..
    -_ALERT
    -_ERRORMESSAGE
    -_INPUT
    -_OUTPUT
    -_PROMPT
    -_STDERR
    -_STDIN
    -_STDOUT
    - -

    - -abs
    -acceptable index
    -acos
    -``add'' event
    -adjustment
    -alert
    -and
    -appendto
    -arg
    -arguments
    -arithmetic operators
    -arrays
    -asin
    -assert
    -assignment
    -associative arrays
    -atan
    -atan2
    - -

    - -basic expressions
    -basic types
    -block
    -break statement
    - -

    - -C API
    -....... LUA_ANYTAG
    -....... lua_baselibopen
    -....... lua_call
    -....... lua_CFunction
    -....... lua_close
    -....... lua_concat
    -....... lua_copytagmethods
    -....... lua_dblibopen
    -....... lua_Debug
    -....... lua_dobuffer
    -....... lua_dofile
    -....... lua_dostring
    -....... lua_equal
    -....... LUA_ERRERR
    -....... LUA_ERRFILE
    -....... LUA_ERRMEM
    -....... lua_error
    -....... LUA_ERRRUN
    -....... LUA_ERRSYNTAX
    -....... lua_getgccount
    -....... lua_getgcthreshold
    -....... lua_getglobal
    -....... lua_getglobals
    -....... lua_getinfo
    -....... lua_getlocal
    -....... lua_getn
    -....... lua_getref
    -....... lua_getregistry
    -....... lua_getstack
    -....... lua_gettable
    -....... lua_gettagmethod
    -....... lua_gettop
    -....... lua_Hook
    -....... lua_insert
    -....... lua_iolibopen
    -....... lua_iscfunction
    -....... lua_isfunction
    -....... lua_isnil
    -....... lua_isnumber
    -....... lua_isstring
    -....... lua_istable
    -....... lua_isuserdata
    -....... lua_lessthan
    -....... lua_mathlibopen
    -....... LUA_MINSTACK
    -....... LUA_MULTRET
    -....... lua_newtable
    -....... lua_newtag
    -....... lua_next
    -....... LUA_NOREF
    -....... lua_open
    -....... lua_pushcclosure
    -....... lua_pushcfunction
    -....... lua_pushlstring
    -....... lua_pushnil
    -....... lua_pushnumber
    -....... lua_pushstring
    -....... lua_pushuserdata
    -....... lua_pushusertag
    -....... lua_pushvalue
    -....... lua_rawcall
    -....... lua_rawget
    -....... lua_rawgeti
    -....... lua_rawset
    -....... lua_rawseti
    -....... lua_ref
    -....... LUA_REFNIL
    -....... LUA_REFREGISTRY
    -....... lua_register
    -....... lua_remove
    -....... lua_setcallhook
    -....... lua_setgcthreshold
    -....... lua_setglobal
    -....... lua_setglobals
    -....... lua_setlinehook
    -....... lua_setlocal
    -....... lua_settable
    -....... lua_settag
    -....... lua_settagmethod
    -....... lua_settop
    -....... lua_stackspace
    -....... lua_State
    -....... lua_strlen
    -....... lua_strlibopen
    -....... lua_tag
    -....... lua_tocfunction
    -....... lua_tonumber
    -....... lua_tostring
    -....... lua_touserdata
    -....... lua_type
    -....... lua_typename
    -....... lua_unref
    -C closure
    -C pointers
    -call
    -captures
    -ceil
    -character class
    -chunk
    -clock
    -closefile
    -closing a file
    -coercion
    -collectgarbage
    -comments
    -concatenation
    -``concatenation'' event
    -condition expression
    -constructors
    -copytagmethods
    -cos
    - -

    - -date
    -def
    -``div'' event
    -dofile
    -dostring
    - -

    - -eight-bit clean
    -error
    -event
    -execute
    -exit
    -exp
    -exponentiation
    -expressions
    - -

    - -file handles
    -floor
    -flush
    -for statement
    -foreach
    -foreachi
    -format
    -frexp
    -function
    -function call
    -function definitions
    -``function'' event
    - -

    - -``gc'' event
    -getargs
    -getenv
    -getglobal
    -``getglobal'' event
    -getinfo
    -getlocal
    -getn
    -``gettable'' event
    -gettagmethod
    -global environment
    -global variables
    -globals
    -grammar
    -....... args
    -....... binop
    -....... block
    -....... chunk
    -....... declist
    -....... exp
    -....... exp1
    -....... explist1
    -....... ffield
    -....... ffieldlist
    -....... ffieldlist1
    -....... fieldlist
    -....... funcname
    -....... function
    -....... functioncall
    -....... init
    -....... lfieldlist
    -....... lfieldlist1
    -....... parlist1
    -....... stat
    -....... tableconstructor
    -....... unop
    -....... upvalue
    -....... var
    -....... varlist1
    -....... varorfunc
    -gsub
    - -

    - -identifiers
    -if-then-else statement
    -``index'' event
    - -

    - -ldexp
    -literal strings
    -local variables
    -log
    -log10
    -logical operators
    -``lt'' event
    -Lua stand-alone
    -luac
    - -

    - -max
    -methods
    -min
    -mod
    -``mul'' event
    -multiple assignment
    - -

    - -newtag
    -next
    -nil
    -not
    -number
    -numerical constants
    - -

    - -openfile
    -operator precedence
    -or
    - -

    - -pattern
    -pattern item
    -PI
    -piped input
    -popen
    -``pow'' event
    -pre-compilation
    -print
    -protected calls
    - -

    - -rad
    -random
    -randomseed
    -rawget
    -rawset
    -read
    -readfrom
    -records
    -reference
    -relational operators
    -remove
    -rename
    -repeat-until statement
    -reserved words
    -return statement
    - -

    - -seek
    -self
    -setcallhook
    -setglobal
    -``setglobal'' event
    -setlinehook
    -setlocal
    -setlocale
    -``settable'' event
    -settag
    -settagmethod
    -short-cut evaluation
    -sin
    -sort
    -sqrt
    -stack index
    -state
    -statements
    -stderr
    -strbyte
    -strchar
    -strfind
    -string
    -strlen
    -strlower
    -strrep
    -strsub
    -strupper
    -``sub'' event
    - -

    - -table
    -tag
    -tag
    -tag method
    -....... add
    -....... concatenation
    -....... div
    -....... function
    -....... gc
    -....... getglobal
    -....... gettable
    -....... index
    -....... lt
    -....... mul
    -....... pow
    -....... setglobal
    -....... settable
    -....... sub
    -....... unm
    -tan
    -tinsert
    -tmpname
    -tokens
    -tonumber
    -tostring
    -tremove
    -type
    -types and tags
    - -

    - -``unm'' event
    -upvalues
    -userdata
    - -

    - -valid index
    -vararg function
    -version 3.2
    -visibility
    - -

    - -while-do statement
    -write
    -writeto
    - -

    - - -


    - -Last update: -Mon Nov 6 17:35:51 EDT 2000 -by lhf. - - - - diff --git a/doc/index.html b/doc/index.html deleted file mode 100644 index b7603a30a1..0000000000 --- a/doc/index.html +++ /dev/null @@ -1,93 +0,0 @@ - - -Lua: reference manual - contents - - - - -
    -

    -Lua -Reference manual -

    - - -Reference Manual of the Programming Language -Lua -4.0 -[ -top -| -index -| -ps -| -pdf -| -old versions -] -

    - -

    - -
    - -Last update: -Mon Nov 6 17:36:08 EDT 2000 -by lhf. - - - - diff --git a/doc/logo.gif b/doc/logo.gif index f3e68936b2dfa279f75f700f9756eb0849a69cc9..2f5e4ac2e742fbb7675e739879211553758aea9c 100644 GIT binary patch literal 4232 zcmeH``9G8i;K!fm@ywWE@XWZzZ5SF?A>^uN#>^O6HI%DVL*tw8h1>$H%uPC0$QQ=txe!o}PX)Ev+jn>*nFZ-TC=<^76WcLZL(=DJm)| zEiIKwrInSHXU?3duCC_u@5try#>U2`rlw1mF15F}U%!66tE;QKyIUmcDJ<+QF77*W zFJd#&)VAl)kJ6K zi<>tmZ{3>g>+2gB7#JQNe(>OdLh;A=`1q42PbMZNCMPF*dXxhLZw3aYhlZwyhu@Bj z%#4n{d-Q1b$&i4QMce4L#8^!oMdw{PDnm4D66&3*dxX=-YIX6DQL_g`jbzkd4k zZDCoLf=%jL&vIeE zO=XcZ9fxt`f}-DQ^%H*PHMUs(JN%UWkI|Y8h9#6~I$Cw@{RqzO4&P-x;jHCPJ6Ks2 zoU%foi)nXd_sdkiuJa@@5J4RrreKfWSnz5>eMa5yTP=)16uu)TIdx~Fhho))6jZl) z($*i>QrIX4u}u3>m{WSn_ehkUGQ& zs})aUlTH1Cj1g3ZE3=MPXsSniEwJ{e6C3N#HjD=B4`8rWIsz!a7ecYpec?WuH+y?Wsm18^$cS4WmHhH3_=r zh*ILlm*X1dB^E5($KVl&zT524%l}vpHg%;Y+LezV_&TAJCmH`idhuj-n$4FZ)UE|jXLayXa-&O3Q z?Iyo!x*$5hD_HfFnDfGYj-RD|eIb7I?%>Y_kf%}Nbd`BXb4l1(Pc+}zoUR|9%_!7f zum2T;wbx&pohtI+&@~wm3nH9xLbOYkg*`phY~TK5iC#3tZNXo9s`cahx+8j2)rh5C zQgZh6D7Ekgib|hpdhxYf{r!PTJc z!vsYG@{hA}l5kL)g)0N_)(nC<*L0qdUi*3fD5<0sn58>zklX@6Tyv3*X^}m=Cqc40 zQ6GfjG@kd1mFIm`qaubWunm_?P>WUZ`9|f_z%gGHi{n|uu(N8!L=aw5(qAcDj$-QK zu;D#j6e42OXTQD>)i zlvM$LX`$n9EEjxM$_QDF&a z7cme_rat}aXmiN&7`6Q98}dh4Z@8L_uAb#nK&GQiZOOUnA9kAEVb-csuN1AWL=sXt z{z9GCN%%l0N9QvJM;tl1nf?rrhT{*sE%4WqR?{0~aIrfCcCPxf4eh_*jjQ=`$p53Y z@_|Rsx2i}|3dNFetMQQ5y8agTK-E0D&7;@3-LUxfvZ7 z7~!p@&mFe^oca2^F|CBt+4Ly?^ViUVSAhAH>JH1GN{^TQb3QnM*x0ZiZgDyNI@_c3 z@{}(WH4*e3T~}n_^0}da4ElIxAf9B!IaL7z9X0Icvj@cIkE*~W--17&WN`Ea5)Gn> z#gpfRb#44;jVTOS{FuaZgd(-ZD848=fQzgST2MxR>wSLc1P=2HDvByz$B$IsNCC6L zCM?nK*OHj6JA9gz4|b<~2%RqelN^1Y)jIqnRs!mDKV^BQTfo@hOtz7*Ug}Ee^cbsj zNNlumRgAmt`1$b5MO;&X#5-EP<}AaY;52ihIpem&MTea$?3!DrwbYa?V`NjEfWF3z zUq5JY8Ch;L{kx&J<1K&Fe_Vn;8gk{%c;n?nA2(%(f%DCRHko3uT~VI7RE^JWEqaCq z)i|%nfj(*4|V*XhY3W%M# z*yn6SN4eUOHFxAD7B&9E_PO`G5bqgs^@J{9bk>&;PlUAiqo`j3rjQDgD!}mqLUtb` zCB}ZD@m@s#pf7bV4jreOC*JVfHZ|hyHkX!rauVdd_I9FL45d{gWH!DNYu;i(|8wVx z!)eLY6YXxZ2{Coae0xuTnxo1ACb5wtED?VJAz&@114$Ao6uG9YSy*!K;m5_mj=0^j zw%?b%AOs}ql@$TGC-!^^*_#RT5+y_kTzQG9?LPPZNAtt6cJ%d2$q(I)ws21*?xF%p zN+NeGnWRQ<5w70Rc(bl|S0Xr&5@WrmdurS|IgPB|EyuZO#=tf!35)G!HJ`E1jh^lH zTBu~rL#DhQO*XAWtBt}JHH$lc>3%r0yD|maW_(W=B_J+y164F>O4dO|@&@N3Z3p=B zmVl{|^Z&#atHY|9n&la)SBo}=3AFIF=_~LDJk6MTlA73CXtX+4bnn+c!}N}IPa5pp zwyqbqIkN|I3j_3vD6$zlu{Ps(N-J|*qzEt<$5Soh;s^AuKv_ z-Tz+O1_~6*9CJh4r}`}mbUtjbf#fX58RIIkP6&@*y9kI|5fK*_eZ%jv3U$5*x<>D_ za2M(TV8?XY+9xy>0En#Te<6X4$0&dbyd(go$~eq4u(u)EA2msyF<5ssLZ zDP|I}=~Bi_q)whWv=Ri~L1TYaNrR;5cMB@s78HF1{w&r(6GJ;_2@bD?#1p&P4n_?n0#9Vx~$qjMX=Lk?*!@aKo8m&$iPO7S{g3sFUwr`*<53(68xx7?z`2xf# zGSicy_zI(PJ|%qc2VxT+6bOE--a{k&aq7$<<= zFt)C<@|TPs`+eycPGoGL1Wn9|Ed&a2JyAmjnkm3DQBECX&`bt~odH9cUPq4M{#$-q?G3!)qO-it*&YHw+j-O* zYy78V*`4Q=kQ@^Yz*b6Tal4(Me7BGeS^;phWAW8+L^5A(=D)t?k!rLIwVAKtq=f7h z&^n&VX1-T$ScvN~639QLZ^d@niMaS{C-Q)8oHHBhwD*r~-1Ze#Q)GFOFptW32a-uF z;M@ux%i%a25NwIgXt*=GHX$3~aZfwovGL!}sf?j9TsVo^cn(%&a<--0mIXYqGe>c PWz_J}_#7St0k8iB@FZjZ delta 2114 zcmV-I2)*}+A-)xVM@dFFIbnbRfB^UZ0RR90jEszwl$4yDoTa6ut*x!KwY9yyz3=b$ zwY9z8-tVogz0S_(oSe12z220RwXLnzgoLe}oX&fDt&EJugoM3oYo%jjoO5%vV`HsS zQk+Uklu}ZqLPDH5Ig~Lmj4?5kAt8(y7=#cIga`m6FjhR;ev+`AaHu9IpKlJiXT=A9g6Y-%mW7^PB2Ndsne$_NlY-9AOuvEAYeN5 zaJB1G5C{N>9ZR+>00}ESXoYFjt6QQ9%*vfRwt~>CYa?=f%a`lpFtka(fD_0ayfZ>I^4j4F?PQAMIl_4aMMId2Bi44;jVEL0QoOfWf9t{Wu$KmqOJlO1lC7U|&-q zh+3R+$Ne}^qAS&Q8&nRAHC{@8zlDYpYP{VAm{>$fickSYPISNkX(E(Bpo(Ujk_bZ{ zB-xz~3Q#Sg+BTNKL#=@uq5 z06ymIy%u0uZb~E!de8$L6KSVIRo%>2#RMfVtWz6w8)5=B3r#`=%gUv|tS6D6bcn6B zTTqZft90w1X2q$}%L&y9af3&9T>=GQzlmxH3_WO3e+$K|c1lsVZPu?Sb^p+i)(g=M z<=sQ&t@mb5b&Qa5Yeh+aI8me>&cLTnDgIG}3Z*TSua9@CxmS2m=o(B=dGPAvjji=_ zVws)ZlqC6qc_CvLc9*exmU0otDXbg5fv=6PR(49;12Dsklnt!PE_#8 zrZfWEbS;bYes!KKPy|i=-WlRT9WU##W5HX(2xK*7rb3bd{t*X%(I0Mo)CxFY9s<~( z@7q`ifItN*Ac6fgifSj>K#0u75b&XnP49zWp-8l`2Rddd|ALVG2tq##LPddptJ1+1 z@VUo;rm zJRkxv+@eM-B!DAQ(Jeh~iU4gQ(6n96yiXCbC#e32bBv1Eb5eYegvBcspd*R z5FH0V>SiIJfZ@=?m%=23c?^LfLduyE(~-}tUJ(KAD%HBfBDO2=vExT9<=DqU<(fgH ztZm#vJ^xuxuXO3o?X)7;gBY={yUa?GX} zcC)~LTkT0=N35l?6(!o+op{v|Kj4nfz2s@F^~?(Z1UR4q92kN5+8P;D@@Rr_^{w=V;=2CXCj?`G z08y?>6u%~E_TyhRg?l zsu!Laf={!;IdI|{WJDssRn(Edt*qg)!PNP{oMEv-ieAVAtQ;T^WEapF%c(>bkO3*b zg-lMSlMMZf#RWtl10e8p2}A&b3`8K*Vr)&M6E;L9)(gM~li>`zxZN>|C_$Xu(StZb sYA+suVQb-W4SlUU8SYt>@>}*sFvM&TAVPZ}#};L=tIh3hYcU`IJ5au%d;kCd diff --git a/doc/lua.1 b/doc/lua.1 index b156181852..c9bba7d700 100644 --- a/doc/lua.1 +++ b/doc/lua.1 @@ -1,137 +1,161 @@ -.\" lua.man,v 1.3 2000/09/04 21:41:28 lhf Exp -.TH LUA 1 "2000/09/04 21:41:28" +.\" lua.man,v 1.8 2003/04/02 00:05:20 lhf Exp +.TH LUA 1 "2003/04/02 00:05:20" .SH NAME lua \- Lua interpreter .SH SYNOPSIS .B lua [ -.I arguments +.I options +] +[ +.I script +[ +.I args +] ] .SH DESCRIPTION .B lua is the stand-alone Lua interpreter. It loads and executes Lua programs, either in textual source form or -in precompiled binary form, -as output by +in precompiled binary form. +(Precompiled binaries are output by .BR luac , -the Lua compiler. +the Lua compiler.) .B lua can be used as a batch interpreter and also interactively. .LP -The -.I arguments -can be options, assignments, or filenames, -and are processed in order, -from left to right. +The given +.I options +(see below) +are executed and then +the Lua program in file +.I script +is loaded and executed. +The given +.I args +are available to +.I script +as strings in a global table named +.BR arg . +If these arguments contain spaces or other characters special to the shell, +then they should be quoted +(but note that the quotes will be removed by the shell). +The arguments in +.B arg +start at 0, +which contains the string +.RI ` script '. +The index of the last argument is stored in +.BR "arg.n" . +The arguments given in the command line before +.IR script , +including the name of the interpreter, +are available in negative indices in +.BR arg . +.LP +At the very start, +before even handling the command line, +.B lua +executes the contents of the environment variable +.BR LUA_INIT , +if it is defined. +If the value of +.B LUA_INIT +is of the form +.RI `@ filename ', +then +.I filename +is executed. +Otherwise, the string is assumed to be a Lua statement and is executed. .LP Options start with .B \- and are described below. -.LP -An assignment is an argument of the form -.BR a=b , -which assigns the string -.RB ` b ' -to the global variable -.BR a . -Note that no quotes are needed around the string if it does not contain spaces -or other characters special to the shell. -This is for convenience only. -(In general, -you should be careful when using quotes and spaces on the command line -because they are usually handled by the shell.) -.LP -If the argument is neither an option nor an assignment, -then it is assumed to be a filename, -which is then loaded and executed. +You can use +.B "\--" +to signal the end of options. .LP If no arguments are given, then .B "\-v \-i" is assumed when the standard input is a terminal; otherwise, -.B \- +.B "\-" is assumed. +.LP +In interactive mode, +.B lua +prompts the user, +reads lines from the standard input, +and executes them as they are read. +If a line does not contain a complete statement, +then a secondary prompt is displayed and +lines are read until a complete statement is formed or +a syntax error is found. +So, one way to interrupt the reading of an incomplete statement is +to force a syntax error: +adding a +.B `;' +in the middle of a statement is a sure way of forcing a syntax error +(except inside multiline strings and comments; these must be closed explicitly). +If a line starts with +.BR `=' , +then +.B lua +displays the values of all the expressions in the remainder of the +line. The expressions must be separated by commas. +The primary prompt is the value of the global variable +.BR _PROMPT , +if this value is a string; +otherwise, the default prompt is used. +Similarly, the secondary prompt is the value of the global variable +.BR _PROMPT2 . +So, +to change the prompts, +set the corresponding variable to a string of your choice. +You can do that after calling the interpreter +or on the command line with +.BR "_PROMPT" "=\'lua: \'" , +for example. +(Note the need for quotes, because the string contains a space.) +The default prompts are ``> '' and ``>> ''. .SH OPTIONS .TP .B \- -load the standard input as a file, +load and execute the standard input as a file, that is, not interactively, even when the standard input is a terminal. .TP -.B \-c -close Lua before exiting. -.TP .BI \-e " stat" execute statement .IR stat . -You will need to quote +You need to quote .I stat -if it contains spaces or quotes. -.TP -.BI \-f " file" -collect all remaining arguments as strings into a global table named -.B arg -and then execute -.IR file . -The arguments in -.B arg -start at 0, -which contains the string -.RI ` file '. -The index of the last argument is stored in -.BR "arg.n" . +if it contains spaces, quotes, +or other characters special to the shell. .TP .B \-i -enter interactive mode, -displaying a prompt. -In this mode, -.B lua -reads lines from the standard input and executes them as they are read. -Each line must contain a complete statement. -To span a statement across several lines, end each line with a backslash -.BR `\e' . -The prompt shown is the value of the global variable -.BR _PROMPT , -if this value is a string. -So, -to change the prompt, -set -.B _PROMPT -to a string of your choice. -You can do that after calling the interpreter -or on the command line with -.BR "_PROMPT=\'lua: \'" , -for example. -(Note the need for quotes, because the string contains a space.) -The default prompt is ``> ''. -.TP -.B \-q -enter interactive mode, -but without displaying a prompt. +enter interactive mode after +.I script +is executed. .TP -.BI \-s n -set the stack size to -.IB n . -If present, -this must be the first option. -Note that -.I n -is in the same argument as -.BR -s . -For example, -to specify a stack size of 2000, -use -.BR -s2000 . +.BI \-l " file" +call +.BI require( file ) +before executing +.IR script. +Typically used to load libraries +(hence the letter +.IR l ). .TP .B \-v -print version information. +show version information. .SH "SEE ALSO" .BR luac (1) .br -http://www.tecgraf.puc-rio.br/lua/ +http://www.lua.org/ .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS diff --git a/doc/lua.html b/doc/lua.html index ef861bb54b..073d4b525a 100644 --- a/doc/lua.html +++ b/doc/lua.html @@ -1,4 +1,4 @@ - + LUA man page @@ -11,133 +11,157 @@

    NAME

    SYNOPSIS

    lua [ -arguments +options +] +[ +script +[ +args +] ]

    DESCRIPTION

    lua is the stand-alone Lua interpreter. It loads and executes Lua programs, either in textual source form or -in precompiled binary form, -as output by +in precompiled binary form. +(Precompiled binaries are output by luac, -the Lua compiler. +the Lua compiler.) lua can be used as a batch interpreter and also interactively.

    -The -arguments -can be options, assignments, or filenames, -and are processed in order, -from left to right. +The given +options +(see below) +are executed and then +the Lua program in file +script +is loaded and executed. +The given +args +are available to +script +as strings in a global table named +arg. +If these arguments contain spaces or other characters special to the shell, +then they should be quoted +(but note that the quotes will be removed by the shell). +The arguments in +arg +start at 0, +which contains the string +`script'. +The index of the last argument is stored in +"arg.n". +The arguments given in the command line before +script, +including the name of the interpreter, +are available in negative indices in +arg. +

    +At the very start, +before even handling the command line, +lua +executes the contents of the environment variable +LUA_INIT, +if it is defined. +If the value of +LUA_INIT +is of the form +`@filename', +then +filename +is executed. +Otherwise, the string is assumed to be a Lua statement and is executed.

    Options start with - and are described below. -

    -An assignment is an argument of the form -a=b, -which assigns the string -.RB ` b ' -to the global variable -a. -Note that no quotes are needed around the string if it does not contain spaces -or other characters special to the shell. -This is for convenience only. -(In general, -you should be careful when using quotes and spaces on the command line -because they are usually handled by the shell.) -

    -If the argument is neither an option nor an assignment, -then it is assumed to be a filename, -which is then loaded and executed. +You can use +"--" +to signal the end of options.

    If no arguments are given, then "-v -i" is assumed when the standard input is a terminal; otherwise, -- +"-" is assumed. +

    +In interactive mode, +lua +prompts the user, +reads lines from the standard input, +and executes them as they are read. +If a line does not contain a complete statement, +then a secondary prompt is displayed and +lines are read until a complete statement is formed or +a syntax error is found. +So, one way to interrupt the reading of an incomplete statement is +to force a syntax error: +adding a +`;' +in the middle of a statement is a sure way of forcing a syntax error +(except inside multiline strings and comments; these must be closed explicitly). +If a line starts with +`=', +then +lua +displays the values of all the expressions in the remainder of the +line. The expressions must be separated by commas. +The primary prompt is the value of the global variable +_PROMPT, +if this value is a string; +otherwise, the default prompt is used. +Similarly, the secondary prompt is the value of the global variable +_PROMPT2. +So, +to change the prompts, +set the corresponding variable to a string of your choice. +You can do that after calling the interpreter +or on the command line with +"_PROMPT" "=\'lua: \'", +for example. +(Note the need for quotes, because the string contains a space.) +The default prompts are ``> '' and ``>> ''.

    OPTIONS

    - -load the standard input as a file, +load and execute the standard input as a file, that is, not interactively, even when the standard input is a terminal.

    --c -close Lua before exiting. -

    -e "stat" execute statement stat. -You will need to quote +You need to quote stat -if it contains spaces or quotes. -

    --f "file" -collect all remaining arguments as strings into a global table named -arg -and then execute -file. -The arguments in -arg -start at 0, -which contains the string -.RI ` file '. -The index of the last argument is stored in -"arg.n". +if it contains spaces, quotes, +or other characters special to the shell.

    -i -enter interactive mode, -displaying a prompt. -In this mode, -lua -reads lines from the standard input and executes them as they are read. -Each line must contain a complete statement. -To span a statement across several lines, end each line with a backslash -`\e'. -The prompt shown is the value of the global variable -_PROMPT, -if this value is a string. -So, -to change the prompt, -set -_PROMPT -to a string of your choice. -You can do that after calling the interpreter -or on the command line with -"_PROMPT=\'lua: \'", -for example. -(Note the need for quotes, because the string contains a space.) -The default prompt is ``> ''. -

    --q -enter interactive mode, -but without displaying a prompt. +enter interactive mode after +script +is executed.

    --sn -set the stack size to -.IB n . -If present, -this must be the first option. -Note that -n -is in the same argument as --s. -For example, -to specify a stack size of 2000, -use --s2000. +-l "file" +call +require( file) +before executing +script. +Typically used to load libraries +(hence the letter +l).

    -v -print version information. +show version information.

    SEE ALSO

    luac(1)
    -http://www.tecgraf.puc-rio.br/lua/ +http://www.lua.org/

    DIAGNOSTICS

    Error messages should be self explanatory.

    AUTHORS

    @@ -145,7 +169,7 @@

    AUTHORS

    L. H. de Figueiredo, and W. Celes -(lua@tecgraf.puc-rio.br) +(lua AT tecgraf.puc-rio.br) diff --git a/doc/luac.1 b/doc/luac.1 index 212f9b61c6..c6523060f8 100644 --- a/doc/luac.1 +++ b/doc/luac.1 @@ -1,5 +1,5 @@ -.\" luac.man,v 1.20 2000/10/06 15:11:21 lhf Exp -.TH LUAC 1 "2000/10/06 15:11:21" +.\" luac.man,v 1.25 2002/12/13 11:45:12 lhf Exp +.TH LUAC 1 "2002/12/13 11:45:12" .SH NAME luac \- Lua compiler .SH SYNOPSIS @@ -13,17 +13,13 @@ luac \- Lua compiler .B luac is the Lua compiler. It translates programs written in the Lua programming language -into binary files that can be loaded and executed with -.B lua_dofile -in C or with -.B dofile -in Lua. +into binary files that can be latter loaded and executed. .LP The main advantages of precompiling chunks are: faster loading, protecting source code from user changes, and -off-line syntax error detection. +off-line syntax checking. .LP Pre-compiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. @@ -46,9 +42,10 @@ are portable to all architectures with the same word size. This means that binary files created on a 32-bit platform (such as Intel) can be read without change in another 32-bit platform (such as Sparc), -even if the byte order (``endianess'') is different. +even if the byte order (``endianness'') is different. On the other hand, -binary files created on a 16-bit platform cannot be read in a 32-bit platform. +binary files created on a 16-bit platform cannot be read in a 32-bit platform, +nor vice-versa. .LP In the command line, you can mix @@ -60,15 +57,17 @@ into a single precompiled chunk. .LP You can use .B "\-" -to indicate -.I stdin -as a source file. +to indicate the standard input as a source file +and +.B "\--" +to signal the end of options +(that is, +all remaining arguments will be treated as files even if they start with +.BR "\-" ). .LP The internal format of the binary files produced by .B luac -may change when a new version of Lua is released. -We try to maintain compatibility even for binary files, -but it is not always possible. +is likely to change when a new version of Lua is released. So, save the source files of all Lua programs that you precompile. .LP @@ -89,26 +88,16 @@ output to .IR file , instead of the default .BR luac.out . -The output file can be a source file because +The output file may be a source file because all files are loaded before the output file is written. +Be careful not to overwrite precious files. .TP .B \-p load files but do not generate any output file. -Used mainly for syntax checking or testing precompiled chunks: +Used mainly for syntax checking and for testing precompiled chunks: corrupted files will probably generate errors when loaded. -For a thourough integrity test, -use -.BR \-t . -.TP -.B \-s -strip debug information before writing the output file. -This saves some space in very large chunks, -but if errors occur when running these chunks, -then the error messages might not contain the full information they usually do. -.TP -.B \-t -perform a thourough integrity test of precompiled chunks. -Code that passes this test is completely safe, +Lua always performs a thorough integrity test on precompiled chunks. +Bytecode that passes this test is completely safe, in the sense that it will not break the interpreter. However, there is no guarantee that such code does anything sensible. @@ -118,9 +107,17 @@ If no files are given, then loads .B luac.out and tests its contents. +No messages are displayed if the file passes the integrity test. +.TP +.B \-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running these chunks, +then the error messages may not contain the full information they usually do +(line numbers and names of locals are lost). .TP .B \-v -print version information. +show version information. .SH FILES .TP 15 .B luac.out @@ -128,7 +125,7 @@ default output file .SH "SEE ALSO" .BR lua (1) .br -http://www.tecgraf.puc-rio.br/lua/ +http://www.lua.org/ .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS diff --git a/doc/luac.html b/doc/luac.html index e083c2b39a..3a71622e0b 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -1,4 +1,4 @@ - + LUAC man page @@ -19,17 +19,13 @@

    DESCRIPTION

    luac is the Lua compiler. It translates programs written in the Lua programming language -into binary files that can be loaded and executed with -lua_dofile -in C or with -dofile -in Lua. +into binary files that can be latter loaded and executed.

    The main advantages of precompiling chunks are: faster loading, protecting source code from user changes, and -off-line syntax error detection. +off-line syntax checking.

    Pre-compiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. @@ -52,9 +48,10 @@

    DESCRIPTION

    This means that binary files created on a 32-bit platform (such as Intel) can be read without change in another 32-bit platform (such as Sparc), -even if the byte order (``endianess'') is different. +even if the byte order (``endianness'') is different. On the other hand, -binary files created on a 16-bit platform cannot be read in a 32-bit platform. +binary files created on a 16-bit platform cannot be read in a 32-bit platform, +nor vice-versa.

    In the command line, you can mix @@ -66,15 +63,17 @@

    DESCRIPTION

    You can use "-" -to indicate -stdin -as a source file. +to indicate the standard input as a source file +and +"--" +to signal the end of options +(that is, +all remaining arguments will be treated as files even if they start with +"-").

    The internal format of the binary files produced by luac -may change when a new version of Lua is released. -We try to maintain compatibility even for binary files, -but it is not always possible. +is likely to change when a new version of Lua is released. So, save the source files of all Lua programs that you precompile.

    @@ -95,26 +94,16 @@

    OPTIONS

    file, instead of the default luac.out. -The output file can be a source file because +The output file may be a source file because all files are loaded before the output file is written. +Be careful not to overwrite precious files.

    -p load files but do not generate any output file. -Used mainly for syntax checking or testing precompiled chunks: +Used mainly for syntax checking and for testing precompiled chunks: corrupted files will probably generate errors when loaded. -For a thourough integrity test, -use --t. -

    --s -strip debug information before writing the output file. -This saves some space in very large chunks, -but if errors occur when running these chunks, -then the error messages might not contain the full information they usually do. -

    --t -perform a thourough integrity test of precompiled chunks. -Code that passes this test is completely safe, +Lua always performs a thorough integrity test on precompiled chunks. +Bytecode that passes this test is completely safe, in the sense that it will not break the interpreter. However, there is no guarantee that such code does anything sensible. @@ -124,9 +113,17 @@

    OPTIONS

    loads luac.out and tests its contents. +No messages are displayed if the file passes the integrity test. +

    +-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running these chunks, +then the error messages may not contain the full information they usually do +(line numbers and names of locals are lost).

    -v -print version information. +show version information.

    FILES

    luac.out @@ -134,14 +131,14 @@

    FILES

    SEE ALSO

    lua(1)
    -http://www.tecgraf.puc-rio.br/lua/ +http://www.lua.org/

    DIAGNOSTICS

    Error messages should be self explanatory.

    AUTHORS

    L. H. de Figueiredo, R. Ierusalimschy and W. Celes -(lua@tecgraf.puc-rio.br) +(lua AT tecgraf.puc-rio.br) diff --git a/doc/manual.html b/doc/manual.html index 703bd16557..17a932f298 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,948 +1,1025 @@ - - -Lua: reference manual 4.0 - - - - -
    -

    -Lua -Reference Manual of the Programming Language -Lua -4.0 -

    - - -

    -

    + + + + +Lua 5.0 Reference Manual + + + + +


    +

    + +[Lua logo] + +Lua 5.0 Reference Manual +

    + +by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes +

    + +Copyright +© 2003 TeCGraf, PUC-Rio. All rights reserved. + +


    + +

    +

    -


    - -

    1 - Introduction

    -

    -Lua is an extension programming language designed to support + + + +

    1 - Introduction

    + +

    Lua is an extension programming language designed to support general procedural programming with data description facilities. +It also offers good suport for object-oriented programming, +functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight configuration language for any program that needs one. -

    -Lua is implemented as a library, written in C. -Being an extension language, Lua has no notion of a ``main'' program: -it only works embedded in a host client, -called the embedding program. -This host program can invoke functions to execute a piece of -code in Lua, can write and read Lua variables, +Lua is implemented as a library, written in clean C +(that is, in the common subset of ANSI C and C++). + +

    Being an extension language, Lua has no notion of a "main" program: +it only works embedded in a host client, +called the embedding program or simply the host. +This host program can invoke functions to execute a piece of Lua code, +can write and read Lua variables, and can register C functions to be called by Lua code. Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. -

    -Lua is free-distribution software, + +

    The Lua distribuition includes a stand-alone embedding program, +lua, that uses the Lua library to offer a complete Lua interpreter. + +

    Lua is free software, and is provided as usual with no guarantees, as stated in its copyright notice. The implementation described in this manual is available -at the following URL's: -

    -       http://www.tecgraf.puc-rio.br/lua/
    -       ftp://ftp.tecgraf.puc-rio.br/pub/lua/
    -
    -

    -Like any other reference manual, +at Lua's official web site, www.lua.org. + +

    Like any other reference manual, this document is dry in places. For a discussion of the decisions behind the design of Lua, see the papers below, -which are available at the web site above. -

      -
    • +which are available at Lua's web site. +
        +
      • R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. -Lua-an extensible extension language. -Software: Practice & Experience 26 #6 (1996) 635--652. -
      • +Lua---an extensible extension language. +Software: Practice & Experience 26 #6 (1996) 635-652. +
      • L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. The design and implementation of a language for extending applications. -Proceedings of XXI Brazilian Seminar on Software and Hardware (1994) 273--283. -
      • +Proceedings of XXI Brazilian Seminar on Software and Hardware (1994) 273-283. +
      • L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. Lua: an extensible embedded language. -Dr. Dobb's Journal 21 #12 (Dec 1996) 26--33. -
      -

      - -


      - -

      2 - Environment and Chunks

      -

      -All statements in Lua are executed in a global environment. -This environment is initialized with a call from the embedding program to -lua_open and -persists until a call to lua_close, -or the end of the embedding program. -If necessary, -the host programmer can create multiple independent global -environments, and freely switch between them (see Section 5.1). -

      -The global environment can be manipulated by Lua code or -by the embedding program, -which can read and write global variables -using API functions from the library that implements Lua. -

      -Global variables in Lua do not need to be declared. -Any variable is assumed to be global unless explicitly declared local -(see Section 4.4.6). -Before the first assignment, the value of a global variable is nil -(this default can be changed; see Section 4.8). -A table is used to keep all global names and values -(tables are explained in Section 3). -

      -The unit of execution of Lua is called a chunk. -A chunk is simply a sequence of statements, -which are executed sequentially. -Each statement can be optionally followed by a semicolon: -

      -       chunk ::= {stat [`;']}
      -
      -Statements are described in Section 4.4. -(The notation above is the usual extended BNF, +Dr. Dobb's Journal 21 #12 (Dec 1996) 26-33. +
    • +R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. +The evolution of an extension language: a history of Lua, +Proceedings of V Brazilian Symposium on Programming Languages (2001) B-14-B-28. +
    + +

    Lua means "moon" in Portuguese and is pronounced LOO-ah. + +

    +

    2 - The Language

    + +

    This section describes the lexis, the syntax, and the semantics of Lua. +In other words, +this section describes +which tokens are valid, +how they can be combined, +and what their combinations mean. + +

    The language constructs will be explained using the usual extended BNF, in which -{a} means 0 or more a's, -[a] means an optional a, and -(a)+ means one or more a's. -The complete syntax of Lua is given in BNF). -

    -A chunk may be stored in a file or in a string inside the host program. -When a chunk is executed, first it is pre-compiled into bytecodes for -a virtual machine, and then the statements are executed in sequential order, -by simulating the virtual machine. -All modifications a chunk effects on the global environment persist -after the chunk ends. -

    -Chunks may also be pre-compiled into binary form and stored in files; -see program luac for details. -Text files with chunks and their binary pre-compiled forms -are interchangeable. -Lua automatically detects the file type and acts accordingly. - -

    - - -


    - -

    3 - Types and Tags

    -

    -Lua is a dynamically typed language. -This means that -variables do not have types; only values do. -Therefore, there are no type definitions in the language. -All values carry their own type. -Besides a type, all values also have a tag. -

    -There are six basic types in Lua: nil, number, -string, function, userdata, and table. -Nil is the type of the value nil, -whose main property is to be different from any other value. -Number represents real (double-precision floating-point) numbers, -while string has the usual meaning. - -Lua is 8-bit clean, -and so strings may contain any 8-bit character, -including embedded zeros ('\0') (see Section 4.1). -The type function returns a string describing the type -of a given value (see Section 6.1). -

    -Functions are considered first-class values in Lua. -This means that functions can be stored in variables, -passed as arguments to other functions, and returned as results. -Lua can call (and manipulate) functions written in Lua and -functions written in C. -The two kinds of functions can be distinguished by their tags: -all Lua functions have the same tag, -and all C functions have the same tag, -which is different from the tag of Lua functions. -The tag function returns the tag -of a given value (see Section 6.1). -

    -The type userdata is provided to allow -arbitrary C pointers to be stored in Lua variables. -This type corresponds to a void* -and has no pre-defined operations in Lua, -except assignment and equality test. -However, by using tag methods, -the programmer can define operations for userdata values -(see Section 4.8). -

    -The type table implements associative arrays, -that is, arrays that can be indexed not only with numbers, -but with any value (except nil). -Therefore, this type may be used not only to represent ordinary arrays, -but also symbol tables, sets, records, graphs, trees, etc. -Tables are the main data structuring mechanism in Lua. -To represent records, Lua uses the field name as an index. -The language supports this representation by -providing a.name as syntactic sugar for a["name"]. -Tables may also carry methods: -Because functions are first class values, -table fields may contain functions. -The form t:f(x) is syntactic sugar for t.f(t,x), -which calls the method f from the table t passing -the table itself as the first parameter (see Section 4.5.9). -

    -Note that tables are objects, and not values. -Variables do not contain tables, only references to them. -Assignment, parameter passing, and returns always manipulate references -to tables, and do not imply any kind of copy. -Moreover, tables must be explicitly created before used -(see Section 4.5.7). -

    -Each of the types nil, number, and string has a different tag. -All values of each of these types have the same pre-defined tag. -As explained above, -values of type function can have two different tags, -depending on whether they are Lua functions or C functions. -Finally, -values of type userdata and table can have variable tags, -assigned by the programmer (see Section 4.8). -The tag function returns the tag of a given value. -User tags are created with the function newtag. -The settag function -is used to change the tag of a table (see Section 6.1). -The tag of userdata values can only be set from C (see Section 5.7). -Tags are mainly used to select tag methods when -some events occur. -Tag methods are the main mechanism for extending the -semantics of Lua (see Section 4.8). -

    - -


    - -

    4 - The Language

    -

    -This section describes the lexis, the syntax, and the semantics of Lua. -

    -

    - - -

    4.1 - Lexical Conventions

    -

    -Identifiers in Lua can be any string of letters, +{a} means 0 or more a's, and +[a] means an optional a. +Non-terminals are shown in italics, +keywords are shown in bold, +and other terminal symbols are shown in typewriter font, +enclosed in single quotes. + +

    2.1 - Lexical Conventions

    + +

    Identifiers in Lua can be any string of letters, digits, and underscores, not beginning with a digit. -This coincides with the definition of identifiers in most languages, -except that -the definition of letter depends on the current locale: -Any character considered alphabetic by the current locale -can be used in an identifier. -The following words are reserved, and cannot be used as identifiers: - +This coincides with the definition of identifiers in most languages. +(The definition of letter depends on the current locale: +any character considered alphabetic by the current locale +can be used in an identifier.) + +

    The following keywords are reserved +and cannot be used as identifiers: +

            and       break     do        else      elseif
    -       end       for       function  if        in
    -       local     nil       not       or        repeat
    -       return    then      until     while
    -
    -

    -Lua is a case-sensitive language: -and is a reserved word, but And and ánd -(if the locale permits) are two different, valid identifiers. -As a convention, identifiers starting with underscore followed by -uppercase letters (such as _INPUT) -are reserved for internal variables. -

    -The following strings denote other tokens: -

    -       ~=    <=    >=    <     >     ==    =     +     -     *     /     
    -       (     )     {     }     [     ]     ;     ,     .     ..    ...
    -
    -

    -Literal strings + end false for function if + in local nil not or + repeat return then true until + while +

  • + +

    Lua is a case-sensitive language: +and is a reserved word, but And and AND +are two different, valid identifiers. +As a convention, identifiers starting with an underscore followed by +uppercase letters (such as _VERSION) +are reserved for internal variables used by Lua. + +

    The following strings denote other tokens: +

    +       +     -     *     /     ^     =
    +       ~=    <=    >=    <     >     ==
    +       (     )     {     }     [     ]
    +       ;     :     ,     .     ..    ...
    +
    + +

    Literal strings can be delimited by matching single or double quotes, -and can contain the C-like escape sequences -`\a' (bell), -`\b' (backspace), -`\f' (form feed), -`\n' (newline), -`\r' (carriage return), -`\t' (horizontal tab), -`\v' (vertical tab), -`\\' (backslash), -`\"' (double quote), -`\'' (single quote), -and `\newline' (that is, a backslash followed by a real newline, -which results in a newline in the string). -A character in a string may also be specified by its numerical value, -through the escape sequence `\ddd', -where ddd is a sequence of up to three decimal digits. +and can contain the following C-like escape sequences: +

      +
    • \a --- bell +
    • \b --- backspace +
    • \f --- form feed +
    • \n --- newline +
    • \r --- carriage return +
    • \t --- horizontal tab +
    • \v --- vertical tab +
    • \\ --- backslash +
    • \" --- quotation mark +
    • \' --- apostrophe +
    • \[ --- left square bracket +
    • \] --- right square bracket +
    +Moreover, a `\newline´ +(that is, a backslash followed by a real newline) +results in a newline in the string. +A character in a string may also be specified by its numerical value +using the escape sequence `\ddd´, +where ddd is a sequence of up to three decimal digits. Strings in Lua may contain any 8-bit value, including embedded zeros, -which can be specified as `\000'. -

    -Literal strings can also be delimited by matching [[ ... ]]. +which can be specified as `\0´. + +

    Literal strings can also be delimited by matching double square brackets +[[ · · · ]]. Literals in this bracketed form may run for several lines, -may contain nested [[ ... ]] pairs, -and do not interpret escape sequences. -This form is specially convenient for -writing strings that contain program pieces or -other quoted strings. -As an example, in a system using ASCII, -the following three literals are equivalent: -

    -       1)   "alo\n123\""
    -       2)   '\97lo\10\04923"'
    -       3)   [[alo
    +may contain nested [[ · · · ]] pairs,
    +and do not interpret any escape sequences.
    +For convenience,
    +when the opening `[[´ is immediately followed by a newline,
    +the newline is not included in the string.  
    +As an example, in a system using ASCII
    +(in which `a´ is coded as 97,
    +newline is coded as 10, and `1´ is coded as 49),
    +the four literals below denote the same string:
    +
    +      (1)   "alo\n123\""
    +      (2)   '\97lo\10\04923"'
    +      (3)   [[alo
    +            123"]]
    +      (4)   [[
    +            alo
                 123"]]
     
    -

    -Comments start anywhere outside a string with a -double hyphen (--) and run until the end of the line. -Moreover, -the first line of a chunk is skipped if it starts with #. -This facility allows the use of Lua as a script interpreter -in Unix systems (see Section 8). -

    -Numerical constants may be written with an optional decimal part + +

    Numerical constants may be written with an optional decimal part and an optional decimal exponent. Examples of valid numerical constants are

            3     3.0     3.1416  314.16e-2   0.31416E1
     
    -

    - - -

    4.2 - Coercion

    -

    -Lua provides some automatic conversions between values at run time. + +

    Comments start anywhere outside a string with a +double hyphen (--). +If the text immediately after -- is different from [[, +the comment is a short comment, +which runs until the end of the line. +Otherwise, it is a long comment, +which runs until the corresponding ]]. +Long comments may run for several lines +and may contain nested [[ · · · ]] pairs. + +

    For convenience, +the first line of a chunk is skipped if it starts with #. +This facility allows the use of Lua as a script interpreter +in Unix systems (see 6). + +

    2.2 - Values and Types

    + +

    Lua is a dynamically typed language. +That means that +variables do not have types; only values do. +There are no type definitions in the language. +All values carry their own type. + +

    There are eight basic types in Lua: +nil, boolean, number, +string, function, userdata, thread, and table. +Nil is the type of the value nil, +whose main property is to be different from any other value; +usually it represents the absence of a useful value. +Boolean is the type of the values false and true. +In Lua, both nil and false make a condition false; +any other value makes it true. +Number represents real (double-precision floating-point) numbers. +(It is easy to build Lua interpreters that use other +internal representations for numbers, +such as single-precision float or long integers.) +String represents arrays of characters. + +Lua is 8-bit clean: +Strings may contain any 8-bit character, +including embedded zeros ('\0') (see 2.1). + +

    Functions are first-class values in Lua. +That means that functions can be stored in variables, +passed as arguments to other functions, and returned as results. +Lua can call (and manipulate) functions written in Lua and +functions written in C +(see 2.5.7). + +

    The type userdata is provided to allow arbitrary C data to +be stored in Lua variables. +This type corresponds to a block of raw memory +and has no pre-defined operations in Lua, +except assignment and identity test. +However, by using metatables, +the programmer can define operations for userdata values +(see 2.8). +Userdata values cannot be created or modified in Lua, +only through the C API. +This guarantees the integrity of data owned by the host program. + +

    The type thread represents independent threads of execution +and it is used to implement coroutines. + +

    The type table implements associative arrays, +that is, arrays that can be indexed not only with numbers, +but with any value (except nil). +Moreover, +tables can be heterogeneous, +that is, they can contain values of all types (except nil). +Tables are the sole data structuring mechanism in Lua; +they may be used to represent ordinary arrays, +symbol tables, sets, records, graphs, trees, etc. +To represent records, Lua uses the field name as an index. +The language supports this representation by +providing a.name as syntactic sugar for a["name"]. +There are several convenient ways to create tables in Lua +(see 2.5.6). + +

    Like indices, +the value of a table field can be of any type (except nil). +In particular, +because functions are first class values, +table fields may contain functions. +Thus tables may also carry methods (see 2.5.8). + +

    Tables, functions, and userdata values are objects: +variables do not actually contain these values, +only references to them. +Assignment, parameter passing, and function returns +always manipulate references to such values; +these operations do not imply any kind of copy. + +

    The library function type returns a string describing the type +of a given value (see 5.1). + +

    2.2.1 - Coercion

    + +

    Lua provides automatic conversion between +string and number values at run time. Any arithmetic operation applied to a string tries to convert that string to a number, following the usual rules. -Conversely, whenever a number is used when a string is expected, -that number is converted to a string, in a reasonable format. -The format is chosen so that -a conversion from number to string then back to number -reproduces the original number exactly. -Thus, -the conversion does not necessarily produces nice-looking text for some numbers. +Conversely, whenever a number is used where a string is expected, +the number is converted to a string, in a reasonable format. For complete control of how numbers are converted to strings, -use the format function (see Section 6.2). -

    -

    - - -

    4.3 - Adjustment

    -

    -Functions in Lua can return many values. -Because there are no type declarations, -when a function is called -the system does not know how many values the function will return, -or how many parameters it needs. -Therefore, sometimes, a list of values must be adjusted, at run time, -to a given length. -If there are more values than are needed, -then the excess values are thrown away. -If there are less values than are needed, -then the list is extended with as many nil's as needed. -This adjustment occurs in multiple assignments (see Section 4.4.2) -and in function calls (see Section 4.5.8). -

    -

    - - -

    4.4 - Statements

    -

    -Lua supports an almost conventional set of statements, -similar to those in Pascal or C. -The conventional commands include -assignment, control structures, and procedure calls. -Non-conventional commands include table constructors -(see Section 4.5.7) -and local variable declarations (see Section 4.4.6). -

    -

    4.4.1 - Blocks

    -A block is a list of statements; -syntactically, a block is equal to a chunk: -
    -       block ::= chunk
    -
    -

    -A block may be explicitly delimited: +use the format function from the string library (see 5.3). + +

    2.3 - Variables

    + +

    Variables are places that store values. + +There are three kinds of variables in Lua: +global variables, local variables, and table fields. + +

    A single name can denote a global variable or a local variable +(or a formal parameter of a function, +which is a particular form of local variable): +

    +	var ::= Name
    +
    +Variables are assumed to be global unless explicitly declared local +(see 2.4.7). +Local variables are lexically scoped: +Local variables can be freely accessed by functions +defined inside their scope (see 2.6). + +

    Before the first assignment to a variable, its value is nil. + +

    Square brackets are used to index a table: +

    +	var ::= prefixexp `[´ exp `]´
    +
    +The first expression (prefixexp)should result in a table value; +the second expression (exp) +identifies a specific entry inside that table. +The expression denoting the table to be indexed has a restricted syntax; +see 2.5 for details. + +

    The syntax var.NAME is just syntactic sugar for +var["NAME"]: +

    +	var ::= prefixexp `.´ Name
    +
    + +

    The meaning of accesses to global variables +and table fields can be changed via metatables. +An access to an indexed variable t[i] is equivalent to +a call gettable_event(t,i). +(See 2.8 for a complete description of the +gettable_event function. +This function is not defined or callable in Lua. +We use it here only for explanatory purposes.) + +

    All global variables live as fields in ordinary Lua tables, +called environment tables or simply environments. +Functions written in C and exported to Lua (C functions) +all share a common global environment. +Each function written in Lua (a Lua function) +has its own reference to an environment, +so that all global variables in that function +will refer to that environment table. +When a function is created, +it inherits the environment from the function that created it. +To change or get the environment table of a Lua function, +you call setfenv or getfenv (see 5.1). + +

    An access to a global variable x +is equivalent to _env.x, +which in turn is equivalent to

    -       stat ::= do block end
    +       gettable_event(_env, "x")
     
    +where _env is the environment of the running function. +(The _env variable is not defined in Lua. +We use it here only for explanatory purposes.) + +

    2.4 - Statements

    + +

    Lua supports an almost conventional set of statements, +similar to those in Pascal or C. +This set includes +assignment, control structures, procedure calls, +table constructors, and variable declarations. + +

    2.4.1 - Chunks

    + +

    The unit of execution of Lua is called a chunk. +A chunk is simply a sequence of statements, +which are executed sequentially. +Each statement can be optionally followed by a semicolon: +

    +	chunk ::= {stat [`;´]}
    +
    + +

    Lua handles a chunk as the body of an anonymous function (see 2.5.8). +As such, chunks can define local variables and return values. + +

    A chunk may be stored in a file or in a string inside the host program. +When a chunk is executed, first it is pre-compiled into opcodes for +a virtual machine, +and then the compiled code is executed +by an interpreter for the virtual machine. + +

    Chunks may also be pre-compiled into binary form; +see program luac for details. +Programs in source and compiled forms are interchangeable; +Lua automatically detects the file type and acts accordingly. + + +

    2.4.2 - Blocks

    +A block is a list of statements; +syntactically, a block is equal to a chunk: +
    +	block ::= chunk
    +
    + +

    A block may be explicitly delimited to produce a single statement: +

    +	stat ::= do block end
    +
    Explicit blocks are useful -to control the scope of local variables (see Section 4.4.6). +to control the scope of variable declarations. Explicit blocks are also sometimes used to -add a return or break statement in the middle -of another block (see Section 4.4.3). -

    - -

    4.4.2 - Assignment

    -Lua allows multiple assignment. +add a return or break statement in the middle +of another block (see 2.4.4). + + +

    2.4.3 - Assignment

    + +

    Lua allows multiple assignment. Therefore, the syntax for assignment defines a list of variables on the left side and a list of expressions on the right side. The elements in both lists are separated by commas: -

    -       stat ::= varlist1 `=' explist1
    -       varlist1 ::= var {`,' var}
    -
    -This statement first evaluates all values on the right side -and eventual indices on the left side, -and then makes the assignments. -So, the code +
    +	stat ::= varlist1 `=´ explist1
    +	varlist1 ::= var {`,´ var}
    +	explist1 ::= exp {`,´ exp}
    +
    +Expressions are discussed in 2.5. + +

    Before the assignment, +the list of values is adjusted to the length of +the list of variables. +If there are more values than needed, +the excess values are thrown away. +If there are fewer values than needed, +the list is extended with as many nil's as needed. +If the list of expressions ends with a function call, +then all values returned by that function call enter in the list of values, +before the adjustment +(except when the call is enclosed in parentheses; see 2.5). + +

    The assignment statement first evaluates all its expressions +and only then are the assignments performed. +Thus the code

            i = 3
    -       i, a[i] = 4, 20
    +       i, a[i] = i+1, 20
     
    -sets a[3] to 20, but does not affect a[4] -because the i in a[i] is evaluated -before it is assigned 4. -

    -Multiple assignment can be used to exchange two values, as in +sets a[3] to 20, without affecting a[4] +because the i in a[i] is evaluated (to 3) +before it is assigned 4. +Similarly, the line

            x, y = y, x
     
    -

    -The two lists in a multiple assignment may have different lengths. -Before the assignment, the list of values is adjusted to -the length of the list of variables (see Section 4.3). -

    -A single name can denote a global variable, a local variable, -or a formal parameter: -

    -       var ::= name
    -
    -

    -Square brackets are used to index a table: -

    -       var ::= varorfunc `[' exp1 `]'
    -       varorfunc ::= var | functioncall
    -
    -The varorfunc should result in a table value, -from where the field indexed by the expression exp1 -value gets the assigned value. -

    -The syntax var.NAME is just syntactic sugar for -var["NAME"]: -

    -       var ::= varorfunc `.' name
    -
    -

    -The meaning of assignments and evaluations of global variables and -indexed variables can be changed by tag methods (see Section 4.8). -Actually, -an assignment x = val, where x is a global variable, -is equivalent to a call setglobal("x", val) and -an assignment t[i] = val is equivalent to -settable_event(t,i,val). -See Section 4.8 for a complete description of these functions -(setglobal is in the basic library; -settable_event is used for explanatory purposes only). -

    - -

    4.4.3 - Control Structures

    -The control structures -if, while, and repeat have the usual meaning and -familiar syntax - - - -
    -       stat ::= while exp1 do block end
    -       stat ::= repeat block until exp1
    -       stat ::= if exp1 then block {elseif exp1 then block} [else block] end
    -
    -The condition expression exp1 of a control structure may return any value. -All values different from nil are considered true; -only nil is considered false. -

    -The return statement is used to return values -from a function or from a chunk. - +exchanges the values of x and y. - -Because functions or chunks may return more than one value, -the syntax for the return statement is -

    -       stat ::= return [explist1]
    -
    -

    -The break statement can be used to terminate the execution of a loop, -skipping to the next statement after the loop: - +

    The meaning of assignments to global variables +and table fields can be changed via metatables. +An assignment to an indexed variable t[i] = val is equivalent to +settable_event(t,i,val). +(See 2.8 for a complete description of the +settable_event function. +This function is not defined or callable in Lua. +We use it here only for explanatory purposes.) + +

    An assignment to a global variable x = val +is equivalent to the assignment +_env.x = val, +which in turn is equivalent to

    -       stat ::= break
    +       settable_event(_env, "x", val)
     
    -A break ends the innermost enclosing loop -(while, repeat, or for). -

    -For syntactic reasons, return and break -statements can only be written as the last statements of a block. -If it is really necessary to return or break in the +where _env is the environment of the running function. +(The _env variable is not defined in Lua. +We use it here only for explanatory purposes.) + +

    2.4.4 - Control Structures

    +The control structures +if, while, and repeat have the usual meaning and +familiar syntax: + + + +
    +	stat ::= while exp do block end
    +	stat ::= repeat block until exp
    +	stat ::= if exp then block {elseif exp then block} [else block] end
    +
    +Lua also has a for statement, in two flavors (see 2.4.5). + +

    The condition expression exp of a +control structure may return any value. +Both false and nil are considered false. +All values different from nil and false are considered true +(in particular, the number 0 and the empty string are also true). + +

    The return statement is used to return values +from a function or from a chunk. + +Functions and chunks may return more than one value, +so the syntax for the return statement is +

    +	stat ::= return [explist1]
    +
    + +

    The break statement can be used to terminate the execution of a +while, repeat, or for loop, +skiping to the next statement after the loop: + +

    +	stat ::= break
    +
    +A break ends the innermost enclosing loop. + +

    For syntactic reasons, return and break +statements can only be written as the last statement of a block. +If it is really necessary to return or break in the middle of a block, -an explicit inner block can used, -as in the idiom `do return end', -because now return is last statement in the inner block. -

    - -

    4.4.4 - For Statement

    -

    -The for statement has two forms, -one for numbers and one for tables. -The numerical for loop has the following syntax: -

    -       stat ::= for name `=' exp1 `,' exp1 [`,' exp1] do block end
    -
    -A for statement like +then an explicit inner block can be used, +as in the idioms +`do return end´ and +`do break end´, +because now return and break are the last statements in +their (inner) blocks. +In practice, +those idioms are only used during debugging. + +

    2.4.5 - For Statement

    + +

    The for statement has two forms: +one numeric and one generic. + + +

    The numeric for loop repeats a block of code while a +control variable runs through an arithmetic progression. +It has the following syntax: +

    +	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end
    +
    +The block is repeated for name starting at the value of +the first exp, until it passes the second exp by steps of the +third exp. +More precisely, a for statement like
    -       for var = e1 ,e2, e3 do block end
    +       for var = e1, e2, e3 do block end
     
    is equivalent to the code:
            do
              local var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
              if not (var and _limit and _step) then error() end
    -         while (_step>0 and var<=_limit) or (_step<=0 and var>=_limit) do
    +         while (_step>0 and var<=_limit) or (_step<=0 and var>=_limit) do
                block
    -           var = var+_step
    +           var = var + _step
              end
            end
     
    Note the following: -
    • sep=0pt -
    • _limit and _step are invisible variables. +
        +
      • All three control expressions are evaluated only once, +before the loop starts. +They must all result in numbers. +
      • _limit and _step are invisible variables. The names are here for explanatory purposes only. -
      • The behavior is undefined if you assign to var inside +
      • The behavior is undefined if you assign to var inside the block. -
      • If the third expression (the step) is absent, then a step of 1 is used. -
      • Both the limit and the step are evaluated only once, -before the loop starts. -
      • The variable var is local to the statement; -you cannot use its value after the for ends. -
      • You can use break to exit a for. -If you need the value of the index, -assign it to another variable before breaking. -
      -

      -The table for statement traverses all pairs -(index,value) of a given table. -It has the following syntax: -

      -       stat ::= for name `,' name in exp1 do block end
      -
      -A for statement like -
      -       for index, value in exp do block end
      +
    • If the third expression (the step) is absent, then a step of 1 is used. +
    • You can use break to exit a for loop. +
    • The loop variable var is local to the statement; +you cannot use its value after the for ends or is broken. +If you need the value of the loop variable var, +then assign it to another variable before breaking or exiting the loop. +
    + +

    The generic for statement works over functions, +called iterators. +For each iteration, it calls its iterator function to produce a new value, +stopping when the new value is nil. +The generic for loop has the following syntax: +

    +	stat ::= for Name {`,´ Name} in explist1 do block end
    +
    +A for statement like +
    +       for var_1, ..., var_n in explist do block end
     
    is equivalent to the code:
            do
    -         local _t = exp
    -         local index, value = next(t, nil)
    -         while index do
    +         local _f, _s, var_1 = explist
    +         local var_2, ... , var_n
    +         while true do
    +           var_1, ..., var_n = _f(_s, var_1)
    +           if var_1 == nil then break end
                block
    -           index, value = next(t, index)
              end
            end
     
    Note the following: -
    • sep=0pt -
    • _t is an invisible variable. -The name is here for explanatory purposes only. -
    • The behavior is undefined if you assign to index inside -the block. -
    • The behavior is undefined if you change -the table _t during the traversal. -
    • The variables index and value are local to the statement; -you cannot use their values after the for ends. -
    • You can use break to exit a for. -If you need the value of index or value, -assign them to other variables before breaking. -
    • The order that table elements are traversed is undefined, -even for numerical indices. -If you want to traverse indices in numerical order, -use a numerical for. -
    -

    -

    - -

    4.4.5 - Function Calls as Statements

    -Because of possible side-effects, +
      +
    • explist is evaluated only once. +Its results are an iterator function, +a state, and an initial value for the first iterator variable. +
    • _f and _s are invisible variables. +The names are here for explanatory purposes only. +
    • The behavior is undefined if you assign to +var_1 inside the block. +
    • You can use break to exit a for loop. +
    • The loop variables var_i are local to the statement; +you cannot use their values after the for ends. +If you need these values, +then assign them to other variables before breaking or exiting the loop. +
    + +

    2.4.6 - Function Calls as Statements

    +To allow possible side-effects, function calls can be executed as statements: -
    -       stat ::= functioncall
    -
    +
    +	stat ::= functioncall
    +
    In this case, all returned values are thrown away. -Function calls are explained in Section 4.5.8. -

    - -

    4.4.6 - Local Declarations

    -Local variables may be declared anywhere inside a block. +Function calls are explained in 2.5.7. + +

    2.4.7 - Local Declarations

    +Local variables may be declared anywhere inside a block. The declaration may include an initial assignment: -
    -       stat ::= local declist [init]
    -       declist ::= name {`,' name}
    -       init ::= `=' explist1
    -
    +
    +	stat ::= local namelist [`=´ explist1]
    +	namelist ::= Name {`,´ Name}
    +
    If present, an initial assignment has the same semantics -of a multiple assignment. +of a multiple assignment (see 2.4.3). Otherwise, all variables are initialized with nil. -

    -A chunk is also a block, -and so local variables can be declared outside any explicit block. -

    -The scope of local variables begins after -the declaration and lasts until the end of the block. -Thus, the code -local print=print -creates a local variable called print whose -initial value is that of the global variable of the same name. -

    -

    - -

    4.5 - Expressions

    -

    -

    4.5.1 - Basic Expressions

    -The basic expressions in Lua are -
    -       exp ::= `(' exp `)'
    -       exp ::= nil
    -       exp ::= number
    -       exp ::= literal
    -       exp ::= var
    -       exp ::= upvalue
    -       exp ::= function
    -       exp ::= functioncall
    -       exp ::= tableconstructor
    -
    -

    -Numbers (numerical constants) and -literal strings are explained in Section 4.1; -variables are explained in Section 4.4.2; -upvalues are explained in Section 4.6; -function definitions are explained in Section 4.5.9; -function calls are explained in Section 4.5.8. -Table constructors are explained in Section 4.5.7. -

    -An access to a global variable x is equivalent to a -call getglobal("x") and -an access to an indexed variable t[i] is equivalent to -a call gettable_event(t,i). -See Section 4.8 for a description of these functions -(getglobal is in the basic library; -gettable_event is used for explanatory purposes only). -

    -The non-terminal exp1 is used to indicate that the values -returned by an expression must be adjusted to one single value: -

    -       exp1 ::= exp
    -
    -

    -

    4.5.2 - Arithmetic Operators

    -Lua supports the usual arithmetic operators: -the binary + (addition), -- (subtraction), * (multiplication), -/ (division), and ^ (exponentiation); -and unary - (negation). + +

    A chunk is also a block (see 2.4.1), +so local variables can be declared in a chunk outside any explicit block. +Such local variables die when the chunk ends. + +

    The visibility rules for local variables are explained in 2.6. + +

    2.5 - Expressions

    + +

    +The basic expressions in Lua are the following: +

    +	exp ::= prefixexp
    +	exp ::= nil | false | true
    +	exp ::= Number
    +	exp ::= Literal
    +	exp ::= function
    +	exp ::= tableconstructor
    +	prefixexp ::= var | functioncall | `(´ exp `)´
    +
    + +

    Numbers and literal strings are explained in 2.1; +variables are explained in 2.3; +function definitions are explained in 2.5.8; +function calls are explained in 2.5.7; +table constructors are explained in 2.5.6. + + +

    An expression enclosed in parentheses always results in only one value. +Thus, +(f(x,y,z)) is always a single value, +even if f returns several values. +(The value of (f(x,y,z)) is the first value returned by f +or nil if f does not return any values.) + +

    Expressions can also be built with arithmetic operators, relational operators, +and logical operators, all of which are explained below. + +

    2.5.1 - Arithmetic Operators

    +Lua supports the usual arithmetic operators: +the binary + (addition), +- (subtraction), * (multiplication), +/ (division), and ^ (exponentiation); +and unary - (negation). If the operands are numbers, or strings that can be converted to -numbers (according to the rules given in Section 4.2), +numbers (see 2.2.1), then all operations except exponentiation have the usual meaning. -Otherwise, an appropriate tag method is called (see Section 4.8). -An exponentiation always calls a tag method. -The standard mathematical library redefines this method for numbers, -giving the expected meaning to exponentiation -(see Section 6.3). -

    -

    4.5.3 - Relational Operators

    -The relational operators in Lua are -
    -       ==    ~=    <     >     <=    >=
    -
    -These operators return nil as false and a value different from nil as true. -

    -Equality (==) first compares the tags of its operands. -If they are different, then the result is nil. -Otherwise, their values are compared. +Exponentiation calls a global function __pow; +otherwise, an appropriate metamethod is called (see 2.8). +The standard mathematical library defines function __pow, +giving the expected meaning to exponentiation +(see 5.5). + +

    2.5.2 - Relational Operators

    +The relational operators in Lua are +
    +       ==    ~=    <     >     <=    >=
    +
    +These operators always result in false or true. + +

    Equality (==) first compares the type of its operands. +If the types are different, then the result is false. +Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. -Tables, userdata, and functions are compared by reference, -that is, two tables are considered equal only if they are the same table. -The operator ~= is exactly the negation of equality (==). -

    -The conversion rules of Section 4.2 -do not apply to equality comparisons. -Thus, "0"==0 evaluates to false, -and t[0] and t["0"] denote different +Objects (tables, userdata, threads, and functions) +are compared by reference: +Two objects are considered equal only if they are the same object. +Every time you create a new object (a table, userdata, or function), +this new object is different from any previously existing object. + +

    You can change the way that Lua compares tables and userdata +using the "eq" metamethod (see 2.8). + +

    The conversion rules of 2.2.1 +do not apply to equality comparisons. +Thus, "0"==0 evaluates to false, +and t[0] and t["0"] denote different entries in a table. -

    -The order operators work as follows. + + +

    The operator ~= is exactly the negation of equality (==). + +

    The order operators work as follows. If both arguments are numbers, then they are compared as such. Otherwise, if both arguments are strings, -then their values are compared using lexicographical order. -Otherwise, the ``lt'' tag method is called (see Section 4.8). -

    -

    4.5.4 - Logical Operators

    -The logical operators in Lua are - +then their values are compared according to the current locale. +Otherwise, Lua tries to call the "lt" or the "le" +metamethod (see 2.8). + +

    2.5.3 - Logical Operators

    +The logical operators in Lua are +
            and   or    not
     
    -Like the control structures, all logical operators -consider nil as false and anything else as true. -

    -The conjunction operator and returns nil if its first argument is nil; -otherwise, it returns its second argument. -The disjunction operator or returns its first argument -if it is different from nil; -otherwise, it returns its second argument. -Both and and or use short-cut evaluation, +Like the control structures (see 2.4.4), +all logical operators consider both false and nil as false +and anything else as true. + + +

    The operator not always return false or true. + +

    The conjunction operator and returns its first argument +if this value is false or nil; +otherwise, and returns its second argument. +The disjunction operator or returns its first argument +if this value is different from nil and false; +otherwise, or returns its second argument. +Both and and or use short-cut evaluation, that is, the second operand is evaluated only if necessary. -

    -There are two useful Lua idioms that use logical operators. -The first idiom is -

    -       x = x or v
    -
    -which is equivalent to -
    -       if x == nil then x = v end
    -
    -This idiom sets x to a default value v when x is not set. -

    -The second idiom is -

    -       x = a and b or c
    -
    -which should be read as x = (a and b) or c. -This idiom is equivalent to +For example,
    -       if a then x = b else x = c end
    +       10 or error()       -> 10
    +       nil or "a"          -> "a"
    +       nil and 10          -> nil
    +       false and error()   -> false
    +       false and nil       -> false
    +       false or nil        -> nil
    +       10 and 20           -> 20
     
    -provided that b is not nil. -

    - -

    4.5.5 - Concatenation

    -The string concatenation operator in Lua is -denoted by two dots (`..'). + +

    2.5.4 - Concatenation

    +The string concatenation operator in Lua is +denoted by two dots (`..´). If both operands are strings or numbers, then they are converted to -strings according to the rules in Section 4.2. -Otherwise, the ``concat'' tag method is called (see Section 4.8). -

    -

    4.5.6 - Precedence

    -Operator precedence in Lua follows the table below, -from the lower to the higher priority: -
    -       and   or
    -       <     >     <=    >=    ~=    ==
    +strings according to the rules mentioned in 2.2.1.
    +Otherwise, the "concat" metamethod is called (see 2.8).
    +
    +

    2.5.5 - Precedence

    +Operator precedence in Lua follows the table below, +from lower to higher priority: +
    +       or
    +       and
    +       <     >     <=    >=    ~=    ==
            ..
            +     -
            *     /
            not   - (unary)
            ^
     
    -All binary operators are left associative, -except for ^ (exponentiation), -which is right associative. -The pre-compiler may rearrange the order of evaluation of -associative operators (such as .. or +), -as long as these optimizations do not change normal results. -However, these optimizations may change some results -if you define non-associative -tag methods for these operators. -

    - -

    4.5.7 - Table Constructors

    -Table constructors are expressions that create tables; -every time a constructor is evaluated, a new table is created. +As usual, you can use parentheses to change the precedences of an expression. +The concatenation (`..´) and exponentiation (`^´) +operators are right associative. +All other binary operators are left associative. + +

    2.5.6 - Table Constructors

    +Table constructors are expressions that create tables. +Every time a constructor is evaluated, a new table is created. Constructors can be used to create empty tables, or to create a table and initialize some of its fields. The general syntax for constructors is -
    -       tableconstructor ::= `{' fieldlist `}'
    -       fieldlist ::= lfieldlist | ffieldlist | lfieldlist `;' ffieldlist | ffieldlist `;' lfieldlist
    -       lfieldlist ::= [lfieldlist1]
    -       ffieldlist ::= [ffieldlist1]
    -
    -

    -The form lfieldlist1 is used to initialize lists: -

    -       lfieldlist1 ::= exp {`,' exp} [`,']
    -
    -The expressions in the list are assigned to consecutive numerical indices, -starting with 1. -For example, -
    -       a = {"v1", "v2", 34}
    -
    -is equivalent to -
    -       do
    -         local temp = {}
    -         temp[1] = "v1"
    -         temp[2] = "v2"
    -         temp[3] = 34
    -         a = temp
    -       end
    -
    -

    -The form ffieldlist1 initializes other fields in a table: -

    -       ffieldlist1 ::= ffield {`,' ffield} [`,']
    -       ffield ::= `[' exp `]' `=' exp | name `=' exp
    -
    +
    +	tableconstructor ::= `{´ [fieldlist] `}´
    +	fieldlist ::= field {fieldsep field} [fieldsep]
    +	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
    +	fieldsep ::= `,´ | `;´
    +
    + +

    Each field of the form [exp1] = exp2 adds to the new table an entry +with key exp1 and value exp2. +A field of the form name = exp is equivalent to +["name"] = exp. +Finally, fields of the form exp are equivalent to +[i] = exp, where i are consecutive numerical integers, +starting with 1. +Fields in the other formats do not affect this counting. For example,

    -       a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
    +       a = {[f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45}
     
    is equivalent to
            do
              local temp = {}
    -         temp[f(k)] = g(y)
    -         temp.x = 1    -- or temp["x"] = 1
    -         temp.y = 3    -- or temp["y"] = 3
    -         temp[0] = b+c
    +         temp[f(1)] = g
    +         temp[1] = "x"         -- 1st exp
    +         temp[2] = "y"         -- 2nd exp
    +         temp.x = 1            -- temp["x"] = 1
    +         temp[3] = f(x)        -- 3rd exp
    +         temp[30] = 23
    +         temp[4] = 45          -- 4th exp
              a = temp
            end
     
    -An expression like {x = 1, y = 4} is -in fact syntactic sugar for {["x"] = 1, ["y"] = 4}. -

    -Both forms may have an optional trailing comma, -and can be used in the same constructor separated by -a semi-colon. -For example, all forms below are correct. -

    -       x = {;}
    -       x = {"a", "b",}
    -       x = {type="list"; "a", "b"}
    -       x = {f(0), f(1), f(2),; n=3,}
    -
    -

    - -

    4.5.8 - Function Calls

    -A function call in Lua has the following syntax: -
    -       functioncall ::= varorfunc args
    -
    -First, varorfunc is evaluated. -If its value has type function, -then this function is called, + +

    If the last field in the list has the form exp +and the expression is a function call, +then all values returned by the call enter the list consecutively +(see 2.5.7). +To avoid this, +enclose the function call in parentheses (see 2.5). + +

    The field list may have an optional trailing separator, +as a convenience for machine-generated code. + +

    2.5.7 - Function Calls

    +A function call in Lua has the following syntax: +
    +	functioncall ::= prefixexp args
    +
    +In a function call, +first prefixexp and args are evaluated. +If the value of prefixexp has type function, +then that function is called with the given arguments. -Otherwise, the ``function'' tag method is called, -having as first parameter the value of varorfunc, -and then the original call arguments -(see Section 4.8). -

    -The form -

    -       functioncall ::= varorfunc `:' name args
    -
    -can be used to call ``methods''. -A call v:name(...) -is syntactic sugar for v.name(v, ...), -except that v is evaluated only once. -

    -Arguments have the following syntax: -

    -       args ::= `(' [explist1] `)'
    -       args ::= tableconstructor
    -       args ::= literal
    -       explist1 ::= {exp1 `,'} exp
    -
    +Otherwise, its "call" metamethod is called, +having as first parameter the value of prefixexp, +followed by the original call arguments +(see 2.8). + +

    The form +

    +	functioncall ::= prefixexp `:´ Name args
    +
    +can be used to call "methods". +A call v:name(...) +is syntactic sugar for v.name(v,...), +except that v is evaluated only once. + +

    Arguments have the following syntax: +

    +	args ::= `(´ [explist1] `)´
    +	args ::= tableconstructor
    +	args ::= Literal
    +
    All argument expressions are evaluated before the call. -A call of the form f{...} is syntactic sugar for -f({...}), that is, +A call of the form f{...} is syntactic sugar for +f({...}), that is, the argument list is a single new table. -A call of the form f'...' -(or f"..." or f[[...]]) is syntactic sugar for -f('...'), that is, +A call of the form f'...' +(or f"..." or f[[...]]) is syntactic sugar for +f('...'), that is, the argument list is a single literal string. -

    -Because a function can return any number of results -(see Section 4.4.3), -the number of results must be adjusted before they are used (see Section 4.3). -If the function is called as a statement (see Section 4.4.5), -then its return list is adjusted to 0, + +

    Because a function can return any number of results +(see 2.4.4), +the number of results must be adjusted before they are used. +If the function is called as a statement (see 2.4.6), +then its return list is adjusted to zero elements, thus discarding all returned values. -If the function is called in a place that needs a single value -(syntactically denoted by the non-terminal exp1), -then its return list is adjusted to 1, -thus discarding all returned values but the first one. -If the function is called in a place that can hold many values -(syntactically denoted by the non-terminal exp), -then no adjustment is made. -The only places that can hold many values -is the last (or the only) expression in an assignment, -in an argument list, or in the return statement. -Here are some examples: +If the function is called inside another expression +or in the middle of a list of expressions, +then its return list is adjusted to one element, +thus discarding all returned values except the first one. +If the function is called as the last element of a list of expressions, +then no adjustment is made +(unless the call is enclosed in parentheses). + +

    Here are some examples:

            f()                -- adjusted to 0 results
            g(f(), x)          -- f() is adjusted to 1 result
            g(x, f())          -- g gets x plus all values returned by f()
            a,b,c = f(), x     -- f() is adjusted to 1 result (and c gets nil)
    -       a,b,c = x, f()     -- f() is adjusted to 2
    -       a,b,c = f()        -- f() is adjusted to 3
    +       a,b,c = x, f()     -- f() is adjusted to 2 results
    +       a,b,c = f()        -- f() is adjusted to 3 results
            return f()         -- returns all values returned by f()
    -       return x,y,f()     -- returns a, b, and all values returned by f()
    +       return x,y,f()     -- returns x, y, and all values returned by f()
    +       {f()}              -- creates a list with all values returned by f()
    +       {f(), nil}         -- f() is adjusted to 1 result
     
    -

    - -

    4.5.9 - Function Definitions

    -

    -The syntax for function definition is + +

    If you enclose a function call in parentheses, +then it is adjusted to return exactly one value:

    -       function ::= function `(' [parlist1] `)' block end
    -       stat ::= function funcname `(' [parlist1] `)' block end
    -       funcname ::= name | name `.' name | name `:' name
    +       return x,y,(f())   -- returns x, y, and the first value from f()
    +       {(f())}            -- creates a table with exactly one element
    +
    + +

    As an exception to the free-format syntax of Lua, +you cannot put a line break before the `(´ in a function call. +That restriction avoids some ambiguities in the language. +If you write +

    +       a = f
    +       (g).x(a)
    +
    +Lua would read that as a = f(g).x(a). +So, if you want two statements, you must add a semi-colon between them. +If you actually want to call f, +you must remove the line break before (g). + +

    A call of the form return functioncall is called +a tail call. +Lua implements proper tail calls +(or proper tail recursion): +In a tail call, +the called function reuses the stack entry of the calling function. +Therefore, there is no limit on the number of nested tail calls that +a program can execute. +However, a tail call erases any debug information about the +calling function. +Note that a tail call only happens with a particular syntax, +where the return has one single function call as argument; +this syntax makes the calling function returns exactly +the returns of the called function. +So, all the following examples are not tails calls: +

    +  return (f(x))        -- results adjusted to 1
    +  return 2 * f(x)
    +  return x, f(x)       -- adicional results
    +  f(x); return         -- results discarded
    +  return x or f(x)     -- results adjusted to 1
     
    + +

    2.5.8 - Function Definitions

    + +

    The syntax for function definition is +

    +	function ::= function funcbody
    +	funcbody ::= `(´ [parlist1] `)´ block end
    +
    + +

    The following syntactic sugar simplifies function definitions: +

    +	stat ::= function funcname funcbody
    +	stat ::= local function Name funcbody
    +	funcname ::= Name {`.´ Name} [`:´ Name]
    +
    The statement
            function f () ... end
     
    -is just syntactic sugar for +translates to
            f = function () ... end
     
    -and the statement +The statement +
    +       function t.a.b.c.f () ... end
    +
    +translates to
    -       function v.f () ... end
    +       t.a.b.c.f = function () ... end
     
    -is syntactic sugar for +The statement
    -       v.f = function () ... end
    +       local function f () ... end
     
    -

    -A function definition is an executable expression, -whose value has type function. +translates to +

    +       local f; f = function () ... end
    +
    + +

    A function definition is an executable expression, +whose value has type function. When Lua pre-compiles a chunk, all its function bodies are pre-compiled too. Then, whenever Lua executes the function definition, -its upvalues are fixed (see Section 4.6), -and the function is instantiated (or closed). -This function instance (or closure) +the function is instantiated (or closed). +This function instance (or closure) is the final value of the expression. Different instances of the same function -may have different upvalues. -

    -Parameters act as local variables, -initialized with the argument values: -

    -       parlist1 ::= `...'
    -       parlist1 ::= name {`,' name} [`,' `...']
    -
    - +may refer to different external local variables +and may have different environment tables. +

    Parameters act as local variables that are +initialized with the argument values: +

    +	parlist1 ::= namelist [`,´ `...´]
    +	parlist1 ::= `...´
    +
    When a function is called, -the list of arguments is adjusted to -the length of the list of parameters (see Section 4.3), -unless the function is a vararg function, +the list of arguments is adjusted to +the length of the list of parameters, +unless the function is a variadic or vararg function, which is -indicated by three dots (`...') at the end of its parameter list. +indicated by three dots (`...´) at the end of its parameter list. A vararg function does not adjust its argument list; instead, it collects all extra arguments into an implicit parameter, -called arg. -The value of arg is a table, -with a field n whose value is the number of extra arguments, -and the extra arguments at positions 1, 2, ..., n. -

    -As an example, consider the following definitions: +called arg. +The value of arg is a table, +with a field n that holds the number of extra arguments +and with the extra arguments at positions 1, 2, ..., n. + +

    As an example, consider the following definitions:

            function f(a, b) end
            function g(a, b, ...) end
    @@ -951,1200 +1028,1428 @@ 

    4.5.9 - Function Definitions

    Then, we have the following mapping from arguments to parameters:
            CALL            PARAMETERS
    -

    + f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) a=3, b=4 f(r(), 10) a=1, b=10 f(r()) a=1, b=2 -

    + g(3) a=3, b=nil, arg={n=0} - g(3, 4) a=3, b=4, arg={n=0} - g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2} - g(5, r()) a=5, b=1, arg={2, 3; n=2} + g(3, 4) a=3, b=4, arg={n=0} + g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2} + g(5, r()) a=5, b=1, arg={2, 3; n=2}

    -

    -Results are returned using the return statement (see Section 4.4.3). + +

    Results are returned using the return statement (see 2.4.4). If control reaches the end of a function -without encountering a return statement, +without encountering a return statement, then the function returns with no results. -

    -The syntax + +

    The colon syntax +is used for defining methods, +that is, functions that have an implicit extra parameter self. +Thus, the statement

    -       funcname ::= name `:' name
    +       function t.a.b.c:f (...) ... end
     
    -is used for defining methods, -that is, functions that have an implicit extra parameter self. -

    -The statement +is syntactic sugar for

    -       function v:f (...) ... end
    -
    -is just syntactic sugar for -
    -       v.f = function (self, ...) ... end
    -
    -Note that the function gets an extra formal parameter called self. -

    -

    - - -

    4.6 - Visibility and Upvalues

    - -

    -A function body may refer to its own local variables -(which include its parameters) and to global variables, -as long as they are not shadowed by local -variables with the same name from enclosing functions. -A function cannot access a local -variable from an enclosing function, -since such variables may no longer exist when the function is called. -However, a function may access the value of a local variable -from an enclosing function, using upvalues, -whose syntax is -

    -       upvalue ::= `%' name
    -
    -

    -An upvalue is somewhat similar to a variable expression, -but whose value is frozen when the function wherein it -appears is instantiated. -The name used in an upvalue may be the name of any variable visible -at the point where the function is defined, -that is, -global variables and local variables -from the immediately enclosing function. -Note that when the upvalue is a table, -only the reference to that table -(which is the value of the upvalue) is frozen; -the table contents can be changed at will. -Using table values as upvalues is a technique for having -writable but private state attached to functions. -

    -Here are some examples: -

    -       a,b,c = 1,2,3   -- global variables
    -       local d
    -       function f (x)
    -         local b = {}  -- x and b are local to f; b shadows the global b
    -         local g = function (a)
    -           local y     -- a and y are local to g
    -           p = a       -- OK, access local `a'
    -           p = c       -- OK, access global `c'
    -           p = b       -- ERROR: cannot access a variable in outer scope
    -           p = %b      -- OK, access frozen value of `b' (local to `f')
    -           %b = 3      -- ERROR: cannot change an upvalue
    -           %b.x = 3    -- OK, change the table contents
    -           p = %c      -- OK, access frozen value of global `c'
    -           p = %y      -- ERROR: `y' is not visible where `g' is defined
    -           p = %d      -- ERROR: `d' is not visible where `g' is defined
    -         end           -- g
    -       end             -- f
    -
    -

    -

    - - -

    4.7 - Error Handling

    -

    -Because Lua is an extension language, + t.a.b.c.f = function (self, ...) ... end +

    + +

    2.6 - Visibility Rules

    + + +

    Lua is a lexically scoped language. +The scope of variables begins at the first statement after +their declaration and lasts until the end of the innermost block that +includes the declaration. +For instance: +

    +  x = 10                -- global variable
    +  do                    -- new block
    +    local x = x         -- new `x', with value 10
    +    print(x)            --> 10
    +    x = x+1
    +    do                  -- another block
    +      local x = x+1     -- another `x'
    +      print(x)          --> 12
    +    end
    +    print(x)            --> 11
    +  end
    +  print(x)              --> 10  (the global one)
    +
    +Notice that, in a declaration like local x = x, +the new x being declared is not in scope yet, +and so the second x refers to the outside variable. + +

    Because of the lexical scoping rules, +local variables can be freely accessed by functions +defined inside their scope. +For instance: +

    +  local counter = 0
    +  function inc (x)
    +    counter = counter + x
    +    return counter
    +  end
    +
    +A local variable used by an inner function is called +an upvalue, or external local variable, +inside the inner function. + +

    Notice that each execution of a local statement +defines new local variables. +Consider the following example: +

    +  a = {}
    +  local x = 20
    +  for i=1,10 do
    +    local y = 0
    +    a[i] = function () y=y+1; return x+y end
    +  end
    +
    +The loop creates ten closures +(that is, ten instances of the anonymous function). +Each of these closures uses a different y variable, +while all of them share the same x. + +

    2.7 - Error Handling

    + +

    Because Lua is an extension language, all Lua actions start from C code in the host program -calling a function from the Lua library. +calling a function from the Lua library (see 3.15). Whenever an error occurs during Lua compilation or execution, -the function _ERRORMESSAGE is called -(provided it is different from nil), -and then the corresponding function from the library -(lua_dofile, lua_dostring, -lua_dobuffer, or lua_call) -is terminated, returning an error condition. -

    -Memory allocation errors are an exception to the previous rule. -When memory allocation fails, Lua may not be able to execute the -_ERRORMESSAGE function. -So, for this kind of error, Lua does not call -the _ERRORMESSAGE function; -instead, the corresponding function from the library -returns immediately with a special error code (LUA_ERRMEM). -This and other error codes are defined in lua.h; -Section 5.8. -

    -The only argument to _ERRORMESSAGE is a string -describing the error. -The default definition for -this function calls _ALERT, -which prints the message to stderr (see Section 6.1). -The standard I/O library redefines _ERRORMESSAGE -and uses the debug facilities (see Section 7) -to print some extra information, -such as a call stack traceback. -

    -Lua code can explicitly generate an error by calling the -function error (see Section 6.1). -Lua code can ``catch'' an error using the function -call (see Section 6.1). -

    -

    - - -

    4.8 - Tag Methods

    -

    -Lua provides a powerful mechanism to extend its semantics, -called tag methods. -A tag method is a programmer-defined function -that is called at specific key points during the execution of a Lua program, -allowing the programmer to change the standard Lua behavior at these points. -Each of these points is called an event. -

    -The tag method called for any specific event is selected -according to the tag of the values involved -in the event (see Section 3). -The function settagmethod changes the tag method -associated with a given pair (tag, event). -Its first parameter is the tag, the second parameter is the event name -(a string; see below), -and the third parameter is the new method (a function), -or nil to restore the default behavior for the pair. -The settagmethod function returns the previous tag method for that pair. -A companion function gettagmethod -receives a tag and an event name and returns the -current method associated with the pair. -

    -Tag methods are called in the following events, -identified by the given names. -The semantics of tag methods is better explained by a Lua function -describing the behavior of the interpreter at each event. -This function not only shows when a tag method is called, -but also its arguments, its results, and the default behavior. -The code shown here is only illustrative; -the real behavior is hard coded in the interpreter, -and it is much more efficient than this simulation. -All functions used in these descriptions -(rawget, tonumber, call, etc.) -are described in Section 6.1. -

    -

    -

    -

    ``add'':
    -called when a + operation is applied to non-numerical operands. -

    -The function getbinmethod below defines how Lua chooses a tag method -for a binary operation. -First, Lua tries the first operand. -If its tag does not define a tag method for the operation, -then Lua tries the second operand. -If it also fails, then it gets a tag method from tag 0. +control returns to C, +which can take appropriate measures +(such as print an error message). + +

    Lua code can explicitly generate an error by calling the +error function (see 5.1). +If you need to catch errors in Lua, +you can use the pcall function (see 5.1). + +

    2.8 - Metatables

    + +

    Every table and userdata object in Lua may have a metatable. +This metatable is an ordinary Lua table +that defines the behavior of the original table and userdata +under certain special operations. +You can change several aspects of the behavior +of an object by setting specific fields in its metatable. +For instance, when an object is the operand of an addition, +Lua checks for a function in the field "__add" in its metatable. +If it finds one, +Lua calls that function to perform the addition. + +

    We call the keys in a metatable events +and the values metamethods. +In the previous example, the event is "add" +and the metamethod is the function that performs the addition. + +

    You can query and change the metatable of an object +through the set/getmetatable +functions (see 5.1). + +

    A metatable may control how an object behaves in arithmetic operations, +order comparisons, concatenation, and indexing. +A metatable can also define a function to be called when a userdata +is garbage collected. +For each of those operations Lua associates a specific key +called an event. +When Lua performs one of those operations over a table or a userdata, +it checks whether that object has a metatable with the corresponding event. +If so, the value associated with that key (the metamethod) +controls how Lua will perform the operation. + +

    Metatables control the operations listed next. +Each operation is identified by its corresponding name. +The key for each operation is a string with its name prefixed by +two underscores; +for instance, the key for operation "add" is the +string "__add". +The semantics of these operations is better explained by a Lua function +describing how the interpreter executes that operation. + +

    The code shown here in Lua is only illustrative; +the real behavior is hard coded in the interpreter +and it is much more efficient than this simulation. +All functions used in these descriptions +(rawget, tonumber, etc.) +are described in 5.1. +In particular, to retrieve the metamethod of a given object, +we use the expression

    -       function getbinmethod (op1, op2, event)
    -         return gettagmethod(tag(op1), event) or
    -                gettagmethod(tag(op2), event) or
    -                gettagmethod(0, event)
    -       end
    -
    -Using this function, -the tag method for the ``add'' event is -
    -       function add_event (op1, op2)
    -         local o1, o2 = tonumber(op1), tonumber(op2)
    -         if o1 and o2 then  -- both operands are numeric
    -           return o1+o2  -- '+' here is the primitive 'add'
    -         else  -- at least one of the operands is not numeric
    -           local tm = getbinmethod(op1, op2, "add")
    -           if tm then
    -             -- call the method with both operands and an extra
    -             -- argument with the event name
    -             return tm(op1, op2, "add")
    -           else  -- no tag method available: default behavior
    -             error("unexpected type at arithmetic operation")
    -           end
    -         end
    -       end
    +  metatable(obj)[event]
     
    -

    -

    ``sub'':
    -called when a - operation is applied to non-numerical operands. -Behavior similar to the ``add'' event. -

    -

    ``mul'':
    -called when a * operation is applied to non-numerical operands. -Behavior similar to the ``add'' event. -

    -

    ``div'':
    -called when a / operation is applied to non-numerical operands. -Behavior similar to the ``add'' event. -

    -

    ``pow'':
    -called when a ^ operation (exponentiation) is applied, -even for numerical operands. -
    -       function pow_event (op1, op2)
    -         local tm = getbinmethod(op1, op2, "pow")
    -         if tm then
    -           -- call the method with both operands and an extra
    -           -- argument with the event name
    -           return tm(op1, op2, "pow")
    -         else  -- no tag method available: default behavior
    -           error("unexpected type at arithmetic operation")
    -         end
    -       end
    +This should be read as
    +
    +  rawget(metatable(obj) or {}, event)
     
    -

    -

    ``unm'':
    -called when a unary - operation is applied to a non-numerical operand. -
    -       function unm_event (op)
    -         local o = tonumber(op)
    -         if o then  -- operand is numeric
    -           return -o  -- '-' here is the primitive 'unm'
    -         else  -- the operand is not numeric.
    -           -- Try to get a tag method from the operand;
    -           --  if it does not have one, try a "global" one (tag 0)
    -           local tm = gettagmethod(tag(op), "unm") or
    -                      gettagmethod(0, "unm")
    -           if tm then
    -             -- call the method with the operand, nil, and an extra
    -             -- argument with the event name
    -             return tm(op, nil, "unm")
    -           else  -- no tag method available: default behavior
    -             error("unexpected type at arithmetic operation")
    -           end
    -         end
    -       end
    +That is, the access to a metamethod does not invoke other metamethods,
    +and the access to objects with no metatables does not fail
    +(it simply results in nil).
    +
    +

      + +

    • "add": +the + operation. + +

      The function getbinhandler below defines how Lua chooses a handler +for a binary operation. +First, Lua tries the first operand. +If its type does not define a handler for the operation, +then Lua tries the second operand. +

      + function getbinhandler (op1, op2, event)
      +   return metatable(op1)[event] or metatable(op2)[event]
      + end
      +
      +Using that function, +the behavior of the op1 + op2 is +
      + function add_event (op1, op2)
      +   local o1, o2 = tonumber(op1), tonumber(op2)
      +   if o1 and o2 then  -- both operands are numeric?
      +     return o1 + o2   -- `+' here is the primitive `add'
      +   else  -- at least one of the operands is not numeric
      +     local h = getbinhandler(op1, op2, "__add")
      +     if h then
      +       -- call the handler with both operands
      +       return h(op1, op2)
      +     else  -- no handler available: default behavior
      +       error("...")
      +     end
      +   end
      + end
       
      -

      -

      ``lt'':
      -called when an order operation is applied to non-numerical -or non-string operands. -It corresponds to the < operator. -
      -       function lt_event (op1, op2)
      -         if type(op1) == "number" and type(op2) == "number" then
      -           return op1 < op2   -- numeric comparison
      -         elseif type(op1) == "string" and type(op2) == "string" then
      -           return op1 < op2   -- lexicographic comparison
      -         else
      -           local tm = getbinmethod(op1, op2, "lt")
      -           if tm then
      -             return tm(op1, op2, "lt")
      -           else
      -             error("unexpected type at comparison");
      -           end
      -         end
      -       end
      +
      +

    • "sub": +the - operation. +Behavior similar to the "add" operation. + +

    • "mul": +the * operation. +Behavior similar to the "add" operation. + +

    • "div": +the / operation. +Behavior similar to the "add" operation. + +

    • "pow": +the ^ (exponentiation) operation. +
      + function pow_event (op1, op2)
      +   local o1, o2 = tonumber(op1), tonumber(op2)
      +   if o1 and o2 then  -- both operands are numeric?
      +     return __pow(o1, o2)   -- call global `__pow'
      +   else  -- at least one of the operands is not numeric
      +     local h = getbinhandler(op1, op2, "__pow")
      +     if h then
      +       -- call the handler with both operands
      +       return h(op1, op2)
      +     else  -- no handler available: default behavior
      +       error("...")
      +     end
      +   end
      +  end
       
      -The other order operators use this tag method according to the -usual equivalences: -
      -       a>b    <=>  b<a
      -       a<=b   <=>  not (b<a)
      -       a>=b   <=>  not (a<b)
      -
      -

      -

      ``concat'':
      -called when a concatenation is applied to non-string operands. -
      -       function concat_event (op1, op2)
      -         if (type(op1) == "string" or type(op1) == "number") and
      -            (type(op2) == "string" or type(op2) == "number") then
      -           return op1..op2  -- primitive string concatenation
      -         else
      -           local tm = getbinmethod(op1, op2, "concat")
      -           if tm then
      -             return tm(op1, op2, "concat")
      -           else
      -             error("unexpected type for concatenation")
      -           end
      -         end
      -       end
      +
      +

    • "unm": +the unary - operation. +
      + function unm_event (op)
      +   local o = tonumber(op)
      +   if o then  -- operand is numeric?
      +     return -o  -- `-' here is the primitive `unm'
      +   else  -- the operand is not numeric.
      +     -- Try to get a handler from the operand
      +     local h = metatable(op).__unm
      +     if h then
      +       -- call the handler with the operand and nil
      +       return h(op, nil)
      +     else  -- no handler available: default behavior
      +       error("...")
      +     end
      +   end
      + end
       
      -

      -

      ``index'':
      -called when Lua tries to retrieve the value of an index -not present in a table. -See the ``gettable'' event for its semantics. -

      -

      ``getglobal'':
      -called whenever Lua needs the value of a global variable. -This method can only be set for nil and for tags -created by newtag. -Note that -the tag is that of the current value of the global variable. -
      -       function getglobal (varname)
      -         -- access the table of globals
      -         local value = rawget(globals(), varname)
      -         local tm = gettagmethod(tag(value), "getglobal")
      -         if not tm then
      -           return value
      -         else
      -           return tm(varname, value)
      -         end
      -       end
      +
      +

    • "concat": +the .. (concatenation) operation. +
      + function concat_event (op1, op2)
      +   if (type(op1) == "string" or type(op1) == "number") and
      +      (type(op2) == "string" or type(op2) == "number") then
      +     return op1 .. op2  -- primitive string concatenation
      +   else
      +     local h = getbinhandler(op1, op2, "__concat")
      +     if h then
      +       return h(op1, op2)
      +     else
      +       error("...")
      +     end
      +   end
      + end
       
      -The function getglobal is defined in the basic library (see Section 6.1). -

      -

      ``setglobal'':
      -called whenever Lua assigns to a global variable. -This method cannot be set for numbers, strings, and tables and -userdata with the default tag. -
      -       function setglobal (varname, newvalue)
      -         local oldvalue = rawget(globals(), varname)
      -         local tm = gettagmethod(tag(oldvalue), "setglobal")
      -         if not tm then
      -           rawset(globals(), varname, newvalue)
      -         else
      -           tm(varname, oldvalue, newvalue)
      -         end
      +
      +

    • "eq": +the == operation. +The function getcomphandler defines how Lua chooses a metamethod +for comparison operators. +A metamethod only is selected when both objects +being compared have the same type +and the same metamethod for the selected operation. +
      + function getcomphandler (op1, op2, event)
      +   if type(op1) ~= type(op2) then return nil end
      +   local mm1 = metatable(op1)[event]
      +   local mm2 = metatable(op2)[event]
      +   if mm1 == mm2 then return mm1 else return nil end
      + end
      +
      +The "eq" event is defined as follows: +
      + function eq_event (op1, op2)
      +   if type(op1) ~= type(op2) then  -- diferent types?
      +     return false   -- different objects
      +   end
      +   if op1 == op2 then   -- primitive equal?
      +     return true   -- objects are equal
      +   end
      +   -- try metamethod
      +   local h = getcomphandler(op1, op2, "__eq")
      +   if h then
      +     return h(op1, op2)
      +   else
      +     return false
      +   end
      + end
      +
      +a ~= b is equivalent to not (a == b). + +

    • "lt": +the < operation. +
      + function lt_event (op1, op2)
      +   if type(op1) == "number" and type(op2) == "number" then
      +     return op1 < op2   -- numeric comparison
      +   elseif type(op1) == "string" and type(op2) == "string" then
      +     return op1 < op2   -- lexicographic comparison
      +   else
      +     local h = getcomphandler(op1, op2, "__lt")
      +     if h then
      +       return h(op1, op2)
      +     else
      +       error("...");
      +     end
      +   end
      + end
      +
      +a > b is equivalent to b < a. + +

    • "le": +the <= operation. +
      + function le_event (op1, op2)
      +   if type(op1) == "number" and type(op2) == "number" then
      +     return op1 <= op2   -- numeric comparison
      +   elseif type(op1) == "string" and type(op2) == "string" then
      +     return op1 <= op2   -- lexicographic comparison
      +   else
      +     local h = getcomphandler(op1, op2, "__le")
      +     if h then
      +       return h(op1, op2)
      +     else
      +       h = getcomphandler(op1, op2, "__lt")
      +       if h then
      +         return not h(op2, op1)
      +       else
      +         error("...");
              end
      +     end
      +   end
      + end
      +
      +a >= b is equivalent to b <= a. +Note that, in the absence of a "le" metamethod, +Lua tries the "lt", assuming that a <= b is +equivalent to not (b < a). + +

    • "index": +The indexing access table[key]. +
      + function gettable_event (table, key)
      +   local h
      +   if type(table) == "table" then
      +     local v = rawget(table, key)
      +     if v ~= nil then return v end
      +     h = metatable(table).__index
      +     if h == nil then return nil end
      +   else
      +     h = metatable(table).__index
      +     if h == nil then
      +       error("...");
      +     end
      +   end
      +   if type(h) == "function" then
      +     return h(table, key)      -- call the handler
      +   else return h[key]          -- or repeat operation on it
      + end
       
      -The function setglobal is defined in the basic library (see Section 6.1). -

      -

      ``gettable'':
      -called whenever Lua accesses an indexed variable. -This method cannot be set for tables with the default tag. -
      -       function gettable_event (table, index)
      -         local tm = gettagmethod(tag(table), "gettable")
      -         if tm then
      -           return tm(table, index)
      -         elseif type(table) ~= "table" then
      -           error("indexed expression not a table");
      -         else
      -           local v = rawget(table, index)
      -           tm = gettagmethod(tag(table), "index")
      -           if v == nil and tm then
      -             return tm(table, index)
      -           else
      -             return v
      -           end
      -         end
      -       end
      +
      +

    • "newindex": +The indexing assignment table[key] = value. +
      + function settable_event (table, key, value)
      +   local h
      +   if type(table) == "table" then
      +     local v = rawget(table, key)
      +     if v ~= nil then rawset(table, key, value); return end
      +     h = metatable(table).__newindex
      +     if h == nil then rawset(table, key, value); return end
      +   else
      +     h = metatable(table).__newindex
      +     if h == nil then
      +       error("...");
      +     end
      +   end
      +   if type(h) == "function" then
      +     return h(table, key,value)    -- call the handler
      +   else h[key] = value             -- or repeat operation on it
      + end
       
      -

      -

      ``settable'':
      -called when Lua assigns to an indexed variable. -This method cannot be set for tables with the default tag. -
      -       function settable_event (table, index, value)
      -         local tm = gettagmethod(tag(table), "settable")
      -         if tm then
      -           tm(table, index, value)
      -         elseif type(table) ~= "table" then
      -           error("indexed expression not a table")
      -         else
      -           rawset(table, index, value)
      -         end
      -       end
      +
      +

    • "call": +called when Lua calls a value. +
      + function function_event (func, ...)
      +   if type(func) == "function" then
      +     return func(unpack(arg))   -- primitive call
      +   else
      +     local h = metatable(func).__call
      +     if h then
      +       return h(func, unpack(arg))
      +     else
      +       error("...")
      +     end
      +   end
      + end
       
      -

      -

      ``function'':
      -called when Lua tries to call a non-function value. -
      -       function function_event (func, ...)
      -         if type(func) == "function" then
      -           return call(func, arg)
      -         else
      -           local tm = gettagmethod(tag(func), "function")
      -           if tm then
      -             for i=arg.n,1,-1 do
      -               arg[i+1] = arg[i]
      -             end
      -             arg.n = arg.n+1
      -             arg[1] = func
      -             return call(tm, arg)
      -           else
      -             error("call expression not a function")
      -           end
      -         end
      -       end
      +
      +

    + +

    2.9 - Garbage Collection

    + +

    Lua does automatic memory management. +That means that +you do not have to worry about allocating memory for new objects +and freeing it when the objects are no longer needed. +Lua manages memory automatically by running +a garbage collector from time to time +to collect all dead objects +(that is, those objects that are no longer accessible from Lua). +All objects in Lua are subject to automatic management: +tables, userdata, functions, threads, and strings. + +

    Lua uses two numbers to control its garbage-collection cycles. +One number counts how many bytes of dynamic memory Lua is using; +the other is a threshold. +When the number of bytes crosses the threshold, +Lua runs the garbage collector, +which reclaims the memory of all dead objects. +The byte counter is adjusted, +and then the threshold is reset to twice the new value of the byte counter. + +

    Through the C API, you can query those numbers +and change the threshold (see 3.7). +Setting the threshold to zero actually forces an immediate +garbage-collection cycle, +while setting it to a huge number effectively stops the garbage collector. +Using Lua code you have a more limited control over garbage-collection cycles, +through the gcinfo and collectgarbage functions +(see 5.1). + +

    2.9.1 - Garbage-Collection Metamethods

    + +

    Using the C API, +you can set garbage-collector metamethods for userdata (see 2.8). +These metamethods are also called finalizers. +Finalizers allow you to coordinate Lua's garbage collection +with external resource management +(such as closing files, network or database connections, +or freeing your own memory). + +

    Free userdata with a field __gc in their metatables are not +collected immediately by the garbage collector. +Instead, Lua puts them in a list. +After the collection, +Lua does the equivalent of the following function +for each userdata in that list: +

    + function gc_event (udata)
    +   local h = metatable(udata).__gc
    +   if h then
    +     h(udata)
    +   end
    + end
     
    -

    -

    ``gc'':
    -called when Lua is ``garbage collecting'' a userdata. -This tag method can be set only from C, -and cannot be set for a userdata with the default tag. -For each userdata to be collected, -Lua does the equivalent of the following function: -
    -       function gc_event (obj)
    -         local tm = gettagmethod(tag(obj), "gc")
    -         if tm then
    -           tm(obj)
    -         end
    -       end
    +
    +

    At the end of each garbage-collection cycle, +the finalizers for userdata are called in reverse +order of their creation, +among those collected in that cycle. +That is, the first finalizer to be called is the one associated +with the userdata created last in the program. + +

    2.9.2 - Weak Tables

    + +

    A weak table is a table whose elements are +weak references. +A weak reference is ignored by the garbage collector. +In other words, +if the only references to an object are weak references, +then the garbage collector will collect that object. + +

    A weak table can have weak keys, weak values, or both. +A table with weak keys allows the collection of its keys, +but prevents the collection of its values. +A table with both weak keys and weak values allows the collection of +both keys and values. +In any case, if either the key or the value is collected, +the whole pair is removed from the table. +The weakness of a table is controlled by the value of the +__mode field of its metatable. +If the __mode field is a string containing the character `k´, +the keys in the table are weak. +If __mode contains `v´, +the values in the table are weak. + +

    After you use a table as a metatable, +you should not change the value of its field __mode. +Otherwise, the weak behavior of the tables controlled by this +metatable is undefined. + +

    2.10 - Coroutines

    + +

    Lua supports coroutines, +also called semi-coroutines +or collaborative multithreading. +A coroutine in Lua represents an independent thread of execution. +Unlike threads in multithread systems, however, +a coroutine only suspends its execution by explicitly calling +a yield function. + +

    You create a coroutine with a call to coroutine.create. +Its sole argument is a function +that is the main function of the coroutine. +The create function only creates a new coroutine and +returns a handle to it (an object of type thread); +it does not start the coroutine execution. + +

    When you first call coroutine.resume, +passing as argument the thread returned by coroutine.create, +the coroutine starts its execution, +at the first line of its main function. +Extra arguments passed to coroutine.resume are given as +parameters for the coroutine main function. +After the coroutine starts running, +it runs until it terminates or yields. + +

    A coroutine can terminate its execution in two ways: +Normally, when its main function returns +(explicitly or implicitly, after the last instruction); +and abnormally, if there is an unprotected error. +In the first case, coroutine.resume returns true, +plus any values returned by the coroutine main function. +In case of errors, coroutine.resume returns false +plus an error message. + +

    A coroutine yields by calling coroutine.yield. +When a coroutine yields, +the corresponding coroutine.resume returns immediately, +even if the yield happens inside nested function calls +(that is, not in the main function, +but in a function directly or indirectly called by the main function). +In the case of a yield, coroutine.resume also returns true, +plus any values passed to coroutine.yield. +The next time you resume the same coroutine, +it continues its execution from the point where it yielded, +with the call to coroutine.yield returning any extra +arguments passed to coroutine.resume. + +

    The coroutine.wrap function creates a coroutine +like coroutine.create, +but instead of returning the coroutine itself, +it returns a function that, when called, resumes the coroutine. +Any arguments passed to that function +go as extra arguments to resume. +The function returns all the values returned by resume, +except the first one (the boolean error code). +Unlike coroutine.resume, +this function does not catch errors; +any error is propagated to the caller. + +

    As an example, +consider the next code: +

    +function foo1 (a)
    +  print("foo", a)
    +  return coroutine.yield(2*a)
    +end
    +
    +co = coroutine.create(function (a,b)
    +      print("co-body", a, b)
    +      local r = foo1(a+1)
    +      print("co-body", r)
    +      local r, s = coroutine.yield(a+b, a-b)
    +      print("co-body", r, s)
    +      return b, "end"
    +end)
    +       
    +a, b = coroutine.resume(co, 1, 10)
    +print("main", a, b)
    +a, b, c = coroutine.resume(co, "r")
    +print("main", a, b, c)
    +a, b, c = coroutine.resume(co, "x", "y")
    +print("main", a, b, c)
    +a, b = coroutine.resume(co, "x", "y")
    +print("main", a, b)
    +
    +When you run it, it produces the following output: +
    +co-body 1       10
    +foo     2
    +main    true    4
    +co-body r
    +main    true    11      -9
    +co-body x       y
    +main    true    10      end
    +main    false   cannot resume dead coroutine
     
    -In a garbage-collection cycle, -the tag methods for userdata are called in reverse order of tag creation, -that is, the first tag methods to be called are those associated -with the last tag created in the program. -Moreover, at the end of the cycle, -Lua does the equivalent of the call gc_event(nil). -

    -

    -

    -

    -

    -

    - -


    - -

    5 - The Application Program Interface

    - -This section describes the API for Lua, that is, + +

    +

    3 - The Application Program Interface

    + + +

    This section describes the C API for Lua, that is, the set of C functions available to the host program to communicate with Lua. All API functions and related types and constants -are declared in the header file lua.h. -

    -Even when we use the term ``function'', -any facility in the API may be provided as a macro instead. -All such macros use each of its arguments exactly once, +are declared in the header file lua.h. + +

    Even when we use the term "function", +any facility in the API may be provided as a macro instead. +All such macros use each of its arguments exactly once +(except for the first argument, which is always a Lua state), and so do not generate hidden side-effects. -

    -

    - - -

    5.1 - States

    -

    -The Lua library is fully reentrant: -it does not have any global variables. - + +

    3.1 - States

    + +

    The Lua library is fully reentrant: +it has no global variables. + The whole state of the Lua interpreter -(global variables, stack, tag methods, etc.) -is stored in a dynamically allocated structure of type lua_State; -this state must be passed as the first argument to -every function in the library (except lua_open below). -

    -Before calling any API function, -you must create a state by calling - -

    -       lua_State *lua_open (int stacksize);
    -
    -The sole argument to this function is the stack size for the interpreter. -(Each function call needs one stack position for each argument, local variable, -and temporary value, plus one position for book-keeping. -The stack must also have some 20 extra positions available. -For very small implementations, without recursive functions, -a stack size of 100 should be enough.) -If stacksize is zero, -then a default size of 1024 is used. -

    -To release a state created with lua_open, call - +(global variables, stack, etc.) +is stored in a dynamically allocated structure of type lua_State. + +A pointer to this state must be passed as the first argument to +every function in the library, except to lua_open, +which creates a Lua state from scratch. + +

    Before calling any API function, +you must create a state by calling lua_open: +

    +       lua_State *lua_open (void);
    +
    + + +

    To release a state created with lua_open, call lua_close:

            void lua_close (lua_State *L);
     
    -This function destroys all objects in the given Lua environment -(calling the corresponding garbage-collection tag methods, if any) + +This function destroys all objects in the given Lua state +(calling the corresponding garbage-collection metamethods, if any) and frees all dynamic memory used by that state. -Usually, you do not need to call this function, -because all resources are naturally released when your program ends. +On several platforms, you may not need to call this function, +because all resources are naturally released when the host program ends. On the other hand, -long-running programs - -like a daemon or a web server - +long-running programs, +such as a daemon or a web server, might need to release states as soon as they are not needed, -to avoid growing too big. -

    -With the exception of lua_open, -all functions in the Lua API need a state as their first argument. -

    -

    - -

    5.2 - The Stack and Indices

    -

    -Lua uses a stack to pass values to and from C. +to avoid growing too large. + +

    3.2 - The Stack and Indices

    + +

    Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value -(nil, number, string, etc.). -

    -For convenience, +(nil, number, string, etc.). + +

    Whenever Lua calls C, the called function gets a new stack, +which is independent of previous stacks and of stacks of +C functions that are still active. +That stack initially contains any arguments to the C function, +and it is where the C function pushes its results (see 3.16) +to be returned to the caller. + +

    For convenience, most query operations in the API do not follow a strict stack discipline. -Instead, they can refer to any element in the stack by using an index: -A positive index represents an absolute stack position -(starting at 1, not 0 as in C); -a negative index represents an offset from the top of the stack. -More specifically, if the stack has n elements, -index 1 represents the first element -(that is, the first element pushed onto the stack), +Instead, they can refer to any element in the stack by using an index: +A positive index represents an absolute stack position +(starting at 1); +a negative index represents an offset from the top of the stack. +More specifically, if the stack has n elements, +then index 1 represents the first element +(that is, the element that was pushed onto the stack first) and -index n represents the last element; -index -1 also represents the last element -(that is, the element at the top), -and index -n represents the first element. -We say that an index is valid -if it lays between 1 and the stack top -(that is, if 1 <= abs(index) <= top). - -

    -At any time, you can get the index of the top element by calling - +index n represents the last element; +index -1 also represents the last element +(that is, the element at the top) +and index -n represents the first element. +We say that an index is valid +if it lies between 1 and the stack top +(that is, if 1 <= abs(index) <= top). + + +

    At any time, you can get the index of the top element by calling +lua_gettop:

            int lua_gettop (lua_State *L);
     
    Because indices start at 1, -the result of lua_gettop is equal to the number of elements in the stack +the result of lua_gettop is equal to the number of elements in the stack (and so 0 means an empty stack). -

    -When you interact with Lua API, -you are responsible for controlling stack overflow. -The function -

    -       int lua_stackspace (lua_State *L);
    -
    -returns the number of stack positions still available. -Whenever Lua calls C, -it ensures that -at least LUA_MINSTACK positions are still available. -LUA_MINSTACK is defined in lua.h and is at least 16, -and so you have to worry about stack space only -when your code has loops pushing elements onto the stack. -

    -Most query functions accept as indices any value inside the -available stack space. -Such indices are called acceptable indices. -More formally, we can define an acceptable index -as -

    -     (index < 0 && abs(index) <= top) || (index > 0 && index <= top + stackspace)
    -
    -Note that 0 is not an acceptable index. -

    - -

    5.3 - Stack Manipulation

    + +

    When you interact with Lua API, +you are responsible for controlling stack overflow. +The function +

    +       int lua_checkstack (lua_State *L, int extra);
    +
    + +grows the stack size to top + extra elements; +it returns false if it cannot grow the stack to that size. +This function never shrinks the stack; +if the stack is already larger than the new size, +it is left unchanged. + +

    Whenever Lua calls C, +it ensures that at least LUA_MINSTACK positions are available. +LUA_MINSTACK is defined in lua.h as 20, +so that usually you do not have to worry about stack space +unless your code has loops pushing elements onto the stack. + +

    Most query functions accept as indices any value inside the +available stack space, that is, indices up to the maximum stack size +you have set through lua_checkstack. +Such indices are called acceptable indices. +More formally, we define an acceptable index +as follows: +

    +     (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
    +
    +Note that 0 is never an acceptable index. + +

    Unless otherwise noted, +any function that accepts valid indices can also be called with +pseudo-indices, +which represent some Lua values that are accessible to the C code +but are not in the stack. +Pseudo-indices are used to access the global environment, +the registry, and the upvalues of a C function (see 3.17). + +

    3.3 - Stack Manipulation

    The API offers the following functions for basic stack manipulation: - -
            void lua_settop    (lua_State *L, int index);
            void lua_pushvalue (lua_State *L, int index);
            void lua_remove    (lua_State *L, int index);
            void lua_insert    (lua_State *L, int index);
    +       void lua_replace   (lua_State *L, int index);
     
    -

    -lua_settop accepts any acceptable index, + + + +

    lua_settop accepts any acceptable index, or 0, and sets the stack top to that index. If the new top is larger than the old one, then the new elements are filled with nil. -If index is 0, then all stack elements are removed. -A useful macro defined in the API is +If index is 0, then all stack elements are removed. +A useful macro defined in the lua.h is

    -       #define lua_pop(L,n) lua_settop(L, -(n)-1)
    +       #define lua_pop(L,n)   lua_settop(L, -(n)-1)
     
    -which pops n elements from the stack. -

    -lua_pushvalue pushes onto the stack a copy of the element + +which pops n elements from the stack. + +

    lua_pushvalue pushes onto the stack a copy of the element at the given index. -lua_remove removes the element at the given position, -shifting down the elements on top of that position to fill in the gap. -lua_insert moves the top element into the given position, -shifting up the elements on top of that position to open space. -These functions accept only valid indices. -As an example, if the stack starts as 10 20 30 40 50 -(from bottom to top), +lua_remove removes the element at the given position, +shifting down the elements above that position to fill the gap. +lua_insert moves the top element into the given position, +shifting up the elements above that position to open space. +lua_replace moves the top element into the given position, +without shifting any element (therefore replacing the value at +the given position). +All these functions accept only valid indices. +(You cannot call lua_remove or lua_insert with +pseudo-indices, as they do not represent a stack position.) + +

    As an example, if the stack starts as 10 20 30 40 50* +(from bottom to top; the `*´ marks the top), then

    -       lua_pushvalue(L, 3)    --> 10 20 30 40 50 30
    -       lua_pushvalue(L, -1)   --> 10 20 30 40 50 30 30
    -       lua_remove(L, -3)      --> 10 20 30 40 30 30
    -       lua_remove(L,  6)      --> 10 20 30 40 30
    -       lua_insert(L,  1)      --> 30 10 20 30 40
    -       lua_insert(L, -1)      --> 30 10 20 30 40  (no effect)
    -       lua_settop(L, -3)      --> 30 10 20
    -       lua_settop(L, 6)       --> 30 10 20 nil nil nil
    -
    -

    -

    - -

    5.4 - Querying the Stack

    -

    -To check the type of a stack element, + lua_pushvalue(L, 3) --> 10 20 30 40 50 30* + lua_pushvalue(L, -1) --> 10 20 30 40 50 30 30* + lua_remove(L, -3) --> 10 20 30 40 30 30* + lua_remove(L, 6) --> 10 20 30 40 30* + lua_insert(L, 1) --> 30 10 20 30 40* + lua_insert(L, -1) --> 30 10 20 30 40* (no effect) + lua_replace(L, 2) --> 30 40 20 30* + lua_settop(L, -3) --> 30 40* + lua_settop(L, 6) --> 30 40 nil nil nil nil* +

    + +

    3.4 - Querying the Stack

    + +

    To check the type of a stack element, the following functions are available: - - - - -

    -       int         lua_type        (lua_State *L, int index);
    -       int         lua_tag         (lua_State *L, int index);
    -       int         lua_isnil       (lua_State *L, int index);
    -       int         lua_isnumber    (lua_State *L, int index);
    -       int         lua_isstring    (lua_State *L, int index);
    -       int         lua_istable     (lua_State *L, int index);
    -       int         lua_isfunction  (lua_State *L, int index);
    -       int         lua_iscfunction (lua_State *L, int index);
    -       int         lua_isuserdata  (lua_State *L, int index);
    +
    +       int lua_type            (lua_State *L, int index);
    +       int lua_isnil           (lua_State *L, int index);
    +       int lua_isboolean       (lua_State *L, int index);
    +       int lua_isnumber        (lua_State *L, int index);
    +       int lua_isstring        (lua_State *L, int index);
    +       int lua_istable         (lua_State *L, int index);
    +       int lua_isfunction      (lua_State *L, int index);
    +       int lua_iscfunction     (lua_State *L, int index);
    +       int lua_isuserdata      (lua_State *L, int index);
    +       int lua_islightuserdata (lua_State *L, int index);
     
    + + + + + These functions can be called with any acceptable index. -

    -lua_type returns one of the following constants, -according to the type of the given object: -LUA_TNIL, -LUA_TNUMBER, -LUA_TSTRING, -LUA_TTABLE, -LUA_TFUNCTION, -LUA_TUSERDATA. -If the index is non-valid -(that is, if that stack position is ``empty''), -then lua_type returns LUA_TNONE. -These constants can be converted to strings with - -

    -       const char *lua_typename (lua_State *L, int t);
    -
    -where t is a type returned by lua_type. -The strings returned by lua_typename are -"nil", "number", "string", "table", -"function", "userdata", and "no value", -

    -lua_tag returns the tag of a value, -or LUA_NOTAG for a non-valid index. -

    -The lua_is* functions return 1 if the object is compatible + +

    lua_type returns the type of a value in the stack, +or LUA_TNONE for a non-valid index +(that is, if that stack position is "empty"). +The types returned by lua_type are coded by the following constants +defined in lua.h: +LUA_TNIL, +LUA_TNUMBER, +LUA_TBOOLEAN, +LUA_TSTRING, +LUA_TTABLE, +LUA_TFUNCTION, +LUA_TUSERDATA, +LUA_TTHREAD, +LUA_TLIGHTUSERDATA. +The following function translates these constants to strings: +

    +       const char *lua_typename  (lua_State *L, int type);
    +
    + + +

    The lua_is* functions return 1 if the object is compatible with the given type, and 0 otherwise. +lua_isboolean is an exception to this rule: +It succeeds only for boolean values +(otherwise it would be useless, +as any value has a boolean value). They always return 0 for a non-valid index. -lua_isnumber accepts numbers and numerical strings, -lua_isstring accepts strings and numbers (see Section 4.2), -and lua_isfunction accepts both Lua functions and C functions. +lua_isnumber accepts numbers and numerical strings; +lua_isstring accepts strings and numbers (see 2.2.1); +lua_isfunction accepts both Lua functions and C functions; +and lua_isuserdata accepts both full and light userdata. To distinguish between Lua functions and C functions, -you should use lua_iscfunction. +you can use lua_iscfunction. +To distinguish between full and light userdata, +you can use lua_islightuserdata. To distinguish between numbers and numerical strings, -you can use lua_type. -

    -The API also has functions to compare two values in the stack: - - +you can use lua_type. + +

    The API also contains functions to compare two values in the stack:

            int lua_equal    (lua_State *L, int index1, int index2);
    +       int lua_rawequal (lua_State *L, int index1, int index2);
            int lua_lessthan (lua_State *L, int index1, int index2);
     
    -These functions are equivalent to their counterparts in Lua. -Specifically, lua_lessthan is equivalent to the lt_event -described in Section 4.8. -Both functions return 0 if any of the indices are non-valid. -

    -To translate a value in the stack to a specific C type, + +lua_equal and lua_lessthan +are equivalent to their counterparts in Lua (see 2.5.2). +lua_rawequal compares the values for primitive equality, +without metamethods. +These functions return 0 (false) if any of the indices are non-valid. + +

    3.5 - Getting Values from the Stack

    + +

    To translate a value in the stack to a specific C type, you can use the following conversion functions: - -

    -       double         lua_tonumber    (lua_State *L, int index);
    +       int            lua_toboolean   (lua_State *L, int index);
    +       lua_Number     lua_tonumber    (lua_State *L, int index);
            const char    *lua_tostring    (lua_State *L, int index);
            size_t         lua_strlen      (lua_State *L, int index);
            lua_CFunction  lua_tocfunction (lua_State *L, int index);
            void          *lua_touserdata  (lua_State *L, int index);
    +       lua_State     *lua_tothread    (lua_State *L, int index);
    +       void          *lua_topointer   (lua_State *L, int index);
     
    + + + These functions can be called with any acceptable index. When called with a non-valid index, they act as if the given value had an incorrect type. -

    -lua_tonumber converts the value at the given index -to a floating-point number. -This value must be a number or a string convertible to number -(see Section 4.2); otherwise, lua_tonumber returns 0. -

    -lua_tostring converts a Lua value to a string -(const char*). -This value must be a string or a number; -otherwise, the function returns NULL. -This function returns a pointer to a string inside the Lua environment. -Those strings always have a zero ('\0') after their last character (as in C), -but may contain other zeros in their body. + +

    lua_toboolean converts the Lua value at the given index +to a C "boolean" value (0 or 1). +Like all tests in Lua, lua_toboolean returns 1 for any Lua value +different from false and nil; +otherwise it returns 0. +It also returns 0 when called with a non-valid index. +(If you want to accept only real boolean values, +use lua_isboolean to test the type of the value.) + +

    lua_tonumber converts the Lua value at the given index +to a number (by default, lua_Number is double). + +The Lua value must be a number or a string convertible to number +(see 2.2.1); otherwise, lua_tonumber returns 0. + +

    lua_tostring converts the Lua value at the given index to a string +(const char*). +The Lua value must be a string or a number; +otherwise, the function returns NULL. +If the value is a number, +then lua_tostring also +changes the actual value in the stack to a string. +(This change confuses lua_next +when lua_tostring is applied to keys.) +lua_tostring returns a fully aligned pointer +to a string inside the Lua state. +This string always has a zero ('\0') +after its last character (as in C), +but may contain other zeros in its body. If you do not know whether a string may contain zeros, -you should use lua_strlen to get its actual length. +you can use lua_strlen to get its actual length. Because Lua has garbage collection, -there is no guarantee that the pointer returned by lua_tostring -will be valid after the respective value is removed from the stack. -

    -lua_tocfunction converts a value in the stack to a C function. +there is no guarantee that the pointer returned by lua_tostring +will be valid after the corresponding value is removed from the stack. +If you need the string after the current function returns, +then you should duplicate it or put it into the registry (see 3.18). + +

    lua_tocfunction converts a value in the stack to a C function. This value must be a C function; -otherwise, lua_tocfunction returns NULL. -The type lua_CFunction is explained in Section 5.13. -

    -lua_touserdata converts a value to void*. -This value must have type userdata; -otherwise, lua_touserdata returns NULL. -

    -

    -

    - -

    5.5 - Pushing values onto the Stack

    -

    -The API has the following functions to +otherwise, lua_tocfunction returns NULL. +The type lua_CFunction is explained in 3.16. + +

    lua_tothread converts a value in the stack to a Lua thread +(represented as lua_State *). +This value must be a thread; +otherwise, lua_tothread returns NULL. + +

    lua_topointer converts a value in the stack to a generic +C pointer (void *). +The value may be a userdata, a table, a thread, or a function; +otherwise, lua_topointer returns NULL. +Lua ensures that different objects of the +same type return different pointers. +There is no direct way to convert the pointer back to its original value. +Typically this function is used for debug information. + +

    lua_touserdata is explained in 3.8. + +

    3.6 - Pushing Values onto the Stack

    + +

    The API has the following functions to push C values onto the stack: - - - - -

    -       void lua_pushnumber    (lua_State *L, double n);
    -       void lua_pushlstring   (lua_State *L, const char *s, size_t len);
    -       void lua_pushstring    (lua_State *L, const char *s);
    -       void lua_pushusertag   (lua_State *L, void *u, int tag);
    -       void lua_pushnil       (lua_State *L);
    -       void lua_pushcfunction (lua_State *L, lua_CFunction f);
    +
    +       void lua_pushboolean       (lua_State *L, int b);
    +       void lua_pushnumber        (lua_State *L, lua_Number n);
    +       void lua_pushlstring       (lua_State *L, const char *s, size_t len);
    +       void lua_pushstring        (lua_State *L, const char *s);
    +       void lua_pushnil           (lua_State *L);
    +       void lua_pushcfunction     (lua_State *L, lua_CFunction f);
    +       void lua_pushlightuserdata (lua_State *L, void *p);
     
    + +

    + + These functions receive a C value, convert it to a corresponding Lua value, and push the result onto the stack. -In particular, lua_pushlstring and lua_pushstring -make an internal copy of the given string. -lua_pushstring can only be used to push proper C strings +In particular, lua_pushlstring and lua_pushstring +make an internal copy of the given string. +lua_pushstring can only be used to push proper C strings (that is, strings that end with a zero and do not contain embedded zeros); -otherwise you should use the more general lua_pushlstring, +otherwise, you should use the more general lua_pushlstring, which accepts an explicit size. -

    -

    - - -

    5.6 - Garbage Collection

    -

    -Lua uses two numbers to control its garbage collection. -One number counts how many bytes of dynamic memory Lua is using, -and the other is a threshold. -(This internal byte counter kept by Lua is not completely acurate; -it is just a lower bound, usually within 10% of the correct value.) -When the number of bytes crosses the threshold, -Lua runs a garbage-collection cycle, -which reclaims the memory of all ``dead'' objects -(that is, objects no longer accessible from Lua). -The byte counter is corrected, -and then the threshold is reset to twice the value of the byte counter. -

    -You can access the current values of these two numbers through the + +

    You can also push "formatted" strings: +

    +       const char *lua_pushfstring  (lua_State *L, const char *fmt, ...);
    +       const char *lua_pushvfstring (lua_State *L, const char *fmt,
    +                                                   va_list argp);
    +
    + +These functions push onto the stack a formatted string +and return a pointer to that string. +They are similar to sprintf and vsprintf, +but with some important differences: +
      +
    • You do not have to allocate the space for the result: +The result is a Lua string and Lua takes care of memory allocation +(and deallocation, through garbage collection). +
    • The conversion specifiers are quite restricted. +There are no flags, widths, or precisions. +The conversion specifiers can be simply +`%%´ (inserts a `%´ in the string), +`%s´ (inserts a zero-terminated string, with no size restrictions), +`%f´ (inserts a lua_Number), +`%d´ (inserts an int), and +`%c´ (inserts an int as a character). +
    + +

    The function +

    +       void lua_concat (lua_State *L, int n);
    +
    + +concatenates the n values at the top of the stack, +pops them, and leaves the result at the top. +If n is 1, the result is that single string +(that is, the function does nothing); +if n is 0, the result is the empty string. +Concatenation is done following the usual semantics of Lua +(see 2.5.4). + +

    3.7 - Controlling Garbage Collection

    + +

    Lua uses two numbers to control its garbage collection: +the count and the threshold (see 2.9). +The first counts the amount of memory in use by Lua; +when the count reaches the threshold, +Lua runs its garbage collector. +After the collection, the count is updated +and the threshold is set to twice the count value. + +

    You can access the current values of these two numbers through the following functions: -

            int  lua_getgccount (lua_State *L);
            int  lua_getgcthreshold (lua_State *L);
     
    + Both return their respective values in Kbytes. You can change the threshold value with -
            void  lua_setgcthreshold (lua_State *L, int newthreshold);
     
    -Again, the newthreshold value is given in Kbytes. + +Again, the newthreshold value is given in Kbytes. When you call this function, Lua sets the new threshold and checks it against the byte counter. -If the new threshold is smaller than the byte counter, -then Lua immediately runs the garbage collector; -after the collection, +If the new threshold is less than the byte counter, +then Lua immediately runs the garbage collector. +In particular +lua_setgcthreshold(L,0) forces a garbage collection. +After the collection, a new threshold is set according to the previous rule. -

    -If you want to change the adaptative behavior of the garbage collector, -you can use the garbage-collection tag method for nil -to set your own threshold -(the tag method is called after Lua resets the threshold). -

    -

    - - -

    5.7 - Userdata and Tags

    -

    -Because userdata are objects, -the function lua_pushusertag may create a new userdata. -If Lua has a userdata with the given value (void*) and tag, -then that userdata is pushed. -Otherwise, a new userdata is created, with the given value and tag. -If this function is called with -tag equal to LUA_ANYTAG, -then Lua will try to find any userdata with the given value, -regardless of its tag. -If there is no userdata with that value, then a new one is created, -with tag equal to 0. -

    -Userdata can have different tags, -whose semantics are only known to the host program. -Tags are created with the function - -

    -       int lua_newtag (lua_State *L);
    -
    -The function lua_settag changes the tag of -the object on top of the stack (without popping it): - -
    -       void lua_settag (lua_State *L, int tag);
    -
    -The object must be a userdata or a table; -the given tag must be a value created with lua_newtag. -

    - - -

    5.8 - Executing Lua Code

    -A host program can execute Lua chunks written in a file or in a string -by using the following functions: - -
    -       int lua_dofile   (lua_State *L, const char *filename);
    -       int lua_dostring (lua_State *L, const char *string);
    -       int lua_dobuffer (lua_State *L, const char *buff,
    -                         size_t size, const char *name);
    -
    -These functions return -0 in case of success, or one of the following error codes if they fail: -
      -
    • LUA_ERRRUN - -error while running the chunk. -
    • LUA_ERRSYNTAX - + +

      3.8 - Userdata

      + +

      Userdata represents C values in Lua. +Lua supports two types of userdata: +full userdata and light userdata. + +

      A full userdata represents a block of memory. +It is an object (like a table): +You must create it, it can have its own metatable, +and you can detect when it is being collected. +A full userdata is only equal to itself (under raw equality). + +

      A light userdata represents a pointer. +It is a value (like a number): +You do not create it, it has no metatables, +it is not collected (as it was never created). +A light userdata is equal to "any" +light userdata with the same C address. + +

      In Lua code, there is no way to test whether a userdata is full or light; +both have type userdata. +In C code, lua_type returns LUA_TUSERDATA for full userdata, +and LUA_TLIGHTUSERDATA for light userdata. + +

      You can create a new full userdata with the following function: +

      +       void *lua_newuserdata (lua_State *L, size_t size);
      +
      + +This function allocates a new block of memory with the given size, +pushes on the stack a new userdata with the block address, +and returns this address. + +

      To push a light userdata into the stack you use +lua_pushlightuserdata (see 3.6). + +

      lua_touserdata (see 3.5) retrieves the value of a userdata. +When applied on a full userdata, it returns the address of its block; +when applied on a light userdata, it returns its pointer; +when applied on a non-userdata value, it returns NULL. + +

      When Lua collects a full userdata, +it calls the userdata's gc metamethod, if any, +and then it frees the userdata's corresponding memory. + +

      3.9 - Metatables

      + +

      The following functions allow you to manipulate the metatables +of an object: +

      +       int lua_getmetatable (lua_State *L, int index);
      +       int lua_setmetatable (lua_State *L, int index);
      +
      + +lua_getmetatable pushes on the stack the metatable of a given object. +If the index is not valid, +or if the object does not have a metatable, +lua_getmetatable returns 0 and pushes nothing on the stack. + +

      lua_setmetatable pops a table from the stack and +sets it as the new metatable for the given object. +lua_setmetatable returns 0 when it cannot +set the metatable of the given object +(that is, when the object is neither a userdata nor a table); +even then it pops the table from the stack. + +

      3.10 - Loading Lua Chunks

      + +

      You can load a Lua chunk with lua_load: +

      +       typedef const char * (*lua_Chunkreader)
      +                                (lua_State *L, void *data, size_t *size);
      +
      +       int lua_load (lua_State *L, lua_Chunkreader reader, void *data,
      +                                   const char *chunkname);
      +
      + +The return values of lua_load are: +
        +
      • 0 --- no errors; +
      • LUA_ERRSYNTAX --- syntax error during pre-compilation. -
      • LUA_ERRMEM - +
      • LUA_ERRMEM --- memory allocation error. -For such errors, Lua does not call _ERRORMESSAGE (see Section 4.7). -
      • LUA_ERRERR - -error while running _ERRORMESSAGE. -For such errors, Lua does not call _ERRORMESSAGE again, to avoid loops. -
      • LUA_ERRFILE - -error opening the file (only for lua_dofile). -In this case, -you may want to -check errno, -call strerror, -or call perror to tell the user what went wrong. -
      -These constants are defined in lua.h. -

      -When called with argument NULL, -lua_dofile executes the stdin stream. -lua_dofile and lua_dobuffer -are both able to execute pre-compiled chunks. -They automatically detect whether the chunk is text or binary, -and load it accordingly (see program luac). -lua_dostring executes only source code, -given in textual form. -

      -The third parameter to lua_dobuffer -is the ``name of the chunk'', -which is used in error messages and debug information. -If name is NULL, -then Lua gives a default name to the chunk. -

      -These functions push onto the stack -any values eventually returned by the chunk. -A chunk may return any number of values; -Lua takes care that these values fit into the stack space, -but after the call the responsibility is back to you. -If you need to push other elements after calling any of these functions, -and you want to ``play safe'', -you must either check the stack space -with lua_stackspace -or remove the returned elements -from the stack (if you do not need them). -For instance, the following code -loads a chunk in a file and discards all results returned by this chunk, -leaving the stack as it was before the call: -

      -      {
      -       int oldtop = lua_gettop(L);
      -       lua_dofile(L, filename);
      -       lua_settop(L, oldtop);
      -      }
      -
      -

      -

      - -

      5.9 - Manipulating Global Variables in Lua

      -

      -To read the value of a global Lua variable, -you call - -

      -       void lua_getglobal (lua_State *L, const char *varname);
      -
      -which pushes onto the stack the value of the given variable. -As in Lua, this function may trigger a tag method -for the ``getglobal'' event (see Section 4.8). -To read the real value of a global variable, -without invoking any tag method, -use lua_rawget over the table of globals -(see below). -

      -To store a value in a global variable, -you call - -

      -       void lua_setglobal (lua_State *L, const char *varname);
      -
      -which pops from the stack the value to be stored in the given variable. -As in Lua, this function may trigger a tag method -for the ``setglobal'' event (see Section 4.8). -To set the real value of a global variable, -without invoking any tag method, -use lua_rawset over the table of globals -(see below). -

      -All global variables are kept in an ordinary Lua table. -You can get this table calling - -

      -       void lua_getglobals (lua_State *L);
      -
      -which pushes the current table of globals onto the stack. -To set another table as the table of globals, -you call - -
      -       void lua_setglobals (lua_State *L);
      -
      -The table to be used is popped from the stack. -

      - -

      5.10 - Manipulating Tables in Lua

      -Lua tables can also be manipulated through the API. -

      -To read the value of in a table, -the table must reside somewhere in the stack. -With this set, -you call - +

    +If there are no errors, +lua_load pushes the compiled chunk as a Lua +function on top of the stack. +Otherwise, it pushes an error message. + +

    lua_load automatically detects whether the chunk is text or binary, +and loads it accordingly (see program luac). + +

    lua_load uses an user-supplied reader function to read the chunk. +Everytime it needs another piece of the chunk, +it calls the reader, +passing along its data parameter. +The reader must return a pointer to a block of memory +with a new piece of the chunk +and set size to the block size. +To signal the end of the chunk, the reader returns NULL. +The reader function may return pieces of any size greater than zero. + +

    In the current implementation, +the reader function cannot call any Lua function; +to ensure that, it always receives NULL as the Lua state. + +

    The chunkname is used for error messages +and debug information (see 4). + +

    See the auxiliary library (lauxlib.c) +for examples of how to use lua_load +and for some ready-to-use functions to load chunks +from files and strings. + +

    3.11 - Manipulating Tables

    + +

    Tables are created by calling +the function +

    +       void lua_newtable (lua_State *L);
    +
    + +This function creates a new, empty table and pushes it onto the stack. + +

    To read a value from a table that resides somewhere in the stack, +call

            void lua_gettable (lua_State *L, int index);
     
    -where index refers to the table. -lua_gettable pops a key from the stack, + +where index points to the table. +lua_gettable pops a key from the stack and returns (on the stack) the contents of the table at that key. -As in Lua, this operation may trigger a tag method -for the ``gettable'' event. +The table is left where it was in the stack. +As in Lua, this function may trigger a metamethod +for the "index" event (see 2.8). To get the real value of any table key, -without invoking any tag method, -use the raw version: - +without invoking any metamethod, +use the raw version:
            void lua_rawget (lua_State *L, int index);
     
    -

    -To store a value into a table that resides somewhere in the stack, -you push the key and the value onto the stack -(in this order), -and then call - + + +

    To store a value into a table that resides somewhere in the stack, +you push the key and then the value onto the stack, +and call

            void lua_settable (lua_State *L, int index);
     
    -where index refers to the table. -lua_settable pops from the stack both the key and the value. -As in Lua, this operation may trigger a tag method -for the ``settable'' event. + +where index points to the table. +lua_settable pops from the stack both the key and the value. +The table is left where it was in the stack. +As in Lua, this operation may trigger a metamethod +for the "settable" or "newindex" events. To set the real value of any table index, -without invoking any tag method, -use the raw version: - +without invoking any metamethod, +use the raw version:
            void lua_rawset (lua_State *L, int index);
     
    -

    -Finally, the function - + + +

    You can traverse a table with the function +

    +       int lua_next (lua_State *L, int index);
    +
    + +where index points to the table to be traversed. +The function pops a key from the stack, +and pushes a key-value pair from the table +(the "next" pair after the given key). +If there are no more elements, then lua_next returns 0 +(and pushes nothing). +Use a nil key to signal the start of a traversal. + +

    A typical traversal looks like this:

    -       void lua_newtable (lua_State *L);
    +       /* table is in the stack at index `t' */
    +       lua_pushnil(L);  /* first key */
    +       while (lua_next(L, t) != 0) {
    +         /* `key' is at index -2 and `value' at index -1 */
    +         printf("%s - %s\n",
    +           lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
    +         lua_pop(L, 1);  /* removes `value'; keeps `key' for next iteration */
    +       }
     
    -creates a new, empty table and pushes it onto the stack. -

    - -

    5.11 - Using Tables as Arrays

    + +

    While traversing a table, +do not call lua_tostring directly on a key, +unless you know that the key is actually a string. +Recall that lua_tostring changes the value at the given index; +this confuses the next call to lua_next. + +

    3.12 - Manipulating Environments

    + +

    All global variables are kept in ordinary Lua tables, +called environments. +The initial environment is called the global environment. +This table is always at pseudo-index LUA_GLOBALSINDEX. + +

    To access and change the value of global variables, +you can use regular table operations over an environment table. +For instance, to access the value of a global variable, do +

    +       lua_pushstring(L, varname);
    +       lua_gettable(L, LUA_GLOBALSINDEX);
    +
    + +

    You can change the global environment of a Lua thread using lua_replace. + +

    The following functions get and set the environment of Lua functions: +

    +       void lua_getfenv (lua_State *L, int index);
    +       int  lua_setfenv (lua_State *L, int index);
    +
    + +lua_getfenv pushes on the stack the environment table of +the function at index index in the stack. +If the function is a C function, +lua_getfenv pushes the global environment. +lua_setfenv pops a table from the stack and sets it as +the new environment for the function at index index in the stack. +If the object at the given index is not a Lua function, +lua_setfenv returns 0. + +

    3.13 - Using Tables as Arrays

    The API has functions that help to use Lua tables as arrays, that is, tables indexed by numbers only: - - -
            void lua_rawgeti (lua_State *L, int index, int n);
            void lua_rawseti (lua_State *L, int index, int n);
    -       int  lua_getn    (lua_State *L, int index);
    -
    -

    -lua_rawgeti gets the value of the n-th element of the table -at stack position index. -

    -lua_rawseti sets the value of the n-th element of the table -at stack position index to the value at the top of the stack. -

    -lua_getn returns the number of elements in the table -at stack position index. -This number is the value of the table field n, -if it has a numeric value, -or -the largest numerical index with a non-nil value in the table. -

    - -

    5.12 - Calling Lua Functions

    -

    -Functions defined in Lua -(and C functions registered in Lua) +

    + + + +

    lua_rawgeti pushes the value of the n-th element of the table +at stack position index. +lua_rawseti sets the value of the n-th element of the table +at stack position index to the value at the top of the stack, +removing this value from the stack. + +

    3.14 - Calling Functions

    + +

    Functions defined in Lua +and C functions registered in Lua can be called from the host program. This is done using the following protocol: First, the function to be called is pushed onto the stack; then, the arguments to the function are pushed -(see Section 5.5) in direct order, that is, the first argument is pushed first. +in direct order, that is, the first argument is pushed first. Finally, the function is called using - -

    -       int lua_call (lua_State *L, int nargs, int nresults);
    -
    -This function returns the same error codes as lua_dostring and -friends (see Section 5.8). -If you want to propagate the error, -instead of returning an error code, -use -
    -       void lua_rawcall (lua_State *L, int nargs, int nresults);
    +       void lua_call (lua_State *L, int nargs, int nresults);
     
    -

    -In both functions, -nargs is the number of arguments that you pushed onto the stack. + +nargs is the number of arguments that you pushed onto the stack. All arguments and the function value are popped from the stack, and the function results are pushed. -The number of results are adjusted (see Section 4.3) to nresults, -unless nresults is LUA_MULTRET. -In that case, all results from the function are pushed. -The function results are pushed in direct order +The number of results are adjusted to nresults, +unless nresults is LUA_MULTRET. +In that case, all results from the function are pushed. +Lua takes care that the returned values fit into the stack space. +The function results are pushed onto the stack in direct order (the first result is pushed first), so that after the call the last result is on the top. -

    -The following example shows how the host program may do the -equivalent to the Lua code: + +

    The following example shows how the host program may do the +equivalent to this Lua code:

    -       a,b = f("how", t.x, 4)
    +       a = f("how", t.x, 14)
     
    Here it is in C:
    -    lua_getglobal(L, "t");                      /* global `t' (for later use) */
    -    lua_getglobal(L, "f");                           /* function to be called */
    +    lua_pushstring(L, "t");
    +    lua_gettable(L, LUA_GLOBALSINDEX);          /* global `t' (for later use) */
    +    lua_pushstring(L, "a");                                       /* var name */
    +    lua_pushstring(L, "f");                                  /* function name */
    +    lua_gettable(L, LUA_GLOBALSINDEX);               /* function to be called */
         lua_pushstring(L, "how");                                 /* 1st argument */
    -    lua_pushstring(L, "x");                            /* push the string `x' */
    -    lua_gettable(L, -4);                      /* push result of t.x (2nd arg) */
    -    lua_pushnumber(L, 4);                                     /* 3rd argument */
    -    lua_call(L, 3, 2);        /* call function with 3 arguments and 2 results */
    -    lua_setglobal(L, "b");                         /* set global variable `b' */
    -    lua_setglobal(L, "a");                         /* set global variable `a' */
    +    lua_pushstring(L, "x");                            /* push the string "x" */
    +    lua_gettable(L, -5);                      /* push result of t.x (2nd arg) */
    +    lua_pushnumber(L, 14);                                    /* 3rd argument */
    +    lua_call(L, 3, 1);         /* call function with 3 arguments and 1 result */
    +    lua_settable(L, LUA_GLOBALSINDEX);             /* set global variable `a' */
         lua_pop(L, 1);                               /* remove `t' from the stack */
     
    -Notice that the code above is ``balanced'': -at its end ,the stack is back to its original configuration. +Note that the code above is "balanced": +at its end, the stack is back to its original configuration. This is considered good programming practice. -

    -

    -

    -Some special Lua functions have their own C interfaces. -The host program can generate a Lua error calling the function - -

    -       void lua_error (lua_State *L, const char *message);
    -
    -This function never returns. -If lua_error is called from a C function that has been called from Lua, -then the corresponding Lua execution terminates, -as if an error had occurred inside Lua code. -Otherwise, the whole host program terminates with a call to -exit(EXIT_FAILURE). -Before terminating execution, -the message is passed to the error handler function, -_ERRORMESSAGE (see Section 4.7). -If message is NULL, -then _ERRORMESSAGE is not called. -

    -

    -Tag methods can be changed with -

    -       void lua_settagmethod (lua_State *L, int tag, const char *event);
    -
    -The second parameter is the tag, -and the third is the event name (see Section 4.8); -the new method is popped from the stack. -To get the current value of a tag method, -use the function -
    -       void lua_gettagmethod (lua_State *L, int tag, const char *event);
    -
    -

    -It is also possible to copy all tag methods from one tag -to another: -

    -       int lua_copytagmethods (lua_State *L, int tagto, int tagfrom);
    -
    -This function returns tagto. -

    -

    -You can traverse a table with the function -

    -       int lua_next (lua_State *L, int index);
    -
    -where index refers to the table to be traversed. -The function pops a key from the stack, -and pushes a key-value pair from the table -(the ``next'' pair after the given key). -If there are no more elements, then the function returns 0 -(and pushes nothing). -A typical traversal looks like this: -
    -       /* table is in the stack at index `t' */
    -       lua_pushnil(L);  /* first key */
    -       while (lua_next(L, t) != 0) {
    -         /* `key' is at index -2 and `value' at index -1 */
    -         printf("%s - %s\n",
    -           lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
    -         lua_pop(L, 1);  /* removes `value'; keeps `index' for next iteration */
    -       }
    -
    -

    -The function -

    -       void lua_concat (lua_State *L, int n);
    -
    -concatenates the n values at the top of the stack, -pops them, and leaves the result at the top; -n must be at least 2. -Concatenation is done following the usual semantics of Lua -(see Section 4.5.5). -

    -

    - - -

    5.13 - Defining C Functions

    -To register a C function to Lua, -there is the following convenience macro: - -
    -     #define lua_register(L, n, f) (lua_pushcfunction(L, f), lua_setglobal(L, n))
    -     /* const char *n;   */
    -     /* lua_CFunction f; */
    -
    -which receives the name the function will have in Lua, -and a pointer to the function. -This pointer must have type lua_CFunction, -which is defined as - + +

    (We did this example using only the raw functions provided by Lua's API, +to show all the details. +Usually programmers define and use several macros and auxiliary functions +that provide higher level access to Lua. +See the source code of the standard libraries for examples.) + +

    3.15 - Protected Calls

    + +

    When you call a function with lua_call, +any error inside the called function is propagated upwards +(with a longjmp). +If you need to handle errors, +then you should use lua_pcall: +

    +       int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
    +
    +Both nargs and nresults have the same meaning as +in lua_call. +If there are no errors during the call, +lua_pcall behaves exactly like lua_call. +However, if there is any error, +lua_pcall catches it, +pushes a single value at the stack (the error message), +and returns an error code. +Like lua_call, +lua_pcall always removes the function +and its arguments from the stack. + +

    If errfunc is 0, +then the error message returned is exactly the original error message. +Otherwise, errfunc gives the stack index for an +error handler function. +(In the current implementation, that index cannot be a pseudo-index.) +In case of runtime errors, +that function will be called with the error message +and its return value will be the message returned by lua_pcall. + +

    Typically, the error handler function is used to add more debug +information to the error message, such as a stack traceback. +Such information cannot be gathered after the return of lua_pcall, +since by then the stack has unwound. + +

    The lua_pcall function returns 0 in case of success +or one of the following error codes +(defined in lua.h): +

      +
    • LUA_ERRRUN --- a runtime error. +
    • LUA_ERRMEM --- memory allocation error. +For such errors, Lua does not call the error handler function. +
    • LUA_ERRERR --- +error while running the error handler function. +
    + +

    3.16 - Defining C Functions

    + +

    Lua can be extended with functions written in C. +These functions must be of type lua_CFunction, +which is defined as

            typedef int (*lua_CFunction) (lua_State *L);
     
    -that is, a pointer to a function with integer result and a single argument, -a Lua environment. -

    -In order to communicate properly with Lua, + +A C function receives a Lua state and returns an integer, +the number of values it wants to return to Lua. + +

    In order to communicate properly with Lua, a C function must follow the following protocol, which defines the way parameters and results are passed: -A C function receives its arguments from Lua in the stack, +A C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first). +So, when the function starts, +its first argument (if any) is at index 1. To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results. +Any other value in the stack below the results will be properly +discharged by Lua. Like a Lua function, a C function called by Lua can also return many results. -

    -As an example, the following function receives a variable number + +

    As an example, the following function receives a variable number of numerical arguments and returns their average and sum:

            static int foo (lua_State *L) {
              int n = lua_gettop(L);    /* number of arguments */
    -         double sum = 0;
    +         lua_Number sum = 0;
              int i;
    -         for (i = 1; i <= n; i++) {
    -           if (!lua_isnumber(L, i))
    -             lua_error(L, "incorrect argument to function `average'");
    +         for (i = 1; i <= n; i++) {
    +           if (!lua_isnumber(L, i)) {
    +             lua_pushstring(L, "incorrect argument to function `average'");
    +             lua_error(L);
    +           }
                sum += lua_tonumber(L, i);
              }
              lua_pushnumber(L, sum/n);        /* first result */
    @@ -2152,1648 +2457,2157 @@ 

    5.13 - Defining C Functions

    return 2; /* number of results */ }
    -This function may be registered in Lua as `average' by calling + +

    To register a C function to Lua, +there is the following convenience macro: +

    +       #define lua_register(L,n,f) \
    +               (lua_pushstring(L, n), \
    +                lua_pushcfunction(L, f), \
    +                lua_settable(L, LUA_GLOBALSINDEX))
    +     /* lua_State *L;    */
    +     /* const char *n;   */
    +     /* lua_CFunction f; */
    +
    + +which receives the name the function will have in Lua +and a pointer to the function. +Thus, +the C function foo above may be registered in Lua as +average by calling
            lua_register(L, "average", foo);
     
    -

    -

    -When a C function is created, -it is possible to associate some upvalues to it -(see Section 4.6), -thus creating a C closure; -these values are passed to the function whenever it is called, -as ordinary arguments. -To associate upvalues to a C function, -first these values should be pushed onto the stack. -Then the function + +

    3.17 - Defining C Closures

    + +

    When a C function is created, +it is possible to associate some values with it, +thus creating a C closure; +these values are then accessible to the function whenever it is called. +To associate values with a C function, +first these values should be pushed onto the stack +(when there are multiple values, the first value is pushed first). +Then the function

            void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
     
    + is used to push the C function onto the stack, -with the argument n telling how many upvalues should be +with the argument n telling how many values should be associated with the function -(these upvalues are popped from the stack); -in fact, the macro lua_pushcfunction is defined as -lua_pushcclosure with n set to 0. -Then, whenever the C function is called, -these upvalues are inserted as the last arguments to the function, -after the actual arguments provided in the call. -This makes it easy to get the upvalues without knowing how many arguments -the function received (recall that functions in Lua can receive any number of -arguments): The i-th upvalue is in the stack at index i-(n+1), -where n is the number of upvalues. -

    -For more examples of C functions and closures, see files -lbaselib.c, liolib.c, lmathlib.c, and lstrlib.c -in the official Lua distribution. -

    - -

    5.14 - References to Lua Objects

    -

    -If the C code needs to keep a Lua value -outside the life span of a C function, -then it must create a reference to the value. -The functions to manipulate references are the following: - - -

    -       int   lua_ref    (lua_State *L, int lock);
    -       int   lua_getref (lua_State *L, int ref);
    -       void  lua_unref  (lua_State *L, int ref);
    -
    -

    -lua_ref pops a value from -the stack, creates a reference to it, -and returns this reference. -For a nil value, -the reference is always LUA_REFNIL. -(lua.h also defines a constant LUA_NOREF -that -is different from any valid reference.) -If lock is not zero, then the object is locked: -this means the object will not be garbage collected. -Unlocked references may be garbage collected. -

    -Whenever the referenced object is needed in C, -a call to lua_getref -pushes that object onto the stack; -if the object has been collected, -lua_getref returns 0 (and does not push anything). -

    -When a reference is no longer needed, -it should be released with a call to lua_unref. -

    -

    -

    Registry

    -

    -When Lua starts, it registers a table at position -LUA_REFREGISTRY. -It can be accessed through the macro -

    -  #define lua_getregistry(L)      lua_getref(L, LUA_REFREGISTRY)
    -
    -This table can be used by C libraries as a general registry mechanism. +(lua_pushcclosure also pops these values from the stack); +in fact, the macro lua_pushcfunction is defined as +lua_pushcclosure with n set to 0. + +

    Then, whenever the C function is called, +those values are located at specific pseudo-indices. +Those pseudo-indices are produced by a macro lua_upvalueindex. +The first value associated with a function is at position +lua_upvalueindex(1), and so on. +Any access to lua_upvalueindex(n), +where n is greater than the number of upvalues of the +current function, +produces an acceptable (but invalid) index. + +

    For examples of C functions and closures, +see the standard libraries in the official Lua distribution +(src/lib/*.c). + +

    3.18 - Registry

    + +

    Lua provides a registry, +a pre-defined table that can be used by any C code to +store whatever Lua value it needs to store, +specially if the C code needs to keep that Lua value +outside the life span of a C function. +This table is always located at pseudo-index +LUA_REGISTRYINDEX. Any C library can store data into this table, -as long as it chooses a key different from other libraries. -

    -

    - -


    - -

    6 - Standard Libraries

    -

    -The standard libraries provide useful functions -that are implemented directly through the standard API. -Therefore, they are not necessary to the language, -and are provided as separate C modules. -Currently, Lua has the following standard libraries: -

      -
    • basic library; -
    • string manipulation; -
    • mathematical functions (sin, log, etc); -
    • input and output (plus some system facilities). -
    -To have access to these libraries, -the C host program must call the functions -lua_baselibopen, -lua_strlibopen, lua_mathlibopen, -and lua_iolibopen, which are declared in lualib.h. - - - - -

    - - -

    6.1 - Basic Functions

    -

    -The basic library provides some core functions to Lua. -Therefore, if you do not include this library in your application, -you should check carefully whether you need to provide some alternative -implementation for some facilities. -(For instance, -without function _ERRORMESSAGE, -Lua is unable to show error messages.) -

    - -

    _ALERT (message)

    -Prints its only string argument to stderr. -All error messages in Lua are printed through the function stored -in the _ALERT global variable -(see Section 4.7). -Therefore, a program may assign another function to this variable -to change the way such messages are shown -(for instance, for systems without stderr). -

    -

    assert (v [, message])

    -Issues an ``assertion failed!'' error -when its argument v is nil. -This function is equivalent to the following Lua function: -
    -       function assert (v, m)
    -         if not v then
    -           m = m or ""
    -           error("assertion failed!  " .. m)
    -         end
    -       end
    -
    -

    -

    call (func, arg [, mode [, errhandler]])

    - - -Calls function func with -the arguments given by the table arg. -The call is equivalent to -
    -       func(arg[1], arg[2], ..., arg[n])
    -
    -where n is the result of getn(arg) (see Section 6.1). -All results from func are simply returned by call. -

    -By default, -if an error occurs during the call to func, -the error is propagated. -If the string mode contains "x", -then the call is protected. -In this mode, function call does not propagate an error, -regardless of what happens during the call. -Instead, it returns nil to signal the error -(besides calling the appropriated error handler). -

    -If errhandler is provided, -the error function _ERRORMESSAGE is temporarily set to errhandler, -while func runs. -In particular, if errhandler is nil, -no error messages will be issued during the execution of the called function. -

    -

    collectgarbage ([limit])

    -

    -Sets the garbage-collection threshold for the given limit -(in Kbytes), and checks it against the byte counter. -If the new threshold is smaller than the byte counter, -then Lua immediately runs the garbage collector (see Section 5.6). -If limit is absent, it defaults to zero -(thus forcing a garbage-collection cycle). -

    -

    copytagmethods (tagto, tagfrom)

    - -Copies all tag methods from one tag to another; -returns tagto. -

    -

    dofile (filename)

    -Receives a file name, -opens the named file, and executes its contents as a Lua chunk, -or as pre-compiled chunks. -When called without arguments, -dofile executes the contents of the standard input (stdin). -If there is any error executing the file, -then dofile returns nil. -Otherwise, it returns the values returned by the chunk, -or a non-nil value if the chunk returns no values. -It issues an error when called with a non-string argument. -

    -

    dostring (string [, chunkname])

    -Executes a given string as a Lua chunk. -If there is any error executing the string, -then dostring returns nil. -Otherwise, it returns the values returned by the chunk, -or a non-nil value if the chunk returns no values. -The optional parameter chunkname -is the ``name of the chunk'', -used in error messages and debug information. -

    - -

    error (message)

    -Calls the error handler (see Section 4.7) and then terminates -the last protected function called -(in C: lua_dofile, lua_dostring, -lua_dobuffer, or lua_callfunction; -in Lua: dofile, dostring, or call in protected mode). -If message is nil, then the error handler is not called. -Function error never returns. -

    -

    foreach (table, func)

    -Executes the given func over all elements of table. -For each element, the function is called with the index and -respective value as arguments. -If the function returns any non-nil value, -then the loop is broken, and this value is returned -as the final value of foreach. -This function could be defined in Lua: +as long as it chooses keys different from other libraries. +Typically, you should use as key a string containing your library name +or a light userdata with the address of a C object in your code. + +

    The integer keys in the registry are used by the reference mechanism, +implemented by the auxiliary library, +and therefore should not be used by other purposes. + +

    3.19 - Error Handling in C

    + +

    Internally, Lua uses the C longjmp facility to handle errors. +When Lua faces any error +(such as memory allocation errors, type errors, syntax errors) +it raises an error, that is, it does a long jump. +A protected environment uses setjmp +to set a recover point, +and any error jumps to the most recent active recover point. + +

    If an error happens outside any protected environment, +Lua calls a panic function, +and then calls exit(EXIT_FAILURE). +You can change the panic function with

    -       function foreach (t, f)
    -         for i, v in t do
    -           local res = f(i, v)
    -           if res then return res end
    -         end
    -       end
    +       lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
     
    -

    -The behavior of foreach is undefined if you change -the table t during the traversal. -

    -

    -

    foreachi (table, func)

    -Executes the given func over the -numerical indices of table. -For each index, the function is called with the index and -respective value as arguments. -Indices are visited in sequential order, -from 1 to n, -where n is the result of getn(table) (see Section 6.1). -If the function returns any non-nil value, -then the loop is broken, and this value is returned -as the final value of foreachi. -This function could be defined in Lua: +Your new panic function may avoid the application exit by +never returning (e.g. doing a long jump). +Nevertheless, the corresponding Lua will not be consistent; +the only safe operation with it is to close it. + +

    Almost any function in the API may raise an error, +for instance due to a memory allocation error. +The following functions run in protected mode +(that is, they create a protected environment to run), +so they never raise an error: +lua_open, lua_close, lua_load, +and lua_pcall. + +

    There is yet another function that runs a given C function in protected mode:

    -       function foreachi (t, f)
    -         for i=1,getn(t) do
    -           local res = f(i, t[i])
    -           if res then return res end
    -         end
    -       end
    +       int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
     
    -

    -

    -

    getglobal (name)

    -Gets the value of a global variable, -or calls a tag method for ``getglobal''. -Its full semantics is explained in Section 4.8. -The string name does not need to be a -syntactically valid variable name. -

    - -

    getn (table)

    -Returns the ``size'' of a table, when seen as a list. -If the table has an n field with a numeric value, -this value is the ``size'' of the table. -Otherwise, the ``size'' is the largest numerical index with a non-nil -value in the table. -This function could be defined in Lua: -
    -       function getn (t)
    -         if type(t.n) == "number" then return t.n end
    -         local max = 0
    -         for i, _ in t do
    -           if type(i) == "number" and i>max then max=i end
    -         end
    -         return max
    -       end
    +
    +lua_cpcall calls func in protected mode.
    +func starts with only one element in its stack,
    +a light userdata containing ud.
    +In case of errors,
    +lua_cpcall returns the same error codes as lua_pcall
    +(see 3.15),
    +plus the error object on the top of the stack;
    +otherwise, it returns zero, and does not change the stack.
    +Any value returned by func is dicarded.
    +
    +

    C code can generate a Lua error calling the function +

    +       void lua_error (lua_State *L);
     
    -

    -

    gettagmethod (tag, event)

    - -Returns the current tag method -for a given pair (tag, event). -This function cannot be used to get a tag method for the ``gc'' event. -(Such tag methods can only be manipulated by C code.) -

    -

    globals ([table])

    -Returns the current table of globals. -If the argument table is given, -then it also sets this table as the table of globals. -

    - -

    newtag ()

    -Returns a new tag. -

    -

    next (table, [index])

    -Allows a program to traverse all fields of a table. -Its first argument is a table and its second argument -is an index in this table. -next returns the next index of the table and the -value associated with the index. -When called with nil as its second argument, -next returns the first index -of the table and its associated value. -When called with the last index, -or with nil in an empty table, -next returns nil. -If the second argument is absent, then it is interpreted as nil. -

    -Lua has no declaration of fields; -semantically, there is no difference between a -field not present in a table or a field with value nil. -Therefore, next only considers fields with non-nil values. -The order in which the indices are enumerated is not specified, -even for numeric indices -(to traverse a table in numeric order, -use a numerical for or the function foreachi). -

    -The behavior of next is undefined if you change -the table during the traversal. -

    -

    print (e1, e2, ...)

    -Receives any number of arguments, -and prints their values using the strings returned by tostring. -This function is not intended for formatted output, -but only as a quick way to show a value, -for instance for debugging. -See Section 6.4 for functions for formatted output. -

    -

    rawget (table, index)

    -Gets the real value of table[index], -without invoking any tag method. -table must be a table, -and index is any value different from nil. -

    -

    rawset (table, index, value)

    -Sets the real value of table[index] to value, -without invoking any tag method. -table must be a table, -index is any value different from nil, -and value is any Lua value. -

    -

    setglobal (name, value)

    -Sets the named global variable to the given value, -or calls a tag method for ``setglobal''. -Its full semantics is explained in Section 4.8. -The string name does not need to be a -syntactically valid variable name. -

    -

    settag (t, tag)

    -Sets the tag of a given table (see Section 3). -tag must be a value created with newtag -(see Section 6.1). -settag returns the value of its first argument (the table). -For the safety of host programs, -it is impossible to change the tag of a userdata from Lua. -

    -

    settagmethod (tag, event, newmethod)

    - -Sets a new tag method to the given pair (tag, event) and -returns the old method. -If newmethod is nil, -then settagmethod restores the default behavior for the given event. -This function cannot be used to set a tag method for the ``gc'' event. -(Such tag methods can only be manipulated by C code.) -

    -

    sort (table [, comp])

    -Sorts table elements in a given order, in-place, -from table[1] to table[n], -where n is the result of getn(table) (see Section 6.1). -If comp is given, -then it must be a function that receives two table elements, -and returns true (that is, a value different from nil) -when the first is less than the second -(so that not comp(a[i+1], a[i]) will be true after the sort). -If comp is not given, -then the standard Lua operator < is used instead. -

    -The sort algorithm is not stable -(that is, elements considered equal by the given order -may have their relative positions changed by the sort). -

    - -

    tag (v)

    -Allows Lua programs to test the tag of a value (see Section 3). -It receives one argument, and returns its tag (a number). -

    -

    tonumber (e [, base])

    -Tries to convert its argument to a number. -If the argument is already a number or a string convertible -to a number, then tonumber returns that number; -otherwise, it returns nil. -

    -An optional argument specifies the base to interpret the numeral. -The base may be any integer between 2 and 36, inclusive. -In bases above 10, the letter `A' (either upper or lower case) -represents 10, `B' represents 11, and so forth, with `Z' representing 35. -In base 10 (the default), the number may have a decimal part, -as well as an optional exponent part (see Section 4.2). -In other bases, only unsigned integers are accepted. -

    -

    tostring (e)

    -Receives an argument of any type and -converts it to a string in a reasonable format. -For complete control of how numbers are converted, -use function format. -

    -

    -

    -

    tinsert (table [, pos] , value)

    -

    -Inserts element value at table position pos, -shifting other elements to open space, if necessary. -The default value for pos is n+1, -where n is the result of getn(table) (see Section 6.1), -so that a call tinsert(t,x) inserts x at the end -of table t. -This function also sets or increments the field n of the table -to n+1. -This function is equivalent to the following Lua function, -except that the table accesses are all raw -(that is, without tag methods): -

    -       function tinsert (t, ...)
    -         local pos, value
    -         local n = getn(t)
    -         if arg.n == 1 then
    -           pos, value = n+1, arg[1]
    -         else
    -           pos, value = arg[1], arg[2]
    -         end
    -         t.n = n+1;
    -         for i=n,pos,-1 do
    -           t[i+1] = t[i]
    -         end
    -         t[pos] = value
    -       end
    +
    +The error message (which actually can be any type of object)
    +must be on the stack top.
    +This function does a long jump,
    +and therefore never returns.
    +
    +

    3.20 - Threads

    + +

    Lua offers partial support for multiple threads of execution. +If you have a C library that offers multi-threading, +then Lua can cooperate with it to implement the equivalent facility in Lua. +Also, Lua implements its own coroutine system on top of threads. +The following function creates a new thread in Lua: +

    +       lua_State *lua_newthread (lua_State *L);
     
    -

    -

    tremove (table [, pos])

    -

    -Removes from table the element at position pos, -shifting other elements to close the space, if necessary. -Returns the value of the removed element. -The default value for pos is n, -where n is the result of getn(table) (see Section 6.1), -so that a call tremove(t) removes the last element -of table t. -This function also sets or decrements the field n of the table -to n-1. -

    -This function is equivalent to the following Lua function, -except that the table accesses are all raw -(that is, without tag methods): -

    -       function tremove (t, pos)
    -         local n = getn(t)
    -         if n<=0 then return end
    -         pos = pos or n
    -         local value = t[pos]
    -         for i=pos,n-1 do
    -           t[i] = t[i+1]
    -         end
    -         t[n] = nil
    -         t.n = n-1
    -         return value
    -       end
    +
    +This function pushes the thread on the stack and returns a pointer to
    +a lua_State that represents this new thread.
    +The new state returned by this function shares with the original state
    +all global objects (such as tables),
    +but has an independent run-time stack.
    +
    +

    Each thread has an independent global environment table. +When you create a thread, this table is the same as that of the given state, +but you can change each one independently. + +

    You destroy threads with lua_closethread: +

    +       void lua_closethread (lua_State *L, lua_State *thread);
     
    -

    - -

    type (v)

    -Allows Lua programs to test the type of a value. -It receives one argument, and returns its type, coded as a string. -The possible results of this function are -"nil" (a string, not the value nil), -"number", -"string", -"table", -"function", -and "userdata". -

    -

    - -

    6.2 - String Manipulation

    -This library provides generic functions for string manipulation, -such as finding and extracting substrings and pattern matching. -When indexing a string in Lua, the first character is at position 1 -(not at 0, as in C). -Also, -indices are allowed to be negative and are intepreted as indexing backwards, -from the end of the string. Thus, the last character is at position -1, -and so on. -

    -

    strbyte (s [, i])

    -Returns the internal numerical code of the i-th character of s. -If i is absent, then it is assumed to be 1. -i may be negative. -

    -Numerical codes are not necessarily portable across platforms. -

    -

    strchar (i1, i2, ...)

    -Receives 0 or more integers. -Returns a string with length equal to the number of arguments, -wherein each character has the internal numerical code equal -to its correspondent argument. -

    -Numerical codes are not necessarily portable across platforms. -

    -

    strfind (s, pattern [, init [, plain]])

    - -Looks for the first match of -pattern in s. -If it finds one, then strfind returns the indices of s -where this occurrence starts and ends; -otherwise, it returns nil. -If the pattern specifies captures (see gsub below), -the captured strings are returned as extra results. -A third, optional numerical argument init specifies -where to start the search; -its default value is 1, and may be negative. -A value of 1 as a fourth, optional argument plain -turns off the pattern matching facilities, -so the function does a plain ``find substring'' operation, -with no characters in pattern being considered ``magic''. -Note that if plain is given, then init must be given too. -

    -

    strlen (s)

    -Receives a string and returns its length. -The empty string "" has length 0. -Embedded zeros are counted, -and so "a\000b\000c" has length 5. -

    -

    strlower (s)

    -Receives a string and returns a copy of that string with all -upper case letters changed to lower case. -All other characters are left unchanged. -The definition of what is an upper-case -letter depends on the current locale. -

    -

    strrep (s, n)

    -Returns a string that is the concatenation of n copies of -the string s. -

    -

    strsub (s, i [, j])

    -Returns another string, which is a substring of s, -starting at i and running until j; -i and j may be negative, -If j is absent, then it is assumed to be equal to -1 -(which is the same as the string length). -In particular, -the call strsub(s,1,j) returns a prefix of s -with length j, -and the call strsub(s, -i) returns a suffix of s -with length i. -

    -

    strupper (s)

    -Receives a string and returns a copy of that string with all -lower case letters changed to upper case. -All other characters are left unchanged. -The definition of what is a lower case -letter depends on the current locale. -

    -

    format (formatstring, e1, e2, ...)

    - +You cannot close the sole (or last) thread of a state. +Instead, you must close the state itself. -Returns a formatted version of its variable number of arguments -following the description given in its first argument (which must be a string). -The format string follows the same rules as the printf family of -standard C functions. -The only differences are that the options/modifiers -*, l, L, n, p, -and h are not supported, -and there is an extra option, q. -The q option formats a string in a form suitable to be safely read -back by the Lua interpreter: -The string is written between double quotes, -and all double quotes, returns, and backslashes in the string -are correctly escaped when written. -For instance, the call +

    To manipulate threads as coroutines, +Lua offers the following functions:

    -       format('%q', 'a string with "quotes" and \n new line')
    +       int lua_resume (lua_State *L, int narg);
    +       int lua_yield (lua_State *L, int nresults);
     
    -will produce the string: + +To start a coroutine, you first create a new thread; +then you push on its stack the body function plus any eventual arguments; +then you call lua_resume, +with narg being the number of arguments. +This call returns when the coroutine suspends or finishes its execution. +When it returns, the stack contains all values passed to lua_yield, +or all values returned by the body function. +lua_resume returns 0 if there is no errors running the coroutine, +or an error code (see 3.15). +In case of errors, +the stack contains only the error message. +To restart a coroutine, you put on its stack only the values to +be passed as results from yield, +and then call lua_resume. + +

    The lua_yield function can only be called as the +return expression of a C function, as follows:

    -"a string with \"quotes\" and \
    - new line"
    +       return lua_yield (L, nresults);
     
    -

    -Conversions can be applied to the n-th argument in the argument list, -rather than the next unused argument. -In this case, the conversion character % is replaced -by the sequence %d$, where d is a -decimal digit in the range [1,9], -giving the position of the argument in the argument list. -For instance, the call format("%2$d -> %1$03d", 1, 34) will -result in "34 -> 001". -The same argument can be used in more than one conversion. -

    -The options c, d, E, e, f, -g, G, i, o, u, X, and x all -expect a number as argument, -whereas q and s expect a string. -The * modifier can be simulated by building -the appropriate format string. -For example, "%*g" can be simulated with -"%"..width.."g". -

    -Neither the format string nor the string values to be formatted with -%s can contain embedded zeros. -%q handles string values with embedded zeros. -

    -

    gsub (s, pat, repl [, n])

    - -Returns a copy of s -in which all occurrences of the pattern pat have been -replaced by a replacement string specified by repl. -gsub also returns, as a second value, -the total number of substitutions made. -

    -If repl is a string, then its value is used for replacement. -Any sequence in repl of the form %n -with n between 1 and 9 -stands for the value of the n-th captured substring. -

    -If repl is a function, then this function is called every time a -match occurs, with all captured substrings passed as arguments, -in order (see below). -If the value returned by this function is a string, -then it is used as the replacement string; -otherwise, the replacement string is the empty string. -

    -The last, optional parameter n limits -the maximum number of substitutions to occur. -For instance, when n is 1 only the first occurrence of -pat is replaced. -

    -Here are some examples: -

    -   x = gsub("hello world", "(%w+)", "%1 %1")
    -   --> x="hello hello world world"
    -

    - x = gsub("hello world", "(%w+)", "%1 %1", 1) - --> x="hello hello world" -

    - x = gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") - --> x="world hello Lua from" -

    - x = gsub("home = $HOME, user = $USER", "%$(%w+)", getenv) - --> x="home = /home/roberto, user = roberto" (for instance) -

    - x = gsub("4+5 = $return 4+5$", "%$(.-)%$", dostring) - --> x="4+5 = 9" -

    - local t = {name="lua", version="4.0"} - x = gsub("$name - $version", "%$(%w+)", function (v) return %t[v] end) - --> x="lua - 4.0" -

    - t = {n=0} - gsub("first second word", "(%w+)", function (w) tinsert(%t, w) end) - --> t={"first", "second", "word"; n=3} -

    -

    -

    - -

    Patterns

    -

    -

    Character Class:

    -a character class is used to represent a set of characters. -The following combinations are allowed in describing a character class: -
    -
    x
    (where x is any magic characters -^$()%.[]*+-?) -- represents the character x itself. -
    .
    - (a dot) represents all characters. -
    %a
    - represents all letters. -
    %c
    - represents all control characters. -
    %d
    - represents all digits. -
    %l
    - represents all lower case letters. -
    %p
    - represents all punctuation characters. -
    %s
    - represents all space characters. -
    %u
    - represents all upper case letters. -
    %w
    - represents all alphanumeric characters. -
    %x
    - represents all hexadecimal digits. -
    %z
    - represents the character with representation 0. -
    %x
    (where x is any non-alphanumeric character) - -represents the character x. -This is the standard way to escape the magic characters. -We recommend that any punctuation character (even the non magic) -should be preceded by a % -when used to represent itself in a pattern. -

    -

    [char-set]
    - -represents the class which is the union of all -characters in char-set. -A range of characters may be specified by -separating the end characters of the range with a -. -All classes %x described above may also be used as -components in a char-set. -All other characters in char-set represent themselves. -For example, [%w_] (or [_%w]) -represents all alphanumeric characters plus the underscore, -[0-7] represents the octal digits, -and [0-7%l%-] represents the octal digits plus -the lower case letters plus the - character. -

    -The interaction between ranges and classes is not defined. -Therefore, patterns like [%a-z] or [a-%%] -have no meaning. -

    -

    [^char-set]
    - -represents the complement of char-set, -where char-set is interpreted as above. -
    -For all classes represented by single letters (%a, %c, ...), -the corresponding upper-case letter represents the complement of the class. -For instance, %S represents all non-space characters. -

    -The definitions of letter, space, etc. depend on the current locale. -In particular, the class [a-z] may not be equivalent to %l. -The second form should be preferred for portability. -

    -

    Pattern Item:

    -a pattern item may be -
      -
    • -a single character class, -which matches any single character in the class; -
    • -a single character class followed by *, -which matches 0 or more repetitions of characters in the class. -These repetition items will always match the longest possible sequence; -
    • -a single character class followed by +, -which matches 1 or more repetitions of characters in the class. -These repetition items will always match the longest possible sequence; -
    • -a single character class followed by -, -which also matches 0 or more repetitions of characters in the class. -Unlike *, -these repetition items will always match the shortest possible sequence; -
    • -a single character class followed by ?, -which matches 0 or 1 occurrence of a character in the class; -
    • -%n, for n between 1 and 9; -such item matches a sub-string equal to the n-th captured string -(see below); -
    • -%bxy, where x and y are two distinct characters; -such item matches strings that start with x, end with y, -and where the x and y are balanced. -This means that, if one reads the string from left to right, -counting +1 for an x and -1 for a y, -the ending y is the first y where the count reaches 0. -For instance, the item %b() matches expressions with -balanced parentheses. -
    -

    -

    Pattern:

    -a pattern is a sequence of pattern items. -A ^ at the beginning of a pattern anchors the match at the -beginning of the subject string. -A $ at the end of a pattern anchors the match at the -end of the subject string. -At other positions, -^ and $ have no special meaning and represent themselves. -

    -

    Captures:

    -A pattern may contain sub-patterns enclosed in parentheses, -they describe captures. -When a match succeeds, the sub-strings of the subject string -that match captures are stored (captured) for future use. -Captures are numbered according to their left parentheses. -For instance, in the pattern "(a*(.)%w(%s*))", -the part of the string matching "a*(.)%w(%s*)" is -stored as the first capture (and therefore has number 1); -the character matching . is captured with number 2, -and the part matching %s* has number 3. -

    -A pattern cannot contain embedded zeros. Use %z instead. -

    -

    - - -

    6.3 - Mathematical Functions

    -

    -This library is an interface to some functions of the standard C math library. -In addition, it registers a tag method for the binary operator ^ that -returns x^y when applied to numbers x^y. -

    -The library provides the following functions: - - - - - +When a C function calls lua_yield in that way, +the running coroutine suspends its execution, +and the call to lua_resume that started this coroutine returns. +The parameter nresults is the number of values from the stack +that are passed as results to lua_resume. + +

    To exchange values between different threads, +you may use lua_xmove:

    -       abs  acos  asin  atan  atan2  ceil  cos  deg    exp    floor   log  log10
    -       max  min   mod   rad   sin    sqrt  tan  frexp  ldexp  random  randomseed
    +       void lua_xmove (lua_State *from, lua_State *to, int n);
     
    -plus a global variable PI. -Most of them -are only interfaces to the homonymous functions in the C library, -except that, for the trigonometric functions, -all angles are expressed in degrees, not radians. -The functions deg and rad can be used to convert -between radians and degrees. -

    -The function max returns the maximum -value of its numeric arguments. -Similarly, min computes the minimum. -Both can be used with 1, 2, or more arguments. -

    -The functions random and randomseed are interfaces to -the simple random generator functions rand and srand, -provided by ANSI C. -(No guarantees can be given for their statistical properties.) -The function random, when called without arguments, -returns a pseudo-random real number in the range [0,1). -When called with a number n, -random returns a pseudo-random integer in the range [1,n]. -When called with two arguments, l and u, -random returns a pseudo-random integer in the range [l,u]. -

    -

    - - -

    6.4 - I/O Facilities

    -

    -All input and output operations in Lua are done, by default, -over two file handles, one for reading and one for writing. -These handles are stored in two Lua global variables, -called _INPUT and _OUTPUT. -The global variables -_STDIN, _STDOUT, and _STDERR -are initialized with file descriptors for -stdin, stdout, and stderr. -Initially, _INPUT=_STDIN and _OUTPUT=_STDOUT. - - -

    -A file handle is a userdata containing the file stream (FILE*), -and with a distinctive tag created by the I/O library. -

    -Unless otherwise stated, -all I/O functions return nil on failure and -some value different from nil on success. -

    -

    openfile (filename, mode)

    -

    -This function opens a file, -in the mode specified in the string mode. -It returns a new file handle, -or, in case of errors, nil plus a string describing the error. -This function does not modify either _INPUT or _OUTPUT. -

    -The mode string can be any of the following: -

    -
    ``r''
    read mode; -
    ``w''
    write mode; -
    ``a''
    append mode; -
    ``r+''
    update mode, all previous data is preserved; -
    ``w+''
    update mode, all previous data is erased; -
    ``a+''
    append update mode, previous data is preserved, - writing is only allowed at the end of file. -
    -The mode string may also have a b at the end, -which is needed in some systems to open the file in binary mode. -This string is exactlty what is used in the standard C function fopen. -

    -

    closefile (handle)

    -

    -This function closes the given file. -It does not modify either _INPUT or _OUTPUT. -

    -

    readfrom (filename)

    -

    -This function may be called in two ways. -When called with a file name, it opens the named file, -sets its handle as the value of _INPUT, -and returns this value. -It does not close the current input file. -When called without parameters, -it closes the _INPUT file, -and restores stdin as the value of _INPUT. -If this function fails, it returns nil, -plus a string describing the error. -

    -If filename starts with a |, -then a piped input is opened, via function popen. -Not all systems implement pipes. -Moreover, -the number of files that can be open at the same time is -usually limited and depends on the system. -

    -

    writeto (filename)

    -

    -This function may be called in two ways. -When called with a file name, -it opens the named file, -sets its handle as the value of _OUTPUT, -and returns this value. -It does not close the current output file. -Note that, if the file already exists, -then it will be completely erased with this operation. -When called without parameters, -this function closes the _OUTPUT file, -and restores stdout as the value of _OUTPUT. - -If this function fails, it returns nil, -plus a string describing the error. -

    -If filename starts with a |, -then a piped input is opened, via function popen. -Not all systems implement pipes. -Moreover, -the number of files that can be open at the same time is -usually limited and depends on the system. -

    -

    appendto (filename)

    -

    -Opens a file named filename and sets it as the -value of _OUTPUT. -Unlike the writeto operation, -this function does not erase any previous contents of the file; -instead, anything written to the file is appended to its end. -If this function fails, it returns nil, -plus a string describing the error. -

    -

    remove (filename)

    -

    -Deletes the file with the given name. -If this function fails, it returns nil, -plus a string describing the error. -

    -

    rename (name1, name2)

    -

    -Renames file named name1 to name2. -If this function fails, it returns nil, -plus a string describing the error. -

    -

    flush ([filehandle])

    -

    -Saves any written data to the given file. -If filehandle is not specified, -then flush flushes all open files. -If this function fails, it returns nil, -plus a string describing the error. -

    -

    seek (filehandle [, whence] [, offset])

    -

    -Sets and gets the file position, -measured in bytes from the beginning of the file, -to the position given by offset plus a base -specified by the string whence, as follows: -

    -
    ``set''
    base is position 0 (beginning of the file); -
    ``cur''
    base is current position; -
    ``end''
    base is end of file; -
    -In case of success, function seek returns the final file position, -measured in bytes from the beginning of the file. -If the call fails, it returns nil, -plus a string describing the error. -

    -The default value for whence is "cur", -and for offset is 0. -Therefore, the call seek(file) returns the current -file position, without changing it; -the call seek(file, "set") sets the position to the -beginning of the file (and returns 0); -and the call seek(file, "end") sets the position to the -end of the file, and returns its size. -

    -

    tmpname ()

    -

    -Returns a string with a file name that can safely -be used for a temporary file. -The file must be explicitly opened before its use -and removed when no longer needed. -

    -

    read ([filehandle,] format1, ...)

    -

    -Reads file _INPUT, -or filehandle if this argument is given, -according to the given formats, which specify what to read. -For each format, -the function returns a string (or a number) with the characters read, -or nil if it cannot read data with the specified format. -When called without formats, -it uses a default format that reads the next line -(see below). -

    -The available formats are -

    -
    ``*n''
    reads a number; -this is the only format that returns a number instead of a string. -
    ``*l''
    reads the next line -(skipping the end of line), or nil on end of file. -This is the default format. -
    ``*a''
    reads the whole file, starting at the current position. -On end of file, it returns the empty string. -
    ``*w''
    reads the next word -(maximal sequence of non--white-space characters), -skipping spaces if necessary, or nil on end of file. -
    number
    reads a string with up to that number of characters, -or nil on end of file. -
    -

    -

    write ([filehandle, ] value1, ...)

    -

    -Writes the value of each of its arguments to -file _OUTPUT, -or to filehandle if this argument is given. -The arguments must be strings or numbers. -To write other values, -use tostring or format before write. -If this function fails, it returns nil, -plus a string describing the error. -

    - - -

    6.5 - System Facilities

    -

    -

    clock ()

    -

    -Returns an approximation of the amount of CPU time -used by the program, in seconds. -

    -

    date ([format])

    -

    -Returns a string containing date and time -formatted according to the given string format, -following the same rules of the ANSI C function strftime. -When called without arguments, -it returns a reasonable date and time representation that depends on -the host system and on the current locale. -

    -

    execute (command)

    -

    -This function is equivalent to the C function system. -It passes command to be executed by an operating system shell. -It returns a status code, which is system-dependent. -

    -

    exit ([code])

    -

    -Calls the C function exit, -with an optional code, -to terminate the program. -The default value for code is the success code. -

    -

    getenv (varname)

    -

    -Returns the value of the process environment variable varname, -or nil if the variable is not defined. -

    -

    setlocale (locale [, category])

    -

    -This function is an interface to the ANSI C function setlocale. -locale is a string specifying a locale; -category is an optional string describing which category to change: -"all", "collate", "ctype", -"monetary", "numeric", or "time"; -the default category is "all". -The function returns the name of the new locale, -or nil if the request cannot be honored. -

    -

    - - -


    - -

    7 - The Debug Interface

    -

    -Lua has no built-in debugging facilities. -Instead, it offers a special interface, -by means of functions and hooks, -which allows the construction of different +It pops n values from the stack from, +and puhses them into the stack to. + +

    +

    4 - The Debug Interface

    + +

    Lua has no built-in debugging facilities. +Instead, it offers a special interface +by means of functions and hooks. +This interface allows the construction of different kinds of debuggers, profilers, and other tools -that need ``inside information'' from the interpreter. -This interface is declared in luadebug.h. -

    - -

    7.1 - Stack and Function Information

    -

    - -The main function to get information about the interpreter stack is +that need "inside information" from the interpreter. + +

    4.1 - Stack and Function Information

    + +

    The main function to get information about the interpreter runtime stack is

            int lua_getstack (lua_State *L, int level, lua_Debug *ar);
     
    -It fills parts of a lua_Debug structure with -an identification of the activation record + +This function fills parts of a lua_Debug structure with +an identification of the activation record of the function executing at a given level. Level 0 is the current running function, -whereas level n+1 is the function that has called level n. -Usually, lua_getstack returns 1; +whereas level n+1 is the function that has called level n. +When there is no errors, lua_getstack returns 1; when called with a level greater than the stack depth, it returns 0. -

    - -The structure lua_Debug is used to carry different pieces of + +

    The structure lua_Debug is used to carry different pieces of information about an active function:

           typedef struct lua_Debug {
    -        const char *event;     /* "call", "return" */
    -        int currentline;       /* (l) */
    +        int event;
             const char *name;      /* (n) */
    -        const char *namewhat;  /* (n) global, tag method, local, field */
    +        const char *namewhat;  /* (n) `global', `local', `field', `method' */
    +        const char *what;      /* (S) `Lua' function, `C' function, Lua `main' */
    +        const char *source;    /* (S) */
    +        int currentline;       /* (l) */
             int nups;              /* (u) number of upvalues */
             int linedefined;       /* (S) */
    -        const char *what;      /* (S) "Lua" function, "C" function, Lua "main" */
    -        const char *source;    /* (S) */
             char short_src[LUA_IDSIZE]; /* (S) */
    -

    + /* private part */ ... } lua_Debug;

    -lua_getstack fills only the private part -of this structure, for future use. -To fill in the other fields of lua_Debug with useful information, -call + +lua_getstack fills only the private part +of this structure, for later use. +To fill the other fields of lua_Debug with useful information, +call
            int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
     
    + This function returns 0 on error -(e.g., an invalid option in what). -Each character in the string what -selects some fields of ar to be filled, -as indicated by the letter in parentheses in the definition of lua_Debug: -`S' fills in the fields source, linedefined, -and what; -`l' fills in the field currentline, etc. -Moreover, `f' pushes onto the stack the function that is +(for instance, an invalid option in what). +Each character in the string what +selects some fields of the structure ar to be filled, +as indicated by the letter in parentheses in the definition of lua_Debug +above: +`S´ fills in the fields source, linedefined, +and what; +`l´ fills in the field currentline, etc. +Moreover, `f´ pushes onto the stack the function that is running at the given level. -

    -To get information about a function that is not active (that is, -it is not in the stack), -you push the function onto the stack, -and start the what string with the character >. -For instance, to know in which line a function f was defined, + +

    To get information about a function that is not active +(that is, not in the stack), +you push it onto the stack +and start the what string with the character `>´. +For instance, to know in which line a function f was defined, you can write

            lua_Debug ar;
    -       lua_getglobal(L, "f");
    -       lua_getinfo(L, ">S", &ar);
    +       lua_pushstring(L, "f");
    +       lua_gettable(L, LUA_GLOBALSINDEX);  /* get global `f' */
    +       lua_getinfo(L, ">S", &ar);
            printf("%d\n", ar.linedefined);
     
    -The fields of lua_Debug have the following meaning: -
    -

    -

    source
    +The fields of lua_Debug have the following meaning: +
      + +

    • source If the function was defined in a string, -source is that string; -if the function was defined in a file, -source starts with a @ followed by the file name. -

      -

      short_src
      -A ``printable'' version of source, to be used in error messages. -

      -

      linedefined
      +then source is that string. +If the function was defined in a file, +then source starts with a `@´ followed by the file name. + +

    • short_src +A "printable" version of source, to be used in error messages. + +

    • linedefined the line number where the definition of the function starts. -

      -

      what
      the string "Lua" if this is a Lua function, -"C" if this is a C function, -or "main" if this is the main part of a chunk. -

      -

      currentline
      + +

    • what the string "Lua" if this is a Lua function, +"C" if this is a C function, +"main" if this is the main part of a chunk, +and "tail" if this was a function that did a tail call. +In the latter case, +Lua has no other information about this function. + +

    • currentline the current line where the given function is executing. When no line information is available, -currentline is set to -1. -

      -

      name
      +currentline is set to -1. + +

    • name a reasonable name for the given function. Because functions in Lua are first class values, they do not have a fixed name: -Some functions may be the value of many global variables, +Some functions may be the value of multiple global variables, while others may be stored only in a table field. -The lua_getinfo function checks whether the given -function is a tag method or the value of a global variable. -If the given function is a tag method, -then name points to the event name. -If the given function is the value of a global variable, -then name points to the variable name. -If the given function is neither a tag method nor a global variable, -then name is set to NULL. -

      -

      namewhat
      -Explains the previous field. -If the function is a global variable, -namewhat is "global"; -if the function is a tag method, -namewhat is "tag-method"; -otherwise namewhat is "" (the empty string). -

      -

      nups
      -Number of upvalues of a function. -

      -

    -

    -

    - -

    7.2 - Manipulating Local Variables

    -

    -For the manipulation of local variables, -luadebug.h uses indices: -The first parameter or local variable has index 1, and so on, -until the last active local variable. -

    - -The following functions allow the manipulation of the -local variables of a given activation record. +The lua_getinfo function checks how the function was +called or whether it is the value of a global variable to +find a suitable name. +If it cannot find a name, +then name is set to NULL. + +

  • namewhat +Explains the name field. +The value of namewhat can be +"global", "local", "method", +"field", or "" (the empty string), +according to how the function was called. +(Lua uses the empty string when no other option seems to apply.) + +

  • nups +The number of upvalues of the function. + +

    + +

    4.2 - Manipulating Local Variables and Upvalues

    + +

    For the manipulation of local variables and upvalues, +the debug interface uses indices: +The first parameter or local variable has index 1, and so on, +until the last active local variable. +Upvalues have no particular order, +as they are active through the whole function. + +

    The following functions allow the manipulation of the +local variables of a given activation record: +

    +       const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
    +       const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
    +
    + +The parameter ar must be a valid activation record that was +filled by a previous call to lua_getstack or +given as argument to a hook (see 4.3). +lua_getlocal gets the index n of a local variable, +pushes the variable's value onto the stack, +and returns its name. +lua_setlocal assigns the value at the top of the stack +to the variable and returns its name. +Both functions return NULL +when the index is greater than +the number of active local variables. + +

    The following functions allow the manipulation of the +upvalues of a given function +(unlike local variables, +the upvalues of a function are accessible even when the +function is not active): +

    +       const char *lua_getupvalue (lua_State *L, int funcindex, int n);
    +       const char *lua_setupvalue (lua_State *L, int funcindex, int n);
    +
    + +These functions operate both on Lua functions and on C functions. +(For Lua functions, +upvalues are the external local variables that the function uses, +and that consequently are included in its closure.) +funcindex points to a function in the stack. +lua_getpuvalue gets the index n of an upvalue, +pushes the upvalue's value onto the stack, +and returns its name. +lua_setupvalue assigns the value at the top of the stack +to the upvalue and returns its name. +Both functions return NULL +when the index is greater than the number of upvalues. +For C functions, these functions use the empty string "" +as a name for all upvalues. + +

    As an example, the following function lists the names of all +local variables and upvalues for a function at a given level of the stack: +

    +       int listvars (lua_State *L, int level) {
    +         lua_Debug ar;
    +         int i;
    +         const char *name;
    +         if (lua_getstack(L, level, &ar) == 0)
    +           return 0;  /* failure: no such level in the stack */
    +         i = 1;
    +         while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
    +           printf("local %d %s\n", i-1, name);
    +           lua_pop(L, 1);  /* remove variable value */
    +         }
    +         lua_getinfo(L, "f", &ar);  /* retrieves function */
    +         i = 1;
    +         while ((name = lua_getpuvalue(L, -1, i++)) != NULL) {
    +           printf("upvalue %d %s\n", i-1, name);
    +           lua_pop(L, 1);  /* remove upvalue value */
    +         }
    +         return 1;
    +       }
    +
    + +

    4.3 - Hooks

    + +

    Lua offers a mechanism of hooks, which are +user-defined C functions that are called during the program execution. +A hook may be called in four different events: +a call event, when Lua calls a function; +a return event, when Lua returns from a function; +a line event, when Lua starts executing a new line of code; +and a count event, which happens every "count" instructions. +Lua identifies these events with the following constants: +LUA_HOOKCALL, +LUA_HOOKRET (or LUA_HOOKTAILRET, see below), +LUA_HOOKLINE, +and LUA_HOOKCOUNT. + +

    A hook has type lua_Hook, defined as follows: +

    +       typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
    +
    + +You can set the hook with the following function: +
    +       int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
    +
    + +func is the hook. +mask specifies on which events the hook will be called: +It is formed by a disjunction of the constants +LUA_MASKCALL, +LUA_MASKRET, +LUA_MASKLINE, +and LUA_MASKCOUNT. +The count argument is only meaningful when the mask +includes LUA_MASKCOUNT. +For each event, the hook is called as explained below: +
      +
    • The call hook is called when the interpreter calls a function. +The hook is called just after Lua enters the new function. +
    • The return hook is called when the interpreter returns from a function. +The hook is called just before Lua leaves the function. +
    • The line hook is called when the interpreter is about to +start the execution of a new line of code, +or when it jumps back in the code (even to the same line). +(This event only happens while Lua is executing a Lua function.) +
    • The count hook is called after the interpreter executes every +count instructions. +(This event only happens while Lua is executing a Lua function.) +
    + +

    A hook is disabled by setting mask to zero. + +

    You can get the current hook, the current mask, +and the current count with the next functions: +

    +       lua_Hook lua_gethook      (lua_State *L);
    +       int      lua_gethookmask  (lua_State *L);
    +       int      lua_gethookcount (lua_State *L);
    +
    + + +

    Whenever a hook is called, its ar argument has its field +event set to the specific event that triggered the hook. +Moreover, for line events, the field currentline is also set. +To get the value of any other field in ar, +the hook must call lua_getinfo. +For return events, event may be LUA_HOOKRET, +the normal value, or LUA_HOOKTAILRET. +In the latter case, Lua is simulating a return from +a function that did a tail call; +in this case, it is useless to call lua_getinfo. + +

    While Lua is running a hook, it disables other calls to hooks. +Therefore, if a hook calls back Lua to execute a function or a chunk, +that execution occurs without any calls to hooks. + +

    +

    5 - Standard Libraries

    + +

    The standard libraries provide useful functions +that are implemented directly through the C API. +Some of these functions provide essential services to the language +(e.g., type and getmetatable); +others provide access to "outside" services (e.g., I/O); +and others could be implemented in Lua itself, +but are quite useful or have critical performance to +deserve an implementation in C (e.g., sort). + +

    All libraries are implemented through the official C API +and are provided as separate C modules. +Currently, Lua has the following standard libraries: +

      +
    • basic library; +
    • string manipulation; +
    • table manipulation; +
    • mathematical functions (sin, log, etc.); +
    • input and output; +
    • operating system facilities; +
    • debug facilities. +
    +Except for the basic library, +each library provides all its functions as fields of a global table +or as methods of its objects. + +

    To have access to these libraries, +the C host program must first call the functions +luaopen_base (for the basic library), +luaopen_string (for the string library), +luaopen_table (for the table library), +luaopen_math (for the mathematical library), +luaopen_io (for the I/O and the Operating System libraries), +and luaopen_debug (for the debug library). +These functions are declared in lualib.h. + + + + + + + +

    5.1 - Basic Functions

    + +

    The basic library provides some core functions to Lua. +If you do not include this library in your application, +you should check carefully whether you need to provide some alternative +implementation for some of its facilities. + +

    assert (v [, message])

    +Issues an error when +the value of its argument v is nil or false; +otherwise, returns this value. +message is an error message; +when absent, it defaults to "assertion failed!" + +

    collectgarbage ([limit])

    + +

    Sets the garbage-collection threshold to the given limit +(in Kbytes) and checks it against the byte counter. +If the new threshold is smaller than the byte counter, +then Lua immediately runs the garbage collector (see 2.9). +If limit is absent, it defaults to zero +(thus forcing a garbage-collection cycle). + +

    dofile (filename)

    +Opens the named file and executes its contents as a Lua chunk. +When called without arguments, +dofile executes the contents of the standard input (stdin). +Returns any value returned by the chunk. +In case of errors, dofile propagates the error +to its caller (that is, it does not run in protected mode). + +

    error (message [, level])

    + +Terminates the last protected function called, +and returns message as the error message. +Function error never returns. + +

    The level argument specifies where the error +message points the error. +With level 1 (the default), the error position is where the +error function was called. +Level 2 points the error to where the function +that called error was called; and so on. + +

    _G

    +A global variable (not a function) that +holds the global environment (that is, _G._G = _G). +Lua itself does not use this variable; +changing its value does not affect any environment. +(Use setfenv to change environments.) + +

    getfenv (f)

    +Returns the current environment in use by the function. +f can be a Lua function or a number, +which specifies the function at that stack level: +Level 1 is the function calling getfenv. +If the given function is not a Lua function, +or if f is 0, +getfenv returns the global environment. +The default for f is 1. + +

    if the environment has a "__fenv" field, +returns the associated value, instead of the environment. + +

    getmetatable (object)

    + + +

    If the object does not have a metatable, returns nil. +Otherwise, +if the object's metatable has a "__metatable" field, +returns the associated value. +Otherwise, returns the metatable of the given object. + +

    gcinfo ()

    + +

    Returns two results: +the number of Kbytes of dynamic memory that Lua is using +and the current garbage collector threshold (also in Kbytes). + +

    ipairs (t)

    + +

    Returns an iterator function, the table t, and 0, +so that the construction +

    +       for i,v in ipairs(t) do ... end
    +
    +will iterate over the pairs (1,t[1]), (2,t[2]), ..., +up to the first integer key with a nil value in the table. + +

    loadfile (filename)

    + +

    Loads a file as a Lua chunk (without running it). +If there are no errors, +returns the compiled chunk as a function; +otherwise, returns nil plus the error message. +The environment of the returned function is the global environment. + +

    loadlib (libname, funcname)

    + +

    Links the program with the dynamic C library libname. +Inside this library, looks for a function funcname +and returns this function as a C function. + +

    libname must be the complete file name of the C library, +including any eventual path and extension. + +

    This function is not supported by ANSI C. +As such, it is only available on some platforms +(Windows, Linux, Solaris, BSD, plus other Unix systems that +support the dlfcn standard). + +

    loadstring (string [, chunkname])

    +Loads a string as a Lua chunk (without running it). +If there are no errors, +returns the compiled chunk as a function; +otherwise, returns nil plus the error message. +The environment of the returned function is the global environment. + +

    The optional parameter chunkname +is the name to be used in error messages and debug information. + +

    To load and run a given string, use the idiom +

    +      assert(loadstring(s))()
    +
    + +

    next (table [, index])

    +Allows a program to traverse all fields of a table. +Its first argument is a table and its second argument +is an index in this table. +next returns the next index of the table and the +value associated with the index. +When called with nil as its second argument, +next returns the first index +of the table and its associated value. +When called with the last index, +or with nil in an empty table, +next returns nil. +If the second argument is absent, then it is interpreted as nil. + +

    Lua has no declaration of fields; +There is no difference between a +field not present in a table or a field with value nil. +Therefore, next only considers fields with non-nil values. +The order in which the indices are enumerated is not specified, +even for numeric indices. +(To traverse a table in numeric order, +use a numerical for or the ipairs function.) + +

    The behavior of next is undefined if, +during the traversal, +you assign any value to a non-existent field in the table. + +

    pairs (t)

    + +

    Returns the next function and the table t (plus a nil), +so that the construction +

    +       for k,v in pairs(t) do ... end
    +
    +will iterate over all key-value pairs of table t. + +

    pcall (f, arg1, arg2, ...)

    + +

    Calls function f with +the given arguments in protected mode. +That means that any error inside f is not propagated; +instead, pcall catches the error +and returns a status code. +Its first result is the status code (a boolean), +which is true if the call succeeds without errors. +In such case, pcall also returns all results from the call, +after this first result. +In case of any error, pcall returns false plus the error message. + +

    print (e1, e2, ...)

    +Receives any number of arguments, +and prints their values in stdout, +using the tostring function to convert them to strings. +This function is not intended for formatted output, +but only as a quick way to show a value, +typically for debugging. +For formatted output, use format (see 5.3). + +

    rawequal (v1, v2)

    +Checks whether v1 is equal to v2, +without invoking any metamethod. +Returns a boolean. + +

    rawget (table, index)

    +Gets the real value of table[index], +without invoking any metamethod. +table must be a table; +index is any value different from nil. + +

    rawset (table, index, value)

    +Sets the real value of table[index] to value, +without invoking any metamethod. +table must be a table, +index is any value different from nil, +and value is any Lua value. + +

    require (packagename)

    + +

    Loads the given package. +The function starts by looking into the table _LOADED +to determine whether packagename is already loaded. +If it is, then require returns the value that the package +returned when it was first loaded. +Otherwise, it searches a path looking for a file to load. + +

    If the global variable LUA_PATH is a string, +this string is the path. +Otherwise, require tries the environment variable LUA_PATH. +As a last resort, it uses the predefined path "?;?.lua". + +

    The path is a sequence of templates separated by semicolons. +For each template, require will change each interrogation +mark in the template to packagename, +and then will try to load the resulting file name. +So, for instance, if the path is +

    +  "./?.lua;./?.lc;/usr/local/?/?.lua;/lasttry"
    +
    +a require "mod" will try to load the files +./mod.lua, +./mod.lc, +/usr/local/mod/mod.lua, +and /lasttry, in that order. + +

    The function stops the search as soon as it can load a file, +and then it runs the file. +After that, it associates, in table _LOADED, +the package name with the value that the package returned, +and returns that value. +If the package returns nil (or no value), +require converts this value to true. +If the package returns false, +require also returns false. +However, as the mark in table _LOADED is false, +any new attempt to reload the file +will happen as if the package was not loaded +(that is, the package will be loaded again). + +

    If there is any error loading or running the file, +or if it cannot find any file in the path, +then require signals an error. + +

    While running a file, +require defines the global variable _REQUIREDNAME +with the package name. +The package being loaded always runs within the global environment. + +

    setfenv (f, table)

    + +

    Sets the current environment to be used by the given function. +f can be a Lua function or a number, +which specifies the function at that stack level: +Level 1 is the function calling setfenv. + +

    As a special case, when f is 0 setfenv changes +the global environment of the running thread. + +

    If the original environment has a "__fenv" field, +setfenv raises an error. + +

    setmetatable (table, metatable)

    + +

    Sets the metatable for the given table. +(You cannot change the metatable of a userdata from Lua.) +If metatable is nil, removes the metatable of the given table. +If the original metatable has a "__metatable" field, +raises an error. + +

    tonumber (e [, base])

    +Tries to convert its argument to a number. +If the argument is already a number or a string convertible +to a number, then tonumber returns that number; +otherwise, it returns nil. + +

    An optional argument specifies the base to interpret the numeral. +The base may be any integer between 2 and 36, inclusive. +In bases above 10, the letter `A´ (in either upper or lower case) +represents 10, `B´ represents 11, and so forth, +with `Z´ representing 35. +In base 10 (the default), the number may have a decimal part, +as well as an optional exponent part (see 2.2.1). +In other bases, only unsigned integers are accepted. + +

    tostring (e)

    +Receives an argument of any type and +converts it to a string in a reasonable format. +For complete control of how numbers are converted, +use format (see 5.3). + +

    If the metatable of e has a "__tostring" field, +tostring calls the corresponding value +with e as argument, +and uses the result of the call as its result. + +

    type (v)

    +Returns the type of its only argument, coded as a string. +The possible results of this function are +"nil" (a string, not the value nil), +"number", +"string", +"boolean, +"table", +"function", +"thread", +and "userdata". + +

    unpack (list)

    +Returns all elements from the given list. +This function is equivalent to +
    +  return list[1], list[2], ..., list[n]
    +
    +except that the above code can be written only for a fixed n. +The number n is the size of the list, +as defined for the table.getn function. + +

    _VERSION

    +A global variable (not a function) that +holds a string containing the current interpreter version. +The current content of this string is "Lua 5.0". + +

    xpcall (f, err)

    + +

    This function is similar to pcall, +except that you can set a new error handler. + +

    xpcall calls function f in protected mode, +using err as the error handler. +Any error inside f is not propagated; +instead, xpcall catches the error, +calls the err function with the original error object, +and returns a status code. +Its first result is the status code (a boolean), +which is true if the call succeeds without errors. +In such case, xpcall also returns all results from the call, +after this first result. +In case of any error, +xpcall returns false plus the result from err. + +

    5.2 - Coroutine Manipulation

    + +

    The operations related to coroutines comprise a sub-library of +the basic library, and come inside the table . +See 2.10 for a general description of coroutines. + +

    coroutine.create (f)

    + +

    Creates a new coroutine, with body f. +f must be a Lua function. +Returns this new coroutine, +an object with type "thread". + +

    coroutine.resume (co, val1, ...)

    + +

    Starts or continues the execution of coroutine co. +The first time you resume a coroutine, +it starts running its body. +The arguments val1, ... go as the arguments to the body function. +If the coroutine has yielded, +resume restarts it; +the arguments val1, ... go as the results from the yield. + +

    If the coroutine runs without any errors, +resume returns true plus any values passed to yield +(if the coroutine yields) or any values returned by the body function +(if the coroutine terminates). +If there is any error, +resume returns false plus the error message. + +

    coroutine.status (co)

    + +

    Returns the status of coroutine co, as a string: +"running", +if the coroutine is running (that is, it called status); +"suspended", if the coroutine is suspended in a call to yield, +or if it has not started running yet; +and "dead" if the coroutine has finished its body function, +or if it has stopped with an error. + +

    coroutine.wrap (f)

    + +

    Creates a new coroutine, with body f. +f must be a Lua function. +Returns a function that resumes the coroutine each time it is called. +Any arguments passed to the function behave as the +extra arguments to resume. +Returns the same values returned by resume, +except the first boolean. +In case of error, propagates the error. + +

    coroutine.yield (val1, ...)

    + +

    Suspends the execution of the calling coroutine. +The coroutine cannot be running neither a C function, +nor a metamethod, nor an iterator. +Any arguments to yield go as extra results to resume. + +

    5.3 - String Manipulation

    +This library provides generic functions for string manipulation, +such as finding and extracting substrings, and pattern matching. +When indexing a string in Lua, the first character is at position 1 +(not at 0, as in C). +Indices are allowed to be negative and are interpreted as indexing backwards, +from the end of the string. +Thus, the last character is at position -1, and so on. + +

    The string library provides all its functions inside the table +string. + +

    string.byte (s [, i])

    +Returns the internal numerical code of the i-th character of s, +or nil if the index is out of range. +If i is absent, then it is assumed to be 1. +i may be negative. + +

    Note that numerical codes are not necessarily portable across platforms. + +

    string.char (i1, i2, ...)

    +Receives 0 or more integers. +Returns a string with length equal to the number of arguments, +in which each character has the internal numerical code equal +to its correspondent argument. + +

    Note that numerical codes are not necessarily portable across platforms. + +

    string.dump (function)

    + +

    Returns a binary representation of the given function, +so that a later loadstring on that string returns +a copy of the function. +function must be a Lua function without upvalues. + +

    string.find (s, pattern [, init [, plain]])

    +Looks for the first match of +pattern in the string s. +If it finds one, then find returns the indices of s +where this occurrence starts and ends; +otherwise, it returns nil. +If the pattern specifies captures (see string.gsub below), +the captured strings are returned as extra results. +A third, optional numerical argument init specifies +where to start the search; +its default value is 1 and may be negative. +A value of true as a fourth, optional argument plain +turns off the pattern matching facilities, +so the function does a plain "find substring" operation, +with no characters in pattern being considered "magic". +Note that if plain is given, then init must be given too. + +

    string.len (s)

    +Receives a string and returns its length. +The empty string "" has length 0. +Embedded zeros are counted, +so "a\000b\000c" has length 5. + +

    string.lower (s)

    +Receives a string and returns a copy of that string with all +uppercase letters changed to lowercase. +All other characters are left unchanged. +The definition of what is an uppercase letter depends on the current locale. + +

    string.rep (s, n)

    +Returns a string that is the concatenation of n copies of +the string s. + +

    string.sub (s, i [, j])

    +Returns the substring of s that +starts at i and continues until j; +i and j may be negative. +If j is absent, then it is assumed to be equal to -1 +(which is the same as the string length). +In particular, +the call string.sub(s,1,j) returns a prefix of s +with length j, +and string.sub(s, -i) returns a suffix of s +with length i. + +

    string.upper (s)

    +Receives a string and returns a copy of that string with all +lowercase letters changed to uppercase. +All other characters are left unchanged. +The definition of what is a lowercase letter depends on the current locale. + +

    string.format (formatstring, e1, e2, ...)

    + +Returns a formatted version of its variable number of arguments +following the description given in its first argument (which must be a string). +The format string follows the same rules as the printf family of +standard C functions. +The only differences are that the options/modifiers +*, l, L, n, p, +and h are not supported, +and there is an extra option, q. +The q option formats a string in a form suitable to be safely read +back by the Lua interpreter: +The string is written between double quotes, +and all double quotes, newlines, and backslashes in the string +are correctly escaped when written. +For instance, the call +
    +       string.format('%q', 'a string with "quotes" and \n new line')
    +
    +will produce the string: +
    +"a string with \"quotes\" and \
    + new line"
    +
    + +

    The options c, d, E, e, f, +g, G, i, o, u, X, and x all +expect a number as argument, +whereas q and s expect a string. +The * modifier can be simulated by building +the appropriate format string. +For example, "%*g" can be simulated with +"%"..width.."g". + +

    String values to be formatted with +%s cannot contain embedded zeros. + +

    string.gfind (s, pat)

    + +

    Returns an iterator function that, +each time it is called, +returns the next captures from pattern pat over string s. + +

    If pat specifies no captures, +then the whole match is produced in each call. + +

    As an example, the following loop +

    +  s = "hello world from Lua"
    +  for w in string.gfind(s, "%a+") do
    +    print(w)
    +  end
    +
    +will iterate over all the words from string s, +printing one per line. +The next example collects all pairs key=value from the +given string into a table: +
    +  t = {}
    +  s = "from=world, to=Lua"
    +  for k, v in string.gfind(s, "(%w+)=(%w+)") do
    +    t[k] = v
    +  end
    +
    + +

    string.gsub (s, pat, repl [, n])

    + +Returns a copy of s +in which all occurrences of the pattern pat have been +replaced by a replacement string specified by repl. +gsub also returns, as a second value, +the total number of substitutions made. + +

    If repl is a string, then its value is used for replacement. +Any sequence in repl of the form %n, +with n between 1 and 9, +stands for the value of the n-th captured substring (see below). + +

    If repl is a function, then this function is called every time a +match occurs, with all captured substrings passed as arguments, +in order; +if the pattern specifies no captures, +then the whole match is passed as a sole argument. +If the value returned by this function is a string, +then it is used as the replacement string; +otherwise, the replacement string is the empty string. + +

    The optional last parameter n limits +the maximum number of substitutions to occur. +For instance, when n is 1 only the first occurrence of +pat is replaced. + +

    Here are some examples: +

    +   x = string.gsub("hello world", "(%w+)", "%1 %1")
    +   --> x="hello hello world world"
    +
    +   x = string.gsub("hello world", "(%w+)", "%1 %1", 1)
    +   --> x="hello hello world"
    +
    +   x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
    +   --> x="world hello Lua from"
    +
    +   x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
    +   --> x="home = /home/roberto, user = roberto"
    +
    +   x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
    +         return loadstring(s)()
    +       end)
    +   --> x="4+5 = 9"
    +
    +   local t = {name="lua", version="5.0"}
    +   x = string.gsub("$name_$version.tar.gz", "%$(%w+)", function (v)
    +         return t[v]
    +       end)
    +   --> x="lua_5.0.tar.gz"
    +
    + +

    Patterns

    + +

    +a character class is used to represent a set of characters. +The following combinations are allowed in describing a character class: +

      +
    • x (where x is not one of the magic characters +^$()%.[]*+-?) +--- represents the character x itself. +
    • . --- (a dot) represents all characters. +
    • %a --- represents all letters. +
    • %c --- represents all control characters. +
    • %d --- represents all digits. +
    • %l --- represents all lowercase letters. +
    • %p --- represents all punctuation characters. +
    • %s --- represents all space characters. +
    • %u --- represents all uppercase letters. +
    • %w --- represents all alphanumeric characters. +
    • %x --- represents all hexadecimal digits. +
    • %z --- represents the character with representation 0. +
    • %x (where x is any non-alphanumeric character) --- +represents the character x. +This is the standard way to escape the magic characters. +Any punctuation character (even the non magic) +can be preceded by a `%´ +when used to represent itself in a pattern. + +

    • [set] --- +represents the class which is the union of all +characters in set. +A range of characters may be specified by +separating the end characters of the range with a `-´. +All classes %x described above may also be used as +components in set. +All other characters in set represent themselves. +For example, [%w_] (or [_%w]) +represents all alphanumeric characters plus the underscore, +[0-7] represents the octal digits, +and [0-7%l%-] represents the octal digits plus +the lowercase letters plus the `-´ character. + +

      The interaction between ranges and classes is not defined. +Therefore, patterns like [%a-z] or [a-%%] +have no meaning. + +

    • [^set] --- +represents the complement of set, +where set is interpreted as above. +
    +For all classes represented by single letters (%a, %c, etc.), +the corresponding uppercase letter represents the complement of the class. +For instance, %S represents all non-space characters. + +

    The definitions of letter, space, and other character groups +depend on the current locale. +In particular, the class [a-z] may not be equivalent to %l. +The second form should be preferred for portability. + +

    +a pattern item may be +

      +
    • +a single character class, +which matches any single character in the class; +
    • +a single character class followed by `*´, +which matches 0 or more repetitions of characters in the class. +These repetition items will always match the longest possible sequence; +
    • +a single character class followed by `+´, +which matches 1 or more repetitions of characters in the class. +These repetition items will always match the longest possible sequence; +
    • +a single character class followed by `-´, +which also matches 0 or more repetitions of characters in the class. +Unlike `*´, +these repetition items will always match the shortest possible sequence; +
    • +a single character class followed by `?´, +which matches 0 or 1 occurrence of a character in the class; +
    • +%n, for n between 1 and 9; +such item matches a substring equal to the n-th captured string +(see below); +
    • +%bxy, where x and y are two distinct characters; +such item matches strings that start with x, end with y, +and where the x and y are balanced. +This means that, if one reads the string from left to right, +counting +1 for an x and -1 for a y, +the ending y is the first y where the count reaches 0. +For instance, the item %b() matches expressions with +balanced parentheses. +
    + +

    +a pattern is a sequence of pattern items. +A `^´ at the beginning of a pattern anchors the match at the +beginning of the subject string. +A `$´ at the end of a pattern anchors the match at the +end of the subject string. +At other positions, +`^´ and `$´ have no special meaning and represent themselves. + +

    +A pattern may contain sub-patterns enclosed in parentheses; +they describe captures. +When a match succeeds, the substrings of the subject string +that match captures are stored (captured) for future use. +Captures are numbered according to their left parentheses. +For instance, in the pattern "(a*(.)%w(%s*))", +the part of the string matching "a*(.)%w(%s*)" is +stored as the first capture (and therefore has number 1); +the character matching . is captured with number 2, +and the part matching %s* has number 3. + +

    As a special case, the empty capture () captures +the current string position (a number). +For instance, if we apply the pattern "()aa()" on the +string "flaaap", there will be two captures: 3 and 5. + +

    A pattern cannot contain embedded zeros. Use %z instead. + +

    5.4 - Table Manipulation

    +This library provides generic functions for table manipulation. +It provides all its functions inside the table table. + +

    Most functions in the table library assume that the table +represents an array or a list. +For those functions, an important concept is the size of the array. +There are three ways to specify that size: +

      +
    • the field "n" --- +When the table has a field "n" with a numerical value, +that value is assumed as its size. +
    • setn --- +You can call the table.setn function to explicitly set +the size of a table. +
    • implicit size --- +Otherwise, the size of the object is one less the first integer index +with a nil value. +
    +For more details, see the descriptions of the table.getn and +table.setn functions. + +

    table.concat (table [, sep [, i [, j]]])

    + +Returns table[i]..sep..table[i+1] ... sep..table[j]. +The default value for sep is the empty string, +the default for i is 1, +and the default for j is the size of the table. +If i is greater than j, returns the empty string. + +

    table.foreach (table, f)

    +Executes the given f over all elements of table. +For each element, f is called with the index and +respective value as arguments. +If f returns a non-nil value, +then the loop is broken, and this value is returned +as the final value of foreach. + +

    See the next function for extra information about table traversals. + +

    table.foreachi (table, f)

    +Executes the given f over the +numerical indices of table. +For each index, f is called with the index and +respective value as arguments. +Indices are visited in sequential order, +from 1 to n, +where n is the size of the table (see 5.4). +If f returns a non-nil value, +then the loop is broken and this value is returned +as the result of foreachi. + +

    table.getn (table)

    +Returns the size of a table, when seen as a list. +If the table has an n field with a numeric value, +this value is the size of the table. +Otherwise, if there was a previous call +to table.setn over this table, +the respective value is returned. +Otherwise, the size is one less the first integer index with +a nil value. + +

    table.sort (table [, comp])

    +Sorts table elements in a given order, in-place, +from table[1] to table[n], +where n is the size of the table (see 5.4). +If comp is given, +then it must be a function that receives two table elements, +and returns true +when the first is less than the second +(so that not comp(a[i+1],a[i]) will be true after the sort). +If comp is not given, +then the standard Lua operator < is used instead. + +

    The sort algorithm is not stable, +that is, elements considered equal by the given order +may have their relative positions changed by the sort. + +

    table.insert (table, [pos,] value)

    + +

    Inserts element value at position pos in table, +shifting up other elements to open space, if necessary. +The default value for pos is n+1, +where n is the size of the table (see 5.4), +so that a call table.insert(t,x) inserts x at the end +of table t. +This function also updates the size of the table by +calling table.setn(table, n+1). + +

    table.remove (table [, pos])

    + +

    Removes from table the element at position pos, +shifting down other elements to close the space, if necessary. +Returns the value of the removed element. +The default value for pos is n, +where n is the size of the table (see 5.4), +so that a call table.remove(t) removes the last element +of table t. +This function also updates the size of the table by +calling table.setn(table, n-1). + +

    table.setn (table, n)

    + +

    Updates the size of a table. +If the table has a field "n" with a numerical value, +that value is changed to the given n. +Otherwise, it updates an internal state +so that subsequent calls to table.getn(table) return n. + +

    5.5 - Mathematical Functions

    + +

    This library is an interface to most of the functions of the +standard C math library. +(Some have slightly different names.) +It provides all its functions inside the table math. +In addition, +it registers the global __pow +for the binary exponentiation operator ^, +so that x^y returns xy. +The library provides the following functions: + + + + + + + + +

    -       const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
    -       const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
    +       math.abs     math.acos    math.asin    math.atan    math.atan2
    +       math.ceil    math.cos     math.deg     math.exp     math.floor
    +       math.log     math.log10   math.max     math.min     math.mod
    +       math.pow     math.rad     math.sin     math.sqrt    math.tan
    +       math.frexp   math.ldexp   math.random  math.randomseed
     
    -The parameter ar must be a valid activation record, -filled by a previous call to lua_getstack or -given as argument to a hook (see Section 7.3). -Function lua_getlocal gets the index of a local variable -(n), pushes its value onto the stack, -and returns its name. -For lua_setlocal, -you push the new value onto the stack, -and the function assigns that value to the variable and returns its name. -Both functions return NULL on failure; -that happens if the index is greater than -the number of active local variables. -

    -As an example, the following function lists the names of all -local variables for a function at a given level of the stack: +plus a variable math.pi. +Most of them +are only interfaces to the corresponding functions in the C library. +All trigonometric functions work in radians +(previous versions of Lua used degrees). +The functions math.deg and math.rad convert +between radians and degrees. + +

    The function math.max returns the maximum +value of its numeric arguments. +Similarly, math.min computes the minimum. +Both can be used with 1, 2, or more arguments. + +

    The functions math.random and math.randomseed +are interfaces to the simple random generator functions +rand and srand that are provided by ANSI C. +(No guarantees can be given for their statistical properties.) +When called without arguments, +math.random returns a pseudo-random real number +in the range [0,1). +When called with a number n, +math.random returns a pseudo-random integer in the range [1,n]. +When called with two arguments, l and u, +math.random returns a pseudo-random integer in the range [l,u]. +The math.randomseed function sets a "seed" +for the pseudo-random generator: +Equal seeds produce equal sequences of numbers. + +

    5.6 - Input and Output Facilities

    + +

    The I/O library provides two different styles for file manipulation. +The first one uses implicit file descriptors, +that is, there are operations to set a default input file and a +default output file, +and all input/output operations are over those default files. +The second style uses explicit file descriptors. + +

    When using implicit file descriptors, +all operations are supplied by table io. +When using explicit file descriptors, +the operation io.open returns a file descriptor +and then all operations are supplied as methods by the file descriptor. + +

    The table io also provides +three predefined file descriptors with their usual meanings from C: +io.stdin, io.stdout, and io.stderr. + +

    A file handle is a userdata containing the file stream (FILE*), +with a distinctive metatable created by the I/O library. + +

    Unless otherwise stated, +all I/O functions return nil on failure +(plus an error message as a second result) +and some value different from nil on success. + +

    io.close ([file])

    + +

    Equivalent to file:close(). +Without a file, closes the default output file. + +

    io.flush ()

    + +

    Equivalent to file:flush over the default output file. + +

    io.input ([file])

    + +

    When called with a file name, it opens the named file (in text mode), +and sets its handle as the default input file. +When called with a file handle, +it simply sets that file handle as the default input file. +When called without parameters, +it returns the current default input file. + +

    In case of errors this function raises the error, +instead of returning an error code. + +

    io.lines ([filename])

    + +

    Opens the given file name in read mode +and returns an iterator function that, +each time it is called, +returns a new line from the file. +Therefore, the construction

    -       int listvars (lua_State *L, int level) {
    -         lua_Debug ar;
    -         int i = 1;
    -         const char *name;
    -         if (lua_getstack(L, level, &ar) == 0)
    -           return 0;  /* failure: no such level in the stack */
    -         while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
    -           printf("%s\n", name);
    -           lua_pop(L, 1);  /* remove variable value */
    -         }
    -         return 1;
    -       }
    +       for line in io.lines(filename) do ... end
     
    -

    -

    - - -

    7.3 - Hooks

    -

    -The Lua interpreter offers two hooks for debugging purposes: -a call hook and a line hook. -Both have the same type, - +will iterate over all lines of the file. +When the iterator function detects the end of file, +it returns nil (to finish the loop) and automatically closes the file. + +

    The call io.lines() (without a file name) is equivalent +to io.input():lines(), that is, it iterates over the +lines of the default input file. + +

    io.open (filename [, mode])

    + +

    This function opens a file, +in the mode specified in the string mode. +It returns a new file handle, +or, in case of errors, nil plus an error message. + +

    The mode string can be any of the following: +

      +
    • "r" read mode (the default); +
    • "w" write mode; +
    • "a" append mode; +
    • "r+" update mode, all previous data is preserved; +
    • "w+" update mode, all previous data is erased; +
    • "a+" append update mode, previous data is preserved, + writing is only allowed at the end of file. +
    +The mode string may also have a b at the end, +which is needed in some systems to open the file in binary mode. +This string is exactly what is used in the standard C function fopen. + +

    io.output ([file])

    + +

    Similar to io.input, but operates over the default output file. + +

    io.read (format1, ...)

    + +

    Equivalent to io.input():read. + +

    io.tmpfile ()

    + +

    Returns a handle for a temporary file. +This file is open in update mode +and it is automatically removed when the program ends. + +

    io.type (obj)

    + +

    Checks whether obj is a valid file handle. +Returns the string "file" if obj is an open file handle, +"closed file" if obj is a closed file handle, +and nil if obj is not a file handle. + +

    io.write (value1, ...)

    + +

    Equivalent to io.output():write. + +

    file:close ()

    + +

    Closes file. + +

    file:flush ()

    + +

    Saves any written data to file. + +

    file:lines ()

    + +

    Returns an iterator function that, +each time it is called, +returns a new line from the file. +Therefore, the construction

    -       typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
    +       for line in file:lines() do ... end
     
    -and you can set them with the following functions: - -
    -       lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
    -       lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
    -
    -A hook is disabled when its value is NULL, -which is the initial value of both hooks. -The functions lua_setcallhook and lua_setlinehook -set their corresponding hooks and return their previous values. -

    -The call hook is called whenever the -interpreter enters or leaves a function. -The event field of ar has the strings "call" -or "return". -This ar can then be used in calls to lua_getinfo, -lua_getlocal, and lua_setlocal -to get more information about the function and to manipulate its -local variables. -

    -The line hook is called every time the interpreter changes -the line of code it is executing. -The event field of ar has the string "line", -and the currentline field has the line number. -Again, you can use this ar in other calls to the debug API. -

    -While Lua is running a hook, it disables other calls to hooks. -Therefore, if a hook calls Lua to execute a function or a chunk, -this execution ocurrs without any calls to hooks. -

    -

    - -

    7.4 - The Reflexive Debug Interface

    -

    -The library ldblib provides +will iterate over all lines of the file. +(Unlike io.lines, this function does not close the file +when the loop ends.) + +

    file:read (format1, ...)

    + +

    Reads the file file, +according to the given formats, which specify what to read. +For each format, +the function returns a string (or a number) with the characters read, +or nil if it cannot read data with the specified format. +When called without formats, +it uses a default format that reads the entire next line +(see below). + +

    The available formats are +

      +
    • "*n" reads a number; +this is the only format that returns a number instead of a string. +
    • "*a" reads the whole file, starting at the current position. +On end of file, it returns the empty string. +
    • "*l" reads the next line (skipping the end of line), +returning nil on end of file. +This is the default format. +
    • number reads a string with up to that number of characters, +returning nil on end of file. +If number is zero, +it reads nothing and returns an empty string, +or nil on end of file. +
    + +

    file:seek ([whence] [, offset])

    + +

    Sets and gets the file position, +measured from the beginning of the file, +to the position given by offset plus a base +specified by the string whence, as follows: +

      +
    • "set" base is position 0 (beginning of the file); +
    • "cur" base is current position; +
    • "end" base is end of file; +
    +In case of success, function seek returns the final file position, +measured in bytes from the beginning of the file. +If this function fails, it returns nil, +plus a string describing the error. + +

    The default value for whence is "cur", +and for offset is 0. +Therefore, the call file:seek() returns the current +file position, without changing it; +the call file:seek("set") sets the position to the +beginning of the file (and returns 0); +and the call file:seek("end") sets the position to the +end of the file, and returns its size. + +

    file:write (value1, ...)

    + +

    Writes the value of each of its arguments to +the filehandle file. +The arguments must be strings or numbers. +To write other values, +use tostring or string.format before write. + +

    5.7 - Operating System Facilities

    + +

    This library is implemented through table os. + +

    os.clock ()

    + +

    Returns an approximation of the amount of CPU time +used by the program, in seconds. + +

    os.date ([format [, time]])

    + +

    Returns a string or a table containing date and time, +formatted according to the given string format. + +

    If the time argument is present, +this is the time to be formatted +(see the os.time function for a description of this value). +Otherwise, date formats the current time. + +

    If format starts with `!´, +then the date is formatted in Coordinated Universal Time. +After that optional character, +if format is *t, +then date returns a table with the following fields: +year (four digits), month (1--12), day (1--31), +hour (0--23), min (0--59), sec (0--61), +wday (weekday, Sunday is 1), +yday (day of the year), +and isdst (daylight saving flag, a boolean). + +

    If format is not *t, +then date returns the date as a string, +formatted according with the same rules as the C function strftime. + +

    When called without arguments, +date returns a reasonable date and time representation that depends on +the host system and on the current locale +(that is, os.date() is equivalent to os.date("%c")). + +

    os.difftime (t2, t1)

    + +

    Returns the number of seconds from time t1 to time t2. +In Posix, Windows, and some other systems, +this value is exactly t2-t1. + +

    os.execute (command)

    + +

    This function is equivalent to the C function system. +It passes command to be executed by an operating system shell. +It returns a status code, which is system-dependent. + +

    os.exit ([code])

    + +

    Calls the C function exit, +with an optional code, +to terminate the host program. +The default value for code is the success code. + +

    os.getenv (varname)

    + +

    Returns the value of the process environment variable varname, +or nil if the variable is not defined. + +

    os.remove (filename)

    + +

    Deletes the file with the given name. +If this function fails, it returns nil, +plus a string describing the error. + +

    os.rename (oldname, newname)

    + +

    Renames file named oldname to newname. +If this function fails, it returns nil, +plus a string describing the error. + +

    os.setlocale (locale [, category])

    + +

    Sets the current locale of the program. +locale is a string specifying a locale; +category is an optional string describing which category to change: +"all", "collate", "ctype", +"monetary", "numeric", or "time"; +the default category is "all". +The function returns the name of the new locale, +or nil if the request cannot be honored. + +

    os.time ([table])

    + +

    Returns the current time when called without arguments, +or a time representing the date and time specified by the given table. +This table must have fields year, month, and day, +and may have fields hour, min, sec, and isdst +(for a description of these fields, see the os.date function). + +

    The returned value is a number, whose meaning depends on your system. +In Posix, Windows, and some other systems, this number counts the number +of seconds since some given start time (the "epoch"). +In other systems, the meaning is not specified, +and the number returned by time can be used only as an argument to +date and difftime. + +

    os.tmpname ()

    + +

    Returns a string with a file name that can +be used for a temporary file. +The file must be explicitly opened before its use +and removed when no longer needed. + +

    This function is equivalent to the tmpnam C function, +and many people (and even some compilers!) advise against its use, +because between the time you call this function +and the time you open the file, +it is possible for another process +to create a file with the same name. + +

    5.8 - The Reflexive Debug Interface

    + +

    The debug library provides the functionality of the debug interface to Lua programs. -If you want to use this library, -your host application must open it, -by calling lua_dblibopen. - -

    -You should exert great care when using this library. +You should exert care when using this library. The functions provided here should be used exclusively for debugging -and similar tasks (e.g., profiling). +and similar tasks, such as profiling. Please resist the temptation to use them as a -usual programming tool. -They are slow and violate some (otherwise) secure aspects of the -language (e.g., privacy of local variables). -As a general rule, if your program does not need this library, -do not open it. -

    -

    -

    getinfo (function, [what])

    -

    -This function returns a table with information about a function. +usual programming tool: +They can be very slow. +Moreover, setlocal and getlocal +violate the privacy of local variables +and therefore can compromise some otherwise secure code. + +

    All functions in this library are provided +inside a debug table. + +

    debug.debug ()

    + +

    Enters an interactive mode with the user, +running each string that the user enters. +Using simple commands and other debug facilities, +the user can inspect global and local variables, +change their values, evaluate expressions, and so on. +A line containing only the word cont finishes this function, +so that the caller continues its execution. + +

    Note that commands for debug.debug are not lexically nested +with any function, so they have no direct access to local variables. + +

    debug.gethook ()

    + +

    Returns the current hook settings, as three values: +the current hook function, the current hook mask, +and the current hook count (as set by the debug.sethook function). + +

    debug.getinfo (function [, what])

    + +

    This function returns a table with information about a function. You can give the function directly, -or you can give a number as the value of function, -which means the function running at level function of the stack: -Level 0 is the current function (getinfo itself); -level 1 is the function that called getinfo; +or you can give a number as the value of function, +which means the function running at level function of the call stack: +Level 0 is the current function (getinfo itself); +level 1 is the function that called getinfo; and so on. -If function is a number larger than the number of active functions, -then getinfo returns nil. -

    -The returned table contains all the fields returned by lua_getinfo, -with the string what describing what to get. -The default for what is to get all information available. -

    -For instance, the expression getinfo(1,"n").name returns +If function is a number larger than the number of active functions, +then getinfo returns nil. + +

    The returned table contains all the fields returned by lua_getinfo, +with the string what describing which fields to fill in. +The default for what is to get all information available. +If present, +the option `f´ +adds a field named func with the function itself. + +

    For instance, the expression debug.getinfo(1,"n").name returns the name of the current function, if a reasonable name can be found, -and getinfo(print) returns a table with all available information -about the print function. -

    -

    -

    getlocal (level, local)

    -

    -This function returns the name and the value of the local variable -with index local of the function at level level of the stack. +and debug.getinfo(print) returns a table with all available information +about the print function. + +

    debug.getlocal (level, local)

    + +

    This function returns the name and the value of the local variable +with index local of the function at level level of the stack. (The first parameter or local variable has index 1, and so on, until the last active local variable.) The function returns nil if there is no local variable with the given index, -and raises an error when called with a level out of range. -(You can call getinfo to check whether the level is valid.) -

    -

    setlocal (level, local, value)

    -

    -This function assigns the value value to the local variable -with index local of the function at level level of the stack. +and raises an error when called with a level out of range. +(You can call debug.getinfo to check whether the level is valid.) + +

    debug.getupvalue (func, up)

    + +

    This function returns the name and the value of the upvalue +with index up of the function func. +The function returns nil if there is no upvalue with the given index. + +

    debug.setlocal (level, local, value)

    + +

    This function assigns the value value to the local variable +with index local of the function at level level of the stack. The function returns nil if there is no local variable with the given index, -and raises an error when called with a level out of range. -

    -

    setcallhook (hook)

    -

    -Sets the function hook as the call hook; -this hook will be called every time the interpreter starts and -exits the execution of a function. -The only argument to the call hook is the event name ("call" or -"return"). -You can call getinfo with level 2 to get more information about -the function being called or returning -(level 0 is the getinfo function, -and level 1 is the hook function). -When called without arguments, -this function turns off call hooks. -setcallhook returns the old hook. -

    -

    setlinehook (hook)

    -

    -Sets the function hook as the line hook; -this hook will be called every time the interpreter changes -the line of code it is executing. -The only argument to the line hook is the line number the interpreter -is about to execute. -When called without arguments, -this function turns off line hooks. -setlinehook returns the old hook. -

    -

    - - -


    - -

    8 - Lua Stand-alone

    -

    -Although Lua has been designed as an extension language, +and raises an error when called with a level out of range. +(You can call getinfo to check whether the level is valid.) + +

    debug.setupvalue (func, up, value)

    + +

    This function assigns the value value to the upvalue +with index up of the function func. +The function returns nil if there is no upvalue +with the given index. + +

    debug.sethook (hook, mask [, count])

    + + +

    Sets the given function as a hook. +The string mask and the number count describe +when the hook will be called. +The string mask may have the following characters, +with the given meaning: +

      +
    • "c" The hook is called every time Lua calls a function; +
    • "r" The hook is called every time Lua returns from a function; +
    • "l" The hook is called every time Lua enters a new line of code. +
    +With a count different from zero, +the hook is called after every count instructions. + +

    When called without arguments, +the debug.sethook function turns off the hook. + +

    When the hook is called, its first parameter is always a string +describing the event that triggered its call: +"call", "return" (or "tail return"), +"line", and "count". +Moreover, for line events, +it also gets as its second parameter the new line number. +Inside a hook, +you can call getinfo with level 2 to get more information about +the running function +(level 0 is the getinfo function, +and level 1 is the hook function), +unless the event is "tail return". +In this case, Lua is only simulating the return, +and a call to getinfo will return invalid data. + +

    debug.traceback ([message])

    + +

    Returns a string with a traceback of the call stack. +An optional message string is appended +at the beginning of the traceback. +This function is typically used with xpcall to produce +better error messages. + +

    +

    6 - Lua Stand-alone

    + +

    Although Lua has been designed as an extension language, to be embedded in a host C program, -it is frequently used as a stand-alone language. +it is also frequently used as a stand-alone language. An interpreter for Lua as a stand-alone language, -called simply lua, +called simply lua, is provided with the standard distribution. -This program can be called with any sequence of the following arguments: -

    -
    -sNUM
    sets the stack size to NUM -(if present, this must be the first option); -
    -
    executes stdin as a file; -
    -c
    calls lua_close after running all arguments; -
    -e \rmstat
    executes string stat; -
    -f filename
    executes file filename with the -remaining arguments in table arg; -
    -i
    enters interactive mode with prompt; -
    -q
    enters interactive mode without prompt; -
    -v
    prints version information; -
    var=value
    sets global var to string "value"; -
    filename
    executes file filename. -
    +The stand-alone interpreter includes +all standard libraries plus the reflexive debug interface. +Its usage is: +
    +      lua [options] [script [args]]
    +
    +The options are: +
      +
    • - executes stdin as a file; +
    • -e stat executes string stat; +
    • -l file "requires" file; +
    • -i enters interactive mode after running script; +
    • -v prints version information; +
    • -- stop handling options. +
    +After handling its options, lua runs the given script, +passing to it the given args. When called without arguments, -lua behaves as lua -v -i when stdin is a terminal, -and as lua - otherwise. -

    -All arguments are handled in order, except -c. +lua behaves as lua -v -i when stdin is a terminal, +and as lua - otherwise. + +

    Before running any argument, +the interpreter checks for an environment variable LUA_INIT. +If its format is @filename, +then lua executes the file. +Otherwise, lua executes the string itself. + +

    All options are handled in order, except -i. For instance, an invocation like

    -       $ lua -i a=test prog.lua
    -
    -will first interact with the user until an EOF in stdin, -then will set a to "test", -and finally will run the file prog.lua. -(Here, -$ is the shell prompt. Your prompt may be different.) -

    -When the option -f filename is used, -all remaining arguments in the command line -are passed to the Lua program filename in a table called arg. -In this table, -the field n gets the index of the last argument, -and the field 0 gets "filename". + $ lua -e'a=1' -e 'print(a)' script.lua +

  • +will first set a to 1, then print a, +and finally run the file script.lua. +(Here, $ is the shell prompt. Your prompt may be different.) + +

    Before starting to run the script, +lua collects all arguments in the command line +in a global table called arg. +The script name is stored in index 0, +the first argument after the script name goes to index 1, +and so on. +The field n gets the number of arguments after the script name. +Any arguments before the script name +(that is, the interpreter name plus the options) +go to negative indices. For instance, in the call

    -       $ lua a.lua -f b.lua t1 t3
    +       $ lua -la.lua b.lua t1 t2
     
    -the interpreter first runs the file a.lua, +the interpreter first runs the file a.lua, then creates a table
    -       arg = {"t1", "t3";  n = 2, [0] = "b.lua"}
    +       arg = { [-2] = "lua", [-1] = "-la.lua", [0] = "b.lua",
    +               [1] = "t1", [2] = "t2"; n = 2 }
     
    -and finally runs the file b.lua. - -The stand-alone interpreter also provides a getargs function that -can be used to access all command line arguments. -For instance, if you call Lua with the line +and finally runs the file b.lua. + +

    In interactive mode, +if you write an incomplete statement, +the interpreter waits for its completion. + +

    If the global variable _PROMPT is defined as a string, +then its value is used as the prompt. +Therefore, the prompt can be changed directly on the command line:

    -       $ lua -c a b
    +       $ lua -e"_PROMPT='myprompt> '" -i
     
    -then a call to getargs in a or b will return the table +(the outer pair of quotes is for the shell, +the inner is for Lua), +or in any Lua programs by assigning to _PROMPT. +Note the use of -i to enter interactive mode; otherwise, +the program would end just after the assignment to _PROMPT. + +

    In Unix systems, Lua scripts can be made into executable programs +by using chmod +x and the #! form, +as in

    -       {[0] = "lua", [1] = "-c", [2] = "a", [3] = "b", n = 3}
    +#!/usr/local/bin/lua
     
    -

    -In interactive mode, -a multi-line statement can be written finishing intermediate -lines with a backslash (`\'). -If the global variable _PROMPT is defined as a string, -then its value is used as the prompt. -Therefore, the prompt can be changed directly on the command line: +(Of course, +the location of the Lua interpreter may be different in your machine. +If lua is in your PATH, +then

    -       $ lua _PROMPT='myprompt> ' -i
    -
    -or in any Lua programs by assigning to _PROMPT. -

    -In Unix systems, Lua scripts can be made into executable programs -by using chmod +x and the #! form, -as in #!/usr/local/bin/lua, -or #!/usr/local/bin/lua -f to get other arguments. -

    -

    -


    - +#!/usr/bin/env lua +
    +is a more portable solution.) + +

    Acknowledgments

    -

    -The authors would like to thank CENPES/PETROBRAS which, -jointly with TeCGraf, used early versions of -this system extensively and gave valuable comments. -The authors would also like to thank Carlos Henrique Levy, -who found the name of the game. -Lua means ``moon'' in Portuguese. -

    -

    -

    -


    - -

    Incompatibilities with Previous Versions

    -

    -Lua 4.0 is a major revision of the language. -We took a great care to avoid incompatibilities with -the previous public versions of Lua, -but some differences had to be introduced. -Here is a list of all these incompatibilities. -

    -

    -

    Incompatibilities with version 3.2

    -

    -

    Changes in the Language

    -
      -

      -

    • -All pragmas ($debug, $if, ...) have been removed. -

      -

    • -for, break, and in are now reserved words. -

      -

    • -Garbage-collection tag methods for tables is now obsolete. -

      -

    • -There is now only one tag method for order operators. -

      -

    • -In nested function calls like f(g(x)), -all return values from g are passed as arguments to f. -This only happens when g is the last -or the only argument to f. -

      -

    • -The pre-compiler may assume that some operators are associative, -for optimizations. -This may cause problems if these operators -have non-associative tag methods. -

      -

    • Old pre-compiled code is obsolete, and must be re-compiled. -

      -

    -

    -

    -

    Changes in the Libraries

    -
      -

      -

    • -When traversing a table with next or foreach, -the table cannot be modified in any way. -

      -

    • -General read patterns are now obsolete. -

      -

    • -The functions rawgettable and rawsettable -have been renamed to rawget and rawset. -

      -

    • -The functions foreachvar, nextvar, -rawsetglobal, and rawgetglobal are obsolete. -You can get their functionality using table operations -over the table of globals, -which is returned by globals. -

      -

    • -setglobal and sort no longer return a value; -type no longer returns a second value. -

      -

    • -The p option in function call is now obsolete. -

      -

    -

    -

    -

    Changes in the API

    -
      -

      -

    • -The API has been completely rewritten: -It is now fully reentrant and much clearer. -

      -

    • -The debug API has been completely rewritten. -

      -

    -

    - - -


    -

    The Complete Syntax of Lua

    -

    - -

    -

    -

    - chunk ::= {stat [`;']} -

    - block ::= chunk -

    - stat ::= varlist1 `=' explist1
    | functioncall
    | do block end
    | while exp1 do block end
    | repeat block until exp1
    | if exp1 then block {elseif exp1 then block} [else block] end
    | return [explist1]
    | break
    | for `name' `=' exp1 `,' exp1 [`,' exp1] do block end
    | for `name' `,' `name' in exp1 do block end
    | function funcname `(' [parlist1] `)' block end
    | local declist [init] -

    - funcname ::= `name' | `name' `.' `name' | `name' `:' `name' -

    - varlist1 ::= var {`,' var} -

    - var ::= `name' | varorfunc `[' exp1 `]' | varorfunc `.' `name' -

    - varorfunc ::= var | functioncall -

    - declist ::= `name' {`,' `name'} -

    - init ::= `=' explist1 -

    - explist1 ::= {exp1 `,'} exp -

    - exp1 ::= exp -

    - exp ::= nil | `number' | `literal' | var | function | upvalue
    | functioncall | tableconstructor | `(' exp `)' | exp binop exp | unop exp -

    -

    - functioncall ::= varorfunc args | varorfunc `:' `name' args -

    - args ::= `(' [explist1] `)' | tableconstructor | `literal' -

    - function ::= function `(' [parlist1] `)' block end -

    - parlist1 ::= `...' | `name' {`,' `name'} [`,' `...'] -

    - upvalue ::= `%' `name' -

    - tableconstructor ::= `{' fieldlist `}' - fieldlist ::= lfieldlist | ffieldlist | lfieldlist `;' ffieldlist | ffieldlist `;' lfieldlist - lfieldlist ::= [lfieldlist1] - ffieldlist ::= [ffieldlist1] - lfieldlist1 ::= exp {`,' exp} [`,'] - ffieldlist1 ::= ffield {`,' ffield} [`,'] - ffield ::= `[' exp `]' `=' exp | `name' `=' exp -

    - binop ::= `+' | `-' | `*' | `/' | `\^{ ' | `..'
    | `<' | `<=' | `>' | `>=' | `==' | `\ { '=}
    | and | or} -

    - unop ::= `-' | not -

    -

    -

    - -


    - -Last update: -Mon Nov 6 17:37:03 EDT 2000 -by lhf. - - - - + +

    The Lua team is grateful to Tecgraf for its continued support to Lua. +We thank everyone at Tecgraf, +specially the head of the group, Marcelo Gattass. +At the risk of omitting several names, +we also thank the following individuals for supporting, +contributing to, and spreading the word about Lua: +Alan Watson. +André Clinio, +André Costa, +Antonio Scuri, +Asko Kauppi, +Bret Mogilefsky, +Cameron Laird, +Carlos Cassino, +Carlos Henrique Levy, +Claudio Terra, +David Jeske, +Ed Ferguson, +Edgar Toernig, +Erik Hougaard, +Jim Mathies, +John Belmonte, +John Passaniti, +John Roll, +Jon Erickson, +Jon Kleiser, +Mark Ian Barlow, +Nick Trout, +Noemi Rodriguez, +Norman Ramsey, +Philippe Lhoste, +Renata Ratton, +Renato Borges, +Renato Cerqueira, +Reuben Thomas, +Stephan Herrmann, +Steve Dekorte, +Thatcher Ulrich, +Tomás Gorham, +Vincent Penquerc'h, +Thank you! + +


    + +

    Incompatibilities with Previous Versions

    + + +

    Lua 5.0 is a major release. +There are several incompatibilities with its previous version, Lua 4.0. + +

    Incompatibilities with version 4.0

    + +

    Changes in the Language

    +
      + +

    • +The whole tag-method scheme was replaced by metatables. + +

    • +Function calls written between parentheses result in exactly one value. + +

    • +A function call as the last expression in a list constructor +(like {a,b,f()}) has all its return values inserted in the list. + +

    • +The precedence of or is smaller than the precedence of and. + +

    • +in, false, and true are reserved words. + +

    • +The old construction for k,v in t, where t is a table, +is deprecated (although it is still supported). +Use for k,v in pairs(t) instead. + +

    • +When a literal string of the form [[...]] starts with a newline, +this newline is ignored. + +

      + +

    • Upvalues in the form %var are obsolete; +use external local variables instead. + +

    + +

    Changes in the Libraries

    +
      + +

    • +Most library functions now are defined inside tables. +There is a compatibility script (compat.lua) that +redefine most of them as global names. + +

    • +In the math library, angles are expressed in radians. +With the compatibility script (compat.lua), +functions still work in degrees. + +

    • +The call function is deprecated. +Use f(unpack(tab)) instead of call(f, tab) +for unprotected calls, +or the new pcall function for protected calls. + +

    • +dofile do not handle errors, but simply propagates them. + +

    • +dostring is deprecated. Use loadstring instead. + +

    • +The read option *w is obsolete. + +

    • +The format option %n$ is obsolete. + +

    + +

    Changes in the API

    +
      + +

    • +lua_open does not have a stack size as its argument +(stacks are dynamic). + +

    • +lua_pushuserdata is deprecated. +Use lua_newuserdata or lua_pushlightuserdata instead. + +

    + +

    + +

    The Complete Syntax of Lua

    + + +

    + +

    +
    +

    chunk ::= {stat [`;´]} + +

    block ::= chunk + +

    stat ::= varlist1 `=´ explist1 | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | return [explist1] | break | for Name `=´ exp `,´ exp [`,´ exp] do block end | for Name {`,´ Name} in explist1 do block end | function funcname funcbody | local function Name funcbody | local namelist [init] + +

    funcname ::= Name {`.´ Name} [`:´ Name] + +

    varlist1 ::= var {`,´ var} + +

    var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name + +

    namelist ::= Name {`,´ Name} + +

    init ::= `=´ explist1 + +

    explist1 ::= {exp `,´} exp + +

    exp ::= nil false true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp + +

    prefixexp ::= var | functioncall | `(´ exp `)´ + +

    functioncall ::= prefixexp args | prefixexp `:´ Name args + +

    args ::= `(´ [explist1] `)´ | tableconstructor | Literal + +

    function ::= function funcbody + +

    funcbody ::= `(´ [parlist1] `)´ block end + +

    parlist1 ::= Name {`,´ Name} [`,´ `...´] | `...´ + +

    tableconstructor ::= `{´ [fieldlist] `}´ + fieldlist ::= field {fieldsep field} [fieldsep] + field ::= `[´ exp `]´ `=´ exp | name `=´ exp | exp + fieldsep ::= `,´ | `;´ + +

    binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `..´ | `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | and | or + +

    unop ::= `-´ | not + +

    + +

    + +

    + + + diff --git a/doc/readme.html b/doc/readme.html index a574eccd36..c50459d15c 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -7,29 +7,28 @@


    -Lua +Lua Documentation


    Last update: -Mon Nov 6 19:13:31 EDT 2000 -by lhf. +Tue Apr 1 14:35:18 EST 2003 diff --git a/etc/.exrc b/etc/.exrc new file mode 120000 index 0000000000..d906774993 --- /dev/null +++ b/etc/.exrc @@ -0,0 +1 @@ +/home/n/lhf/lib/vi/c \ No newline at end of file diff --git a/etc/Makefile b/etc/Makefile index a776869733..1286c6403a 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,16 +1,14 @@ -# makefile for etc +# makefile for Lua etc LUA= .. include $(LUA)/config LIBLUA=$(LIB)/liblua.a -ALL= bin2c min trace lua.def +ALL= bin2c min trace noparser luab -x: - @echo 'choose a target:' all $(ALL) - -all: $(ALL) +all: + @echo 'choose a target:' $(ALL) bin2c: bin2c.c $(CC) $(CFLAGS) -o $@ $@.c @@ -19,20 +17,26 @@ min: min.c $(LIBLUA) $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua trace: trace.c $(LIBLUA) - $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib -lm + $(CC) -g $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib $(EXTRA_LIBS) -def: lua.def +noparser: noparser.c + $(CC) $(CFLAGS) -I$(LUA)/src -o $@.o -c $@.c -lua.def: $(INC)/lua.h - $(BIN)/lua def.lua < $(INC)/lua.h > $@ - # cat $(INC)/l*.h | $(BIN)/lua def.lua > $@ +luab: noparser $(LIBLUA) + cc -o $@ noparser.o $(LUA)/src/lua/lua.o -L$(LIB) -llua -llualib $(EXTRA_LIBS) + $(BIN)/luac $(LUA)/test/hello.lua + $@ luac.out + -$@ -e'a=1' -stdcall: - mkdir -p Stdcall - grep -l _API $(LUA)/src/*.[ch] $(LUA)/src/*/*.[ch] | xargs -n1 -i echo $(BIN)/lua stdcall.lua '<{}' '>Stdcall/{}' +flat: + cd ..; mkdir flat; mv include/*.h src/*.[ch] src/*/*.[ch] flat $(LIBLUA): cd ../src; $(MAKE) clean: - rm -f $(ALL) + rm -f $(ALL) a.out core *.o luac.out + +luser_tests.h: RCS/ltests.h,v + co -q -M ltests.h + mv -f ltests.h $@ diff --git a/etc/README b/etc/README index eaae1c3ddf..c838a7fe19 100644 --- a/etc/README +++ b/etc/README @@ -1,43 +1,54 @@ -This directory contains some code that might be useful. +This directory contains some useful files and code. +Unlike the code in ../src, everything here is in the public domain. bin2c.c - This program converts files to byte arrays that are automatically - run with lua_dobuffer. This allows C programs to include all necessary - Lua code, even in precompiled form. Even if the code is included in - source form, bin2c is useful because it avoids the hassle of having to - quote special characters in C strings. - Example of usage: Run bin2c file1 file2 ... > init.h. Then, in your C - program, just do #include "init.h" anywhere in the *body* of a + This program converts files to byte arrays that are automatically run + with lua_dobuffer. This allows C programs to include all necessary Lua + code, even in precompiled form. Even if the code is included in source + form, bin2c is useful because it avoids the hassle of having to quote + special characters in C strings. + Example of usage: Run bin2c file1 file2 ... > init.h. Then, in your + C program, just do #include "init.h" anywhere in the *body* of a function. This will be equivalent to calling lua_dofile(L,"file1"); lua_dofile(L,"file2"); ... Note that the Lua state is called "L". If you use a different name, - say "mystate", just #define L mystate before #include "init.h". + say "mystate", just #define L mystate before you #include "init.h". -def.lua - A Lua script for creating .DEF for Windows DLLs. - Just do "make def" to create lua.def. +compat.lua + A compatibility module for Lua 4.0 functions. -min.c - A minimal Lua interpreter. +doall.lua + Emulate the command line behaviour of Lua 4.0 lua.ico A Lua icon for Windows. - It was drawn by hand by Markus Gritsch . + Drawn by hand by Markus Gritsch . + +lua.magic + Data for teaching file(1) about Lua precompiled chunks. lua.xpm The same icon as lua.ico, but in XPM format. It was converted with ImageMagick by Andy Tai . -lua.magic - Data for teaching file(1) about Lua precompiled chunks. +luser_number.h + Number type configuration for Lua core. + +luser_tests.h + Self-test configuration for Lua core. + +min.c + A minimal Lua interpreter. + Good for learning and for starting your own. -stdcall.lua - A Lua script for changing the calling convention to __stdcall. - Do "make stdcall" and new modules will be created in stdcall/. +noparser.c + Linking with noparser.o avoids loading the parsing modules in lualib.a. + Do "make luab" to build a sample Lua intepreter that does not parse + Lua programs, only loads precompiled programs. -setfallback.lua - A Lua implementation of fallbacks on top of tag methods. - You only need this module if you have Lua code that uses setfallback. +saconfig.c + Configuration for Lua interpreter. trace.c - A simple execution tracer. An example of how to use the debugging hooks. + A simple execution tracer. + An example of how to use the debug hooks in C. diff --git a/etc/bin2c.c b/etc/bin2c.c index ac95a6e8bc..0993b16d83 100644 --- a/etc/bin2c.c +++ b/etc/bin2c.c @@ -1,34 +1,30 @@ /* * bin2c.c -* convert binary files to byte arrays +* convert files to byte arrays for automatic loading with lua_dobuffer * Luiz Henrique de Figueiredo (lhf@tecgraf.puc-rio.br) -* 11 Sep 2000 22:37:14 +* 02 Apr 2003 20:44:31 */ #include #include #include -void dump(FILE* f, int n) +static void dump(FILE* f, int n) { - printf("static unsigned char B%d[]={\n",n); + printf("static const unsigned char B%d[]={\n",n); for (n=1;;n++) { int c=getc(f); if (c==EOF) break; -#if 0 - printf("0x%02x,",c); -#else printf("%3u,",c); -#endif if (n==20) { putchar('\n'); n=0; } } printf("\n};\n\n"); } -void fdump(char* fn, int n) +static void fdump(const char* fn, int n) { - FILE* f= (fn==NULL) ? stdin : fopen(fn,"rb"); /* must open in binary mode */ + FILE* f= fopen(fn,"rb"); /* must open in binary mode */ if (f==NULL) { fprintf(stderr,"bin2c: cannot open "); @@ -37,15 +33,15 @@ void fdump(char* fn, int n) } else { - if (fn!=NULL) printf("/* %s */\n",fn); + printf("/* %s */\n",fn); dump(f,n); fclose(f); } } -void emit(char* fn, int n) +static void emit(const char* fn, int n) { - printf(" lua_dobuffer(L,B%d,sizeof(B%d),\"%s\");\n",n,n,fn); + printf(" lua_dobuffer(L,(const char*)B%d,sizeof(B%d),\"%s\");\n",n,n,fn); } int main(int argc, char* argv[]) @@ -55,7 +51,7 @@ int main(int argc, char* argv[]) if (argc<2) { dump(stdin,0); - emit("(stdin)",0); + emit("=stdin",0); } else { diff --git a/etc/compat.lua b/etc/compat.lua new file mode 100644 index 0000000000..2a7f3731e0 --- /dev/null +++ b/etc/compat.lua @@ -0,0 +1,192 @@ +------------------------------------------------------------------- +-- Real globals +-- _ALERT +-- _ERRORMESSAGE +-- _VERSION +-- _G +-- assert +-- error +-- metatable +-- next +-- print +-- require +-- tonumber +-- tostring +-- type +-- unpack + +------------------------------------------------------------------- +-- collectgarbage +-- gcinfo + +-- globals + +-- call -> protect(f, err) +-- loadfile +-- loadstring + +-- rawget +-- rawset + +-- getargs = Main.getargs ?? + + +function do_ (f, err) + if not f then print(err); return end + local a,b = pcall(f) + if not a then print(b); return nil + else return b or true + end +end + +function dostring(s) return do_(loadstring(s)) end +-- function dofile(s) return do_(loadfile(s)) end + +------------------------------------------------------------------- +-- Table library +local tab = table +foreach = tab.foreach +foreachi = tab.foreachi +getn = tab.getn +tinsert = tab.insert +tremove = tab.remove +sort = tab.sort + +------------------------------------------------------------------- +-- Debug library +local dbg = debug +getinfo = dbg.getinfo +getlocal = dbg.getlocal +setcallhook = function () error"`setcallhook' is deprecated" end +setlinehook = function () error"`setlinehook' is deprecated" end +setlocal = dbg.setlocal + +------------------------------------------------------------------- +-- math library +local math = math +abs = math.abs +acos = function (x) return math.deg(math.acos(x)) end +asin = function (x) return math.deg(math.asin(x)) end +atan = function (x) return math.deg(math.atan(x)) end +atan2 = function (x,y) return math.deg(math.atan2(x,y)) end +ceil = math.ceil +cos = function (x) return math.cos(math.rad(x)) end +deg = math.deg +exp = math.exp +floor = math.floor +frexp = math.frexp +ldexp = math.ldexp +log = math.log +log10 = math.log10 +max = math.max +min = math.min +mod = math.mod +PI = math.pi +--??? pow = math.pow +rad = math.rad +random = math.random +randomseed = math.randomseed +sin = function (x) return math.sin(math.rad(x)) end +sqrt = math.sqrt +tan = function (x) return math.tan(math.rad(x)) end + +------------------------------------------------------------------- +-- string library +local str = string +strbyte = str.byte +strchar = str.char +strfind = str.find +format = str.format +gsub = str.gsub +strlen = str.len +strlower = str.lower +strrep = str.rep +strsub = str.sub +strupper = str.upper + +------------------------------------------------------------------- +-- os library +clock = os.clock +date = os.date +difftime = os.difftime +execute = os.execute --? +exit = os.exit +getenv = os.getenv +remove = os.remove +rename = os.rename +setlocale = os.setlocale +time = os.time +tmpname = os.tmpname + +------------------------------------------------------------------- +-- compatibility only +getglobal = function (n) return _G[n] end +setglobal = function (n,v) _G[n] = v end + +------------------------------------------------------------------- + +local io, tab = io, table + +-- IO library (files) +_STDIN = io.stdin +_STDERR = io.stderr +_STDOUT = io.stdout +_INPUT = io.stdin +_OUTPUT = io.stdout +seek = io.stdin.seek -- sick ;-) +tmpfile = io.tmpfile +closefile = io.close +openfile = io.open + +function flush (f) + if f then f:flush() + else _OUTPUT:flush() + end +end + +function readfrom (name) + if name == nil then + local f, err, cod = io.close(_INPUT) + _INPUT = io.stdin + return f, err, cod + else + local f, err, cod = io.open(name, "r") + _INPUT = f or _INPUT + return f, err, cod + end +end + +function writeto (name) + if name == nil then + local f, err, cod = io.close(_OUTPUT) + _OUTPUT = io.stdout + return f, err, cod + else + local f, err, cod = io.open(name, "w") + _OUTPUT = f or _OUTPUT + return f, err, cod + end +end + +function appendto (name) + local f, err, cod = io.open(name, "a") + _OUTPUT = f or _OUTPUT + return f, err, cod +end + +function read (...) + local f = _INPUT + if type(arg[1]) == 'userdata' then + f = tab.remove(arg, 1) + end + return f:read(unpack(arg)) +end + +function write (...) + local f = _OUTPUT + if type(arg[1]) == 'userdata' then + f = tab.remove(arg, 1) + end + return f:write(unpack(arg)) +end + diff --git a/etc/def.lua b/etc/def.lua deleted file mode 100644 index 736e32cdcd..0000000000 --- a/etc/def.lua +++ /dev/null @@ -1,9 +0,0 @@ --- def.lua --- make .DEF file from lua.h --- usage: lua def.lua lua.def - -T=read"*a" -write("LIBRARY LUA\nVERSION ") -gsub(T,"LUA_VERSION.-(%d+%.%d+)",write) -write("\nEXPORTS\n") -gsub(T,"(lua_%w+)%s+%(",function (f) write(" ",f,"\n") end) diff --git a/etc/doall.lua b/etc/doall.lua new file mode 100644 index 0000000000..fb0fad702f --- /dev/null +++ b/etc/doall.lua @@ -0,0 +1,6 @@ +-- emulate the command line behaviour of Lua 4.0 +-- usage: lua doall.lua f1.lua f2.lua f3.lua ... + +for i=1,table.getn(arg) do + dofile(arg[i]) +end diff --git a/etc/lua.magic b/etc/lua.magic index eb78f8d0db..c7ae595573 100644 --- a/etc/lua.magic +++ b/etc/lua.magic @@ -1,10 +1,12 @@ -# Lua precompiled files +# Lua precompiled files. Versions 2.3 and 4.1 were never officially released. 0 string \33Lua precompiled chunk for Lua ->4 byte 0x23 2.3 +>4 byte 0x23 2.3* >4 byte 0x24 2.4 >4 byte 0x25 2.5 >4 byte 0x30 3.0 >4 byte 0x31 3.1 >4 byte 0x32 3.2 >4 byte 0x40 4.0 +>4 byte 0x41 4.1* +>4 byte 0x50 5.0 diff --git a/etc/luser_number.h b/etc/luser_number.h new file mode 100644 index 0000000000..8cc2678e50 --- /dev/null +++ b/etc/luser_number.h @@ -0,0 +1,34 @@ +/* luser_number.h -- number type configuration for Lua core +* +* #define LUA_USER_H to this file and #define one of USE_* below +*/ + +#ifdef USE_DOUBLE +#define LUA_NUMBER double +#define LUA_NUMBER_SCAN "%lf" +#define LUA_NUMBER_FMT "%.14g" +#endif + +#ifdef USE_FLOAT +#define LUA_NUMBER float +#define LUA_NUMBER_SCAN "%f" +#define LUA_NUMBER_FMT "%.5g" +#endif + +#ifdef USE_LONG +#define LUA_NUMBER long +#define LUA_NUMBER_SCAN "%ld" +#define LUA_NUMBER_FMT "%ld" +#define lua_str2number(s,p) strtol((s), (p), 10) +#endif + +#ifdef USE_INT +#define LUA_NUMBER int +#define LUA_NUMBER_SCAN "%d" +#define LUA_NUMBER_FMT "%d" +#define lua_str2number(s,p) ((int) strtol((s), (p), 10)) +#endif + +#ifdef USE_FASTROUND +#define lua_number2int(i,d) __asm__("fldl %1\nfistpl %0":"=m"(i):"m"(d)) +#endif diff --git a/etc/luser_tests.h b/etc/luser_tests.h new file mode 100644 index 0000000000..1ee6e3fd81 --- /dev/null +++ b/etc/luser_tests.h @@ -0,0 +1,68 @@ +/* +** $Id: ltests.h,v 1.20 2002/12/04 17:29:05 roberto Exp $ +** Internal Header for Debugging of the Lua Implementation +** See Copyright Notice in lua.h +*/ + +#ifndef ltests_h +#define ltests_h + + +#include + + +#define LUA_DEBUG + +#define LUA_OPNAMES + +#undef NDEBUG +#include +#define lua_assert(c) assert(c) +#define check_exp(c,e) (lua_assert(c), (e)) +#define api_check(L, o) lua_assert(o) + + +/* to avoid warnings, and to make sure value is really unused */ +#define UNUSED(x) (x=0, (void)(x)) + + +/* memory allocator control variables */ +extern unsigned long memdebug_numblocks; +extern unsigned long memdebug_total; +extern unsigned long memdebug_maxmem; +extern unsigned long memdebug_memlimit; + + +#define l_realloc(b, os, s) debug_realloc(b, os, s) +#define l_free(b, os) debug_realloc(b, os, 0) + +void *debug_realloc (void *block, size_t oldsize, size_t size); + + + +/* test for lock/unlock */ +extern int islocked; +#define LUA_USERSTATE int * +#define getlock(l) (*(cast(LUA_USERSTATE *, l) - 1)) +#define lua_userstateopen(l) if (l != NULL) getlock(l) = &islocked; +#define lua_lock(l) lua_assert((*getlock(l))++ == 0) +#define lua_unlock(l) lua_assert(--(*getlock(l)) == 0) + + +int luaB_opentests (lua_State *L); + +#define LUA_EXTRALIBS { "tests", luaB_opentests }, + + +/* real main will be defined at `ltests.c' */ +int l_main (int argc, char *argv[]); +#define main l_main + + + +/* change some sizes to give some bugs a chance */ + +#define LUAL_BUFFERSIZE 27 +#define MINSTRTABSIZE 2 + +#endif diff --git a/etc/min.c b/etc/min.c index 0579ed3f61..45731c9d5a 100644 --- a/etc/min.c +++ b/etc/min.c @@ -1,13 +1,12 @@ /* -* min.c -* a minimal Lua interpreter. loads stdin only. -* no standard library, only a "print" function. +* min.c -- a minimal Lua interpreter +* loads stdin only with minimal error handling. +* no interaction, and no standard library, only a "print" function. */ #include #include "lua.h" -/* a simple "print". based on the code in lbaselib.c */ static int print(lua_State *L) { int n=lua_gettop(L); @@ -17,6 +16,10 @@ static int print(lua_State *L) if (i>1) printf("\t"); if (lua_isstring(L,i)) printf("%s",lua_tostring(L,i)); + else if (lua_isnil(L,i)) + printf("%s","nil"); + else if (lua_isboolean(L,i)) + printf("%s",lua_toboolean(L,i) ? "true" : "false"); else printf("%s:%p",lua_typename(L,lua_type(L,i)),lua_topointer(L,i)); } @@ -24,9 +27,20 @@ static int print(lua_State *L) return 0; } +static const char *getF(lua_State *L, void *ud, size_t *size) +{ + FILE *f=(FILE *)ud; + static char buff[512]; + if (feof(f)) return NULL; + *size=fread(buff,1,sizeof(buff),f); + return (*size>0) ? buff : NULL; +} + int main(void) { - lua_State *L=lua_open(0); + lua_State *L=lua_open(); lua_register(L,"print",print); - return lua_dofile(L,NULL); + if (lua_load(L,getF,stdin,"=stdin") || lua_pcall(L,0,0,0)) + fprintf(stderr,"%s\n",lua_tostring(L,-1)); + return 0; } diff --git a/etc/noparser.c b/etc/noparser.c new file mode 100644 index 0000000000..00c2b12625 --- /dev/null +++ b/etc/noparser.c @@ -0,0 +1,26 @@ +/* +* The code below can be used to make a Lua core that does not contain the +* parsing modules (lcode, llex, lparser), which represent 35% of the total core. +* You'll only be able to load binary files and strings, precompiled with luac. +* (Of course, you'll have to build luac with the original parsing modules!) +* +* To use this module, simply compile it ("make noparser" does that) and +* list its object file before the Lua libraries. The linker should then not +* load the parsing modules. To try it, do "make luab". +*/ + +#include "llex.h" +#include "lparser.h" +#include "lzio.h" + +void luaX_init (lua_State *L) { + UNUSED(L); +} + +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { + UNUSED(z); + UNUSED(buff); + lua_pushstring(L,"parser not loaded"); + lua_error(L); + return NULL; +} diff --git a/etc/saconfig.c b/etc/saconfig.c new file mode 100644 index 0000000000..bf3c64b701 --- /dev/null +++ b/etc/saconfig.c @@ -0,0 +1,87 @@ +/* sa-config.c -- configuration for stand-alone Lua interpreter +* +* #define LUA_USERCONFIG to this file +* +* Here are the features that can be customized using #define: +* +*** Line edit and history: +* #define USE_READLINE to use the GNU readline library. +* +* To use another library for this, use the code below as a start. +* Make sure you #define lua_readline and lua_saveline accordingly. +* If you do not #define lua_readline, you'll get a version based on fgets +* that uses a static buffer of size MAXINPUT. +* +* +*** Static Lua libraries to be loaded at startup: +* #define lua_userinit(L) to a Lua function that loads libraries; typically +* #define lua_userinit(L) openstdlibs(L);myinit(L) +* or +* #define lua_userinit(L) myinit(L) +* +* Another way is to add the prototypes of the init functions here and +* #define LUA_EXTRALIBS accordingly. For example, +* #define LUA_EXTRALIBS {"mylib","luaopen_mylib"}, +* Note the ending comma! +* +* +*** Prompts: +* The stand-alone Lua interpreter uses two prompts: PROMPT and PROMPT2. +* PROMPT is the primary prompt, shown when the intepreter is ready to receive +* a new statement. PROMPT2 is the secondary prompt, shown while a statement +* is being entered but is still incomplete. +* +* +*** Program name: +* Error messages usually show argv[0] as a program name. In systems that do +* not give a valid string as argv[0], error messages show PROGNAME instead. +* +* +*/ + +#ifdef USE_READLINE +/* +* This section implements of lua_readline and lua_saveline for lua.c using +* the GNU readline and history libraries. It should also work with drop-in +* replacements such as editline and libedit (you may have to include +* different headers, though). +* +*/ + +#define lua_readline myreadline +#define lua_saveline mysaveline + +#include +#include +#include + +static int myreadline (lua_State *L, const char *prompt) { + char *s=readline(prompt); + if (s==NULL) + return 0; + else { + lua_pushstring(L,s); + lua_pushliteral(L,"\n"); + lua_concat(L,2); + free(s); + return 1; + } +} + +static void mysaveline (lua_State *L, const char *s) { + const char *p; + for (p=s; isspace(*p); p++) + ; + if (*p!=0) { + size_t n=strlen(s)-1; + if (s[n]!='\n') + add_history(s); + else { + lua_pushlstring(L,s,n); + s=lua_tostring(L,-1); + add_history(s); + lua_remove(L,-1); + } + } +} +#endif diff --git a/etc/setfallback.lua b/etc/setfallback.lua deleted file mode 100644 index 783b8667d7..0000000000 --- a/etc/setfallback.lua +++ /dev/null @@ -1,55 +0,0 @@ --------------------------------------------------------------- --- Definition of "setfallback" using tag methods --- (for compatibility with old code) --------------------------------------------------------------- - - --- default fallbacks for each event: -local defaults = { - gettable = function () error('indexed expression not a table') end, - settable = function () error('indexed expression not a table') end, - index = function () return nil end, - getglobal = function () return nil end, - arith = function () error('number expected in arithmetic operation') end, - order = function () error('incompatible types in comparison') end, - concat = function () error('string expected in concatenation') end, - gc = function () return nil end, - ['function'] = function () error('called expression not a function') end, - error = function (s) write(_STDERR, s, '\n') end, -} - - -function setfallback (name, func) - - -- set the given function as the tag method for all "standard" tags - -- (since some combinations may cause errors, use call to avoid messages) - local fillvalids = function (n, func) - call(settagmethod, {0, n, func}, 'x', nil) - call(settagmethod, {tag(0), n, func}, 'x', nil) - call(settagmethod, {tag(''), n, func}, 'x', nil) - call(settagmethod, {tag{}, n, func}, 'x', nil) - call(settagmethod, {tag(function () end), n, func}, 'x', nil) - call(settagmethod, {tag(settagmethod), n, func}, 'x', nil) - call(settagmethod, {tag(nil), n, func}, 'x', nil) - end - - assert(type(func) == 'function') - local oldfunc - if name == 'error' then - oldfunc = seterrormethod(func) - elseif name == 'getglobal' then - oldfunc = settagmethod(tag(nil), 'getglobal', func) - elseif name == 'arith' then - oldfunc = gettagmethod(tag(0), 'pow') - foreach({"add", "sub", "mul", "div", "unm", "pow"}, - function(_, n) %fillvalids(n, %func) end) - elseif name == 'order' then - oldfunc = gettagmethod(tag(nil), 'lt') - foreach({"lt", "gt", "le", "ge"}, - function(_, n) %fillvalids(n, %func) end) - else - oldfunc = gettagmethod(tag(nil), name) - fillvalids(name, func) - end - return oldfunc or rawgettable(%defaults, name) -end diff --git a/etc/stdcall.lua b/etc/stdcall.lua deleted file mode 100644 index 7eac5c2ec0..0000000000 --- a/etc/stdcall.lua +++ /dev/null @@ -1,10 +0,0 @@ --- stdcall.lua --- add __stdcall where appropriate --- usage: lua stdcall.lua s_lua.h --- usage: lua stdcall.lua s_lapi.c - -T=read"*a" -T=gsub(T,"(lua_%w+%s+%()","__stdcall %1") -T=gsub(T,"(%*lua_CFunction)","__stdcall %1") - -write(T) diff --git a/etc/trace.c b/etc/trace.c index 7c0b86ed9a..c29f1c9d17 100644 --- a/etc/trace.c +++ b/etc/trace.c @@ -1,56 +1,55 @@ /* -* trace.c -* a simple execution tracer for Lua +* trace.c -- a simple execution tracer for Lua */ #include #include #include "lua.h" #include "lualib.h" -#include "luadebug.h" +#include "lauxlib.h" -lua_State *lua_state = NULL; -#define L lua_state /* lazy! */ - -static FILE* LOG; /* output file */ +static FILE* LOG; /* log file */ static int I=0; /* indentation level */ -static void linehook(lua_State *L, lua_Debug *ar) -{ - fprintf(LOG,"%*sdo_line(%d)\t-- %d\n",I,"",ar->currentline,I); -} - -static void callhook(lua_State *L, lua_Debug *ar) +static void hook(lua_State *L, lua_Debug *ar) { - fprintf(LOG,"%*sdo_%s\t-- %p %d\n",I,"",ar->event,ar->_func,I); - if (*ar->event=='r') --I; else ++I; + const char* s=""; + switch (ar->event) + { + case LUA_HOOKTAILRET: ar->event=LUA_HOOKRET; + case LUA_HOOKRET: s="return"; break; + case LUA_HOOKCALL: s="call"; break; + case LUA_HOOKLINE: s="line"; break; + default: break; + } + fprintf(LOG,"[%d]\t%*s%s\t-- %d\n",I,I,"",s,ar->currentline); + if (ar->event==LUA_HOOKCALL) ++I; else if (ar->event==LUA_HOOKRET) --I; } -void start_trace(FILE* logfile) +static void start_trace(lua_State *L, FILE* logfile) { - lua_setlinehook(L,linehook); - lua_setcallhook(L,callhook); + lua_sethook(L,hook,LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 0); LOG=logfile; } -void stop_trace(void) +static void stop_trace(lua_State *L) { - lua_setlinehook(L,NULL); - lua_setcallhook(L,NULL); + lua_sethook(L,NULL,0,0); fclose(LOG); } int main(void) { int rc; - L=lua_open(0); + lua_State *L=lua_open(); lua_baselibopen(L); + lua_tablibopen(L); lua_iolibopen(L); lua_strlibopen(L); lua_mathlibopen(L); lua_dblibopen(L); - start_trace(stderr); - rc=lua_dofile(L,0); - stop_trace(); + start_trace(L,stderr); + rc=lua_dofile(L,NULL); + stop_trace(L); return rc; } diff --git a/include/Makefile b/include/Makefile index 0a2dfd95b7..d75997d9f0 100644 --- a/include/Makefile +++ b/include/Makefile @@ -4,7 +4,7 @@ LUA= .. include $(LUA)/config -SRCS= lua.h lualib.h luadebug.h lauxlib.h +SRCS= lua.h lualib.h lauxlib.h all: diff --git a/include/lauxlib.h b/include/lauxlib.h index 9df0c8e8b4..450e16c720 100644 --- a/include/lauxlib.h +++ b/include/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.30 2000/10/30 12:38:50 roberto Exp $ +** $Id: lauxlib.h,v 1.60 2003/04/03 13:35:34 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -16,29 +16,51 @@ #ifndef LUALIB_API -#define LUALIB_API extern +#define LUALIB_API LUA_API #endif -struct luaL_reg { + +typedef struct luaL_reg { const char *name; lua_CFunction func; -}; +} luaL_reg; + + +LUALIB_API void luaL_openlib (lua_State *L, const char *libname, + const luaL_reg *l, int nup); +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *e); +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *e); +LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname); +LUALIB_API int luaL_argerror (lua_State *L, int numarg, const char *extramsg); +LUALIB_API const char *luaL_checklstring (lua_State *L, int numArg, size_t *l); +LUALIB_API const char *luaL_optlstring (lua_State *L, int numArg, + const char *def, size_t *l); +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int numArg); +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number def); + +LUALIB_API void luaL_checkstack (lua_State *L, int sz, const char *msg); +LUALIB_API void luaL_checktype (lua_State *L, int narg, int t); +LUALIB_API void luaL_checkany (lua_State *L, int narg); +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname); +LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname); +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname); -LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n); -LUALIB_API void luaL_argerror (lua_State *L, int numarg, const char *extramsg); -LUALIB_API const char *luaL_check_lstr (lua_State *L, int numArg, size_t *len); -LUALIB_API const char *luaL_opt_lstr (lua_State *L, int numArg, const char *def, size_t *len); -LUALIB_API double luaL_check_number (lua_State *L, int numArg); -LUALIB_API double luaL_opt_number (lua_State *L, int numArg, double def); +LUALIB_API void luaL_where (lua_State *L, int lvl); +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...); -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg); -LUALIB_API void luaL_checktype (lua_State *L, int narg, int t); -LUALIB_API void luaL_checkany (lua_State *L, int narg); +LUALIB_API int luaL_findstring (const char *st, const char *const lst[]); + +LUALIB_API int luaL_ref (lua_State *L, int t); +LUALIB_API void luaL_unref (lua_State *L, int t, int ref); + +LUALIB_API int luaL_getn (lua_State *L, int t); +LUALIB_API void luaL_setn (lua_State *L, int t, int n); -LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...); -LUALIB_API int luaL_findstring (const char *name, const char *const list[]); +LUALIB_API int luaL_loadfile (lua_State *L, const char *filename); +LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, + const char *name); @@ -48,15 +70,14 @@ LUALIB_API int luaL_findstring (const char *name, const char *const list[]); ** =============================================================== */ -#define luaL_arg_check(L, cond,numarg,extramsg) if (!(cond)) \ +#define luaL_argcheck(L, cond,numarg,extramsg) if (!(cond)) \ luaL_argerror(L, numarg,extramsg) -#define luaL_check_string(L,n) (luaL_check_lstr(L, (n), NULL)) -#define luaL_opt_string(L,n,d) (luaL_opt_lstr(L, (n), (d), NULL)) -#define luaL_check_int(L,n) ((int)luaL_check_number(L, n)) -#define luaL_check_long(L,n) ((long)luaL_check_number(L, n)) -#define luaL_opt_int(L,n,d) ((int)luaL_opt_number(L, n,d)) -#define luaL_opt_long(L,n,d) ((long)luaL_opt_number(L, n,d)) -#define luaL_openl(L,a) luaL_openlib(L, a, (sizeof(a)/sizeof(a[0]))) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) +#define luaL_checkint(L,n) ((int)luaL_checknumber(L, n)) +#define luaL_checklong(L,n) ((long)luaL_checknumber(L, n)) +#define luaL_optint(L,n,d) ((int)luaL_optnumber(L, n,(lua_Number)(d))) +#define luaL_optlong(L,n,d) ((long)luaL_optnumber(L, n,(lua_Number)(d))) /* @@ -73,13 +94,13 @@ LUALIB_API int luaL_findstring (const char *name, const char *const list[]); typedef struct luaL_Buffer { char *p; /* current position in buffer */ - int level; + int lvl; /* number of strings in the stack (level) */ lua_State *L; char buffer[LUAL_BUFFERSIZE]; } luaL_Buffer; #define luaL_putchar(B,c) \ - ((void)((B)->p < &(B)->buffer[LUAL_BUFFERSIZE] || luaL_prepbuffer(B)), \ + ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ (*(B)->p++ = (char)(c))) #define luaL_addsize(B,n) ((B)->p += (n)) @@ -95,6 +116,30 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B); /* }====================================================== */ + +/* +** Compatibility macros and functions +*/ + +LUALIB_API int lua_dofile (lua_State *L, const char *filename); +LUALIB_API int lua_dostring (lua_State *L, const char *str); +LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t sz, + const char *n); + + +#define luaL_check_lstr luaL_checklstring +#define luaL_opt_lstr luaL_optlstring +#define luaL_check_number luaL_checknumber +#define luaL_opt_number luaL_optnumber +#define luaL_arg_check luaL_argcheck +#define luaL_check_string luaL_checkstring +#define luaL_opt_string luaL_optstring +#define luaL_check_int luaL_checkint +#define luaL_check_long luaL_checklong +#define luaL_opt_int luaL_optint +#define luaL_opt_long luaL_optlong + + #endif diff --git a/include/lua.h b/include/lua.h index 660ecd80a1..0d827b10c7 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,9 +1,8 @@ /* -** $Id: lua.h,v 1.79a 2000/10/31 12:44:07 roberto Exp $ +** $Id: lua.h,v 1.175 2003/03/18 12:31:39 roberto Exp $ ** Lua - An Extensible Extension Language -** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil -** e-mail: lua@tecgraf.puc-rio.br -** www: http://www.tecgraf.puc-rio.br/lua/ +** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil +** http://www.lua.org mailto:info@lua.org ** See Copyright Notice at the end of this file */ @@ -11,45 +10,29 @@ #ifndef lua_h #define lua_h - -/* definition of `size_t' */ +#include #include -/* mark for all API functions */ -#ifndef LUA_API -#define LUA_API extern -#endif - - -#define LUA_VERSION "Lua 4.0.1" -#define LUA_COPYRIGHT "Copyright (C) 1994-2000 TeCGraf, PUC-Rio" -#define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" +#define LUA_VERSION "Lua 5.0" +#define LUA_COPYRIGHT "Copyright (C) 1994-2003 Tecgraf, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" -/* name of global variable with error handler */ -#define LUA_ERRORMESSAGE "_ERRORMESSAGE" - - -/* pre-defined references */ -#define LUA_NOREF (-2) -#define LUA_REFNIL (-1) -#define LUA_REFREGISTRY 0 - -/* pre-defined tags */ -#define LUA_ANYTAG (-1) -#define LUA_NOTAG (-2) - -/* option for multiple returns in lua_call */ +/* option for multiple returns in `lua_pcall' and `lua_call' */ #define LUA_MULTRET (-1) -/* minimum stack available for a C function */ -#define LUA_MINSTACK 20 +/* +** pseudo-indices +*/ +#define LUA_REGISTRYINDEX (-10000) +#define LUA_GLOBALSINDEX (-10001) +#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) -/* error codes for lua_do* */ +/* error codes for `lua_load' and `lua_pcall' */ #define LUA_ERRRUN 1 #define LUA_ERRFILE 2 #define LUA_ERRSYNTAX 3 @@ -61,107 +44,164 @@ typedef struct lua_State lua_State; typedef int (*lua_CFunction) (lua_State *L); + +/* +** functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Chunkreader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Chunkwriter) (lua_State *L, const void* p, + size_t sz, void* ud); + + /* -** types returned by `lua_type' +** basic types */ #define LUA_TNONE (-1) -#define LUA_TUSERDATA 0 -#define LUA_TNIL 1 -#define LUA_TNUMBER 2 -#define LUA_TSTRING 3 -#define LUA_TTABLE 4 -#define LUA_TFUNCTION 5 +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 +/* +** generic extra include file +*/ +#ifdef LUA_USER_H +#include LUA_USER_H +#endif + + +/* type of numbers in Lua */ +#ifndef LUA_NUMBER +typedef double lua_Number; +#else +typedef LUA_NUMBER lua_Number; +#endif + + +/* mark for all API functions */ +#ifndef LUA_API +#define LUA_API extern +#endif + /* ** state manipulation */ -LUA_API lua_State *lua_open (int stacksize); +LUA_API lua_State *lua_open (void); LUA_API void lua_close (lua_State *L); +LUA_API lua_State *lua_newthread (lua_State *L); + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf); /* ** basic stack manipulation */ LUA_API int lua_gettop (lua_State *L); -LUA_API void lua_settop (lua_State *L, int index); -LUA_API void lua_pushvalue (lua_State *L, int index); -LUA_API void lua_remove (lua_State *L, int index); -LUA_API void lua_insert (lua_State *L, int index); -LUA_API int lua_stackspace (lua_State *L); +LUA_API void lua_settop (lua_State *L, int idx); +LUA_API void lua_pushvalue (lua_State *L, int idx); +LUA_API void lua_remove (lua_State *L, int idx); +LUA_API void lua_insert (lua_State *L, int idx); +LUA_API void lua_replace (lua_State *L, int idx); +LUA_API int lua_checkstack (lua_State *L, int sz); + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n); /* ** access functions (stack -> C) */ -LUA_API int lua_type (lua_State *L, int index); -LUA_API const char *lua_typename (lua_State *L, int t); -LUA_API int lua_isnumber (lua_State *L, int index); -LUA_API int lua_isstring (lua_State *L, int index); -LUA_API int lua_iscfunction (lua_State *L, int index); -LUA_API int lua_tag (lua_State *L, int index); +LUA_API int lua_isnumber (lua_State *L, int idx); +LUA_API int lua_isstring (lua_State *L, int idx); +LUA_API int lua_iscfunction (lua_State *L, int idx); +LUA_API int lua_isuserdata (lua_State *L, int idx); +LUA_API int lua_type (lua_State *L, int idx); +LUA_API const char *lua_typename (lua_State *L, int tp); -LUA_API int lua_equal (lua_State *L, int index1, int index2); -LUA_API int lua_lessthan (lua_State *L, int index1, int index2); +LUA_API int lua_equal (lua_State *L, int idx1, int idx2); +LUA_API int lua_rawequal (lua_State *L, int idx1, int idx2); +LUA_API int lua_lessthan (lua_State *L, int idx1, int idx2); -LUA_API double lua_tonumber (lua_State *L, int index); -LUA_API const char *lua_tostring (lua_State *L, int index); -LUA_API size_t lua_strlen (lua_State *L, int index); -LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index); -LUA_API void *lua_touserdata (lua_State *L, int index); -LUA_API const void *lua_topointer (lua_State *L, int index); +LUA_API lua_Number lua_tonumber (lua_State *L, int idx); +LUA_API int lua_toboolean (lua_State *L, int idx); +LUA_API const char *lua_tostring (lua_State *L, int idx); +LUA_API size_t lua_strlen (lua_State *L, int idx); +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx); +LUA_API void *lua_touserdata (lua_State *L, int idx); +LUA_API lua_State *lua_tothread (lua_State *L, int idx); +LUA_API const void *lua_topointer (lua_State *L, int idx); /* ** push functions (C -> stack) */ LUA_API void lua_pushnil (lua_State *L); -LUA_API void lua_pushnumber (lua_State *L, double n); -LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len); +LUA_API void lua_pushnumber (lua_State *L, lua_Number n); +LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t l); LUA_API void lua_pushstring (lua_State *L, const char *s); +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...); LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); -LUA_API void lua_pushusertag (lua_State *L, void *u, int tag); +LUA_API void lua_pushboolean (lua_State *L, int b); +LUA_API void lua_pushlightuserdata (lua_State *L, void *p); /* ** get functions (Lua -> stack) */ -LUA_API void lua_getglobal (lua_State *L, const char *name); -LUA_API void lua_gettable (lua_State *L, int index); -LUA_API void lua_rawget (lua_State *L, int index); -LUA_API void lua_rawgeti (lua_State *L, int index, int n); -LUA_API void lua_getglobals (lua_State *L); -LUA_API void lua_gettagmethod (lua_State *L, int tag, const char *event); -LUA_API int lua_getref (lua_State *L, int ref); +LUA_API void lua_gettable (lua_State *L, int idx); +LUA_API void lua_rawget (lua_State *L, int idx); +LUA_API void lua_rawgeti (lua_State *L, int idx, int n); LUA_API void lua_newtable (lua_State *L); +LUA_API void *lua_newuserdata (lua_State *L, size_t sz); +LUA_API int lua_getmetatable (lua_State *L, int objindex); +LUA_API void lua_getfenv (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ -LUA_API void lua_setglobal (lua_State *L, const char *name); -LUA_API void lua_settable (lua_State *L, int index); -LUA_API void lua_rawset (lua_State *L, int index); -LUA_API void lua_rawseti (lua_State *L, int index, int n); -LUA_API void lua_setglobals (lua_State *L); -LUA_API void lua_settagmethod (lua_State *L, int tag, const char *event); -LUA_API int lua_ref (lua_State *L, int lock); +LUA_API void lua_settable (lua_State *L, int idx); +LUA_API void lua_rawset (lua_State *L, int idx); +LUA_API void lua_rawseti (lua_State *L, int idx, int n); +LUA_API int lua_setmetatable (lua_State *L, int objindex); +LUA_API int lua_setfenv (lua_State *L, int idx); + + +/* +** `load' and `call' functions (load and run Lua code) +*/ +LUA_API void lua_call (lua_State *L, int nargs, int nresults); +LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc); +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud); +LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *dt, + const char *chunkname); + +LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data); /* -** "do" functions (run Lua code) +** coroutine functions */ -LUA_API int lua_call (lua_State *L, int nargs, int nresults); -LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults); -LUA_API int lua_dofile (lua_State *L, const char *filename); -LUA_API int lua_dostring (lua_State *L, const char *str); -LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name); +LUA_API int lua_yield (lua_State *L, int nresults); +LUA_API int lua_resume (lua_State *L, int narg); /* -** Garbage-collection functions +** garbage-collection functions */ LUA_API int lua_getgcthreshold (lua_State *L); LUA_API int lua_getgccount (lua_State *L); @@ -170,20 +210,15 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold); /* ** miscellaneous functions */ -LUA_API int lua_newtag (lua_State *L); -LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom); -LUA_API void lua_settag (lua_State *L, int tag); -LUA_API void lua_error (lua_State *L, const char *s); +LUA_API const char *lua_version (void); -LUA_API void lua_unref (lua_State *L, int ref); +LUA_API int lua_error (lua_State *L); -LUA_API int lua_next (lua_State *L, int index); -LUA_API int lua_getn (lua_State *L, int index); +LUA_API int lua_next (lua_State *L, int idx); LUA_API void lua_concat (lua_State *L, int n); -LUA_API void *lua_newuserdata (lua_State *L, size_t size); /* @@ -192,57 +227,165 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size); ** =============================================================== */ +#define lua_boxpointer(L,u) \ + (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u)) + +#define lua_unboxpointer(L,i) (*(void **)(lua_touserdata(L, i))) + #define lua_pop(L,n) lua_settop(L, -(n)-1) -#define lua_register(L,n,f) (lua_pushcfunction(L, f), lua_setglobal(L, n)) -#define lua_pushuserdata(L,u) lua_pushusertag(L, u, 0) +#define lua_register(L,n,f) \ + (lua_pushstring(L, n), \ + lua_pushcfunction(L, f), \ + lua_settable(L, LUA_GLOBALSINDEX)) + #define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) -#define lua_clonetag(L,t) lua_copytagmethods(L, lua_newtag(L), (t)) #define lua_isfunction(L,n) (lua_type(L,n) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L,n) == LUA_TTABLE) -#define lua_isuserdata(L,n) (lua_type(L,n) == LUA_TUSERDATA) +#define lua_islightuserdata(L,n) (lua_type(L,n) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L,n) == LUA_TNIL) -#define lua_isnull(L,n) (lua_type(L,n) == LUA_TNONE) +#define lua_isboolean(L,n) (lua_type(L,n) == LUA_TBOOLEAN) +#define lua_isnone(L,n) (lua_type(L,n) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L,n) <= 0) + +#define lua_pushliteral(L, s) \ + lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) -#define lua_getregistry(L) lua_getref(L, LUA_REFREGISTRY) + +/* +** compatibility macros and functions +*/ + + +LUA_API int lua_pushupvalues (lua_State *L); + +#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) +#define lua_setglobal(L,s) \ + (lua_pushstring(L, s), lua_insert(L, -2), lua_settable(L, LUA_GLOBALSINDEX)) + +#define lua_getglobal(L,s) \ + (lua_pushstring(L, s), lua_gettable(L, LUA_GLOBALSINDEX)) + + +/* compatibility with ref system */ + +/* pre-defined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ + (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) + +#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) + +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, ref) + + + +/* +** {====================================================================== +** useful definitions for Lua kernel and libraries +** ======================================================================= +*/ + +/* formats for Lua numbers */ +#ifndef LUA_NUMBER_SCAN +#define LUA_NUMBER_SCAN "%lf" #endif +#ifndef LUA_NUMBER_FMT +#define LUA_NUMBER_FMT "%.14g" +#endif + +/* }====================================================================== */ + + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILRET 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); + +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook lua_gethook (lua_State *L); +LUA_API int lua_gethookmask (lua_State *L); +LUA_API int lua_gethookcount (lua_State *L); + + +#define LUA_IDSIZE 60 + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) `global', `local', `field', `method' */ + const char *what; /* (S) `Lua', `C', `main', `tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int nups; /* (u) number of upvalues */ + int linedefined; /* (S) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + int i_ci; /* active function */ +}; + +/* }====================================================================== */ /****************************************************************************** -* Copyright (C) 1994-2000 TeCGraf, PUC-Rio. All rights reserved. -* -* Permission is hereby granted, without written agreement and without license -* or royalty fees, to use, copy, modify, and distribute this software and its -* documentation for any purpose, including commercial applications, subject to +* Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to * the following conditions: -* -* - The above copyright notice and this permission notice shall appear in all -* copies or substantial portions of this software. -* -* - The origin of this software must not be misrepresented; you must not -* claim that you wrote the original software. If you use this software in a -* product, an acknowledgment in the product documentation would be greatly -* appreciated (but it is not required). -* -* - Altered source versions must be plainly marked as such, and must not be -* misrepresented as being the original software. -* -* The authors specifically disclaim any warranties, including, but not limited -* to, the implied warranties of merchantability and fitness for a particular -* purpose. The software provided hereunder is on an "as is" basis, and the -* authors have no obligation to provide maintenance, support, updates, -* enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the -* authors be held liable to any party for direct, indirect, special, -* incidental, or consequential damages arising out of the use of this software -* and its documentation. -* -* The Lua language and this implementation have been entirely designed and -* written by Waldemar Celes Filho, Roberto Ierusalimschy and -* Luiz Henrique de Figueiredo at TeCGraf, PUC-Rio. * -* This implementation contains no third-party code. +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ + +#endif diff --git a/include/luadebug.h b/include/luadebug.h deleted file mode 100644 index 77753d3712..0000000000 --- a/include/luadebug.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -** $Id: luadebug.h,v 1.17 2000/10/30 12:38:50 roberto Exp $ -** Debugging API -** See Copyright Notice in lua.h -*/ - - -#ifndef luadebug_h -#define luadebug_h - - -#include "lua.h" - -typedef struct lua_Debug lua_Debug; /* activation record */ -typedef struct lua_Localvar lua_Localvar; - -typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); - - -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); - -LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func); -LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func); - - -#define LUA_IDSIZE 60 - -struct lua_Debug { - const char *event; /* `call', `return' */ - int currentline; /* (l) */ - const char *name; /* (n) */ - const char *namewhat; /* (n) `global', `tag method', `local', `field' */ - int nups; /* (u) number of upvalues */ - int linedefined; /* (S) */ - const char *what; /* (S) `Lua' function, `C' function, Lua `main' */ - const char *source; /* (S) */ - char short_src[LUA_IDSIZE]; /* (S) */ - /* private part */ - struct lua_TObject *_func; /* active function */ -}; - - -#endif diff --git a/include/lualib.h b/include/lualib.h index fe48cb1012..e22c4c3063 100644 --- a/include/lualib.h +++ b/include/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.14 2000/10/27 16:15:53 roberto Exp $ +** $Id: lualib.h,v 1.28 2003/03/18 12:24:26 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -12,23 +12,45 @@ #ifndef LUALIB_API -#define LUALIB_API extern +#define LUALIB_API LUA_API #endif -#define LUA_ALERT "_ALERT" +#define LUA_COLIBNAME "coroutine" +LUALIB_API int luaopen_base (lua_State *L); -LUALIB_API void lua_baselibopen (lua_State *L); -LUALIB_API void lua_iolibopen (lua_State *L); -LUALIB_API void lua_strlibopen (lua_State *L); -LUALIB_API void lua_mathlibopen (lua_State *L); -LUALIB_API void lua_dblibopen (lua_State *L); +#define LUA_TABLIBNAME "table" +LUALIB_API int luaopen_table (lua_State *L); +#define LUA_IOLIBNAME "io" +#define LUA_OSLIBNAME "os" +LUALIB_API int luaopen_io (lua_State *L); +#define LUA_STRLIBNAME "string" +LUALIB_API int luaopen_string (lua_State *L); -/* Auxiliary functions (private) */ +#define LUA_MATHLIBNAME "math" +LUALIB_API int luaopen_math (lua_State *L); -const char *luaI_classend (lua_State *L, const char *p); -int luaI_singlematch (int c, const char *p, const char *ep); +#define LUA_DBLIBNAME "debug" +LUALIB_API int luaopen_debug (lua_State *L); + + +LUALIB_API int luaopen_loadlib (lua_State *L); + + +/* to help testing the libraries */ +#ifndef lua_assert +#define lua_assert(c) /* empty */ +#endif + + +/* compatibility code */ +#define lua_baselibopen luaopen_base +#define lua_tablibopen luaopen_table +#define lua_iolibopen luaopen_io +#define lua_strlibopen luaopen_string +#define lua_mathlibopen luaopen_math +#define lua_dblibopen luaopen_debug #endif diff --git a/src/Makefile b/src/Makefile index 66e0ea8d9e..bf64c03f08 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,11 +9,13 @@ OBJS= \ lcode.o \ ldebug.o \ ldo.o \ + ldump.o \ lfunc.o \ lgc.o \ llex.o \ lmem.o \ lobject.o \ + lopcodes.o \ lparser.o \ lstate.o \ lstring.o \ @@ -29,11 +31,13 @@ SRCS= \ lcode.c \ ldebug.c \ ldo.c \ + ldump.c \ lfunc.c \ lgc.c \ llex.c \ lmem.c \ lobject.c \ + lopcodes.c \ lparser.c \ lstate.c \ lstring.c \ @@ -65,9 +69,9 @@ SRCS= \ T= $(LIB)/liblua.a -all: $T +all: $T -$T: $(OBJS) +$T: $(OBJS) $(AR) $@ $(OBJS) $(RANLIB) $@ diff --git a/src/README b/src/README new file mode 100644 index 0000000000..e5375981f6 --- /dev/null +++ b/src/README @@ -0,0 +1,5 @@ +This is the Lua core. + +The standard Lua library are in lib/. +A sample interpreter is in lua/. +A standalone compiler is in luac/. diff --git a/src/lapi.c b/src/lapi.c index 54c2cba411..d5dd9ca465 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,15 +1,19 @@ /* -** $Id: lapi.c,v 1.110a 2000/10/30 12:50:09 roberto Exp $ +** $Id: lapi.c,v 1.235 2003/04/07 14:36:08 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ +#include #include +#define lapi_c + #include "lua.h" #include "lapi.h" +#include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" @@ -19,43 +23,128 @@ #include "lstring.h" #include "ltable.h" #include "ltm.h" +#include "lundump.h" #include "lvm.h" -const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" - "$Authors: " LUA_AUTHORS " $"; +const char lua_ident[] = + "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" + "$Authors: " LUA_AUTHORS " $\n" + "$URL: www.lua.org $\n"; + +#ifndef api_check +#define api_check(L, o) /*{ assert(o); }*/ +#endif -#define Index(L,i) ((i) >= 0 ? (L->Cbase+((i)-1)) : (L->top+(i))) +#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) -#define api_incr_top(L) incr_top +#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} -TObject *luaA_index (lua_State *L, int index) { - return Index(L, index); +static TObject *negindex (lua_State *L, int idx) { + if (idx > LUA_REGISTRYINDEX) { + api_check(L, idx != 0 && -idx <= L->top - L->base); + return L->top+idx; + } + else switch (idx) { /* pseudo-indices */ + case LUA_REGISTRYINDEX: return registry(L); + case LUA_GLOBALSINDEX: return gt(L); + default: { + TObject *func = (L->base - 1); + idx = LUA_GLOBALSINDEX - idx; + lua_assert(iscfunction(func)); + return (idx <= clvalue(func)->c.nupvalues) + ? &clvalue(func)->c.upvalue[idx-1] + : NULL; + } + } +} + + +static TObject *luaA_index (lua_State *L, int idx) { + if (idx > 0) { + api_check(L, idx <= L->top - L->base); + return L->base + idx - 1; + } + else { + TObject *o = negindex(L, idx); + api_check(L, o != NULL); + return o; + } } -static TObject *luaA_indexAcceptable (lua_State *L, int index) { - if (index >= 0) { - TObject *o = L->Cbase+(index-1); +static TObject *luaA_indexAcceptable (lua_State *L, int idx) { + if (idx > 0) { + TObject *o = L->base+(idx-1); + api_check(L, idx <= L->stack_last - L->base); if (o >= L->top) return NULL; else return o; } - else return L->top+index; + else + return negindex(L, idx); } void luaA_pushobject (lua_State *L, const TObject *o) { - *L->top = *o; - incr_top; + setobj2s(L->top, o); + incr_top(L); +} + + +LUA_API int lua_checkstack (lua_State *L, int size) { + int res; + lua_lock(L); + if ((L->top - L->base + size) > LUA_MAXCSTACK) + res = 0; /* stack overflow */ + else { + luaD_checkstack(L, size); + if (L->ci->top < L->top + size) + L->ci->top = L->top + size; + res = 1; + } + lua_unlock(L); + return res; } -LUA_API int lua_stackspace (lua_State *L) { - return (L->stack_last - L->top); + +LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { + int i; + lua_lock(to); + api_checknelems(from, n); + from->top -= n; + for (i = 0; i < n; i++) { + setobj2s(to->top, from->top + i); + api_incr_top(to); + } + lua_unlock(to); +} + + +LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L)->panic; + G(L)->panic = panicf; + lua_unlock(L); + return old; +} + + +LUA_API lua_State *lua_newthread (lua_State *L) { + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + L1 = luaE_newthread(L); + setthvalue(L->top, L1); + api_incr_top(L); + lua_unlock(L); + lua_userstateopen(L1); + return L1; } @@ -66,37 +155,61 @@ LUA_API int lua_stackspace (lua_State *L) { LUA_API int lua_gettop (lua_State *L) { - return (L->top - L->Cbase); + return (L->top - L->base); } -LUA_API void lua_settop (lua_State *L, int index) { - if (index >= 0) - luaD_adjusttop(L, L->Cbase, index); - else - L->top = L->top+index+1; /* index is negative */ +LUA_API void lua_settop (lua_State *L, int idx) { + lua_lock(L); + if (idx >= 0) { + api_check(L, idx <= L->stack_last - L->base); + while (L->top < L->base + idx) + setnilvalue(L->top++); + L->top = L->base + idx; + } + else { + api_check(L, -(idx+1) <= (L->top - L->base)); + L->top += idx+1; /* `subtract' index (index is negative) */ + } + lua_unlock(L); } -LUA_API void lua_remove (lua_State *L, int index) { - StkId p = luaA_index(L, index); - while (++p < L->top) *(p-1) = *p; +LUA_API void lua_remove (lua_State *L, int idx) { + StkId p; + lua_lock(L); + p = luaA_index(L, idx); + while (++p < L->top) setobjs2s(p-1, p); L->top--; + lua_unlock(L); } -LUA_API void lua_insert (lua_State *L, int index) { - StkId p = luaA_index(L, index); +LUA_API void lua_insert (lua_State *L, int idx) { + StkId p; StkId q; - for (q = L->top; q>p; q--) - *q = *(q-1); - *p = *L->top; + lua_lock(L); + p = luaA_index(L, idx); + for (q = L->top; q>p; q--) setobjs2s(q, q-1); + setobjs2s(p, L->top); + lua_unlock(L); } -LUA_API void lua_pushvalue (lua_State *L, int index) { - *L->top = *luaA_index(L, index); +LUA_API void lua_replace (lua_State *L, int idx) { + lua_lock(L); + api_checknelems(L, 1); + setobj(luaA_index(L, idx), L->top - 1); /* write barrier */ + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_pushvalue (lua_State *L, int idx) { + lua_lock(L); + setobj2s(L->top, luaA_index(L, idx)); api_incr_top(L); + lua_unlock(L); } @@ -106,93 +219,167 @@ LUA_API void lua_pushvalue (lua_State *L, int index) { */ -LUA_API int lua_type (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); +LUA_API int lua_type (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); return (o == NULL) ? LUA_TNONE : ttype(o); } + LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); - return (t == LUA_TNONE) ? "no value" : luaO_typenames[t]; + return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; } -LUA_API int lua_iscfunction (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); +LUA_API int lua_iscfunction (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); return (o == NULL) ? 0 : iscfunction(o); } -LUA_API int lua_isnumber (lua_State *L, int index) { - TObject *o = luaA_indexAcceptable(L, index); - return (o == NULL) ? 0 : (tonumber(o) == 0); + +LUA_API int lua_isnumber (lua_State *L, int idx) { + TObject n; + const TObject *o = luaA_indexAcceptable(L, idx); + return (o != NULL && tonumber(o, &n)); } -LUA_API int lua_isstring (lua_State *L, int index) { - int t = lua_type(L, index); + +LUA_API int lua_isstring (lua_State *L, int idx) { + int t = lua_type(L, idx); return (t == LUA_TSTRING || t == LUA_TNUMBER); } -LUA_API int lua_tag (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); - return (o == NULL) ? LUA_NOTAG : luaT_tag(o); +LUA_API int lua_isuserdata (lua_State *L, int idx) { + const TObject *o = luaA_indexAcceptable(L, idx); + return (o != NULL && (ttisuserdata(o) || ttislightuserdata(o))); } -LUA_API int lua_equal (lua_State *L, int index1, int index2) { + +LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = luaA_indexAcceptable(L, index1); StkId o2 = luaA_indexAcceptable(L, index2); - if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */ - else return luaO_equalObj(o1, o2); + return (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ + : luaO_rawequalObj(o1, o2); +} + + +LUA_API int lua_equal (lua_State *L, int index1, int index2) { + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = luaA_indexAcceptable(L, index1); + o2 = luaA_indexAcceptable(L, index2); + i = (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ + : equalobj(L, o1, o2); + lua_unlock(L); + return i; } + LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { - StkId o1 = luaA_indexAcceptable(L, index1); - StkId o2 = luaA_indexAcceptable(L, index2); - if (o1 == NULL || o2 == NULL) return 0; /* index out-of-range */ - else return luaV_lessthan(L, o1, o2, L->top); + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = luaA_indexAcceptable(L, index1); + o2 = luaA_indexAcceptable(L, index2); + i = (o1 == NULL || o2 == NULL) ? 0 /* index out-of-range */ + : luaV_lessthan(L, o1, o2); + lua_unlock(L); + return i; } -LUA_API double lua_tonumber (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); - return (o == NULL || tonumber(o)) ? 0 : nvalue(o); +LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { + TObject n; + const TObject *o = luaA_indexAcceptable(L, idx); + if (o != NULL && tonumber(o, &n)) + return nvalue(o); + else + return 0; } -LUA_API const char *lua_tostring (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); - return (o == NULL || tostring(L, o)) ? NULL : svalue(o); + +LUA_API int lua_toboolean (lua_State *L, int idx) { + const TObject *o = luaA_indexAcceptable(L, idx); + return (o != NULL) && !l_isfalse(o); } -LUA_API size_t lua_strlen (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); - return (o == NULL || tostring(L, o)) ? 0 : tsvalue(o)->len; + +LUA_API const char *lua_tostring (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); + if (o == NULL) + return NULL; + else if (ttisstring(o)) + return svalue(o); + else { + const char *s; + lua_lock(L); /* `luaV_tostring' may create a new string */ + s = (luaV_tostring(L, o) ? svalue(o) : NULL); + luaC_checkGC(L); + lua_unlock(L); + return s; + } } -LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); - return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->f.c; + +LUA_API size_t lua_strlen (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); + if (o == NULL) + return 0; + else if (ttisstring(o)) + return tsvalue(o)->tsv.len; + else { + size_t l; + lua_lock(L); /* `luaV_tostring' may create a new string */ + l = (luaV_tostring(L, o) ? tsvalue(o)->tsv.len : 0); + lua_unlock(L); + return l; + } } -LUA_API void *lua_touserdata (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); - return (o == NULL || ttype(o) != LUA_TUSERDATA) ? NULL : - tsvalue(o)->u.d.value; + +LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); + return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->c.f; } -LUA_API const void *lua_topointer (lua_State *L, int index) { - StkId o = luaA_indexAcceptable(L, index); + +LUA_API void *lua_touserdata (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); if (o == NULL) return NULL; switch (ttype(o)) { - case LUA_TTABLE: - return hvalue(o); - case LUA_TFUNCTION: - return clvalue(o); + case LUA_TUSERDATA: return (uvalue(o) + 1); + case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } +LUA_API lua_State *lua_tothread (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); + return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o); +} + + +LUA_API const void *lua_topointer (lua_State *L, int idx) { + StkId o = luaA_indexAcceptable(L, idx); + if (o == NULL) return NULL; + else { + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TFUNCTION: return clvalue(o); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return NULL; + } + } +} + + /* ** push functions (C -> stack) @@ -200,22 +387,27 @@ LUA_API const void *lua_topointer (lua_State *L, int index) { LUA_API void lua_pushnil (lua_State *L) { - ttype(L->top) = LUA_TNIL; + lua_lock(L); + setnilvalue(L->top); api_incr_top(L); + lua_unlock(L); } -LUA_API void lua_pushnumber (lua_State *L, double n) { - nvalue(L->top) = n; - ttype(L->top) = LUA_TNUMBER; +LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { + lua_lock(L); + setnvalue(L->top, n); api_incr_top(L); + lua_unlock(L); } LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { - tsvalue(L->top) = luaS_newlstr(L, s, len); - ttype(L->top) = LUA_TSTRING; + lua_lock(L); + luaC_checkGC(L); + setsvalue2s(L->top, luaS_newlstr(L, s, len)); api_incr_top(L); + lua_unlock(L); } @@ -227,159 +419,338 @@ LUA_API void lua_pushstring (lua_State *L, const char *s) { } -LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - luaV_Cclosure(L, fn, n); +LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, + va_list argp) { + const char *ret; + lua_lock(L); + luaC_checkGC(L); + ret = luaO_pushvfstring(L, fmt, argp); + lua_unlock(L); + return ret; } -LUA_API void lua_pushusertag (lua_State *L, void *u, int tag) { - /* ORDER LUA_T */ - if (!(tag == LUA_ANYTAG || tag == LUA_TUSERDATA || validtag(tag))) - luaO_verror(L, "invalid tag for a userdata (%d)", tag); - tsvalue(L->top) = luaS_createudata(L, u, tag); - ttype(L->top) = LUA_TUSERDATA; - api_incr_top(L); +LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + lua_lock(L); + luaC_checkGC(L); + va_start(argp, fmt); + ret = luaO_pushvfstring(L, fmt, argp); + va_end(argp); + lua_unlock(L); + return ret; } - -/* -** get functions (Lua -> stack) -*/ +LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { + Closure *cl; + lua_lock(L); + luaC_checkGC(L); + api_checknelems(L, n); + cl = luaF_newCclosure(L, n); + cl->c.f = fn; + L->top -= n; + while (n--) + setobj2n(&cl->c.upvalue[n], L->top+n); + setclvalue(L->top, cl); + api_incr_top(L); + lua_unlock(L); +} -LUA_API void lua_getglobal (lua_State *L, const char *name) { - StkId top = L->top; - *top = *luaV_getglobal(L, luaS_new(L, name)); - L->top = top; +LUA_API void lua_pushboolean (lua_State *L, int b) { + lua_lock(L); + setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ api_incr_top(L); + lua_unlock(L); } -LUA_API void lua_gettable (lua_State *L, int index) { - StkId t = Index(L, index); - StkId top = L->top; - *(top-1) = *luaV_gettable(L, t); - L->top = top; /* tag method may change top */ +LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { + lua_lock(L); + setpvalue(L->top, p); + api_incr_top(L); + lua_unlock(L); } -LUA_API void lua_rawget (lua_State *L, int index) { - StkId t = Index(L, index); - LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected"); - *(L->top - 1) = *luaH_get(L, hvalue(t), L->top - 1); -} +/* +** get functions (Lua -> stack) +*/ -LUA_API void lua_rawgeti (lua_State *L, int index, int n) { - StkId o = Index(L, index); - LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected"); - *L->top = *luaH_getnum(hvalue(o), n); - api_incr_top(L); + +LUA_API void lua_gettable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = luaA_index(L, idx); + setobj2s(L->top - 1, luaV_gettable(L, t, L->top - 1, 0)); + lua_unlock(L); } -LUA_API void lua_getglobals (lua_State *L) { - hvalue(L->top) = L->gt; - ttype(L->top) = LUA_TTABLE; - api_incr_top(L); +LUA_API void lua_rawget (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = luaA_index(L, idx); + api_check(L, ttistable(t)); + setobj2s(L->top - 1, luaH_get(hvalue(t), L->top - 1)); + lua_unlock(L); } -LUA_API int lua_getref (lua_State *L, int ref) { - if (ref == LUA_REFNIL) - ttype(L->top) = LUA_TNIL; - else if (0 <= ref && ref < L->refSize && - (L->refArray[ref].st == LOCK || L->refArray[ref].st == HOLD)) - *L->top = L->refArray[ref].o; - else - return 0; +LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { + StkId o; + lua_lock(L); + o = luaA_index(L, idx); + api_check(L, ttistable(o)); + setobj2s(L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); - return 1; + lua_unlock(L); } LUA_API void lua_newtable (lua_State *L) { - hvalue(L->top) = luaH_new(L, 0); - ttype(L->top) = LUA_TTABLE; + lua_lock(L); + luaC_checkGC(L); + sethvalue(L->top, luaH_new(L, 0, 0)); api_incr_top(L); + lua_unlock(L); +} + + +LUA_API int lua_getmetatable (lua_State *L, int objindex) { + const TObject *obj; + Table *mt = NULL; + int res; + lua_lock(L); + obj = luaA_indexAcceptable(L, objindex); + if (obj != NULL) { + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->uv.metatable; + break; + } + } + if (mt == NULL || mt == hvalue(defaultmeta(L))) + res = 0; + else { + sethvalue(L->top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; } +LUA_API void lua_getfenv (lua_State *L, int idx) { + StkId o; + lua_lock(L); + o = luaA_index(L, idx); + setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); + api_incr_top(L); + lua_unlock(L); +} + /* ** set functions (stack -> Lua) */ -LUA_API void lua_setglobal (lua_State *L, const char *name) { - StkId top = L->top; - luaV_setglobal(L, luaS_new(L, name)); - L->top = top-1; /* remove element from the top */ +LUA_API void lua_settable (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = luaA_index(L, idx); + luaV_settable(L, t, L->top - 2, L->top - 1); + L->top -= 2; /* pop index and value */ + lua_unlock(L); } -LUA_API void lua_settable (lua_State *L, int index) { - StkId t = Index(L, index); - StkId top = L->top; - luaV_settable(L, t, top-2); - L->top = top-2; /* pop index and value */ +LUA_API void lua_rawset (lua_State *L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = luaA_index(L, idx); + api_check(L, ttistable(t)); + setobj2t(luaH_set(L, hvalue(t), L->top-2), L->top-1); /* write barrier */ + L->top -= 2; + lua_unlock(L); } -LUA_API void lua_rawset (lua_State *L, int index) { - StkId t = Index(L, index); - LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected"); - *luaH_set(L, hvalue(t), L->top-2) = *(L->top-1); - L->top -= 2; +LUA_API void lua_rawseti (lua_State *L, int idx, int n) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = luaA_index(L, idx); + api_check(L, ttistable(o)); + setobj2t(luaH_setnum(L, hvalue(o), n), L->top-1); /* write barrier */ + L->top--; + lua_unlock(L); } -LUA_API void lua_rawseti (lua_State *L, int index, int n) { - StkId o = Index(L, index); - LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected"); - *luaH_setint(L, hvalue(o), n) = *(L->top-1); +LUA_API int lua_setmetatable (lua_State *L, int objindex) { + TObject *obj, *mt; + int res = 1; + lua_lock(L); + api_checknelems(L, 1); + obj = luaA_index(L, objindex); + mt = (!ttisnil(L->top - 1)) ? L->top - 1 : defaultmeta(L); + api_check(L, ttistable(mt)); + switch (ttype(obj)) { + case LUA_TTABLE: { + hvalue(obj)->metatable = hvalue(mt); /* write barrier */ + break; + } + case LUA_TUSERDATA: { + uvalue(obj)->uv.metatable = hvalue(mt); /* write barrier */ + break; + } + default: { + res = 0; /* cannot set */ + break; + } + } L->top--; + lua_unlock(L); + return res; } -LUA_API void lua_setglobals (lua_State *L) { - StkId newtable = --L->top; - LUA_ASSERT(ttype(newtable) == LUA_TTABLE, "table expected"); - L->gt = hvalue(newtable); +LUA_API int lua_setfenv (lua_State *L, int idx) { + StkId o; + int res = 0; + lua_lock(L); + api_checknelems(L, 1); + o = luaA_index(L, idx); + L->top--; + api_check(L, ttistable(L->top)); + if (isLfunction(o)) { + res = 1; + clvalue(o)->l.g = *(L->top); + } + lua_unlock(L); + return res; } -LUA_API int lua_ref (lua_State *L, int lock) { - int ref; - if (ttype(L->top-1) == LUA_TNIL) - ref = LUA_REFNIL; - else { - if (L->refFree != NONEXT) { /* is there a free place? */ - ref = L->refFree; - L->refFree = L->refArray[ref].st; - } - else { /* no more free places */ - luaM_growvector(L, L->refArray, L->refSize, 1, struct Ref, - "reference table overflow", MAX_INT); - L->nblocks += sizeof(struct Ref); - ref = L->refSize++; - } - L->refArray[ref].o = *(L->top-1); - L->refArray[ref].st = lock ? LOCK : HOLD; - } - L->top--; - return ref; +/* +** `load' and `call' functions (run Lua code) +*/ + +LUA_API void lua_call (lua_State *L, int nargs, int nresults) { + StkId func; + lua_lock(L); + api_checknelems(L, nargs+1); + func = L->top - (nargs+1); + luaD_call(L, func, nresults); + lua_unlock(L); } + /* -** "do" functions (run Lua code) -** (most of them are in ldo.c) +** Execute a protected call. */ +struct CallS { /* data to `f_call' */ + StkId func; + int nresults; +}; + -LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults) { - luaD_call(L, L->top-(nargs+1), nresults); +static void f_call (lua_State *L, void *ud) { + struct CallS *c = cast(struct CallS *, ud); + luaD_call(L, c->func, c->nresults); +} + + + +LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { + struct CallS c; + int status; + ptrdiff_t func; + lua_lock(L); + func = (errfunc == 0) ? 0 : savestack(L, luaA_index(L, errfunc)); + c.func = L->top - (nargs+1); /* function to be called */ + c.nresults = nresults; + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + lua_unlock(L); + return status; +} + + +/* +** Execute a protected C call. +*/ +struct CCallS { /* data to `f_Ccall' */ + lua_CFunction func; + void *ud; +}; + + +static void f_Ccall (lua_State *L, void *ud) { + struct CCallS *c = cast(struct CCallS *, ud); + Closure *cl; + cl = luaF_newCclosure(L, 0); + cl->c.f = c->func; + setclvalue(L->top, cl); /* push function */ + incr_top(L); + setpvalue(L->top, c->ud); /* push only argument */ + incr_top(L); + luaD_call(L, L->top - 2, 0); +} + + +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { + struct CCallS c; + int status; + lua_lock(L); + c.func = func; + c.ud = ud; + status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); + lua_unlock(L); + return status; +} + + +LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, + const char *chunkname) { + ZIO z; + int status; + int c; + lua_lock(L); + if (!chunkname) chunkname = "?"; + luaZ_init(&z, reader, data, chunkname); + c = luaZ_lookahead(&z); + status = luaD_protectedparser(L, &z, (c == LUA_SIGNATURE[0])); + lua_unlock(L); + return status; +} + + +LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { + int status; + TObject *o; + lua_lock(L); + api_checknelems(L, 1); + o = L->top - 1; + if (isLfunction(o) && clvalue(o)->l.nupvalues == 0) { + luaU_dump(L, clvalue(o)->l.p, writer, data); + status = 1; + } + else + status = 0; + lua_unlock(L); + return status; } @@ -388,23 +759,34 @@ LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults) { */ /* GC values are expressed in Kbytes: #bytes/2^10 */ -#define GCscale(x) ((int)((x)>>10)) -#define GCunscale(x) ((unsigned long)(x)<<10) +#define GCscalel(x) ((x)>>10) +#define GCscale(x) (cast(int, GCscalel(x))) +#define GCunscale(x) (cast(lu_mem, x)<<10) LUA_API int lua_getgcthreshold (lua_State *L) { - return GCscale(L->GCthreshold); + int threshold; + lua_lock(L); + threshold = GCscale(G(L)->GCthreshold); + lua_unlock(L); + return threshold; } LUA_API int lua_getgccount (lua_State *L) { - return GCscale(L->nblocks); + int count; + lua_lock(L); + count = GCscale(G(L)->nblocks); + lua_unlock(L); + return count; } LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { - if (newthreshold > GCscale(ULONG_MAX)) - L->GCthreshold = ULONG_MAX; + lua_lock(L); + if (cast(lu_mem, newthreshold) > GCscalel(MAX_LUMEM)) + G(L)->GCthreshold = MAX_LUMEM; else - L->GCthreshold = GCunscale(newthreshold); + G(L)->GCthreshold = GCunscale(newthreshold); luaC_checkGC(L); + lua_unlock(L); } @@ -412,83 +794,129 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { ** miscellaneous functions */ -LUA_API void lua_settag (lua_State *L, int tag) { - luaT_realtag(L, tag); - switch (ttype(L->top-1)) { - case LUA_TTABLE: - hvalue(L->top-1)->htag = tag; - break; - case LUA_TUSERDATA: - tsvalue(L->top-1)->u.d.tag = tag; - break; - default: - luaO_verror(L, "cannot change the tag of a %.20s", - luaO_typename(L->top-1)); - } + +LUA_API const char *lua_version (void) { + return LUA_VERSION; } -LUA_API void lua_unref (lua_State *L, int ref) { - if (ref >= 0) { - LUA_ASSERT(ref < L->refSize && L->refArray[ref].st < 0, "invalid ref"); - L->refArray[ref].st = L->refFree; - L->refFree = ref; - } +LUA_API int lua_error (lua_State *L) { + lua_lock(L); + api_checknelems(L, 1); + luaG_errormsg(L); + lua_unlock(L); + return 0; /* to avoid warnings */ } -LUA_API int lua_next (lua_State *L, int index) { - StkId t = luaA_index(L, index); - Node *n; - LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected"); - n = luaH_next(L, hvalue(t), luaA_index(L, -1)); - if (n) { - *(L->top-1) = *key(n); - *L->top = *val(n); +LUA_API int lua_next (lua_State *L, int idx) { + StkId t; + int more; + lua_lock(L); + t = luaA_index(L, idx); + api_check(L, ttistable(t)); + more = luaH_next(L, hvalue(t), L->top - 1); + if (more) { api_incr_top(L); - return 1; } - else { /* no more elements */ + else /* no more elements */ L->top -= 1; /* remove key */ - return 0; + lua_unlock(L); + return more; +} + + +LUA_API void lua_concat (lua_State *L, int n) { + lua_lock(L); + luaC_checkGC(L); + api_checknelems(L, n); + if (n >= 2) { + luaV_concat(L, n, L->top - L->base - 1); + L->top -= (n-1); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L->top, luaS_newlstr(L, NULL, 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + lua_unlock(L); +} + + +LUA_API void *lua_newuserdata (lua_State *L, size_t size) { + Udata *u; + lua_lock(L); + luaC_checkGC(L); + u = luaS_newudata(L, size); + setuvalue(L->top, u); + api_incr_top(L); + lua_unlock(L); + return u + 1; +} + + +LUA_API int lua_pushupvalues (lua_State *L) { + Closure *func; + int n, i; + lua_lock(L); + api_check(L, iscfunction(L->base - 1)); + func = clvalue(L->base - 1); + n = func->c.nupvalues; + luaD_checkstack(L, n + LUA_MINSTACK); + for (i=0; itop, &func->c.upvalue[i]); + L->top++; } + lua_unlock(L); + return n; } -LUA_API int lua_getn (lua_State *L, int index) { - Hash *h = hvalue(luaA_index(L, index)); - const TObject *value = luaH_getstr(h, luaS_new(L, "n")); /* value = h.n */ - if (ttype(value) == LUA_TNUMBER) - return (int)nvalue(value); +static const char *aux_upvalue (lua_State *L, int funcindex, int n, + TObject **val) { + Closure *f; + StkId fi = luaA_index(L, funcindex); + if (!ttisfunction(fi)) return NULL; + f = clvalue(fi); + if (f->c.isC) { + if (n > f->c.nupvalues) return NULL; + *val = &f->c.upvalue[n-1]; + return ""; + } else { - Number max = 0; - int i = h->size; - Node *n = h->node; - while (i--) { - if (ttype(key(n)) == LUA_TNUMBER && - ttype(val(n)) != LUA_TNIL && - nvalue(key(n)) > max) - max = nvalue(key(n)); - n++; - } - return (int)max; + Proto *p = f->l.p; + if (n > p->sizeupvalues) return NULL; + *val = f->l.upvals[n-1]->v; + return getstr(p->upvalues[n-1]); } } -LUA_API void lua_concat (lua_State *L, int n) { - StkId top = L->top; - luaV_strconc(L, n, top); - L->top = top-(n-1); - luaC_checkGC(L); +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TObject *val; + lua_lock(L); + name = aux_upvalue(L, funcindex, n, &val); + if (name) { + setobj2s(L->top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; } -LUA_API void *lua_newuserdata (lua_State *L, size_t size) { - TString *ts = luaS_newudata(L, (size==0) ? 1 : size, NULL); - tsvalue(L->top) = ts; - ttype(L->top) = LUA_TUSERDATA; - api_incr_top(L); - return ts->u.d.value; +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { + const char *name; + TObject *val; + lua_lock(L); + api_checknelems(L, 1); + name = aux_upvalue(L, funcindex, n, &val); + if (name) { + L->top--; + setobj(val, L->top); /* write barrier */ + } + lua_unlock(L); + return name; } diff --git a/src/lapi.h b/src/lapi.h index 5cefdc7aec..d12612f304 100644 --- a/src/lapi.h +++ b/src/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 1.20 2000/08/31 14:08:27 roberto Exp $ +** $Id: lapi.h,v 1.21 2002/03/04 21:29:41 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -11,7 +11,6 @@ #include "lobject.h" -TObject *luaA_index (lua_State *L, int index); void luaA_pushobject (lua_State *L, const TObject *o); #endif diff --git a/src/lcode.c b/src/lcode.c index 6882240d4b..d626ecd60e 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,66 +1,84 @@ /* -** $Id: lcode.c,v 1.51 2000/09/29 12:42:13 roberto Exp $ +** $Id: lcode.c,v 1.117 2003/04/03 13:35:34 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ -#include "stdlib.h" +#include + +#define lcode_c #include "lua.h" #include "lcode.h" +#include "ldebug.h" #include "ldo.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" +#include "ltable.h" -void luaK_error (LexState *ls, const char *msg) { - luaX_error(ls, msg, ls->t.token); -} +#define hasjumps(e) ((e)->t != (e)->f) -/* -** Returns the the previous instruction, for optimizations. -** If there is a jump target between this and the current instruction, -** returns a dummy instruction to avoid wrong optimizations. -*/ -static Instruction previous_instruction (FuncState *fs) { - if (fs->pc > fs->lasttarget) /* no jumps to current position? */ - return fs->f->code[fs->pc-1]; /* returns previous instruction */ - else - return CREATE_0(OP_END); /* no optimizations after an `END' */ +void luaK_nil (FuncState *fs, int from, int n) { + Instruction *previous; + if (fs->pc > fs->lasttarget && /* no jumps to current position? */ + GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; + } + } + luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ } int luaK_jump (FuncState *fs) { - int j = luaK_code1(fs, OP_JMP, NO_JUMP); - if (j == fs->lasttarget) { /* possible jumps to this jump? */ - luaK_concat(fs, &j, fs->jlt); /* keep them on hold */ - fs->jlt = NO_JUMP; - } + int jpc = fs->jpc; /* save list of jumps to here */ + int j; + fs->jpc = NO_JUMP; + j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); + luaK_concat(fs, &j, jpc); /* keep them on hold */ return j; } +static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) { + luaK_codeABC(fs, op, A, B, C); + return luaK_jump(fs); +} + + static void luaK_fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; - if (dest == NO_JUMP) - SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */ - else { /* jump is relative to position following jump instruction */ - int offset = dest-(pc+1); - if (abs(offset) > MAXARG_S) - luaK_error(fs->ls, "control structure too long"); - SETARG_S(*jmp, offset); - } + int offset = dest-(pc+1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + + +/* +** returns current `pc' and marks it as a jump target (to avoid wrong +** optimizations with consecutive instructions not in the same basic block). +*/ +int luaK_getlabel (FuncState *fs) { + fs->lasttarget = fs->pc; + return fs->pc; } static int luaK_getjump (FuncState *fs, int pc) { - int offset = GETARG_S(fs->f->code[pc]); + int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ else @@ -68,634 +86,629 @@ static int luaK_getjump (FuncState *fs, int pc) { } +static Instruction *getjumpcontrol (FuncState *fs, int pc) { + Instruction *pi = &fs->f->code[pc]; + if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT)) + return pi-1; + else + return pi; +} + + /* -** returns current `pc' and marks it as a jump target (to avoid wrong -** optimizations with consecutive instructions not in the same basic block). -** discharge list of jumps to last target. +** check whether list has any jump that do not produce a value +** (or produce an inverted value) */ -int luaK_getlabel (FuncState *fs) { - if (fs->pc != fs->lasttarget) { - int lasttarget = fs->lasttarget; - fs->lasttarget = fs->pc; - luaK_patchlist(fs, fs->jlt, lasttarget); /* discharge old list `jlt' */ - fs->jlt = NO_JUMP; /* nobody jumps to this new label (yet) */ +static int need_value (FuncState *fs, int list, int cond) { + for (; list != NO_JUMP; list = luaK_getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1; } - return fs->pc; + return 0; /* not found */ } -void luaK_deltastack (FuncState *fs, int delta) { - fs->stacklevel += delta; - if (fs->stacklevel > fs->f->maxstacksize) { - if (fs->stacklevel > MAXSTACK) - luaK_error(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = fs->stacklevel; - } +static void patchtestreg (Instruction *i, int reg) { + if (reg == NO_REG) reg = GETARG_B(*i); + SETARG_A(*i, reg); } -void luaK_kstr (LexState *ls, int c) { - luaK_code1(ls->fs, OP_PUSHSTRING, c); +static void luaK_patchlistaux (FuncState *fs, int list, + int ttarget, int treg, int ftarget, int freg, int dtarget) { + while (list != NO_JUMP) { + int next = luaK_getjump(fs, list); + Instruction *i = getjumpcontrol(fs, list); + if (GET_OPCODE(*i) != OP_TEST) { + lua_assert(dtarget != NO_JUMP); + luaK_fixjump(fs, list, dtarget); /* jump to default target */ + } + else { + if (GETARG_C(*i)) { + lua_assert(ttarget != NO_JUMP); + patchtestreg(i, treg); + luaK_fixjump(fs, list, ttarget); + } + else { + lua_assert(ftarget != NO_JUMP); + patchtestreg(i, freg); + luaK_fixjump(fs, list, ftarget); + } + } + list = next; + } } -static int number_constant (FuncState *fs, Number r) { - /* check whether `r' has appeared within the last LOOKBACKNUMS entries */ - Proto *f = fs->f; - int c = f->nknum; - int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS; - while (--c >= lim) - if (f->knum[c] == r) return c; - /* not found; create a new entry */ - luaM_growvector(fs->L, f->knum, f->nknum, 1, Number, - "constant table overflow", MAXARG_U); - c = f->nknum++; - f->knum[c] = r; - return c; -} - - -void luaK_number (FuncState *fs, Number f) { - if (f <= (Number)MAXARG_S && (Number)(int)f == f) - luaK_code1(fs, OP_PUSHINT, (int)f); /* f has a short integer value */ - else - luaK_code1(fs, OP_PUSHNUM, number_constant(fs, f)); +static void luaK_dischargejpc (FuncState *fs) { + luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); + fs->jpc = NO_JUMP; } -void luaK_adjuststack (FuncState *fs, int n) { - if (n > 0) - luaK_code1(fs, OP_POP, n); - else - luaK_code1(fs, OP_PUSHNIL, -n); +void luaK_patchlist (FuncState *fs, int list, int target) { + if (target == fs->pc) + luaK_patchtohere(fs, list); + else { + lua_assert(target < fs->pc); + luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); + } } -int luaK_lastisopen (FuncState *fs) { - /* check whether last instruction is an open function call */ - Instruction i = previous_instruction(fs); - if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) - return 1; - else return 0; +void luaK_patchtohere (FuncState *fs, int list) { + luaK_getlabel(fs); + luaK_concat(fs, &fs->jpc, list); } -void luaK_setcallreturns (FuncState *fs, int nresults) { - if (luaK_lastisopen(fs)) { /* expression is an open function call? */ - SETARG_B(fs->f->code[fs->pc-1], nresults); /* set number of results */ - luaK_deltastack(fs, nresults); /* push results */ +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; + else if (*l1 == NO_JUMP) + *l1 = l2; + else { + int list = *l1; + int next; + while ((next = luaK_getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + luaK_fixjump(fs, list, l2); } } -static int discharge (FuncState *fs, expdesc *var) { - switch (var->k) { - case VLOCAL: - luaK_code1(fs, OP_GETLOCAL, var->u.index); - break; - case VGLOBAL: - luaK_code1(fs, OP_GETGLOBAL, var->u.index); - break; - case VINDEXED: - luaK_code0(fs, OP_GETTABLE); - break; - case VEXP: - return 0; /* nothing to do */ +void luaK_checkstack (FuncState *fs, int n) { + int newstack = fs->freereg + n; + if (newstack > fs->f->maxstacksize) { + if (newstack >= MAXSTACK) + luaX_syntaxerror(fs->ls, "function or expression too complex"); + fs->f->maxstacksize = cast(lu_byte, newstack); } - var->k = VEXP; - var->u.l.t = var->u.l.f = NO_JUMP; - return 1; } -static void discharge1 (FuncState *fs, expdesc *var) { - discharge(fs, var); - /* if it has jumps then it is already discharged */ - if (var->u.l.t == NO_JUMP && var->u.l.f == NO_JUMP) - luaK_setcallreturns(fs, 1); /* call must return 1 value */ +void luaK_reserveregs (FuncState *fs, int n) { + luaK_checkstack(fs, n); + fs->freereg += n; } -void luaK_storevar (LexState *ls, const expdesc *var) { - FuncState *fs = ls->fs; - switch (var->k) { - case VLOCAL: - luaK_code1(fs, OP_SETLOCAL, var->u.index); - break; - case VGLOBAL: - luaK_code1(fs, OP_SETGLOBAL, var->u.index); - break; - case VINDEXED: /* table is at top-3; pop 3 elements after operation */ - luaK_code2(fs, OP_SETTABLE, 3, 3); - break; - default: - LUA_INTERNALERROR("invalid var kind to store"); +static void freereg (FuncState *fs, int reg) { + if (reg >= fs->nactvar && reg < MAXSTACK) { + fs->freereg--; + lua_assert(reg == fs->freereg); } } -static OpCode invertjump (OpCode op) { - switch (op) { - case OP_JMPNE: return OP_JMPEQ; - case OP_JMPEQ: return OP_JMPNE; - case OP_JMPLT: return OP_JMPGE; - case OP_JMPLE: return OP_JMPGT; - case OP_JMPGT: return OP_JMPLE; - case OP_JMPGE: return OP_JMPLT; - case OP_JMPT: case OP_JMPONT: return OP_JMPF; - case OP_JMPF: case OP_JMPONF: return OP_JMPT; - default: - LUA_INTERNALERROR("invalid jump instruction"); - return OP_END; /* to avoid warnings */ - } +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->info); } -static void luaK_patchlistaux (FuncState *fs, int list, int target, - OpCode special, int special_target) { - Instruction *code = fs->f->code; - while (list != NO_JUMP) { - int next = luaK_getjump(fs, list); - Instruction *i = &code[list]; - OpCode op = GET_OPCODE(*i); - if (op == special) /* this `op' already has a value */ - luaK_fixjump(fs, list, special_target); - else { - luaK_fixjump(fs, list, target); /* do the patch */ - if (op == OP_JMPONT) /* remove eventual values */ - SET_OPCODE(*i, OP_JMPT); - else if (op == OP_JMPONF) - SET_OPCODE(*i, OP_JMPF); - } - list = next; +static int addk (FuncState *fs, TObject *k, TObject *v) { + const TObject *idx = luaH_get(fs->h, k); + if (ttisnumber(idx)) { + lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v)); + return cast(int, nvalue(idx)); + } + else { /* constant not found; create a new entry */ + Proto *f = fs->f; + luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject, + MAXARG_Bx, "constant table overflow"); + setobj2n(&f->k[fs->nk], v); + setnvalue(luaH_set(fs->L, fs->h, k), cast(lua_Number, fs->nk)); + return fs->nk++; } } -void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->lasttarget) /* same target that list `jlt'? */ - luaK_concat(fs, &fs->jlt, list); /* delay fixing */ - else - luaK_patchlistaux(fs, list, target, OP_END, 0); +int luaK_stringK (FuncState *fs, TString *s) { + TObject o; + setsvalue(&o, s); + return addk(fs, &o, &o); } -static int need_value (FuncState *fs, int list, OpCode hasvalue) { - /* check whether list has a jump without a value */ - for (; list != NO_JUMP; list = luaK_getjump(fs, list)) - if (GET_OPCODE(fs->f->code[list]) != hasvalue) return 1; - return 0; /* not found */ +int luaK_numberK (FuncState *fs, lua_Number r) { + TObject o; + setnvalue(&o, r); + return addk(fs, &o, &o); } -void luaK_concat (FuncState *fs, int *l1, int l2) { - if (*l1 == NO_JUMP) - *l1 = l2; - else { - int list = *l1; - for (;;) { /* traverse `l1' */ - int next = luaK_getjump(fs, list); - if (next == NO_JUMP) { /* end of list? */ - luaK_fixjump(fs, list, l2); - return; - } - list = next; - } - } +static int nil_constant (FuncState *fs) { + TObject k, v; + setnilvalue(&v); + sethvalue(&k, fs->h); /* cannot use nil as key; instead use table itself */ + return addk(fs, &k, &v); } -static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) { - int prevpos; /* position of last instruction */ - Instruction *previous; - int *golist, *exitlist; - if (!invert) { - golist = &v->u.l.f; /* go if false */ - exitlist = &v->u.l.t; /* exit if true */ - } - else { - golist = &v->u.l.t; /* go if true */ - exitlist = &v->u.l.f; /* exit if false */ - } - discharge1(fs, v); - prevpos = fs->pc-1; - previous = &fs->f->code[prevpos]; - LUA_ASSERT(*previous==previous_instruction(fs), "no jump allowed here"); - if (!ISJUMP(GET_OPCODE(*previous))) - prevpos = luaK_code1(fs, jump, NO_JUMP); - else { /* last instruction is already a jump */ - if (invert) - SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); +void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) { + if (e->k == VCALL) { /* expression is an open function call? */ + SETARG_C(getcode(fs, e), nresults+1); + if (nresults == 1) { /* `regular' expression? */ + e->k = VNONRELOC; + e->info = GETARG_A(getcode(fs, e)); + } } - luaK_concat(fs, exitlist, prevpos); /* insert last jump in `exitlist' */ - luaK_patchlist(fs, *golist, luaK_getlabel(fs)); - *golist = NO_JUMP; } -void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) { - luaK_testgo(fs, v, 1, keepvalue ? OP_JMPONF : OP_JMPF); +void luaK_dischargevars (FuncState *fs, expdesc *e) { + switch (e->k) { + case VLOCAL: { + e->k = VNONRELOC; + break; + } + case VUPVAL: { + e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0); + e->k = VRELOCABLE; + break; + } + case VGLOBAL: { + e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info); + e->k = VRELOCABLE; + break; + } + case VINDEXED: { + freereg(fs, e->aux); + freereg(fs, e->info); + e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux); + e->k = VRELOCABLE; + break; + } + case VCALL: { + luaK_setcallreturns(fs, e, 1); + break; + } + default: break; /* there is one value available (somewhere) */ + } } -static void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) { - luaK_testgo(fs, v, 0, keepvalue ? OP_JMPONT : OP_JMPT); +static int code_label (FuncState *fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); } -static int code_label (FuncState *fs, OpCode op, int arg) { - luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_code1(fs, op, arg); -} - - -void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { - FuncState *fs = ls->fs; - if (!discharge(fs, v)) { /* `v' is an expression? */ - OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]); - if (!ISJUMP(previous) && v->u.l.f == NO_JUMP && v->u.l.t == NO_JUMP) { - /* expression has no jumps */ - if (onlyone) - luaK_setcallreturns(fs, 1); /* call must return 1 value */ - } - else { /* expression has jumps */ - int final; /* position after whole expression */ - int j = NO_JUMP; /* eventual jump over values */ - int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */ - int p_1 = NO_JUMP; /* position of an eventual PUSHINT */ - if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF) - || need_value(fs, v->u.l.t, OP_JMPONT)) { - /* expression needs values */ - if (ISJUMP(previous)) - luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */ - else { - j = code_label(fs, OP_JMP, NO_JUMP); /* to jump over both pushes */ - /* correct stack for compiler and symbolic execution */ - luaK_adjuststack(fs, 1); - } - p_nil = code_label(fs, OP_PUSHNILJMP, 0); - p_1 = code_label(fs, OP_PUSHINT, 1); - luaK_patchlist(fs, j, luaK_getlabel(fs)); - } - final = luaK_getlabel(fs); - luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final); - luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final); - v->u.l.f = v->u.l.t = NO_JUMP; +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case VFALSE: case VTRUE: { + luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); + break; + } + case VK: { + luaK_codeABx(fs, OP_LOADK, reg, e->info); + break; + } + case VRELOCABLE: { + Instruction *pc = &getcode(fs, e); + SETARG_A(*pc, reg); + break; + } + case VNONRELOC: { + if (reg != e->info) + luaK_codeABC(fs, OP_MOVE, reg, e->info, 0); + break; + } + default: { + lua_assert(e->k == VVOID || e->k == VJMP); + return; /* nothing to do... */ } } + e->info = reg; + e->k = VNONRELOC; } -void luaK_prefix (LexState *ls, UnOpr op, expdesc *v) { - FuncState *fs = ls->fs; - if (op == OPR_MINUS) { - luaK_tostack(ls, v, 1); - luaK_code0(fs, OP_MINUS); +static void discharge2anyreg (FuncState *fs, expdesc *e) { + if (e->k != VNONRELOC) { + luaK_reserveregs(fs, 1); + discharge2reg(fs, e, fs->freereg-1); } - else { /* op == NOT */ - Instruction *previous; - discharge1(fs, v); - previous = &fs->f->code[fs->pc-1]; - if (ISJUMP(GET_OPCODE(*previous))) - SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); - else - luaK_code0(fs, OP_NOT); - /* interchange true and false lists */ - { int temp = v->u.l.f; v->u.l.f = v->u.l.t; v->u.l.t = temp; } +} + + +static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) { + discharge2reg(fs, e, reg); + if (e->k == VJMP) + luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e->t, 1) || need_value(fs, e->f, 0)) { + int fj = NO_JUMP; /* first jump (over LOAD ops.) */ + if (e->k != VJMP) + fj = luaK_jump(fs); + p_f = code_label(fs, reg, 0, 1); + p_t = code_label(fs, reg, 1, 0); + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + luaK_patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f); + luaK_patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t); } + e->f = e->t = NO_JUMP; + e->info = reg; + e->k = VNONRELOC; } -void luaK_infix (LexState *ls, BinOpr op, expdesc *v) { - FuncState *fs = ls->fs; - switch (op) { - case OPR_AND: - luaK_goiftrue(fs, v, 1); - break; - case OPR_OR: - luaK_goiffalse(fs, v, 1); - break; - default: - luaK_tostack(ls, v, 1); /* all other binary operators need a value */ +void luaK_exp2nextreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + luaK_exp2reg(fs, e, fs->freereg - 1); +} + + +int luaK_exp2anyreg (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + if (e->k == VNONRELOC) { + if (!hasjumps(e)) return e->info; /* exp is already in a register */ + if (e->info >= fs->nactvar) { /* reg. is not a local? */ + luaK_exp2reg(fs, e, e->info); /* put value on it */ + return e->info; + } } + luaK_exp2nextreg(fs, e); /* default */ + return e->info; } +void luaK_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); +} -static const struct { - OpCode opcode; /* opcode for each binary operator */ - int arg; /* default argument for the opcode */ -} codes[] = { /* ORDER OPR */ - {OP_ADD, 0}, {OP_SUB, 0}, {OP_MULT, 0}, {OP_DIV, 0}, - {OP_POW, 0}, {OP_CONCAT, 2}, - {OP_JMPNE, NO_JUMP}, {OP_JMPEQ, NO_JUMP}, - {OP_JMPLT, NO_JUMP}, {OP_JMPLE, NO_JUMP}, - {OP_JMPGT, NO_JUMP}, {OP_JMPGE, NO_JUMP} -}; +int luaK_exp2RK (FuncState *fs, expdesc *e) { + luaK_exp2val(fs, e); + switch (e->k) { + case VNIL: { + if (fs->nk + MAXSTACK <= MAXARG_C) { /* constant fit in argC? */ + e->info = nil_constant(fs); + e->k = VK; + return e->info + MAXSTACK; + } + else break; + } + case VK: { + if (e->info + MAXSTACK <= MAXARG_C) /* constant fit in argC? */ + return e->info + MAXSTACK; + else break; + } + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); +} -void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2) { - FuncState *fs = ls->fs; - switch (op) { - case OPR_AND: { - LUA_ASSERT(v1->u.l.t == NO_JUMP, "list must be closed"); - discharge1(fs, v2); - v1->u.l.t = v2->u.l.t; - luaK_concat(fs, &v1->u.l.f, v2->u.l.f); + +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { + switch (var->k) { + case VLOCAL: { + freeexp(fs, exp); + luaK_exp2reg(fs, exp, var->info); + return; + } + case VUPVAL: { + int e = luaK_exp2anyreg(fs, exp); + luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0); break; } - case OPR_OR: { - LUA_ASSERT(v1->u.l.f == NO_JUMP, "list must be closed"); - discharge1(fs, v2); - v1->u.l.f = v2->u.l.f; - luaK_concat(fs, &v1->u.l.t, v2->u.l.t); + case VGLOBAL: { + int e = luaK_exp2anyreg(fs, exp); + luaK_codeABx(fs, OP_SETGLOBAL, e, var->info); + break; + } + case VINDEXED: { + int e = luaK_exp2RK(fs, exp); + luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e); break; } default: { - luaK_tostack(ls, v2, 1); /* `v2' must be a value */ - luaK_code1(fs, codes[op].opcode, codes[op].arg); + lua_assert(0); /* invalid var kind to store */ + break; } } + freeexp(fs, exp); } -static void codelineinfo (FuncState *fs) { - Proto *f = fs->f; - LexState *ls = fs->ls; - if (ls->lastline > fs->lastline) { - luaM_growvector(fs->L, f->lineinfo, f->nlineinfo, 2, int, - "line info overflow", MAX_INT); - if (ls->lastline > fs->lastline+1) - f->lineinfo[f->nlineinfo++] = -(ls->lastline - (fs->lastline+1)); - f->lineinfo[f->nlineinfo++] = fs->pc; - fs->lastline = ls->lastline; - } +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int func; + luaK_exp2anyreg(fs, e); + freeexp(fs, e); + func = fs->freereg; + luaK_reserveregs(fs, 2); + luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key)); + freeexp(fs, key); + e->info = func; + e->k = VNONRELOC; } -int luaK_code0 (FuncState *fs, OpCode o) { - return luaK_code2(fs, o, 0, 0); +static void invertjump (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->info); + lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) && + GET_OPCODE(*pc) != OP_TEST); + SETARG_A(*pc, !(GETARG_A(*pc))); } -int luaK_code1 (FuncState *fs, OpCode o, int arg1) { - return luaK_code2(fs, o, arg1, 0); +static int jumponcond (FuncState *fs, expdesc *e, int cond) { + if (e->k == VRELOCABLE) { + Instruction ie = getcode(fs, e); + if (GET_OPCODE(ie) == OP_NOT) { + fs->pc--; /* remove previous OP_NOT */ + return luaK_condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return luaK_condjump(fs, OP_TEST, NO_REG, e->info, cond); } -int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { - Instruction i = previous_instruction(fs); - int delta = luaK_opproperties[o].push - luaK_opproperties[o].pop; - int optm = 0; /* 1 when there is an optimization */ - switch (o) { - case OP_CLOSURE: { - delta = -arg2+1; +void luaK_goiftrue (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VK: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ break; } - case OP_SETTABLE: { - delta = -arg2; + case VFALSE: { + pc = luaK_jump(fs); /* always jump */ break; } - case OP_SETLIST: { - if (arg2 == 0) return NO_JUMP; /* nothing to do */ - delta = -arg2; + case VJMP: { + invertjump(fs, e); + pc = e->info; break; } - case OP_SETMAP: { - if (arg1 == 0) return NO_JUMP; /* nothing to do */ - delta = -2*arg1; + default: { + pc = jumponcond(fs, e, 0); break; } - case OP_RETURN: { - if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) { - SET_OPCODE(i, OP_TAILCALL); - SETARG_B(i, arg1); - optm = 1; - } + } + luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ +} + + +void luaK_goiffalse (FuncState *fs, expdesc *e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ break; } - case OP_PUSHNIL: { - if (arg1 == 0) return NO_JUMP; /* nothing to do */ - delta = arg1; - switch(GET_OPCODE(i)) { - case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); optm = 1; break; - default: break; - } + case VTRUE: { + pc = luaK_jump(fs); /* always jump */ break; } - case OP_POP: { - if (arg1 == 0) return NO_JUMP; /* nothing to do */ - delta = -arg1; - switch(GET_OPCODE(i)) { - case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); optm = 1; break; - default: break; - } + case VJMP: { + pc = e->info; break; } - case OP_GETTABLE: { - switch(GET_OPCODE(i)) { - case OP_PUSHSTRING: /* `t.x' */ - SET_OPCODE(i, OP_GETDOTTED); - optm = 1; - break; - case OP_GETLOCAL: /* `t[i]' */ - SET_OPCODE(i, OP_GETINDEXED); - optm = 1; - break; - default: break; - } + default: { + pc = jumponcond(fs, e, 1); break; } - case OP_ADD: { - switch(GET_OPCODE(i)) { - case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */ - default: break; - } + } + luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ +} + + +static void codenot (FuncState *fs, expdesc *e) { + luaK_dischargevars(fs, e); + switch (e->k) { + case VNIL: case VFALSE: { + e->k = VTRUE; break; } - case OP_SUB: { - switch(GET_OPCODE(i)) { - case OP_PUSHINT: /* `a-k' */ - i = CREATE_S(OP_ADDI, -GETARG_S(i)); - optm = 1; - break; - default: break; - } + case VK: case VTRUE: { + e->k = VFALSE; break; } - case OP_CONCAT: { - delta = -arg1+1; - switch(GET_OPCODE(i)) { - case OP_CONCAT: /* `a..b..c' */ - SETARG_U(i, GETARG_U(i)+1); - optm = 1; - break; - default: break; - } + case VJMP: { + invertjump(fs, e); break; } - case OP_MINUS: { - switch(GET_OPCODE(i)) { - case OP_PUSHINT: /* `-k' */ - SETARG_S(i, -GETARG_S(i)); - optm = 1; - break; - case OP_PUSHNUM: /* `-k' */ - SET_OPCODE(i, OP_PUSHNEGNUM); - optm = 1; - break; - default: break; - } + case VRELOCABLE: + case VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0); + e->k = VRELOCABLE; break; } - case OP_JMPNE: { - if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */ - i = CREATE_S(OP_JMPT, NO_JUMP); - optm = 1; - } + default: { + lua_assert(0); /* cannot happen */ break; } - case OP_JMPEQ: { - if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */ - i = CREATE_0(OP_NOT); - delta = -1; /* just undo effect of previous PUSHNIL */ - optm = 1; - } - break; + } + /* interchange true and false lists */ + { int temp = e->f; e->f = e->t; e->t = temp; } +} + + +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + t->aux = luaK_exp2RK(fs, k); + t->k = VINDEXED; +} + + +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { + if (op == OPR_MINUS) { + luaK_exp2val(fs, e); + if (e->k == VK && ttisnumber(&fs->f->k[e->info])) + e->info = luaK_numberK(fs, -nvalue(&fs->f->k[e->info])); + else { + luaK_exp2anyreg(fs, e); + freeexp(fs, e); + e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0); + e->k = VRELOCABLE; } - case OP_JMPT: - case OP_JMPONT: { - switch (GET_OPCODE(i)) { - case OP_NOT: { - i = CREATE_S(OP_JMPF, NO_JUMP); - optm = 1; - break; - } - case OP_PUSHINT: { - if (o == OP_JMPT) { /* JMPONT must keep original integer value */ - i = CREATE_S(OP_JMP, NO_JUMP); - optm = 1; - } - break; - } - case OP_PUSHNIL: { - if (GETARG_U(i) == 1) { - fs->pc--; /* erase previous instruction */ - luaK_deltastack(fs, -1); /* correct stack */ - return NO_JUMP; - } - break; - } - default: break; - } + } + else /* op == NOT */ + codenot(fs, e); +} + + +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { + switch (op) { + case OPR_AND: { + luaK_goiftrue(fs, v); + luaK_patchtohere(fs, v->t); + v->t = NO_JUMP; break; } - case OP_JMPF: - case OP_JMPONF: { - switch (GET_OPCODE(i)) { - case OP_NOT: { - i = CREATE_S(OP_JMPT, NO_JUMP); - optm = 1; - break; - } - case OP_PUSHINT: { /* `while 1 do ...' */ - fs->pc--; /* erase previous instruction */ - luaK_deltastack(fs, -1); /* correct stack */ - return NO_JUMP; - } - case OP_PUSHNIL: { /* `repeat ... until nil' */ - if (GETARG_U(i) == 1) { - i = CREATE_S(OP_JMP, NO_JUMP); - optm = 1; - } - break; - } - default: break; - } + case OPR_OR: { + luaK_goiffalse(fs, v); + luaK_patchtohere(fs, v->f); + v->f = NO_JUMP; break; } - case OP_GETDOTTED: - case OP_GETINDEXED: - case OP_TAILCALL: - case OP_ADDI: { - LUA_INTERNALERROR("instruction used only for optimizations"); + case OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ break; } default: { - LUA_ASSERT(delta != VD, "invalid delta"); + luaK_exp2RK(fs, v); break; } } - luaK_deltastack(fs, delta); - if (optm) { /* optimize: put instruction in place of last one */ - fs->f->code[fs->pc-1] = i; /* change previous instruction */ - return fs->pc-1; /* do not generate new instruction */ +} + + +static void codebinop (FuncState *fs, expdesc *res, BinOpr op, + int o1, int o2) { + if (op <= OPR_POW) { /* arithmetic operator? */ + OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD); /* ORDER OP */ + res->info = luaK_codeABC(fs, opc, 0, o1, o2); + res->k = VRELOCABLE; } - /* else build new instruction */ - switch ((enum Mode)luaK_opproperties[o].mode) { - case iO: i = CREATE_0(o); break; - case iU: i = CREATE_U(o, arg1); break; - case iS: i = CREATE_S(o, arg1); break; - case iAB: i = CREATE_AB(o, arg1, arg2); break; + else { /* test operator */ + static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE}; + int cond = 1; + if (op >= OPR_GT) { /* `>' or `>='? */ + int temp; /* exchange args and replace by `<' or `<=' */ + temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ + } + else if (op == OPR_NE) cond = 0; + res->info = luaK_condjump(fs, ops[op - OPR_NE], cond, o1, o2); + res->k = VJMP; } - codelineinfo(fs); +} + + +void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { + switch (op) { + case OPR_AND: { + lua_assert(e1->t == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e1->f, e2->f); + e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t; + break; + } + case OPR_OR: { + lua_assert(e1->f == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, &e1->t, e2->t); + e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f; + break; + } + case OPR_CONCAT: { + luaK_exp2val(fs, e2); + if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { + lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getcode(fs, e2), e1->info); + e1->k = e2->k; e1->info = e2->info; + } + else { + luaK_exp2nextreg(fs, e2); + freeexp(fs, e2); + freeexp(fs, e1); + e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info); + e1->k = VRELOCABLE; + } + break; + } + default: { + int o1 = luaK_exp2RK(fs, e1); + int o2 = luaK_exp2RK(fs, e2); + freeexp(fs, e2); + freeexp(fs, e1); + codebinop(fs, e1, op, o1, o2); + } + } +} + + +void luaK_fixline (FuncState *fs, int line) { + fs->f->lineinfo[fs->pc - 1] = line; +} + + +int luaK_code (FuncState *fs, Instruction i, int line) { + Proto *f = fs->f; + luaK_dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ - luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction, - "code size overflow", MAX_INT); - fs->f->code[fs->pc] = i; + luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "code size overflow"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "code size overflow"); + f->lineinfo[fs->pc] = line; return fs->pc++; } -const struct OpProperties luaK_opproperties[NUM_OPCODES] = { - {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, 0, 0}, /* OP_PUSHNILJMP */ - {iS, 0, 0}, /* OP_FORPREP */ - {iS, 0, 3}, /* OP_FORLOOP */ - {iS, 2, 0}, /* OP_LFORPREP */ - {iS, 0, 3}, /* OP_LFORLOOP */ - {iAB, VD, 0} /* OP_CLOSURE */ -}; +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == iABC); + return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); +} + + +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); +} diff --git a/src/lcode.h b/src/lcode.h index 3f0a209a94..74908c6580 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.16 2000/08/09 14:49:13 roberto Exp $ +** $Id: lcode.h,v 1.38 2002/12/11 12:34:22 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -26,45 +26,49 @@ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_POW, OPR_CONCAT, - OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_NE, OPR_EQ, + OPR_LT, OPR_LE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_NOBINOPR } BinOpr; -typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; - +#define binopistest(op) ((op) >= OPR_NE) -enum Mode {iO, iU, iS, iAB}; /* instruction format */ +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; -#define VD 100 /* flag for variable delta */ -extern const struct OpProperties { - char mode; - unsigned char push; - unsigned char pop; -} luaK_opproperties[]; +#define getcode(fs,e) ((fs)->f->code[(e)->info]) +#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) -void luaK_error (LexState *ls, const char *msg); -int luaK_code0 (FuncState *fs, OpCode o); -int luaK_code1 (FuncState *fs, OpCode o, int arg1); -int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2); +int luaK_code (FuncState *fs, Instruction i, int line); +int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +void luaK_fixline (FuncState *fs, int line); +void luaK_nil (FuncState *fs, int from, int n); +void luaK_reserveregs (FuncState *fs, int n); +void luaK_checkstack (FuncState *fs, int n); +int luaK_stringK (FuncState *fs, TString *s); +int luaK_numberK (FuncState *fs, lua_Number r); +void luaK_dischargevars (FuncState *fs, expdesc *e); +int luaK_exp2anyreg (FuncState *fs, expdesc *e); +void luaK_exp2nextreg (FuncState *fs, expdesc *e); +void luaK_exp2val (FuncState *fs, expdesc *e); +int luaK_exp2RK (FuncState *fs, expdesc *e); +void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +void luaK_goiftrue (FuncState *fs, expdesc *e); +void luaK_goiffalse (FuncState *fs, expdesc *e); +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults); int luaK_jump (FuncState *fs); void luaK_patchlist (FuncState *fs, int list, int target); +void luaK_patchtohere (FuncState *fs, int list); void luaK_concat (FuncState *fs, int *l1, int l2); -void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue); int luaK_getlabel (FuncState *fs); -void luaK_deltastack (FuncState *fs, int delta); -void luaK_kstr (LexState *ls, int c); -void luaK_number (FuncState *fs, Number f); -void luaK_adjuststack (FuncState *fs, int n); -int luaK_lastisopen (FuncState *fs); -void luaK_setcallreturns (FuncState *fs, int nresults); -void luaK_tostack (LexState *ls, expdesc *v, int onlyone); -void luaK_storevar (LexState *ls, const expdesc *var); -void luaK_prefix (LexState *ls, UnOpr op, expdesc *v); -void luaK_infix (LexState *ls, BinOpr op, expdesc *v); -void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2); +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); #endif diff --git a/src/ldebug.c b/src/ldebug.c index a5a2ab1d90..8e511e3bd9 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,11 +1,14 @@ /* -** $Id: ldebug.c,v 1.50 2000/10/30 12:38:50 roberto Exp $ +** $Id: ldebug.c,v 1.150 2003/03/19 21:24:04 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ #include +#include + +#define ldebug_c #include "lua.h" @@ -20,447 +23,563 @@ #include "lstring.h" #include "ltable.h" #include "ltm.h" -#include "luadebug.h" +#include "lvm.h" -static const char *getfuncname (lua_State *L, StkId f, const char **name); +static const char *getfuncname (CallInfo *ci, const char **name); -static void setnormalized (TObject *d, const TObject *s) { - if (ttype(s) == LUA_TMARK) { - clvalue(d) = infovalue(s)->func; - ttype(d) = LUA_TFUNCTION; - } - else *d = *s; -} +#define isLua(ci) (!((ci)->state & CI_C)) -static int isLmark (StkId o) { - return (o && ttype(o) == LUA_TMARK && !infovalue(o)->func->isC); +static int currentpc (CallInfo *ci) { + if (!isLua(ci)) return -1; /* function is not a Lua function? */ + if (ci->state & CI_HASFRAME) /* function has a frame? */ + ci->u.l.savedpc = *ci->u.l.pc; /* use `pc' from there */ + /* function's pc is saved */ + return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); } -LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func) { - lua_Hook oldhook = L->callhook; - L->callhook = func; - return oldhook; +static int currentline (CallInfo *ci) { + int pc = currentpc(ci); + if (pc < 0) + return -1; /* only active lua functions have current-line information */ + else + return getline(ci_func(ci)->l.p, pc); } -LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) { - lua_Hook oldhook = L->linehook; - L->linehook = func; - return oldhook; +void luaG_inithooks (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != L->base_ci; ci--) /* update all `savedpc's */ + currentpc(ci); + L->hookinit = 1; } -static StkId aux_stackedfunction (lua_State *L, int level, StkId top) { - int i; - for (i = (top-1) - L->stack; i>=0; i--) { - if (is_T_MARK(L->stack[i].ttype)) { - if (level == 0) - return L->stack+i; - level--; - } +/* +** this function can be called asynchronous (e.g. during a signal) +*/ +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { + if (func == NULL || mask == 0) { /* turn off hooks? */ + mask = 0; + func = NULL; } - return NULL; + L->hook = func; + L->basehookcount = count; + resethookcount(L); + L->hookmask = cast(lu_byte, mask); + L->hookinit = 0; + return 1; } -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { - StkId f = aux_stackedfunction(L, level, L->top); - if (f == NULL) return 0; /* there is no such level */ - else { - ar->_func = f; - return 1; - } +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; } -static int nups (StkId f) { - switch (ttype(f)) { - case LUA_TFUNCTION: - return clvalue(f)->nupvalues; - case LUA_TMARK: - return infovalue(f)->func->nupvalues; - default: - return 0; - } +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; } -int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) { - int refi; - if (lineinfo == NULL || pc == -1) - return -1; /* no line info or function is not active */ - refi = prefi ? *prefi : 0; - if (lineinfo[refi] < 0) - refline += -lineinfo[refi++]; - LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); - while (lineinfo[refi] > pc) { - refline--; - refi--; - if (lineinfo[refi] < 0) - refline -= -lineinfo[refi--]; - LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); - } - for (;;) { - int nextline = refline + 1; - int nextref = refi + 1; - if (lineinfo[nextref] < 0) - nextline += -lineinfo[nextref++]; - LUA_ASSERT(lineinfo[nextref] >= 0, "invalid line info"); - if (lineinfo[nextref] > pc) - break; - refline = nextline; - refi = nextref; - } - if (prefi) *prefi = refi; - return refline; +LUA_API int lua_gethookcount (lua_State *L) { + return L->basehookcount; } -static int currentpc (StkId f) { - CallInfo *ci = infovalue(f); - LUA_ASSERT(isLmark(f), "function has no pc"); - if (ci->pc) - return (*ci->pc - ci->func->f.l->code) - 1; - else - return -1; /* function is not active */ -} - - -static int currentline (StkId f) { - if (!isLmark(f)) - return -1; /* only active lua functions have current-line information */ +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { + int status; + CallInfo *ci; + lua_lock(L); + for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { + level--; + if (!(ci->state & CI_C)) /* Lua function? */ + level -= ci->u.l.tailcalls; /* skip lost tail calls */ + } + if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ + else if (level < 0) { /* level is of a lost tail call */ + status = 1; + ar->i_ci = 0; + } else { - CallInfo *ci = infovalue(f); - int *lineinfo = ci->func->f.l->lineinfo; - return luaG_getline(lineinfo, currentpc(f), 1, NULL); + status = 1; + ar->i_ci = ci - L->base_ci; } + lua_unlock(L); + return status; } - -static Proto *getluaproto (StkId f) { - return (isLmark(f) ? infovalue(f)->func->f.l : NULL); +static Proto *getluaproto (CallInfo *ci) { + return (isLua(ci) ? ci_func(ci)->l.p : NULL); } LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { const char *name; - StkId f = ar->_func; - Proto *fp = getluaproto(f); - if (!fp) return NULL; /* `f' is not a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(f)); - if (!name) return NULL; - luaA_pushobject(L, (f+1)+(n-1)); /* push value */ + CallInfo *ci; + Proto *fp; + lua_lock(L); + name = NULL; + ci = L->base_ci + ar->i_ci; + fp = getluaproto(ci); + if (fp) { /* is a Lua function? */ + name = luaF_getlocalname(fp, n, currentpc(ci)); + if (name) + luaA_pushobject(L, ci->base+(n-1)); /* push value */ + } + lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { const char *name; - StkId f = ar->_func; - Proto *fp = getluaproto(f); + CallInfo *ci; + Proto *fp; + lua_lock(L); + name = NULL; + ci = L->base_ci + ar->i_ci; + fp = getluaproto(ci); L->top--; /* pop new value */ - if (!fp) return NULL; /* `f' is not a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(f)); - if (!name || name[0] == '(') return NULL; /* `(' starts private locals */ - *((f+1)+(n-1)) = *L->top; + if (fp) { /* is a Lua function? */ + name = luaF_getlocalname(fp, n, currentpc(ci)); + if (!name || name[0] == '(') /* `(' starts private locals */ + name = NULL; + else + setobjs2s(ci->base+(n-1), L->top); + } + lua_unlock(L); return name; } -static void infoLproto (lua_Debug *ar, Proto *f) { - ar->source = f->source->str; - ar->linedefined = f->lineDefined; - ar->what = "Lua"; -} - - -static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) { - Closure *cl = NULL; - switch (ttype(func)) { - case LUA_TFUNCTION: - cl = clvalue(func); - break; - case LUA_TMARK: - cl = infovalue(func)->func; - break; - default: - lua_error(L, "value for `lua_getinfo' is not a function"); - } - if (cl->isC) { - ar->source = "=C"; +static void funcinfo (lua_Debug *ar, StkId func) { + Closure *cl = clvalue(func); + if (cl->c.isC) { + ar->source = "=[C]"; ar->linedefined = -1; ar->what = "C"; } - else - infoLproto(ar, cl->f.l); - luaO_chunkid(ar->short_src, ar->source, sizeof(ar->short_src)); - if (ar->linedefined == 0) - ar->what = "main"; -} - - -static const char *travtagmethods (lua_State *L, const TObject *o) { - if (ttype(o) == LUA_TFUNCTION) { - int e; - for (e=0; elast_tag; t++) - if (clvalue(o) == luaT_gettm(L, t, e)) - return luaT_eventname[e]; - } + else { + ar->source = getstr(cl->l.p->source); + ar->linedefined = cl->l.p->lineDefined; + ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } - return NULL; + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); } static const char *travglobals (lua_State *L, const TObject *o) { - Hash *g = L->gt; - int i; - for (i=0; isize; i++) { - if (luaO_equalObj(o, val(node(g, i))) && - ttype(key(node(g, i))) == LUA_TSTRING) - return tsvalue(key(node(g, i)))->str; + Table *g = hvalue(gt(L)); + int i = sizenode(g); + while (i--) { + Node *n = gnode(g, i); + if (luaO_rawequalObj(o, gval(n)) && ttisstring(gkey(n))) + return getstr(tsvalue(gkey(n))); } return NULL; } -static void getname (lua_State *L, StkId f, lua_Debug *ar) { - TObject o; - setnormalized(&o, f); - /* try to find a name for given function */ - if ((ar->name = travglobals(L, &o)) != NULL) - ar->namewhat = "global"; - /* not found: try tag methods */ - else if ((ar->name = travtagmethods(L, &o)) != NULL) - ar->namewhat = "tag-method"; - else ar->namewhat = ""; /* not found at all */ +static void info_tailcall (lua_State *L, lua_Debug *ar) { + ar->name = ar->namewhat = ""; + ar->what = "tail"; + ar->linedefined = ar->currentline = -1; + ar->source = "=(tail call)"; + luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); + ar->nups = 0; + setnilvalue(L->top); } -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { - StkId func; - int isactive = (*what != '>'); - if (isactive) - func = ar->_func; - else { - what++; /* skip the '>' */ - func = L->top - 1; - } +static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, + StkId f, CallInfo *ci) { + int status = 1; for (; *what; what++) { switch (*what) { case 'S': { - funcinfo(L, ar, func); + funcinfo(ar, f); break; } case 'l': { - ar->currentline = currentline(func); + ar->currentline = (ci) ? currentline(ci) : -1; break; } case 'u': { - ar->nups = nups(func); + ar->nups = clvalue(f)->c.nupvalues; break; } case 'n': { - ar->namewhat = (isactive) ? getfuncname(L, func, &ar->name) : NULL; - if (ar->namewhat == NULL) - getname(L, func, ar); + ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; + if (ar->namewhat == NULL) { + /* try to find a global name */ + if ((ar->name = travglobals(L, f)) != NULL) + ar->namewhat = "global"; + else ar->namewhat = ""; /* not found */ + } break; } case 'f': { - setnormalized(L->top, func); - incr_top; /* push function */ + setobj2s(L->top, f); break; } - default: return 0; /* invalid option */ + default: status = 0; /* invalid option */ } } - if (!isactive) L->top--; /* pop function */ - return 1; + return status; +} + + +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { + int status = 1; + lua_lock(L); + if (*what == '>') { + StkId f = L->top - 1; + if (!ttisfunction(f)) + luaG_runerror(L, "value for `lua_getinfo' is not a function"); + status = auxgetinfo(L, what + 1, ar, f, NULL); + L->top--; /* pop function */ + } + else if (ar->i_ci != 0) { /* no tail call? */ + CallInfo *ci = L->base_ci + ar->i_ci; + lua_assert(ttisfunction(ci->base - 1)); + status = auxgetinfo(L, what, ar, ci->base - 1, ci); + } + else + info_tailcall(L, ar); + if (strchr(what, 'f')) incr_top(L); + lua_unlock(L); + return status; } /* ** {====================================================== -** Symbolic Execution +** Symbolic Execution and code checker ** ======================================================= */ +#define check(x) if (!(x)) return 0; + +#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) + +#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) + + -static int pushpc (int *stack, int pc, int top, int n) { - while (n--) - stack[top++] = pc-1; - return top; +static int precheck (const Proto *pt) { + check(pt->maxstacksize <= MAXSTACK); + check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); + lua_assert(pt->numparams+pt->is_vararg <= pt->maxstacksize); + check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); + return 1; } -static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { - int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */ - 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++]; - LUA_ASSERT(0 <= top && top <= pt->maxstacksize, "wrong stack"); - switch (GET_OPCODE(i)) { - case OP_RETURN: { - LUA_ASSERT(top >= GETARG_U(i), "wrong stack"); - top = GETARG_U(i); +static int checkopenop (const Proto *pt, int pc) { + Instruction i = pt->code[pc+1]; + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + case OP_RETURN: { + check(GETARG_B(i) == 0); + return 1; + } + case OP_SETLISTO: return 1; + default: return 0; /* invalid instruction after an open call */ + } +} + + +static int checkRK (const Proto *pt, int r) { + return (r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); +} + + +static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { + int pc; + int last; /* stores position of last instruction that changed `reg' */ + last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ + check(precheck(pt)); + for (pc = 0; pc < lastpc; pc++) { + const Instruction i = pt->code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + int b = 0; + int c = 0; + checkreg(pt, a); + switch (getOpMode(op)) { + case iABC: { + b = GETARG_B(i); + c = GETARG_C(i); + if (testOpMode(op, OpModeBreg)) { + checkreg(pt, b); + } + else if (testOpMode(op, OpModeBrk)) + check(checkRK(pt, b)); + if (testOpMode(op, OpModeCrk)) + check(checkRK(pt, c)); break; } - case OP_TAILCALL: { - LUA_ASSERT(top >= GETARG_A(i), "wrong stack"); - top = GETARG_B(i); + case iABx: { + b = GETARG_Bx(i); + if (testOpMode(op, OpModeK)) check(b < pt->sizek); + break; + } + case iAsBx: { + b = GETARG_sBx(i); break; } - case OP_CALL: { - int nresults = GETARG_B(i); - if (nresults == MULT_RET) nresults = 1; - LUA_ASSERT(top >= GETARG_A(i), "wrong stack"); - top = pushpc(stack, pc, GETARG_A(i), nresults); + } + if (testOpMode(op, OpModesetA)) { + if (a == reg) last = pc; /* change register `a' */ + } + if (testOpMode(op, OpModeT)) { + check(pc+2 < pt->sizecode); /* check skip */ + check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); + } + switch (op) { + case OP_LOADBOOL: { + check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ break; } - case OP_PUSHNIL: { - top = pushpc(stack, pc, top, GETARG_U(i)); + case OP_LOADNIL: { + if (a <= reg && reg <= b) + last = pc; /* set registers from `a' to `b' */ break; } - case OP_POP: { - top -= GETARG_U(i); + case OP_GETUPVAL: + case OP_SETUPVAL: { + check(b < pt->nups); break; } - case OP_SETTABLE: - case OP_SETLIST: { - top -= GETARG_B(i); + case OP_GETGLOBAL: + case OP_SETGLOBAL: { + check(ttisstring(&pt->k[b])); break; } - case OP_SETMAP: { - top -= 2*GETARG_U(i); + case OP_SELF: { + checkreg(pt, a+1); + if (reg == a+1) last = pc; break; } case OP_CONCAT: { - top -= GETARG_U(i); - stack[top++] = pc-1; + /* `c' is a register, and at least two operands */ + check(c < MAXSTACK && b < c); break; } - case OP_CLOSURE: { - top -= GETARG_B(i); - stack[top++] = pc-1; + case OP_TFORLOOP: + checkreg(pt, a+c+5); + if (reg >= a) last = pc; /* affect all registers above base */ + /* go through */ + case OP_FORLOOP: + checkreg(pt, a+2); + /* go through */ + case OP_JMP: { + int dest = pc+1+b; + check(0 <= dest && dest < pt->sizecode); + /* not full check and jump is forward and do not skip `lastpc'? */ + if (reg != NO_REG && pc < dest && dest <= lastpc) + pc += b; /* do the jump */ break; } - case OP_JMPONT: - case OP_JMPONF: { - int newpc = pc + GETARG_S(i); - /* jump is forward and do not skip `lastpc'? */ - if (pc < newpc && newpc <= lastpc) { - stack[top-1] = pc-1; /* value comes from `and'/`or' */ - pc = newpc; /* do the jump */ + case OP_CALL: + case OP_TAILCALL: { + if (b != 0) { + checkreg(pt, a+b-1); } - else - top--; /* do not jump; pop value */ + c--; /* c = num. returns */ + if (c == LUA_MULTRET) { + check(checkopenop(pt, pc)); + } + else if (c != 0) + checkreg(pt, a+c-1); + if (reg >= a) last = pc; /* affect all registers above base */ break; } - default: { - OpCode op = GET_OPCODE(i); - LUA_ASSERT(luaK_opproperties[op].push != VD, - "invalid opcode for default"); - top -= luaK_opproperties[op].pop; - LUA_ASSERT(top >= 0, "wrong stack"); - top = pushpc(stack, pc, top, luaK_opproperties[op].push); + case OP_RETURN: { + b--; /* b = num. returns */ + if (b > 0) checkreg(pt, a+b-1); + break; + } + case OP_SETLIST: { + checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); + break; + } + case OP_CLOSURE: { + int nup; + check(b < pt->sizep); + nup = pt->p[b]->nups; + check(pc + nup < pt->sizecode); + for (; nup>0; nup--) { + OpCode op1 = GET_OPCODE(pt->code[pc+nup]); + check(op1 == OP_GETUPVAL || op1 == OP_MOVE); + } + break; } + default: break; } } - return code[stack[stackpos]]; + return pt->code[last]; } +#undef check +#undef checkjump +#undef checkreg -static const char *getobjname (lua_State *L, StkId obj, const char **name) { - StkId func = aux_stackedfunction(L, 0, obj); - if (!isLmark(func)) - return NULL; /* not an active Lua function */ - else { - Proto *p = infovalue(func)->func->f.l; - int pc = currentpc(func); - int stackpos = obj - (func+1); /* func+1 == function base */ - Instruction i = luaG_symbexec(p, pc, stackpos); - LUA_ASSERT(pc != -1, "function must be active"); +/* }====================================================== */ + + +int luaG_checkcode (const Proto *pt) { + return luaG_symbexec(pt, pt->sizecode, NO_REG); +} + + +static const char *kname (Proto *p, int c) { + c = c - MAXSTACK; + if (c >= 0 && ttisstring(&p->k[c])) + return svalue(&p->k[c]); + else + return "?"; +} + + +static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { + if (isLua(ci)) { /* a Lua function? */ + Proto *p = ci_func(ci)->l.p; + int pc = currentpc(ci); + Instruction i; + *name = luaF_getlocalname(p, stackpos+1, pc); + if (*name) /* is a local? */ + return "local"; + i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */ + lua_assert(pc != -1); switch (GET_OPCODE(i)) { case OP_GETGLOBAL: { - *name = p->kstr[GETARG_U(i)]->str; + int g = GETARG_Bx(i); /* global index */ + lua_assert(ttisstring(&p->k[g])); + *name = svalue(&p->k[g]); return "global"; } - case OP_GETLOCAL: { - *name = luaF_getlocalname(p, GETARG_U(i)+1, pc); - LUA_ASSERT(*name, "local must exist"); - return "local"; + case OP_MOVE: { + int a = GETARG_A(i); + int b = GETARG_B(i); /* move from `b' to `a' */ + if (b < a) + return getobjname(ci, b, name); /* get name for `b' */ + break; } - case OP_PUSHSELF: - case OP_GETDOTTED: { - *name = p->kstr[GETARG_U(i)]->str; + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); return "field"; } - default: - return NULL; /* no useful name found */ + case OP_SELF: { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + return "method"; + } + default: break; } } + return NULL; /* no useful name found */ } -static const char *getfuncname (lua_State *L, StkId f, const char **name) { - StkId func = aux_stackedfunction(L, 0, f); /* calling function */ - if (!isLmark(func)) - return NULL; /* not an active Lua function */ - else { - Proto *p = infovalue(func)->func->f.l; - int pc = currentpc(func); - Instruction i; - if (pc == -1) return NULL; /* function is not activated */ - i = p->code[pc]; - switch (GET_OPCODE(i)) { - case OP_CALL: case OP_TAILCALL: - return getobjname(L, (func+1)+GETARG_A(i), name); - default: - return NULL; /* no useful name found */ - } - } +static const char *getfuncname (CallInfo *ci, const char **name) { + Instruction i; + if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci - 1)) + return NULL; /* calling function is not Lua (or is unknown) */ + ci--; /* calling function */ + i = ci_func(ci)->l.p->code[currentpc(ci)]; + if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL) + return getobjname(ci, GETARG_A(i), name); + else + return NULL; /* no useful name can be found */ } -/* }====================================================== */ +/* only ANSI way to check whether a pointer points to an array */ +static int isinstack (CallInfo *ci, const TObject *o) { + StkId p; + for (p = ci->base; p < ci->top; p++) + if (o == p) return 1; + return 0; +} -void luaG_typeerror (lua_State *L, StkId o, const char *op) { - const char *name; - const char *kind = getobjname(L, o, &name); - const char *t = luaO_typename(o); +void luaG_typeerror (lua_State *L, const TObject *o, const char *op) { + const char *name = NULL; + const char *t = luaT_typenames[ttype(o)]; + const char *kind = (isinstack(L->ci, o)) ? + getobjname(L->ci, o - L->base, &name) : NULL; if (kind) - luaO_verror(L, "attempt to %.30s %.20s `%.40s' (a %.10s value)", + luaG_runerror(L, "attempt to %s %s `%s' (a %s value)", op, kind, name, t); else - luaO_verror(L, "attempt to %.30s a %.10s value", op, t); + luaG_runerror(L, "attempt to %s a %s value", op, t); +} + + +void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { + if (ttisstring(p1)) p1 = p2; + lua_assert(!ttisstring(p1)); + luaG_typeerror(L, p1, "concatenate"); } -void luaG_binerror (lua_State *L, StkId p1, int t, const char *op) { - if (ttype(p1) == t) p1++; - LUA_ASSERT(ttype(p1) != t, "must be an error"); - luaG_typeerror(L, p1, op); +void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2) { + TObject temp; + if (luaV_tonumber(p1, &temp) == NULL) + p2 = p1; /* first operand is wrong */ + luaG_typeerror(L, p2, "perform arithmetic on"); } -void luaG_ordererror (lua_State *L, StkId top) { - const char *t1 = luaO_typename(top-2); - const char *t2 = luaO_typename(top-1); +int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) { + const char *t1 = luaT_typenames[ttype(p1)]; + const char *t2 = luaT_typenames[ttype(p2)]; if (t1[2] == t2[2]) - luaO_verror(L, "attempt to compare two %.10s values", t1); + luaG_runerror(L, "attempt to compare two %s values", t1); else - luaO_verror(L, "attempt to compare %.10s with %.10s", t1, t2); + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); + return 0; +} + + +static void addinfo (lua_State *L, const char *msg) { + CallInfo *ci = L->ci; + if (isLua(ci)) { /* is Lua code? */ + char buff[LUA_IDSIZE]; /* add file:line information */ + int line = currentline(ci); + luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); + luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); + } +} + + +void luaG_errormsg (lua_State *L) { + if (L->errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L->errfunc); + if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); + setobjs2s(L->top, L->top - 1); /* move argument */ + setobjs2s(L->top - 1, errfunc); /* push function */ + incr_top(L); + luaD_call(L, L->top - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); +} + + +void luaG_runerror (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + addinfo(L, luaO_pushvfstring(L, fmt, argp)); + va_end(argp); + luaG_errormsg(L); } diff --git a/src/ldebug.h b/src/ldebug.h index d4b2d3b08a..7ff395839c 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 1.7 2000/10/05 12:14:08 roberto Exp $ +** $Id: ldebug.h,v 1.32 2002/11/18 11:01:55 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -9,13 +9,23 @@ #include "lstate.h" -#include "luadebug.h" -void luaG_typeerror (lua_State *L, StkId o, const char *op); -void luaG_binerror (lua_State *L, StkId p1, int t, const char *op); -int luaG_getline (int *lineinfo, int pc, int refline, int *refi); -void luaG_ordererror (lua_State *L, StkId top); +#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) + +#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) + +#define resethookcount(L) (L->hookcount = L->basehookcount) + + +void luaG_inithooks (lua_State *L); +void luaG_typeerror (lua_State *L, const TObject *o, const char *opname); +void luaG_concaterror (lua_State *L, StkId p1, StkId p2); +void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2); +int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2); +void luaG_runerror (lua_State *L, const char *fmt, ...); +void luaG_errormsg (lua_State *L); +int luaG_checkcode (const Proto *pt); #endif diff --git a/src/ldo.c b/src/ldo.c index 8a779bbe03..ae4f22fd44 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,22 +1,25 @@ /* -** $Id: ldo.c,v 1.109a 2000/10/30 12:38:50 roberto Exp $ +** $Id: ldo.c,v 1.217 2003/04/03 13:35:34 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #include -#include #include #include +#define ldo_c + #include "lua.h" #include "ldebug.h" #include "ldo.h" +#include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" +#include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" @@ -27,362 +30,429 @@ #include "lzio.h" -/* space to handle stack overflow errors */ -#define EXTRA_STACK (2*LUA_MINSTACK) -void luaD_init (lua_State *L, int stacksize) { - L->stack = luaM_newvector(L, stacksize+EXTRA_STACK, TObject); - L->nblocks += stacksize*sizeof(TObject); - L->stack_last = L->stack+(stacksize-1); - L->stacksize = stacksize; - L->Cbase = L->top = L->stack; -} +/* +** {====================================================== +** Error-recovery functions (based on long jumps) +** ======================================================= +*/ -void luaD_checkstack (lua_State *L, int n) { - if (L->stack_last - L->top <= n) { /* stack overflow? */ - if (L->stack_last-L->stack > (L->stacksize-1)) { - /* overflow while handling overflow */ - luaD_breakrun(L, LUA_ERRERR); /* break run without error message */ +/* chain list of long jump buffers */ +struct lua_longjmp { + struct lua_longjmp *previous; + jmp_buf b; + volatile int status; /* error code */ +}; + + +static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { + setsvalue2s(oldtop, luaS_new(L, MEMERRMSG)); + break; + } + case LUA_ERRERR: { + setsvalue2s(oldtop, luaS_new(L, "error in error handling")); + break; } - else { - L->stack_last += EXTRA_STACK; /* to be used by error message */ - lua_error(L, "stack overflow"); + case LUA_ERRSYNTAX: + case LUA_ERRRUN: { + setobjs2s(oldtop, L->top - 1); /* error message on current top */ + break; } } + L->top = oldtop + 1; +} + + +void luaD_throw (lua_State *L, int errcode) { + if (L->errorJmp) { + L->errorJmp->status = errcode; + longjmp(L->errorJmp->b, 1); + } + else { + G(L)->panic(L); + exit(EXIT_FAILURE); + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + struct lua_longjmp lj; + lj.status = 0; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + if (setjmp(lj.b) == 0) + (*f)(L, ud); + L->errorJmp = lj.previous; /* restore old error handler */ + return lj.status; } static void restore_stack_limit (lua_State *L) { - if (L->top - L->stack < L->stacksize - 1) - L->stack_last = L->stack + (L->stacksize-1); + L->stack_last = L->stack+L->stacksize-1; + if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */ + int inuse = (L->ci - L->base_ci); + if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUA_MAXCALLS); + } } +/* }====================================================== */ -/* -** Adjust stack. Set top to base+extra, pushing NILs if needed. -** (we cannot add base+extra unless we are sure it fits in the stack; -** otherwise the result of such operation on pointers is undefined) -*/ -void luaD_adjusttop (lua_State *L, StkId base, int extra) { - int diff = extra-(L->top-base); - if (diff <= 0) - L->top = base+extra; - else { - luaD_checkstack(L, diff); - while (diff--) - ttype(L->top++) = LUA_TNIL; + +static void correctstack (lua_State *L, TObject *oldstack) { + CallInfo *ci; + GCObject *up; + L->top = (L->top - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->gch.next) + gcotouv(up)->v = (gcotouv(up)->v - oldstack) + L->stack; + for (ci = L->base_ci; ci <= L->ci; ci++) { + ci->top = (ci->top - oldstack) + L->stack; + ci->base = (ci->base - oldstack) + L->stack; } + L->base = L->ci->base; } -/* -** Open a hole inside the stack at `pos' -*/ -static void luaD_openstack (lua_State *L, StkId pos) { - int i = L->top-pos; - while (i--) pos[i+1] = pos[i]; - incr_top; +void luaD_reallocstack (lua_State *L, int newsize) { + TObject *oldstack = L->stack; + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject); + L->stacksize = newsize; + L->stack_last = L->stack+newsize-1-EXTRA_STACK; + correctstack(L, oldstack); } -static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) { - StkId old_Cbase = L->Cbase; - StkId old_top = L->Cbase = L->top; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - L->allowhooks = 0; /* cannot call hooks inside a hook */ - (*hook)(L, ar); - LUA_ASSERT(L->allowhooks == 0, "invalid allow"); - L->allowhooks = 1; - L->top = old_top; - L->Cbase = old_Cbase; +void luaD_reallocCI (lua_State *L, int newsize) { + CallInfo *oldci = L->base_ci; + luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); + L->size_ci = cast(unsigned short, newsize); + L->ci = (L->ci - oldci) + L->base_ci; + L->end_ci = L->base_ci + L->size_ci; } -void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) { - if (L->allowhooks) { - lua_Debug ar; - ar._func = func; - ar.event = "line"; - ar.currentline = line; - dohook(L, &ar, linehook); +void luaD_growstack (lua_State *L, int n) { + if (n <= L->stacksize) /* double size is enough? */ + luaD_reallocstack(L, 2*L->stacksize); + else + luaD_reallocstack(L, L->stacksize + n + EXTRA_STACK); +} + + +static void luaD_growCI (lua_State *L) { + if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */ + luaD_throw(L, LUA_ERRERR); + else { + luaD_reallocCI(L, 2*L->size_ci); + if (L->size_ci > LUA_MAXCALLS) + luaG_runerror(L, "stack overflow"); } } -static void luaD_callHook (lua_State *L, StkId func, lua_Hook callhook, - const char *event) { - if (L->allowhooks) { +void luaD_callhook (lua_State *L, int event, int line) { + lua_Hook hook = L->hook; + if (hook && L->allowhook) { + ptrdiff_t top = savestack(L, L->top); + ptrdiff_t ci_top = savestack(L, L->ci->top); lua_Debug ar; - ar._func = func; ar.event = event; - infovalue(func)->pc = NULL; /* function is not active */ - dohook(L, &ar, callhook); + ar.currentline = line; + if (event == LUA_HOOKTAILRET) + ar.i_ci = 0; /* tail call; no debug information about it */ + else + ar.i_ci = L->ci - L->base_ci; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + L->ci->top = L->top + LUA_MINSTACK; + L->allowhook = 0; /* cannot call hooks inside a hook */ + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!L->allowhook); + L->allowhook = 1; + L->ci->top = restorestack(L, ci_top); + L->top = restorestack(L, top); } } -static StkId callCclosure (lua_State *L, const struct Closure *cl, StkId base) { - int nup = cl->nupvalues; /* number of upvalues */ - StkId old_Cbase = L->Cbase; - int n; - L->Cbase = base; /* new base for C function */ - luaD_checkstack(L, nup+LUA_MINSTACK); /* ensure minimum stack size */ - for (n=0; ntop++) = cl->upvalue[n]; - n = (*cl->f.c)(L); /* do the actual call */ - L->Cbase = old_Cbase; /* restore old C base */ - return L->top - n; /* return index of first result */ +static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { + int i; + Table *htab; + TObject nname; + int actual = L->top - base; /* actual number of arguments */ + if (actual < nfixargs) { + luaD_checkstack(L, nfixargs - actual); + for (; actual < nfixargs; ++actual) + setnilvalue(L->top++); + } + actual -= nfixargs; /* number of extra arguments */ + htab = luaH_new(L, actual, 1); /* create `arg' table */ + for (i=0; itop - actual + i); + /* store counter in field `n' */ + setsvalue(&nname, luaS_newliteral(L, "n")); + setnvalue(luaH_set(L, htab, &nname), cast(lua_Number, actual)); + L->top -= actual; /* remove extra elements from the stack */ + sethvalue(L->top, htab); + incr_top(L); } -void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults) { - StkId base = L->top - nParams; - luaD_openstack(L, base); - clvalue(base) = f; - ttype(base) = LUA_TFUNCTION; - luaD_call(L, base, nResults); +static StkId tryfuncTM (lua_State *L, StkId func) { + const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); + StkId p; + ptrdiff_t funcr = savestack(L, func); + if (!ttisfunction(tm)) + luaG_typeerror(L, func, "call"); + /* Open a hole inside the stack at `func' */ + for (p = L->top; p > func; p--) setobjs2s(p, p-1); + incr_top(L); + func = restorestack(L, funcr); /* previous call may change stack */ + setobj2s(func, tm); /* tag method is the new function to be called */ + return func; } -/* -** Call a function (C or Lua). The function to be called is at *func. -** The arguments are on the stack, right after the function. -** When returns, the results are on the stack, starting at the original -** function position. -** The number of results is nResults, unless nResults=LUA_MULTRET. -*/ -void luaD_call (lua_State *L, StkId func, int nResults) { - lua_Hook callhook; - StkId firstResult; - CallInfo ci; - Closure *cl; - if (ttype(func) != LUA_TFUNCTION) { - /* `func' is not a function; check the `function' tag method */ - Closure *tm = luaT_gettmbyObj(L, func, TM_FUNCTION); - if (tm == NULL) - luaG_typeerror(L, func, "call"); - luaD_openstack(L, func); - clvalue(func) = tm; /* tag method is the new function to be called */ - ttype(func) = LUA_TFUNCTION; +StkId luaD_precall (lua_State *L, StkId func) { + LClosure *cl; + ptrdiff_t funcr = savestack(L, func); + if (!ttisfunction(func)) /* `func' is not a function? */ + func = tryfuncTM(L, func); /* check the `function' tag method */ + if (L->ci + 1 == L->end_ci) luaD_growCI(L); + else condhardstacktests(luaD_reallocCI(L, L->size_ci)); + cl = &clvalue(func)->l; + if (!cl->isC) { /* Lua function? prepare its call */ + CallInfo *ci; + Proto *p = cl->p; + if (p->is_vararg) /* varargs? */ + adjust_varargs(L, p->numparams, func+1); + luaD_checkstack(L, p->maxstacksize); + ci = ++L->ci; /* now `enter' new function */ + L->base = L->ci->base = restorestack(L, funcr) + 1; + ci->top = L->base + p->maxstacksize; + ci->u.l.savedpc = p->code; /* starting point */ + ci->u.l.tailcalls = 0; + ci->state = CI_SAVEDPC; + while (L->top < ci->top) + setnilvalue(L->top++); + L->top = ci->top; + return NULL; } - cl = clvalue(func); - ci.func = cl; - infovalue(func) = &ci; - ttype(func) = LUA_TMARK; - callhook = L->callhook; - if (callhook) - luaD_callHook(L, func, callhook, "call"); - firstResult = (cl->isC ? callCclosure(L, cl, func+1) : - luaV_execute(L, cl, func+1)); - if (callhook) /* same hook that was active at entry */ - luaD_callHook(L, func, callhook, "return"); - LUA_ASSERT(ttype(func) == LUA_TMARK, "invalid tag"); - /* move results to `func' (to erase parameters and function) */ - if (nResults == LUA_MULTRET) { - while (firstResult < L->top) /* copy all results */ - *func++ = *firstResult++; - L->top = func; + else { /* if is a C function, call it */ + CallInfo *ci; + int n; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci = ++L->ci; /* now `enter' new function */ + L->base = L->ci->base = restorestack(L, funcr) + 1; + ci->top = L->top + LUA_MINSTACK; + ci->state = CI_C; /* a C function */ + if (L->hookmask & LUA_MASKCALL) + luaD_callhook(L, LUA_HOOKCALL, -1); + lua_unlock(L); +#ifdef LUA_COMPATUPVALUES + lua_pushupvalues(L); +#endif + n = (*clvalue(L->base - 1)->c.f)(L); /* do the actual call */ + lua_lock(L); + return L->top - n; } - else { /* copy at most `nResults' */ - for (; nResults > 0 && firstResult < L->top; nResults--) - *func++ = *firstResult++; - L->top = func; - for (; nResults > 0; nResults--) { /* if there are not enough results */ - ttype(L->top) = LUA_TNIL; /* adjust the stack */ - incr_top; /* must check stack space */ - } - } - luaC_checkGC(L); } -/* -** Execute a protected call. -*/ -struct CallS { /* data to `f_call' */ - StkId func; - int nresults; -}; - -static void f_call (lua_State *L, void *ud) { - struct CallS *c = (struct CallS *)ud; - luaD_call(L, c->func, c->nresults); +static StkId callrethooks (lua_State *L, StkId firstResult) { + ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ + luaD_callhook(L, LUA_HOOKRET, -1); + if (!(L->ci->state & CI_C)) { /* Lua function? */ + while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ + luaD_callhook(L, LUA_HOOKTAILRET, -1); + } + return restorestack(L, fr); } -LUA_API int lua_call (lua_State *L, int nargs, int nresults) { - StkId func = L->top - (nargs+1); /* function to be called */ - struct CallS c; - int status; - c.func = func; c.nresults = nresults; - status = luaD_runprotected(L, f_call, &c); - if (status != 0) /* an error occurred? */ - L->top = func; /* remove parameters from the stack */ - return status; +void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { + StkId res; + if (L->hookmask & LUA_MASKRET) + firstResult = callrethooks(L, firstResult); + res = L->base - 1; /* res == final position of 1st result */ + L->ci--; + L->base = L->ci->base; /* restore base */ + /* move results to correct place */ + while (wanted != 0 && firstResult < L->top) { + setobjs2s(res++, firstResult++); + wanted--; + } + while (wanted-- > 0) + setnilvalue(res++); + L->top = res; } /* -** Execute a protected parser. -*/ -struct ParserS { /* data to `f_parser' */ - ZIO *z; - int bin; -}; - -static void f_parser (lua_State *L, void *ud) { - struct ParserS *p = (struct ParserS *)ud; - Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z); - luaV_Lclosure(L, tf, 0); +** Call a function (C or Lua). The function to be called is at *func. +** The arguments are on the stack, right after the function. +** When returns, all the results are on the stack, starting at the original +** function position. +*/ +void luaD_call (lua_State *L, StkId func, int nResults) { + StkId firstResult; + lua_assert(!(L->ci->state & CI_CALLING)); + if (++L->nCcalls >= LUA_MAXCCALLS) { + if (L->nCcalls == LUA_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + } + firstResult = luaD_precall(L, func); + if (firstResult == NULL) /* is a Lua function? */ + firstResult = luaV_execute(L); /* call it */ + luaD_poscall(L, nResults, firstResult); + L->nCcalls--; + luaC_checkGC(L); } -static int protectedparser (lua_State *L, ZIO *z, int bin) { - struct ParserS p; - unsigned long old_blocks; - int status; - p.z = z; p.bin = bin; - /* before parsing, give a (good) chance to GC */ - if (L->nblocks/8 >= L->GCthreshold/10) - luaC_collectgarbage(L); - old_blocks = L->nblocks; - status = luaD_runprotected(L, f_parser, &p); - if (status == 0) { - /* add new memory to threshold (as it probably will stay) */ - L->GCthreshold += (L->nblocks - old_blocks); +static void resume (lua_State *L, void *ud) { + StkId firstResult; + int nargs = *cast(int *, ud); + CallInfo *ci = L->ci; + if (ci == L->base_ci) { /* no activation record? */ + if (nargs >= L->top - L->base) + luaG_runerror(L, "cannot resume dead coroutine"); + luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ } - else if (status == LUA_ERRRUN) /* an error occurred: correct error code */ - status = LUA_ERRSYNTAX; - return status; + else if (ci->state & CI_YIELD) { /* inside a yield? */ + if (ci->state & CI_C) { /* `common' yield? */ + /* finish interrupted execution of `OP_CALL' */ + int nresults; + lua_assert((ci-1)->state & CI_SAVEDPC); + lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || + GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); + nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; + luaD_poscall(L, nresults, L->top - nargs); /* complete it */ + if (nresults >= 0) L->top = L->ci->top; + } + else { /* yielded inside a hook: just continue its execution */ + ci->state &= ~CI_YIELD; + } + } + else + luaG_runerror(L, "cannot resume non-suspended coroutine"); + firstResult = luaV_execute(L); + if (firstResult != NULL) /* return? */ + luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ } -static int parse_file (lua_State *L, const char *filename) { - ZIO z; +LUA_API int lua_resume (lua_State *L, int nargs) { int status; - int bin; /* flag for file mode */ - int c; /* look ahead char */ - FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); - if (f == NULL) return LUA_ERRFILE; /* unable to open file */ - c = fgetc(f); - ungetc(c, f); - bin = (c == ID_CHUNK); - if (bin && f != stdin) { - f = freopen(filename, "rb", f); /* set binary mode */ - if (f == NULL) return LUA_ERRFILE; /* unable to reopen file */ + lu_byte old_allowhooks; + lua_lock(L); + old_allowhooks = L->allowhook; + lua_assert(L->errfunc == 0 && L->nCcalls == 0); + status = luaD_rawrunprotected(L, resume, &nargs); + if (status != 0) { /* error? */ + L->ci = L->base_ci; /* go back to initial level */ + L->base = L->ci->base; + L->nCcalls = 0; + luaF_close(L, L->base); /* close eventual pending closures */ + seterrorobj(L, status, L->base); + L->allowhook = old_allowhooks; + restore_stack_limit(L); } - lua_pushstring(L, "@"); - lua_pushstring(L, (filename == NULL) ? "(stdin)" : filename); - lua_concat(L, 2); - c = lua_gettop(L); - filename = lua_tostring(L, c); /* filename = '@'..filename */ - luaZ_Fopen(&z, f, filename); - status = protectedparser(L, &z, bin); - lua_remove(L, c); /* remove `filename' from the stack */ - if (f != stdin) - fclose(f); - return status; -} - - -LUA_API int lua_dofile (lua_State *L, const char *filename) { - int status = parse_file(L, filename); - if (status == 0) /* parse OK? */ - status = lua_call(L, 0, LUA_MULTRET); /* call main */ + lua_unlock(L); return status; } -static int parse_buffer (lua_State *L, const char *buff, size_t size, - const char *name) { - ZIO z; - if (!name) name = "?"; - luaZ_mopen(&z, buff, size, name); - return protectedparser(L, &z, buff[0]==ID_CHUNK); +LUA_API int lua_yield (lua_State *L, int nresults) { + CallInfo *ci; + lua_lock(L); + ci = L->ci; + if (L->nCcalls > 0) + luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + if (ci->state & CI_C) { /* usual yield */ + if ((ci-1)->state & CI_C) + luaG_runerror(L, "cannot yield a C function"); + if (L->top - nresults > L->base) { /* is there garbage in the stack? */ + int i; + for (i=0; ibase + i, L->top - nresults + i); + L->top = L->base + nresults; + } + } /* else it's an yield inside a hook: nothing to do */ + ci->state |= CI_YIELD; + lua_unlock(L); + return -1; } -LUA_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name) { - int status = parse_buffer(L, buff, size, name); - if (status == 0) /* parse OK? */ - status = lua_call(L, 0, LUA_MULTRET); /* call main */ +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + unsigned short oldnCcalls = L->nCcalls; + ptrdiff_t old_ci = saveci(L, L->ci); + lu_byte old_allowhooks = L->allowhook; + ptrdiff_t old_errfunc = L->errfunc; + L->errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (status != 0) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close eventual pending closures */ + seterrorobj(L, status, oldtop); + L->nCcalls = oldnCcalls; + L->ci = restoreci(L, old_ci); + L->base = L->ci->base; + L->allowhook = old_allowhooks; + restore_stack_limit(L); + } + L->errfunc = old_errfunc; return status; } -LUA_API int lua_dostring (lua_State *L, const char *str) { - return lua_dobuffer(L, str, strlen(str), str); -} - /* -** {====================================================== -** Error-recover functions (based on long jumps) -** ======================================================= +** Execute a protected parser. */ - -/* chain list of long jump buffers */ -struct lua_longjmp { - jmp_buf b; - struct lua_longjmp *previous; - volatile int status; /* error code */ +struct SParser { /* data to `f_parser' */ + ZIO *z; + Mbuffer buff; /* buffer to be used by the scanner */ + int bin; }; - -static void message (lua_State *L, const char *s) { - const TObject *em = luaH_getglobal(L, LUA_ERRORMESSAGE); - if (ttype(em) == LUA_TFUNCTION) { - *L->top = *em; - incr_top; - lua_pushstring(L, s); - luaD_call(L, L->top-2, 0); - } -} - - -/* -** Reports an error, and jumps up to the available recovery label -*/ -LUA_API void lua_error (lua_State *L, const char *s) { - if (s) message(L, s); - luaD_breakrun(L, LUA_ERRRUN); -} - - -void luaD_breakrun (lua_State *L, int errcode) { - if (L->errorJmp) { - L->errorJmp->status = errcode; - longjmp(L->errorJmp->b, 1); - } - else { - if (errcode != LUA_ERRMEM) - message(L, "unable to recover; exiting\n"); - exit(EXIT_FAILURE); - } +static void f_parser (lua_State *L, void *ud) { + struct SParser *p; + Proto *tf; + Closure *cl; + luaC_checkGC(L); + p = cast(struct SParser *, ud); + tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff); + cl = luaF_newLclosure(L, 0, gt(L)); + cl->l.p = tf; + setclvalue(L->top, cl); + incr_top(L); } -int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) { - StkId oldCbase = L->Cbase; - StkId oldtop = L->top; - struct lua_longjmp lj; - int allowhooks = L->allowhooks; - lj.status = 0; - lj.previous = L->errorJmp; /* chain new error handler */ - L->errorJmp = &lj; - if (setjmp(lj.b) == 0) - (*f)(L, ud); - else { /* an error occurred: restore the state */ - L->allowhooks = allowhooks; - L->Cbase = oldCbase; - L->top = oldtop; - restore_stack_limit(L); +int luaD_protectedparser (lua_State *L, ZIO *z, int bin) { + struct SParser p; + int status; + ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */ + p.z = z; p.bin = bin; + luaZ_initbuffer(L, &p.buff); + status = luaD_rawrunprotected(L, f_parser, &p); + luaZ_freebuffer(L, &p.buff); + if (status != 0) { /* error? */ + StkId oldtop = restorestack(L, oldtopr); + seterrorobj(L, status, oldtop); } - L->errorJmp = lj.previous; /* restore old error handler */ - return lj.status; + return status; } -/* }====================================================== */ diff --git a/src/ldo.h b/src/ldo.h index 3fba1f5650..2a61bf5bb2 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.28 2000/10/06 12:45:25 roberto Exp $ +** $Id: ldo.h,v 1.56 2002/12/04 17:29:32 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -10,24 +10,51 @@ #include "lobject.h" #include "lstate.h" +#include "lzio.h" /* -** macro to increment stack top. -** There must be always an empty slot at the L->stack.top -*/ -#define incr_top {if (L->top == L->stack_last) luaD_checkstack(L, 1); L->top++;} +** macro to control inclusion of some hard tests on stack reallocation +*/ +#ifndef HARDSTACKTESTS +#define condhardstacktests(x) { /* empty */ } +#else +#define condhardstacktests(x) x +#endif -void luaD_init (lua_State *L, int stacksize); -void luaD_adjusttop (lua_State *L, StkId base, int extra); -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, Closure *f, int nParams, int nResults); -void luaD_checkstack (lua_State *L, int n); +#define luaD_checkstack(L,n) \ + if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TObject)) \ + luaD_growstack(L, n); \ + else condhardstacktests(luaD_reallocstack(L, L->stacksize)); + + +#define incr_top(L) {luaD_checkstack(L,1); L->top++;} -void luaD_breakrun (lua_State *L, int errcode); -int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud); +#define savestack(L,p) ((char *)(p) - (char *)L->stack) +#define restorestack(L,n) ((TObject *)((char *)L->stack + (n))) + +#define saveci(L,p) ((char *)(p) - (char *)L->base_ci) +#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) + + +/* type of protected functions, to be ran by `runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +void luaD_resetprotection (lua_State *L); +int luaD_protectedparser (lua_State *L, ZIO *z, int bin); +void luaD_callhook (lua_State *L, int event, int line); +StkId luaD_precall (lua_State *L, StkId func); +void luaD_call (lua_State *L, StkId func, int nResults); +int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +void luaD_poscall (lua_State *L, int wanted, StkId firstResult); +void luaD_reallocCI (lua_State *L, int newsize); +void luaD_reallocstack (lua_State *L, int newsize); +void luaD_growstack (lua_State *L, int n); + +void luaD_throw (lua_State *L, int errcode); +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); #endif diff --git a/src/ldump.c b/src/ldump.c new file mode 100644 index 0000000000..234b011f5f --- /dev/null +++ b/src/ldump.c @@ -0,0 +1,170 @@ +/* +** $Id: ldump.c,v 1.4 2003/02/11 23:52:12 lhf Exp $ +** save bytecodes +** See Copyright Notice in lua.h +*/ + +#include + +#define ldump_c + +#include "lua.h" + +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lundump.h" + +#define DumpVector(b,n,size,D) DumpBlock(b,(n)*(size),D) +#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D) + +typedef struct { + lua_State* L; + lua_Chunkwriter write; + void* data; +} DumpState; + +static void DumpBlock(const void* b, size_t size, DumpState* D) +{ + lua_unlock(D->L); + (*D->write)(D->L,b,size,D->data); + lua_lock(D->L); +} + +static void DumpByte(int y, DumpState* D) +{ + char x=(char)y; + DumpBlock(&x,sizeof(x),D); +} + +static void DumpInt(int x, DumpState* D) +{ + DumpBlock(&x,sizeof(x),D); +} + +static void DumpSize(size_t x, DumpState* D) +{ + DumpBlock(&x,sizeof(x),D); +} + +static void DumpNumber(lua_Number x, DumpState* D) +{ + DumpBlock(&x,sizeof(x),D); +} + +static void DumpString(TString* s, DumpState* D) +{ + if (s==NULL || getstr(s)==NULL) + DumpSize(0,D); + else + { + size_t size=s->tsv.len+1; /* include trailing '\0' */ + DumpSize(size,D); + DumpBlock(getstr(s),size,D); + } +} + +static void DumpCode(const Proto* f, DumpState* D) +{ + DumpInt(f->sizecode,D); + DumpVector(f->code,f->sizecode,sizeof(*f->code),D); +} + +static void DumpLocals(const Proto* f, DumpState* D) +{ + int i,n=f->sizelocvars; + DumpInt(n,D); + for (i=0; ilocvars[i].varname,D); + DumpInt(f->locvars[i].startpc,D); + DumpInt(f->locvars[i].endpc,D); + } +} + +static void DumpLines(const Proto* f, DumpState* D) +{ + DumpInt(f->sizelineinfo,D); + DumpVector(f->lineinfo,f->sizelineinfo,sizeof(*f->lineinfo),D); +} + +static void DumpUpvalues(const Proto* f, DumpState* D) +{ + int i,n=f->sizeupvalues; + DumpInt(n,D); + for (i=0; iupvalues[i],D); +} + +static void DumpFunction(const Proto* f, const TString* p, DumpState* D); + +static void DumpConstants(const Proto* f, DumpState* D) +{ + int i,n; + DumpInt(n=f->sizek,D); + for (i=0; ik[i]; + DumpByte(ttype(o),D); + switch (ttype(o)) + { + case LUA_TNUMBER: + DumpNumber(nvalue(o),D); + break; + case LUA_TSTRING: + DumpString(tsvalue(o),D); + break; + case LUA_TNIL: + break; + default: + lua_assert(0); /* cannot happen */ + break; + } + } + DumpInt(n=f->sizep,D); + for (i=0; ip[i],f->source,D); +} + +static void DumpFunction(const Proto* f, const TString* p, DumpState* D) +{ + DumpString((f->source==p) ? NULL : f->source,D); + DumpInt(f->lineDefined,D); + DumpByte(f->nups,D); + DumpByte(f->numparams,D); + DumpByte(f->is_vararg,D); + DumpByte(f->maxstacksize,D); + DumpLines(f,D); + DumpLocals(f,D); + DumpUpvalues(f,D); + DumpConstants(f,D); + DumpCode(f,D); +} + +static void DumpHeader(DumpState* D) +{ + DumpLiteral(LUA_SIGNATURE,D); + DumpByte(VERSION,D); + DumpByte(luaU_endianness(),D); + DumpByte(sizeof(int),D); + DumpByte(sizeof(size_t),D); + DumpByte(sizeof(Instruction),D); + DumpByte(SIZE_OP,D); + DumpByte(SIZE_A,D); + DumpByte(SIZE_B,D); + DumpByte(SIZE_C,D); + DumpByte(sizeof(lua_Number),D); + DumpNumber(TEST_NUMBER,D); +} + +/* +** dump function as precompiled chunk +*/ +void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data) +{ + DumpState D; + D.L=L; + D.write=w; + D.data=data; + DumpHeader(&D); + DumpFunction(Main,NULL,&D); +} + diff --git a/src/lfunc.c b/src/lfunc.c index 6841ef71a5..31044fa56b 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 1.34 2000/10/30 12:20:29 roberto Exp $ +** $Id: lfunc.c,v 1.67 2003/03/18 12:50:04 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -7,87 +7,113 @@ #include +#define lfunc_c + #include "lua.h" #include "lfunc.h" +#include "lgc.h" #include "lmem.h" +#include "lobject.h" #include "lstate.h" -#define sizeclosure(n) ((int)sizeof(Closure) + (int)sizeof(TObject)*((n)-1)) +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TObject)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TObject *)*((n)-1))) + -Closure *luaF_newclosure (lua_State *L, int nelems) { - int size = sizeclosure(nelems); - Closure *c = (Closure *)luaM_malloc(L, size); - c->next = L->rootcl; - L->rootcl = c; - c->mark = c; - c->nupvalues = nelems; - L->nblocks += size; +Closure *luaF_newCclosure (lua_State *L, int nelems) { + Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); + luaC_link(L, valtogco(c), LUA_TFUNCTION); + c->c.isC = 1; + c->c.nupvalues = cast(lu_byte, nelems); return c; } +Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) { + Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); + luaC_link(L, valtogco(c), LUA_TFUNCTION); + c->l.isC = 0; + c->l.g = *e; + c->l.nupvalues = cast(lu_byte, nelems); + return c; +} + + +UpVal *luaF_findupval (lua_State *L, StkId level) { + GCObject **pp = &L->openupval; + UpVal *p; + UpVal *v; + while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { + if (p->v == level) return p; + pp = &p->next; + } + v = luaM_new(L, UpVal); /* not found: create a new one */ + v->tt = LUA_TUPVAL; + v->marked = 1; /* open upvalues should not be collected */ + v->v = level; /* current value lives in the stack */ + v->next = *pp; /* chain it in the proper position */ + *pp = valtogco(v); + return v; +} + + +void luaF_close (lua_State *L, StkId level) { + UpVal *p; + while ((p = ngcotouv(L->openupval)) != NULL && p->v >= level) { + setobj(&p->value, p->v); /* save current value (write barrier) */ + p->v = &p->value; /* now current value lives here */ + L->openupval = p->next; /* remove from `open' list */ + luaC_link(L, valtogco(p), LUA_TUPVAL); + } +} + + Proto *luaF_newproto (lua_State *L) { Proto *f = luaM_new(L, Proto); - f->knum = NULL; - f->nknum = 0; - f->kstr = NULL; - f->nkstr = 0; - f->kproto = NULL; - f->nkproto = 0; + luaC_link(L, valtogco(f), LUA_TPROTO); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; f->code = NULL; - f->ncode = 0; + f->sizecode = 0; + f->sizelineinfo = 0; + f->sizeupvalues = 0; + f->nups = 0; + f->upvalues = NULL; f->numparams = 0; f->is_vararg = 0; f->maxstacksize = 0; - f->marked = 0; f->lineinfo = NULL; - f->nlineinfo = 0; - f->nlocvars = 0; + f->sizelocvars = 0; f->locvars = NULL; f->lineDefined = 0; f->source = NULL; - f->next = L->rootproto; /* chain in list of protos */ - L->rootproto = f; return f; } -static size_t protosize (Proto *f) { - return sizeof(Proto) - + f->nknum*sizeof(Number) - + f->nkstr*sizeof(TString *) - + f->nkproto*sizeof(Proto *) - + f->ncode*sizeof(Instruction) - + f->nlocvars*sizeof(struct LocVar) - + f->nlineinfo*sizeof(int); -} - - -void luaF_protook (lua_State *L, Proto *f, int pc) { - f->ncode = pc; /* signal that proto was properly created */ - L->nblocks += protosize(f); -} - - void luaF_freeproto (lua_State *L, Proto *f) { - if (f->ncode > 0) /* function was properly created? */ - L->nblocks -= protosize(f); - luaM_free(L, f->code); - luaM_free(L, f->locvars); - luaM_free(L, f->kstr); - luaM_free(L, f->knum); - luaM_free(L, f->kproto); - luaM_free(L, f->lineinfo); - luaM_free(L, f); + luaM_freearray(L, f->code, f->sizecode, Instruction); + luaM_freearray(L, f->p, f->sizep, Proto *); + luaM_freearray(L, f->k, f->sizek, TObject); + luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); + luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); + luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); + luaM_freelem(L, f); } void luaF_freeclosure (lua_State *L, Closure *c) { - L->nblocks -= sizeclosure(c->nupvalues); - luaM_free(L, c); + int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : + sizeLclosure(c->l.nupvalues); + luaM_free(L, c, size); } @@ -97,11 +123,11 @@ void luaF_freeclosure (lua_State *L, Closure *c) { */ const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { int i; - for (i = 0; inlocvars && f->locvars[i].startpc <= pc; i++) { + for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { if (pc < f->locvars[i].endpc) { /* is variable active? */ local_number--; if (local_number == 0) - return f->locvars[i].varname->str; + return getstr(f->locvars[i].varname); } } return NULL; /* not found */ diff --git a/src/lfunc.h b/src/lfunc.h index 32afbc5d30..5d5325076b 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 1.13 2000/09/29 12:42:13 roberto Exp $ +** $Id: lfunc.h,v 1.21 2003/03/18 12:50:04 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -11,10 +11,11 @@ #include "lobject.h" - Proto *luaF_newproto (lua_State *L); -void luaF_protook (lua_State *L, Proto *f, int pc); -Closure *luaF_newclosure (lua_State *L, int nelems); +Closure *luaF_newCclosure (lua_State *L, int nelems); +Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e); +UpVal *luaF_findupval (lua_State *L, StkId level); +void luaF_close (lua_State *L, StkId level); void luaF_freeproto (lua_State *L, Proto *f); void luaF_freeclosure (lua_State *L, Closure *c); diff --git a/src/lgc.c b/src/lgc.c index f1eee9ab09..4cc45e39d0 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,11 +1,16 @@ /* -** $Id: lgc.c,v 1.72+ 2000/10/26 12:47:05 roberto Exp $ +** $Id: lgc.c,v 1.171 2003/04/03 13:35:34 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ +#include + +#define lgc_c + #include "lua.h" +#include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" @@ -18,336 +23,471 @@ typedef struct GCState { - Hash *tmark; /* list of marked tables to be visited */ - Closure *cmark; /* list of marked closures to be visited */ + GCObject *tmark; /* list of marked objects to be traversed */ + GCObject *wk; /* list of traversed key-weak tables (to be cleared) */ + GCObject *wv; /* list of traversed value-weak tables */ + GCObject *wkv; /* list of traversed key-value weak tables */ + global_State *g; } GCState; +/* +** some userful bit tricks +*/ +#define setbit(x,b) ((x) |= (1<<(b))) +#define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b)))) +#define testbit(x,b) ((x) & (1<<(b))) -static void markobject (GCState *st, TObject *o); +#define unmark(x) resetbit((x)->gch.marked, 0) +#define ismarked(x) ((x)->gch.marked & ((1<<4)|1)) +#define stringmark(s) setbit((s)->tsv.marked, 0) -/* mark a string; marks larger than 1 cannot be changed */ -#define strmark(s) {if ((s)->marked == 0) (s)->marked = 1;} +#define isfinalized(u) (!testbit((u)->uv.marked, 1)) +#define markfinalized(u) resetbit((u)->uv.marked, 1) -static void protomark (Proto *f) { - if (!f->marked) { - int i; - f->marked = 1; - strmark(f->source); - for (i=0; inkstr; i++) - strmark(f->kstr[i]); - for (i=0; inkproto; i++) - protomark(f->kproto[i]); - for (i=0; inlocvars; i++) /* mark local-variable names */ - strmark(f->locvars[i].varname); - } -} +#define KEYWEAKBIT 1 +#define VALUEWEAKBIT 2 +#define KEYWEAK (1<stack; otop; o++) - markobject(st, o); -} +#define markobject(st,o) { checkconsistency(o); \ + if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); } -static void marklock (lua_State *L, GCState *st) { - int i; - for (i=0; irefSize; i++) { - if (L->refArray[i].st == LOCK) - markobject(st, &L->refArray[i].o); +#define condmarkobject(st,o,c) { checkconsistency(o); \ + if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \ + reallymarkobject(st,gcvalue(o)); } + +#define markvalue(st,t) { if (!ismarked(valtogco(t))) \ + reallymarkobject(st, valtogco(t)); } + + + +static void reallymarkobject (GCState *st, GCObject *o) { + lua_assert(!ismarked(o)); + setbit(o->gch.marked, 0); /* mark object */ + switch (o->gch.tt) { + case LUA_TUSERDATA: { + markvalue(st, gcotou(o)->uv.metatable); + break; + } + case LUA_TFUNCTION: { + gcotocl(o)->c.gclist = st->tmark; + st->tmark = o; + break; + } + case LUA_TTABLE: { + gcotoh(o)->gclist = st->tmark; + st->tmark = o; + break; + } + case LUA_TTHREAD: { + gcototh(o)->gclist = st->tmark; + st->tmark = o; + break; + } + case LUA_TPROTO: { + gcotop(o)->gclist = st->tmark; + st->tmark = o; + break; + } + default: lua_assert(o->gch.tt == LUA_TSTRING); } } -static void markclosure (GCState *st, Closure *cl) { - if (!ismarked(cl)) { - if (!cl->isC) - protomark(cl->f.l); - cl->mark = st->cmark; /* chain it for later traversal */ - st->cmark = cl; +static void marktmu (GCState *st) { + GCObject *u; + for (u = st->g->tmudata; u; u = u->gch.next) { + unmark(u); /* may be marked, if left from previous GC */ + reallymarkobject(st, u); } } -static void marktagmethods (lua_State *L, GCState *st) { - int e; - for (e=0; elast_tag; t++) { - Closure *cl = luaT_gettm(L, t, e); - if (cl) markclosure(st, cl); +/* move `dead' udata that need finalization to list `tmudata' */ +void luaC_separateudata (lua_State *L) { + GCObject **p = &G(L)->rootudata; + GCObject *curr; + GCObject *collected = NULL; /* to collect udata with gc event */ + GCObject **lastcollected = &collected; + while ((curr = *p) != NULL) { + lua_assert(curr->gch.tt == LUA_TUSERDATA); + if (ismarked(curr) || isfinalized(gcotou(curr))) + p = &curr->gch.next; /* don't bother with them */ + + else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { + markfinalized(gcotou(curr)); /* don't need finalization */ + p = &curr->gch.next; + } + else { /* must call its gc method */ + *p = curr->gch.next; + curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ + *lastcollected = curr; + lastcollected = &curr->gch.next; } } + /* insert collected udata with gc event into `tmudata' list */ + *lastcollected = G(L)->tmudata; + G(L)->tmudata = collected; } -static void markobject (GCState *st, TObject *o) { - switch (ttype(o)) { - case LUA_TUSERDATA: case LUA_TSTRING: - strmark(tsvalue(o)); - break; - case LUA_TMARK: - markclosure(st, infovalue(o)->func); - break; - case LUA_TFUNCTION: - markclosure(st, clvalue(o)); - break; - case LUA_TTABLE: { - if (!ismarked(hvalue(o))) { - hvalue(o)->mark = st->tmark; /* chain it in list of marked */ - st->tmark = hvalue(o); - } - break; - } - default: break; /* numbers, etc */ - } +static void removekey (Node *n) { + setnilvalue(gval(n)); /* remove corresponding value ... */ + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ } -static void markall (lua_State *L) { - GCState st; - st.cmark = NULL; - st.tmark = L->gt; /* put table of globals in mark list */ - L->gt->mark = NULL; - marktagmethods(L, &st); /* mark tag methods */ - markstack(L, &st); /* mark stack objects */ - marklock(L, &st); /* mark locked objects */ - for (;;) { /* mark tables and closures */ - if (st.cmark) { - int i; - Closure *f = st.cmark; /* get first closure from list */ - st.cmark = f->mark; /* remove it from list */ - for (i=0; inupvalues; i++) /* mark its upvalues */ - markobject(&st, &f->upvalue[i]); +static void traversetable (GCState *st, Table *h) { + int i; + int weakkey = 0; + int weakvalue = 0; + const TObject *mode; + markvalue(st, h->metatable); + lua_assert(h->lsizenode || h->node == st->g->dummynode); + mode = gfasttm(st->g, h->metatable, TM_MODE); + if (mode && ttisstring(mode)) { /* is there a weak mode? */ + weakkey = (strchr(svalue(mode), 'k') != NULL); + weakvalue = (strchr(svalue(mode), 'v') != NULL); + if (weakkey || weakvalue) { /* is really weak? */ + GCObject **weaklist; + h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ + h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) | + (weakvalue << VALUEWEAKBIT)); + weaklist = (weakkey && weakvalue) ? &st->wkv : + (weakkey) ? &st->wk : + &st->wv; + h->gclist = *weaklist; /* must be cleared after GC, ... */ + *weaklist = valtogco(h); /* ... so put in the appropriate list */ } - else if (st.tmark) { - int i; - Hash *h = st.tmark; /* get first table from list */ - st.tmark = h->mark; /* remove it from list */ - for (i=0; isize; i++) { - Node *n = node(h, i); - if (ttype(key(n)) != LUA_TNIL) { - if (ttype(val(n)) == LUA_TNIL) - luaH_remove(h, key(n)); /* dead element; try to remove it */ - markobject(&st, &n->key); - markobject(&st, &n->val); - } - } + } + if (!weakvalue) { + i = h->sizearray; + while (i--) + markobject(st, &h->array[i]); + } + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + if (!ttisnil(gval(n))) { + lua_assert(!ttisnil(gkey(n))); + condmarkobject(st, gkey(n), !weakkey); + condmarkobject(st, gval(n), !weakvalue); } - else break; /* nothing else to mark */ } } -static int hasmark (const TObject *o) { - /* valid only for locked objects */ - switch (o->ttype) { - case LUA_TSTRING: case LUA_TUSERDATA: - return tsvalue(o)->marked; - case LUA_TTABLE: - return ismarked(hvalue(o)); - case LUA_TFUNCTION: - return ismarked(clvalue(o)); - default: /* number */ - return 1; +static void traverseproto (GCState *st, Proto *f) { + int i; + stringmark(f->source); + for (i=0; isizek; i++) { /* mark literal strings */ + if (ttisstring(f->k+i)) + stringmark(tsvalue(f->k+i)); } + for (i=0; isizeupvalues; i++) /* mark upvalue names */ + stringmark(f->upvalues[i]); + for (i=0; isizep; i++) /* mark nested protos */ + markvalue(st, f->p[i]); + for (i=0; isizelocvars; i++) /* mark local-variable names */ + stringmark(f->locvars[i].varname); + lua_assert(luaG_checkcode(f)); } -/* macro for internal debugging; check if a link of free refs is valid */ -#define VALIDLINK(L, st,n) (NONEXT <= (st) && (st) < (n)) -static void invalidaterefs (lua_State *L) { - int n = L->refSize; - int i; - for (i=0; irefArray[i]; - if (r->st == HOLD && !hasmark(&r->o)) - r->st = COLLECTED; - LUA_ASSERT((r->st == LOCK && hasmark(&r->o)) || - (r->st == HOLD && hasmark(&r->o)) || - r->st == COLLECTED || - r->st == NONEXT || - (r->st < n && VALIDLINK(L, L->refArray[r->st].st, n)), - "inconsistent ref table"); +static void traverseclosure (GCState *st, Closure *cl) { + if (cl->c.isC) { + int i; + for (i=0; ic.nupvalues; i++) /* mark its upvalues */ + markobject(st, &cl->c.upvalue[i]); + } + else { + int i; + lua_assert(cl->l.nupvalues == cl->l.p->nups); + markvalue(st, hvalue(&cl->l.g)); + markvalue(st, cl->l.p); + for (i=0; il.nupvalues; i++) { /* mark its upvalues */ + UpVal *u = cl->l.upvals[i]; + if (!u->marked) { + markobject(st, &u->value); + u->marked = 1; + } + } } - LUA_ASSERT(VALIDLINK(L, L->refFree, n), "inconsistent ref table"); } +static void checkstacksizes (lua_State *L, StkId max) { + int used = L->ci - L->base_ci; /* number of `ci' in use */ + if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) + luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ + else condhardstacktests(luaD_reallocCI(L, L->size_ci)); + used = max - L->stack; /* part of stack in use */ + if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) + luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ + else condhardstacktests(luaD_reallocstack(L, L->stacksize)); +} -static void collectproto (lua_State *L) { - Proto **p = &L->rootproto; - Proto *next; - while ((next = *p) != NULL) { - if (next->marked) { - next->marked = 0; - p = &next->next; - } - else { - *p = next->next; - luaF_freeproto(L, next); - } + +static void traversestack (GCState *st, lua_State *L1) { + StkId o, lim; + CallInfo *ci; + markobject(st, gt(L1)); + lim = L1->top; + for (ci = L1->base_ci; ci <= L1->ci; ci++) { + lua_assert(ci->top <= L1->stack_last); + lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC)); + if (!(ci->state & CI_C) && lim < ci->top) + lim = ci->top; } + for (o = L1->stack; o < L1->top; o++) + markobject(st, o); + for (; o <= lim; o++) + setnilvalue(o); + checkstacksizes(L1, lim); } -static void collectclosure (lua_State *L) { - Closure **p = &L->rootcl; - Closure *next; - while ((next = *p) != NULL) { - if (ismarked(next)) { - next->mark = next; /* unmark */ - p = &next->next; +static void propagatemarks (GCState *st) { + while (st->tmark) { /* traverse marked objects */ + switch (st->tmark->gch.tt) { + case LUA_TTABLE: { + Table *h = gcotoh(st->tmark); + st->tmark = h->gclist; + traversetable(st, h); + break; + } + case LUA_TFUNCTION: { + Closure *cl = gcotocl(st->tmark); + st->tmark = cl->c.gclist; + traverseclosure(st, cl); + break; + } + case LUA_TTHREAD: { + lua_State *th = gcototh(st->tmark); + st->tmark = th->gclist; + traversestack(st, th); + break; + } + case LUA_TPROTO: { + Proto *p = gcotop(st->tmark); + st->tmark = p->gclist; + traverseproto(st, p); + break; + } + default: lua_assert(0); } - else { - *p = next->next; - luaF_freeclosure(L, next); + } +} + + +static int valismarked (const TObject *o) { + if (ttisstring(o)) + stringmark(tsvalue(o)); /* strings are `values', so are never weak */ + return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0); +} + + +/* +** clear collected keys from weaktables +*/ +static void cleartablekeys (GCObject *l) { + while (l) { + Table *h = gcotoh(l); + int i = sizenode(h); + lua_assert(h->marked & KEYWEAK); + while (i--) { + Node *n = gnode(h, i); + if (!valismarked(gkey(n))) /* key was collected? */ + removekey(n); /* remove entry from table */ } + l = h->gclist; } } -static void collecttable (lua_State *L) { - Hash **p = &L->roottable; - Hash *next; - while ((next = *p) != NULL) { - if (ismarked(next)) { - next->mark = next; /* unmark */ - p = &next->next; +/* +** clear collected values from weaktables +*/ +static void cleartablevalues (GCObject *l) { + while (l) { + Table *h = gcotoh(l); + int i = h->sizearray; + lua_assert(h->marked & VALUEWEAK); + while (i--) { + TObject *o = &h->array[i]; + if (!valismarked(o)) /* value was collected? */ + setnilvalue(o); /* remove value */ } - else { - *p = next->next; - luaH_free(L, next); + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + if (!valismarked(gval(n))) /* value was collected? */ + removekey(n); /* remove entry from table */ } + l = h->gclist; } } -static void checktab (lua_State *L, stringtable *tb) { - if (tb->nuse < (lint32)(tb->size/4) && tb->size > 10) - luaS_resize(L, tb, tb->size/2); /* table is too big */ +static void freeobj (lua_State *L, GCObject *o) { + switch (o->gch.tt) { + case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break; + case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break; + case LUA_TTABLE: luaH_free(L, gcotoh(o)); break; + case LUA_TTHREAD: { + lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread); + luaE_freethread(L, gcototh(o)); + break; + } + case LUA_TSTRING: { + luaM_free(L, o, sizestring(gcotots(o)->tsv.len)); + break; + } + case LUA_TUSERDATA: { + luaM_free(L, o, sizeudata(gcotou(o)->uv.len)); + break; + } + default: lua_assert(0); + } } -static void collectstrings (lua_State *L, int all) { - int i; - for (i=0; istrt.size; i++) { /* for each list */ - TString **p = &L->strt.hash[i]; - TString *next; - while ((next = *p) != NULL) { - if (next->marked && !all) { /* preserve? */ - if (next->marked < FIXMARK) /* does not change FIXMARKs */ - next->marked = 0; - p = &next->nexthash; - } - else { /* collect */ - *p = next->nexthash; - L->strt.nuse--; - L->nblocks -= sizestring(next->len); - luaM_free(L, next); - } +static int sweeplist (lua_State *L, GCObject **p, int limit) { + GCObject *curr; + int count = 0; /* number of collected items */ + while ((curr = *p) != NULL) { + if (curr->gch.marked > limit) { + unmark(curr); + p = &curr->gch.next; + } + else { + count++; + *p = curr->gch.next; + freeobj(L, curr); } } - checktab(L, &L->strt); + return count; } -static void collectudata (lua_State *L, int all) { +static void sweepstrings (lua_State *L, int all) { int i; - for (i=0; iudt.size; i++) { /* for each list */ - TString **p = &L->udt.hash[i]; - TString *next; - while ((next = *p) != NULL) { - LUA_ASSERT(next->marked <= 1, "udata cannot be fixed"); - if (next->marked && !all) { /* preserve? */ - next->marked = 0; - p = &next->nexthash; - } - else { /* collect */ - int tag = next->u.d.tag; - *p = next->nexthash; - next->nexthash = L->TMtable[tag].collected; /* chain udata */ - L->TMtable[tag].collected = next; - L->nblocks -= sizestring(next->len); - L->udt.nuse--; - } - } + for (i=0; istrt.size; i++) { /* for each list */ + G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all); } - checktab(L, &L->udt); } -#define MINBUFFER 256 -static void checkMbuffer (lua_State *L) { - if (L->Mbuffsize > MINBUFFER*2) { /* is buffer too big? */ - size_t newsize = L->Mbuffsize/2; /* still larger than MINBUFFER */ - L->nblocks += (newsize - L->Mbuffsize)*sizeof(char); - L->Mbuffsize = newsize; - luaM_reallocvector(L, L->Mbuffer, newsize, char); +static void checkSizes (lua_State *L) { + /* check size of string hash */ + if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && + G(L)->strt.size > MINSTRTABSIZE*2) + luaS_resize(L, G(L)->strt.size/2); /* table is too big */ + /* check size of buffer */ + if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ + size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2; + luaZ_resizebuffer(L, &G(L)->buff, newsize); } + G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ } -static void callgcTM (lua_State *L, const TObject *o) { - Closure *tm = luaT_gettmbyObj(L, o, TM_GC); +static void do1gcTM (lua_State *L, Udata *udata) { + const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { - int oldah = L->allowhooks; - L->allowhooks = 0; /* stop debug hooks during GC tag methods */ - luaD_checkstack(L, 2); - clvalue(L->top) = tm; - ttype(L->top) = LUA_TFUNCTION; - *(L->top+1) = *o; + setobj2s(L->top, tm); + setuvalue(L->top+1, udata); L->top += 2; - luaD_call(L, L->top-2, 0); - L->allowhooks = oldah; /* restore hooks */ + luaD_call(L, L->top - 2, 0); } } -static void callgcTMudata (lua_State *L) { - int tag; - TObject o; - ttype(&o) = LUA_TUSERDATA; - L->GCthreshold = 2*L->nblocks; /* avoid GC during tag methods */ - for (tag=L->last_tag; tag>=0; tag--) { /* for each tag (in reverse order) */ - TString *udata; - while ((udata = L->TMtable[tag].collected) != NULL) { - L->TMtable[tag].collected = udata->nexthash; /* remove it from list */ - tsvalue(&o) = udata; - callgcTM(L, &o); - luaM_free(L, udata); - } +void luaC_callGCTM (lua_State *L) { + lu_byte oldah = L->allowhook; + L->allowhook = 0; /* stop debug hooks during GC tag methods */ + L->top++; /* reserve space to keep udata while runs its gc method */ + while (G(L)->tmudata != NULL) { + GCObject *o = G(L)->tmudata; + Udata *udata = gcotou(o); + G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ + udata->uv.next = G(L)->rootudata; /* return it to `root' list */ + G(L)->rootudata = o; + setuvalue(L->top - 1, udata); /* keep a reference to it */ + unmark(o); + markfinalized(udata); + do1gcTM(L, udata); } + L->top--; + L->allowhook = oldah; /* restore hooks */ } -void luaC_collect (lua_State *L, int all) { - collectudata(L, all); - callgcTMudata(L); - collectstrings(L, all); - collecttable(L); - collectproto(L); - collectclosure(L); +void luaC_sweep (lua_State *L, int all) { + if (all) all = 256; /* larger than any mark */ + sweeplist(L, &G(L)->rootudata, all); + sweepstrings(L, all); + sweeplist(L, &G(L)->rootgc, all); +} + + +/* mark root set */ +static void markroot (GCState *st, lua_State *L) { + global_State *g = st->g; + markobject(st, defaultmeta(L)); + markobject(st, registry(L)); + traversestack(st, g->mainthread); + if (L != g->mainthread) /* another thread is running? */ + markvalue(st, L); /* cannot collect it */ +} + + +static void mark (lua_State *L) { + GCState st; + GCObject *wkv; + st.g = G(L); + st.tmark = NULL; + st.wkv = st.wk = st.wv = NULL; + markroot(&st, L); + propagatemarks(&st); /* mark all reachable objects */ + cleartablevalues(st.wkv); + cleartablevalues(st.wv); + wkv = st.wkv; /* keys must be cleared after preserving udata */ + st.wkv = NULL; + st.wv = NULL; + luaC_separateudata(L); /* separate userdata to be preserved */ + marktmu(&st); /* mark `preserved' userdata */ + propagatemarks(&st); /* remark, to propagate `preserveness' */ + cleartablekeys(wkv); + /* `propagatemarks' may resuscitate some weak tables; clear them too */ + cleartablekeys(st.wk); + cleartablevalues(st.wv); + cleartablekeys(st.wkv); + cleartablevalues(st.wkv); } void luaC_collectgarbage (lua_State *L) { - markall(L); - invalidaterefs(L); /* check unlocked references */ - luaC_collect(L, 0); - checkMbuffer(L); - L->GCthreshold = 2*L->nblocks; /* set new threshold */ - callgcTM(L, &luaO_nilobject); + mark(L); + luaC_sweep(L, 0); + checkSizes(L); + luaC_callGCTM(L); } -void luaC_checkGC (lua_State *L) { - if (L->nblocks >= L->GCthreshold) - luaC_collectgarbage(L); +void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { + o->gch.next = G(L)->rootgc; + G(L)->rootgc = o; + o->gch.marked = 0; + o->gch.tt = tt; } diff --git a/src/lgc.h b/src/lgc.h index 09b66a2bd3..6ab6c91749 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 1.9 2001/02/02 16:23:20 roberto Exp $ +** $Id: lgc.h,v 1.19 2003/02/28 19:45:15 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -11,9 +11,15 @@ #include "lobject.h" -void luaC_collect (lua_State *L, int all); +#define luaC_checkGC(L) { lua_assert(!(L->ci->state & CI_CALLING)); \ + if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); } + + +void luaC_separateudata (lua_State *L); +void luaC_callGCTM (lua_State *L); +void luaC_sweep (lua_State *L, int all); void luaC_collectgarbage (lua_State *L); -void luaC_checkGC (lua_State *L); +void luaC_link (lua_State *L, GCObject *o, lu_byte tt); #endif diff --git a/src/lib/Makefile b/src/lib/Makefile index 081b886721..3c6c07ab2f 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -4,17 +4,16 @@ LUA= ../.. include $(LUA)/config -# actually only used in liolib.c -EXTRA_DEFS= $(POPEN) +EXTRA_DEFS= $(POPEN) $(TMPNAM) $(DEGREES) $(LOADLIB) -OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o lstrlib.o -SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c lstrlib.c +OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o ltablib.o lstrlib.o loadlib.o +SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c ltablib.c lstrlib.c loadlib.c T= $(LIB)/liblualib.a -all: $T +all: $T -$T: $(OBJS) +$T: $(OBJS) $(AR) $@ $(OBJS) $(RANLIB) $@ diff --git a/src/lib/README b/src/lib/README index c04a12e26f..c5600b8eca 100644 --- a/src/lib/README +++ b/src/lib/README @@ -1,6 +1,8 @@ This is the standard Lua library. -It is implemented entirely on top of the official Lua API as declared in lua.h, -using lauxlib.c, which contains several useful functions for writing libraries. -We encourage developers to use lauxlib.c in their own libraries. + The code of the standard library can be read as an example of how to export -C functions to Lua. +C functions to Lua. The easiest library to read is lmathlib.c. + +The library is implemented entirely on top of the official Lua API as declared +in lua.h, using lauxlib.c, which contains several useful functions for writing +libraries. We encourage developers to use lauxlib.c in their own libraries. diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c index 4bdaeeff8e..ee2d1339b0 100644 --- a/src/lib/lauxlib.c +++ b/src/lib/lauxlib.c @@ -1,25 +1,101 @@ /* -** $Id: lauxlib.c,v 1.43 2000/10/30 13:07:48 roberto Exp $ +** $Id: lauxlib.c,v 1.100 2003/04/07 14:35:00 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ +#include +#include #include #include #include + /* This file uses only the official API of Lua. ** Any function declared here could be written as an application function. -** With care, these functions can be used by other libraries. */ +#define lauxlib_c + #include "lua.h" #include "lauxlib.h" -#include "luadebug.h" +/* number of prereserved references (for internal use) */ +#define RESERVED_REFS 2 + +/* reserved references */ +#define FREELIST_REF 1 /* free list of references */ +#define ARRAYSIZE_REF 2 /* array sizes */ + + +/* convert a stack index to positive */ +#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ + lua_gettop(L) + (i) + 1) + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + + +LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { + lua_Debug ar; + lua_getstack(L, 0, &ar); + lua_getinfo(L, "n", &ar); + if (strcmp(ar.namewhat, "method") == 0) { + narg--; /* do not count `self' */ + if (narg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg); + } + if (ar.name == NULL) + ar.name = "?"; + return luaL_error(L, "bad argument #%d to `%s' (%s)", + narg, ar.name, extramsg); +} + + +LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", + tname, lua_typename(L, lua_type(L,narg))); + return luaL_argerror(L, narg, msg); +} + + +static void tag_error (lua_State *L, int narg, int tag) { + luaL_typerror(L, narg, lua_typename(L, tag)); +} + + +LUALIB_API void luaL_where (lua_State *L, int level) { + lua_Debug ar; + if (lua_getstack(L, level, &ar)) { /* check function at level */ + lua_getinfo(L, "Snl", &ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushliteral(L, ""); /* else, no information available... */ +} + + +LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + +/* }====================================================== */ + LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { int i; @@ -29,34 +105,55 @@ LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { return -1; /* name not found */ } -LUALIB_API void luaL_argerror (lua_State *L, int narg, const char *extramsg) { - lua_Debug ar; - lua_getstack(L, 0, &ar); - lua_getinfo(L, "n", &ar); - if (ar.name == NULL) - ar.name = "?"; - luaL_verror(L, "bad argument #%d to `%.50s' (%.100s)", - narg, ar.name, extramsg); + +LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { + lua_pushstring(L, tname); + lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */ + if (!lua_isnil(L, -1)) /* name already in use? */ + return 0; /* leave previous value on top, but return 0 */ + lua_pop(L, 1); + lua_newtable(L); /* create metatable */ + lua_pushstring(L, tname); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */ + lua_pushvalue(L, -1); + lua_pushstring(L, tname); + lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ + return 1; } -static void type_error (lua_State *L, int narg, int t) { - char buff[50]; - sprintf(buff, "%.8s expected, got %.8s", lua_typename(L, t), - lua_typename(L, lua_type(L, narg))); - luaL_argerror(L, narg, buff); +LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) { + lua_pushstring(L, tname); + lua_rawget(L, LUA_REGISTRYINDEX); +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + const char *tn; + if (!lua_getmetatable(L, ud)) return NULL; /* no metatable? */ + lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[metatable] */ + tn = lua_tostring(L, -1); + if (tn && (strcmp(tn, tname) == 0)) { + lua_pop(L, 1); + return lua_touserdata(L, ud); + } + else { + lua_pop(L, 1); + return NULL; + } } LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { - if (space > lua_stackspace(L)) - luaL_verror(L, "stack overflow (%.30s)", mes); + if (!lua_checkstack(L, space)) + luaL_error(L, "stack overflow (%s)", mes); } -LUALIB_API void luaL_checktype(lua_State *L, int narg, int t) { +LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { if (lua_type(L, narg) != t) - type_error(L, narg, t); + tag_error(L, narg, t); } @@ -66,55 +163,164 @@ LUALIB_API void luaL_checkany (lua_State *L, int narg) { } -LUALIB_API const char *luaL_check_lstr (lua_State *L, int narg, size_t *len) { +LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { const char *s = lua_tostring(L, narg); - if (!s) type_error(L, narg, LUA_TSTRING); + if (!s) tag_error(L, narg, LUA_TSTRING); if (len) *len = lua_strlen(L, narg); return s; } -LUALIB_API const char *luaL_opt_lstr (lua_State *L, int narg, const char *def, size_t *len) { - if (lua_isnull(L, narg)) { +LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, narg)) { if (len) *len = (def ? strlen(def) : 0); return def; } - else return luaL_check_lstr(L, narg, len); + else return luaL_checklstring(L, narg, len); } -LUALIB_API double luaL_check_number (lua_State *L, int narg) { - double d = lua_tonumber(L, narg); +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { + lua_Number d = lua_tonumber(L, narg); if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ - type_error(L, narg, LUA_TNUMBER); + tag_error(L, narg, LUA_TNUMBER); return d; } -LUALIB_API double luaL_opt_number (lua_State *L, int narg, double def) { - if (lua_isnull(L, narg)) return def; - else return luaL_check_number(L, narg); +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { + if (lua_isnoneornil(L, narg)) return def; + else return luaL_checknumber(L, narg); } -LUALIB_API void luaL_openlib (lua_State *L, const struct luaL_reg *l, int n) { - int i; - for (i=0; iname; l++) { + int i; + lua_pushstring(L, l->name); + for (i=0; ifunc, nup); + lua_settable(L, -(nup+3)); + } + lua_pop(L, nup); /* remove upvalues */ +} + + + +/* +** {====================================================== +** getn-setn: size for arrays +** ======================================================= +*/ + +static int checkint (lua_State *L, int topop) { + int n = (int)lua_tonumber(L, -1); + if (n == 0 && !lua_isnumber(L, -1)) n = -1; + lua_pop(L, topop); + return n; +} + + +static void getsizes (lua_State *L) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); + if (lua_isnil(L, -1)) { /* no `size' table? */ + lua_pop(L, 1); /* remove nil */ + lua_newtable(L); /* create it */ + lua_pushvalue(L, -1); /* `size' will be its own metatable */ + lua_setmetatable(L, -2); + lua_pushliteral(L, "__mode"); + lua_pushliteral(L, "k"); + lua_rawset(L, -3); /* metatable(N).__mode = "k" */ + lua_pushvalue(L, -1); + lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */ + } +} + + +void luaL_setn (lua_State *L, int t, int n) { + t = abs_index(L, t); + lua_pushliteral(L, "n"); + lua_rawget(L, t); + if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ + lua_pushliteral(L, "n"); /* use it */ + lua_pushnumber(L, (lua_Number)n); + lua_rawset(L, t); + } + else { /* use `sizes' */ + getsizes(L); + lua_pushvalue(L, t); + lua_pushnumber(L, (lua_Number)n); + lua_rawset(L, -3); /* sizes[t] = n */ + lua_pop(L, 1); /* remove `sizes' */ + } +} + + +int luaL_getn (lua_State *L, int t) { + int n; + t = abs_index(L, t); + lua_pushliteral(L, "n"); /* try t.n */ + lua_rawget(L, t); + if ((n = checkint(L, 1)) >= 0) return n; + getsizes(L); /* else try sizes[t] */ + lua_pushvalue(L, t); + lua_rawget(L, -2); + if ((n = checkint(L, 2)) >= 0) return n; + for (n = 1; ; n++) { /* else must count elements */ + lua_rawgeti(L, t, n); + if (lua_isnil(L, -1)) break; + lua_pop(L, 1); + } + lua_pop(L, 1); + return n - 1; +} + +/* }====================================================== */ + + + /* ** {====================================================== ** Generic Buffer manipulation @@ -122,7 +328,6 @@ LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...) { */ -#define buffempty(B) ((B)->p == (B)->buffer) #define bufflen(B) ((B)->p - (B)->buffer) #define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) @@ -135,29 +340,27 @@ static int emptybuffer (luaL_Buffer *B) { else { lua_pushlstring(B->L, B->buffer, l); B->p = B->buffer; - B->level++; + B->lvl++; return 1; } } static void adjuststack (luaL_Buffer *B) { - if (B->level > 1) { + if (B->lvl > 1) { lua_State *L = B->L; int toget = 1; /* number of levels to concat */ size_t toplen = lua_strlen(L, -1); do { size_t l = lua_strlen(L, -(toget+1)); - if (B->level - toget + 1 >= LIMIT || toplen > l) { + if (B->lvl - toget + 1 >= LIMIT || toplen > l) { toplen += l; toget++; } else break; - } while (toget < B->level); - if (toget >= 2) { - lua_concat(L, toget); - B->level = B->level - toget + 1; - } + } while (toget < B->lvl); + lua_concat(L, toget); + B->lvl = B->lvl - toget + 1; } } @@ -182,11 +385,8 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) { emptybuffer(B); - if (B->level == 0) - lua_pushlstring(B->L, NULL, 0); - else if (B->level > 1) - lua_concat(B->L, B->level); - B->level = 1; + lua_concat(B->L, B->lvl); + B->lvl = 1; } @@ -201,7 +401,7 @@ LUALIB_API void luaL_addvalue (luaL_Buffer *B) { else { if (emptybuffer(B)) lua_insert(L, -2); /* put buffer before new value */ - B->level++; /* add new value into B stack */ + B->lvl++; /* add new value into B stack */ adjuststack(B); } } @@ -210,7 +410,182 @@ LUALIB_API void luaL_addvalue (luaL_Buffer *B) { LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { B->L = L; B->p = B->buffer; - B->level = 0; + B->lvl = 0; +} + +/* }====================================================== */ + + +LUALIB_API int luaL_ref (lua_State *L, int t) { + int ref; + t = abs_index(L, t); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* `nil' has a unique fixed reference */ + } + lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ + ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */ + lua_pop(L, 1); /* remove it from stack */ + if (ref != 0) { /* any free element? */ + lua_rawgeti(L, t, ref); /* remove it from list */ + lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ + } + else { /* no free elements */ + ref = luaL_getn(L, t); + if (ref < RESERVED_REFS) + ref = RESERVED_REFS; /* skip reserved references */ + ref++; /* create new reference */ + luaL_setn(L, t, ref); + } + lua_rawseti(L, t, ref); + return ref; +} + + +LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { + if (ref >= 0) { + t = abs_index(L, t); + lua_rawgeti(L, t, FREELIST_REF); + lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ + lua_pushnumber(L, (lua_Number)ref); + lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ + } +} + + + +/* +** {====================================================== +** Load functions +** ======================================================= +*/ + +typedef struct LoadF { + FILE *f; + char buff[LUAL_BUFFERSIZE]; +} LoadF; + + +static const char *getF (lua_State *L, void *ud, size_t *size) { + LoadF *lf = (LoadF *)ud; + (void)L; + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); + return (*size > 0) ? lf->buff : NULL; +} + + +static int errfile (lua_State *L, int fnameindex) { + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno)); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { + LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + } + if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ + c = ungetc(getc(lf.f), lf.f); + if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */ + fclose(lf.f); + lf.f = fopen(filename, "rb"); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */ + } + status = lua_load(L, getF, &lf, lua_tostring(L, -1)); + readstatus = ferror(lf.f); + if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from `lua_load' */ + return errfile(L, fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +typedef struct LoadS { + const char *s; + size_t size; +} LoadS; + + +static const char *getS (lua_State *L, void *ud, size_t *size) { + LoadS *ls = (LoadS *)ud; + (void)L; + if (ls->size == 0) return NULL; + *size = ls->size; + ls->size = 0; + return ls->s; +} + + +LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, + const char *name) { + LoadS ls; + ls.s = buff; + ls.size = size; + return lua_load(L, getS, &ls, name); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** compatibility code +** ======================================================= +*/ + + +static void callalert (lua_State *L, int status) { + if (status != 0) { + lua_getglobal(L, "_ALERT"); + if (lua_isfunction(L, -1)) { + lua_insert(L, -2); + lua_call(L, 1, 0); + } + else { /* no _ALERT function; print it on stderr */ + fprintf(stderr, "%s\n", lua_tostring(L, -2)); + lua_pop(L, 2); /* remove error message and _ALERT */ + } + } +} + + +static int aux_do (lua_State *L, int status) { + if (status == 0) { /* parse OK? */ + status = lua_pcall(L, 0, LUA_MULTRET, 0); /* call main */ + } + callalert(L, status); + return status; +} + + +LUALIB_API int lua_dofile (lua_State *L, const char *filename) { + return aux_do(L, luaL_loadfile(L, filename)); +} + + +LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, + const char *name) { + return aux_do(L, luaL_loadbuffer(L, buff, size, name)); +} + + +LUALIB_API int lua_dostring (lua_State *L, const char *str) { + return lua_dobuffer(L, str, strlen(str), str); } /* }====================================================== */ diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index 29bad6a8f2..7381cf3357 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.17a 2000/11/06 13:45:18 roberto Exp $ +** $Id: lbaselib.c,v 1.130 2003/04/03 13:35:34 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -11,51 +11,15 @@ #include #include +#define lbaselib_c + #include "lua.h" #include "lauxlib.h" -#include "luadebug.h" #include "lualib.h" -/* -** If your system does not support `stderr', redefine this function, or -** redefine _ERRORMESSAGE so that it won't need _ALERT. -*/ -static int luaB__ALERT (lua_State *L) { - fputs(luaL_check_string(L, 1), stderr); - return 0; -} - - -/* -** Basic implementation of _ERRORMESSAGE. -** The library `liolib' redefines _ERRORMESSAGE for better error information. -*/ -static int luaB__ERRORMESSAGE (lua_State *L) { - luaL_checktype(L, 1, LUA_TSTRING); - lua_getglobal(L, LUA_ALERT); - if (lua_isfunction(L, -1)) { /* avoid error loop if _ALERT is not defined */ - lua_Debug ar; - lua_pushstring(L, "error: "); - lua_pushvalue(L, 1); - if (lua_getstack(L, 1, &ar)) { - lua_getinfo(L, "Sl", &ar); - if (ar.source && ar.currentline > 0) { - char buff[100]; - sprintf(buff, "\n <%.70s: line %d>", ar.short_src, ar.currentline); - lua_pushstring(L, buff); - lua_concat(L, 2); - } - } - lua_pushstring(L, "\n"); - lua_concat(L, 3); - lua_rawcall(L, 1, 0); - } - return 0; -} - /* ** If your system does not support `stdout', you can just remove this function. @@ -71,10 +35,10 @@ static int luaB_print (lua_State *L) { const char *s; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ - lua_rawcall(L, 1, 1); + lua_call(L, 1, 1); s = lua_tostring(L, -1); /* get result */ if (s == NULL) - lua_error(L, "`tostring' must return a string to `print'"); + return luaL_error(L, "`tostring' must return a string to `print'"); if (i>1) fputs("\t", stdout); fputs(s, stdout); lua_pop(L, 1); /* pop result */ @@ -85,7 +49,7 @@ static int luaB_print (lua_State *L) { static int luaB_tonumber (lua_State *L) { - int base = luaL_opt_int(L, 2, 10); + int base = luaL_optint(L, 2, 10); if (base == 10) { /* standard conversion */ luaL_checkany(L, 1); if (lua_isnumber(L, 1)) { @@ -94,15 +58,15 @@ static int luaB_tonumber (lua_State *L) { } } else { - const char *s1 = luaL_check_string(L, 1); + const char *s1 = luaL_checkstring(L, 1); char *s2; unsigned long n; - luaL_arg_check(L, 2 <= base && base <= 36, 2, "base out of range"); + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); n = strtoul(s1, &s2, base); if (s1 != s2) { /* at least one valid digit? */ - while (isspace((unsigned char)*s2)) s2++; /* skip trailing spaces */ + while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ if (*s2 == '\0') { /* no invalid trailing characters? */ - lua_pushnumber(L, n); + lua_pushnumber(L, (lua_Number)n); return 1; } } @@ -113,55 +77,99 @@ static int luaB_tonumber (lua_State *L) { static int luaB_error (lua_State *L) { - lua_error(L, luaL_opt_string(L, 1, NULL)); - return 0; /* to avoid warnings */ + int level = luaL_optint(L, 2, 1); + luaL_checkany(L, 1); + if (!lua_isstring(L, 1) || level == 0) + lua_pushvalue(L, 1); /* propagate error message without changes */ + else { /* add extra information */ + luaL_where(L, level); + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); } -static int luaB_setglobal (lua_State *L) { - luaL_checkany(L, 2); - lua_setglobal(L, luaL_check_string(L, 1)); - return 0; + +static int luaB_getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ } -static int luaB_getglobal (lua_State *L) { - lua_getglobal(L, luaL_check_string(L, 1)); + +static int luaB_setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + if (luaL_getmetafield(L, 1, "__metatable")) + luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); return 1; } -static int luaB_tag (lua_State *L) { - luaL_checkany(L, 1); - lua_pushnumber(L, lua_tag(L, 1)); - return 1; + +static void getfunc (lua_State *L) { + if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); + else { + lua_Debug ar; + int level = luaL_optint(L, 1, 1); + luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); + if (lua_getstack(L, level, &ar) == 0) + luaL_argerror(L, 1, "invalid level"); + lua_getinfo(L, "f", &ar); + if (lua_isnil(L, -1)) + luaL_error(L, "no function environment for tail call at level %d", + level); + } } -static int luaB_settag (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, 1); /* push table */ - lua_settag(L, luaL_check_int(L, 2)); - return 1; /* return table */ + +static int aux_getfenv (lua_State *L) { + lua_getfenv(L, -1); + lua_pushliteral(L, "__fenv"); + lua_rawget(L, -2); + return !lua_isnil(L, -1); } -static int luaB_newtag (lua_State *L) { - lua_pushnumber(L, lua_newtag(L)); + +static int luaB_getfenv (lua_State *L) { + getfunc(L); + if (!aux_getfenv(L)) /* __fenv not defined? */ + lua_pop(L, 1); /* remove it, to return real environment */ return 1; } -static int luaB_copytagmethods (lua_State *L) { - lua_pushnumber(L, lua_copytagmethods(L, luaL_check_int(L, 1), - luaL_check_int(L, 2))); - return 1; + +static int luaB_setfenv (lua_State *L) { + luaL_checktype(L, 2, LUA_TTABLE); + getfunc(L); + if (aux_getfenv(L)) /* __fenv defined? */ + luaL_error(L, "`setfenv' cannot change a protected environment"); + else + lua_pop(L, 2); /* remove __fenv and real environment table */ + lua_pushvalue(L, 2); + if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) + lua_replace(L, LUA_GLOBALSINDEX); + else if (lua_setfenv(L, -2) == 0) + luaL_error(L, "`setfenv' cannot change environment of given function"); + return 0; } -static int luaB_globals (lua_State *L) { - lua_getglobals(L); /* value to be returned */ - if (!lua_isnull(L, 1)) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, 1); /* new table of globals */ - lua_setglobals(L); - } + +static int luaB_rawequal (lua_State *L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); return 1; } + static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); @@ -177,39 +185,16 @@ static int luaB_rawset (lua_State *L) { return 1; } -static int luaB_settagmethod (lua_State *L) { - int tag = luaL_check_int(L, 1); - const char *event = luaL_check_string(L, 2); - luaL_arg_check(L, lua_isfunction(L, 3) || lua_isnil(L, 3), 3, - "function or nil expected"); - if (strcmp(event, "gc") == 0) - lua_error(L, "deprecated use: cannot set the `gc' tag method from Lua"); - lua_gettagmethod(L, tag, event); - lua_pushvalue(L, 3); - lua_settagmethod(L, tag, event); - return 1; -} - - -static int luaB_gettagmethod (lua_State *L) { - int tag = luaL_check_int(L, 1); - const char *event = luaL_check_string(L, 2); - if (strcmp(event, "gc") == 0) - lua_error(L, "deprecated use: cannot get the `gc' tag method from Lua"); - lua_gettagmethod(L, tag, event); - return 1; -} - static int luaB_gcinfo (lua_State *L) { - lua_pushnumber(L, lua_getgccount(L)); - lua_pushnumber(L, lua_getgcthreshold(L)); + lua_pushnumber(L, (lua_Number)lua_getgccount(L)); + lua_pushnumber(L, (lua_Number)lua_getgcthreshold(L)); return 2; } static int luaB_collectgarbage (lua_State *L) { - lua_setgcthreshold(L, luaL_opt_int(L, 1, 0)); + lua_setgcthreshold(L, luaL_optint(L, 1, 0)); return 0; } @@ -233,83 +218,116 @@ static int luaB_next (lua_State *L) { } -static int passresults (lua_State *L, int status, int oldtop) { - static const char *const errornames[] = - {"ok", "run-time error", "file error", "syntax error", - "memory error", "error in error handling"}; - if (status == 0) { - int nresults = lua_gettop(L) - oldtop; - if (nresults > 0) - return nresults; /* results are already on the stack */ - else { - lua_pushuserdata(L, NULL); /* at least one result to signal no errors */ - return 1; - } +static int luaB_pairs (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushliteral(L, "next"); + lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnil(L); /* and initial value */ + return 3; +} + + +static int luaB_ipairs (lua_State *L) { + lua_Number i = lua_tonumber(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */ + lua_pushliteral(L, "ipairs"); + lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnumber(L, 0); /* and initial value */ + return 3; + } + else { /* `for' step */ + i++; /* next value */ + lua_pushnumber(L, i); + lua_rawgeti(L, 1, (int)i); + return (lua_isnil(L, -1)) ? 0 : 2; } - else { /* error */ +} + + +static int load_aux (lua_State *L, int status) { + if (status == 0) /* OK? */ + return 1; + else { lua_pushnil(L); - lua_pushstring(L, errornames[status]); /* error code */ - return 2; + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ } } -static int luaB_dostring (lua_State *L) { - int oldtop = lua_gettop(L); + +static int luaB_loadstring (lua_State *L) { size_t l; - const char *s = luaL_check_lstr(L, 1, &l); - if (*s == '\33') /* binary files start with ESC... */ - lua_error(L, "`dostring' cannot run pre-compiled code"); - return passresults(L, lua_dobuffer(L, s, l, luaL_opt_string(L, 2, s)), oldtop); + const char *s = luaL_checklstring(L, 1, &l); + const char *chunkname = luaL_optstring(L, 2, s); + return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); +} + + +static int luaB_loadfile (lua_State *L) { + const char *fname = luaL_optstring(L, 1, NULL); + return load_aux(L, luaL_loadfile(L, fname)); } static int luaB_dofile (lua_State *L) { - int oldtop = lua_gettop(L); - const char *fname = luaL_opt_string(L, 1, NULL); - return passresults(L, lua_dofile(L, fname), oldtop); + const char *fname = luaL_optstring(L, 1, NULL); + int status = luaL_loadfile(L, fname); + if (status != 0) lua_error(L); + lua_call(L, 0, LUA_MULTRET); + return lua_gettop(L) - 1; } -static int luaB_call (lua_State *L) { - int oldtop; - const char *options = luaL_opt_string(L, 3, ""); - int err = 0; /* index of old error method */ - int i, status; - int n; - luaL_checktype(L, 2, LUA_TTABLE); - n = lua_getn(L, 2); - if (!lua_isnull(L, 4)) { /* set new error method */ - lua_getglobal(L, LUA_ERRORMESSAGE); - err = lua_gettop(L); /* get index */ - lua_pushvalue(L, 4); - lua_setglobal(L, LUA_ERRORMESSAGE); - } - oldtop = lua_gettop(L); /* top before function-call preparation */ - /* push function */ - lua_pushvalue(L, 1); - luaL_checkstack(L, n, "too many arguments"); - for (i=0; i=pos; n--) { - lua_rawgeti(L, 1, n); - lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ - } - lua_pushvalue(L, v); - lua_rawseti(L, 1, pos); /* t[pos] = v */ - return 0; -} - +/* +** {====================================================== +** `require' function +** ======================================================= +*/ -static int luaB_tremove (lua_State *L) { - int pos, n; - luaL_checktype(L, 1, LUA_TTABLE); - n = lua_getn(L, 1); - pos = luaL_opt_int(L, 2, n); - if (n <= 0) return 0; /* table is "empty" */ - lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos= P */ - while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>u) lua_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* repeat --j until a[j] <= P */ - while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j #include +#define ldblib_c + #include "lua.h" #include "lauxlib.h" -#include "luadebug.h" #include "lualib.h" @@ -20,43 +21,41 @@ static void settabss (lua_State *L, const char *i, const char *v) { lua_pushstring(L, i); lua_pushstring(L, v); - lua_settable(L, -3); + lua_rawset(L, -3); } static void settabsi (lua_State *L, const char *i, int v) { lua_pushstring(L, i); - lua_pushnumber(L, v); - lua_settable(L, -3); + lua_pushnumber(L, (lua_Number)v); + lua_rawset(L, -3); } static int getinfo (lua_State *L) { lua_Debug ar; - const char *options = luaL_opt_string(L, 2, "flnSu"); - char buff[20]; + const char *options = luaL_optstring(L, 2, "flnSu"); if (lua_isnumber(L, 1)) { - if (!lua_getstack(L, (int)lua_tonumber(L, 1), &ar)) { + if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } else if (lua_isfunction(L, 1)) { + lua_pushfstring(L, ">%s", options); + options = lua_tostring(L, -1); lua_pushvalue(L, 1); - sprintf(buff, ">%.10s", options); - options = buff; } else - luaL_argerror(L, 1, "function or level expected"); + return luaL_argerror(L, 1, "function or level expected"); if (!lua_getinfo(L, options, &ar)) - luaL_argerror(L, 2, "invalid option"); + return luaL_argerror(L, 2, "invalid option"); lua_newtable(L); for (; *options; options++) { switch (*options) { case 'S': settabss(L, "source", ar.source); - if (ar.source) - settabss(L, "short_src", ar.short_src); + settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabss(L, "what", ar.what); break; @@ -71,9 +70,9 @@ static int getinfo (lua_State *L) { settabss(L, "namewhat", ar.namewhat); break; case 'f': - lua_pushstring(L, "func"); + lua_pushliteral(L, "func"); lua_pushvalue(L, -3); - lua_settable(L, -3); + lua_rawset(L, -3); break; } } @@ -84,9 +83,9 @@ static int getinfo (lua_State *L) { static int getlocal (lua_State *L) { lua_Debug ar; const char *name; - if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ - luaL_argerror(L, 1, "level out of range"); - name = lua_getlocal(L, &ar, luaL_check_int(L, 2)); + if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ + return luaL_argerror(L, 1, "level out of range"); + name = lua_getlocal(L, &ar, luaL_checkint(L, 2)); if (name) { lua_pushstring(L, name); lua_pushvalue(L, -2); @@ -101,88 +100,200 @@ static int getlocal (lua_State *L) { static int setlocal (lua_State *L) { lua_Debug ar; - if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ - luaL_argerror(L, 1, "level out of range"); + if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ + return luaL_argerror(L, 1, "level out of range"); luaL_checkany(L, 3); - lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2))); + lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2))); return 1; } +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); + return get + 1; +} + + +static int getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + -/* dummy variables (to define unique addresses) */ -static char key1, key2; -#define KEY_CALLHOOK (&key1) -#define KEY_LINEHOOK (&key2) +static const char KEY_HOOK = 'h'; -static void hookf (lua_State *L, void *key) { - lua_getregistry(L); - lua_pushuserdata(L, key); - lua_gettable(L, -2); +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail return"}; + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); if (lua_isfunction(L, -1)) { - lua_pushvalue(L, 1); - lua_rawcall(L, 1, 0); + lua_pushstring(L, hooknames[(int)ar->event]); + if (ar->currentline >= 0) + lua_pushnumber(L, (lua_Number)ar->currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); } else lua_pop(L, 1); /* pop result from gettable */ - lua_pop(L, 1); /* pop table */ } -static void callf (lua_State *L, lua_Debug *ar) { - lua_pushstring(L, ar->event); - hookf(L, KEY_CALLHOOK); +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; } -static void linef (lua_State *L, lua_Debug *ar) { - lua_pushnumber(L, ar->currentline); - hookf(L, KEY_LINEHOOK); +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; } -static void sethook (lua_State *L, void *key, lua_Hook hook, - lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) { - lua_settop(L, 1); - if (lua_isnil(L, 1)) - (*sethookf)(L, NULL); - else if (lua_isfunction(L, 1)) - (*sethookf)(L, hook); - else - luaL_argerror(L, 1, "function expected"); - lua_getregistry(L); - lua_pushuserdata(L, key); - lua_pushvalue(L, -1); /* dup key */ - lua_gettable(L, -3); /* get old value */ - lua_pushvalue(L, -2); /* key (again) */ +static int sethook (lua_State *L) { + if (lua_isnoneornil(L, 1)) { + lua_settop(L, 1); + lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, 2); + int count = luaL_optint(L, 3, 0); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_sethook(L, hookf, makemask(smask, count), count); + } + lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_pushvalue(L, 1); - lua_settable(L, -5); /* set new value */ + lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ + return 0; } -static int setcallhook (lua_State *L) { - sethook(L, KEY_CALLHOOK, callf, lua_setcallhook); - return 1; +static int gethook (lua_State *L) { + char buff[5]; + int mask = lua_gethookmask(L); + lua_Hook hook = lua_gethook(L); + if (hook != NULL && hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ + } + lua_pushstring(L, unmakemask(mask, buff)); + lua_pushnumber(L, (lua_Number)lua_gethookcount(L)); + return 3; +} + + +static int debug (lua_State *L) { + for (;;) { + char buffer[250]; + fputs("lua_debug> ", stderr); + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return 0; + lua_dostring(L, buffer); + lua_settop(L, 0); /* remove eventual returns */ + } } -static int setlinehook (lua_State *L) { - sethook(L, KEY_LINEHOOK, linef, lua_setlinehook); +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ + +static int errorfb (lua_State *L) { + int level = 1; /* skip level 0 (it's this function) */ + int firstpart = 1; /* still before eventual `...' */ + lua_Debug ar; + if (lua_gettop(L) == 0) + lua_pushliteral(L, ""); + else if (!lua_isstring(L, 1)) return 1; /* no string message */ + else lua_pushliteral(L, "\n"); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L, level++, &ar)) { + if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (!lua_getstack(L, level+LEVELS2, &ar)) + level--; /* keep going */ + else { + lua_pushliteral(L, "\n\t..."); /* too many levels */ + while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + level++; + } + firstpart = 0; + continue; + } + lua_pushliteral(L, "\n\t"); + lua_getinfo(L, "Snl", &ar); + lua_pushfstring(L, "%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + switch (*ar.namewhat) { + case 'g': /* global */ + case 'l': /* local */ + case 'f': /* field */ + case 'm': /* method */ + lua_pushfstring(L, " in function `%s'", ar.name); + break; + default: { + if (*ar.what == 'm') /* main? */ + lua_pushfstring(L, " in main chunk"); + else if (*ar.what == 'C' || *ar.what == 't') + lua_pushliteral(L, " ?"); /* C function or tail call */ + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); + } + } + lua_concat(L, lua_gettop(L)); + } + lua_concat(L, lua_gettop(L)); return 1; } -static const struct luaL_reg dblib[] = { +static const luaL_reg dblib[] = { {"getlocal", getlocal}, {"getinfo", getinfo}, - {"setcallhook", setcallhook}, - {"setlinehook", setlinehook}, - {"setlocal", setlocal} + {"gethook", gethook}, + {"getupvalue", getupvalue}, + {"sethook", sethook}, + {"setlocal", setlocal}, + {"setupvalue", setupvalue}, + {"debug", debug}, + {"traceback", errorfb}, + {NULL, NULL} }; -LUALIB_API void lua_dblibopen (lua_State *L) { - luaL_openl(L, dblib); +LUALIB_API int luaopen_debug (lua_State *L) { + luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); + lua_pushliteral(L, "_TRACEBACK"); + lua_pushcfunction(L, errorfb); + lua_settable(L, LUA_GLOBALSINDEX); + return 1; } diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 70f8057ac9..14bd7d9909 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,302 +1,309 @@ /* -** $Id: liolib.c,v 1.91 2000/10/31 13:10:24 roberto Exp $ +** $Id: liolib.c,v 2.39 2003/03/19 21:16:12 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ -#include +#include +#include #include #include #include #include +#define liolib_c + #include "lua.h" #include "lauxlib.h" -#include "luadebug.h" #include "lualib.h" -#ifndef OLD_ANSI -#include -#include -#define realloc(b,s) ((b) == NULL ? malloc(s) : (realloc)(b, s)) -#define free(b) if (b) (free)(b) + +/* +** by default, gcc does not get `tmpname' +*/ +#ifndef USE_TMPNAME +#ifdef __GNUC__ +#define USE_TMPNAME 0 #else -/* no support for locale and for strerror: fake them */ -#define setlocale(a,b) ((void)a, strcmp((b),"C")==0?"C":NULL) -#define LC_ALL 0 -#define LC_COLLATE 0 -#define LC_CTYPE 0 -#define LC_MONETARY 0 -#define LC_NUMERIC 0 -#define LC_TIME 0 -#define strerror(e) "generic I/O error" -#define errno (-1) +#define USE_TMPNAME 1 +#endif #endif +/* +** by default, posix systems get `popen' +*/ +#ifndef USE_POPEN +#ifdef _POSIX_C_SOURCE +#if _POSIX_C_SOURCE >= 2 +#define USE_POPEN 1 +#endif +#endif +#endif -#ifdef POPEN -/* FILE *popen(); -int pclose(); */ -#define CLOSEFILE(L, f) ((pclose(f) == -1) ? fclose(f) : 0) -#else -/* no support for popen */ -#define popen(x,y) NULL /* that is, popen always fails */ -#define CLOSEFILE(L, f) (fclose(f)) +#ifndef USE_POPEN +#define USE_POPEN 0 #endif -#define INFILE 0 -#define OUTFILE 1 -typedef struct IOCtrl { - int ref[2]; /* ref for strings _INPUT/_OUTPUT */ - int iotag; /* tag for file handles */ - int closedtag; /* tag for closed handles */ -} IOCtrl; + +/* +** {====================================================== +** FILE Operations +** ======================================================= +*/ + + +#if !USE_POPEN +#define pclose(f) (-1) +#endif +#define FILEHANDLE "FILE*" -static const char *const filenames[] = {"_INPUT", "_OUTPUT"}; +#define IO_INPUT "_input" +#define IO_OUTPUT "_output" -static int pushresult (lua_State *L, int i) { +static int pushresult (lua_State *L, int i, const char *filename) { if (i) { - lua_pushuserdata(L, NULL); + lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); - lua_pushstring(L, strerror(errno)); + if (filename) + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + else + lua_pushfstring(L, "%s", strerror(errno)); lua_pushnumber(L, errno); - return 3;; - } -} - - -/* -** {====================================================== -** FILE Operations -** ======================================================= -*/ - - -static FILE *gethandle (lua_State *L, IOCtrl *ctrl, int f) { - void *p = lua_touserdata(L, f); - if (p != NULL) { /* is `f' a userdata ? */ - int ftag = lua_tag(L, f); - if (ftag == ctrl->iotag) /* does it have the correct tag? */ - return (FILE *)p; - else if (ftag == ctrl->closedtag) - lua_error(L, "cannot access a closed file"); - /* else go through */ + return 3; } - return NULL; } -static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) { - FILE *f = gethandle(L, ctrl, arg); - luaL_arg_check(L, f, arg, "invalid file handle"); +static FILE **topfile (lua_State *L, int findex) { + FILE **f = (FILE **)luaL_checkudata(L, findex, FILEHANDLE); + if (f == NULL) luaL_argerror(L, findex, "bad file"); return f; } -static FILE *getfilebyref (lua_State *L, IOCtrl *ctrl, int inout) { - FILE *f; - lua_getglobals(L); - lua_getref(L, ctrl->ref[inout]); - lua_rawget(L, -2); - f = gethandle(L, ctrl, -1); - if (f == NULL) - luaL_verror(L, "global variable `%.10s' is not a file handle", - filenames[inout]); - return f; +static int io_type (lua_State *L) { + FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE); + if (f == NULL) lua_pushnil(L); + else if (*f == NULL) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; } -static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f, - const char *name) { - lua_pushusertag(L, f, ctrl->iotag); - lua_setglobal(L, name); +static FILE *tofile (lua_State *L, int findex) { + FILE **f = topfile(L, findex); + if (*f == NULL) + luaL_error(L, "attempt to use a closed file"); + return *f; } -#define setfile(L,ctrl,f,inout) (setfilebyname(L,ctrl,f,filenames[inout])) +/* +** When creating file handles, always creates a `closed' file handle +** before opening the actual file; so, if there is a memory error, the +** file is not left opened. +*/ +static FILE **newfile (lua_State *L) { + FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); + *pf = NULL; /* file handle is currently `closed' */ + luaL_getmetatable(L, FILEHANDLE); + lua_setmetatable(L, -2); + return pf; +} -static int setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) { - if (f == NULL) - return pushresult(L, 0); - else { - setfile(L, ctrl, f, inout); - lua_pushusertag(L, f, ctrl->iotag); - return 1; + +/* +** assumes that top of the stack is the `io' library, and next is +** the `io' metatable +*/ +static void registerfile (lua_State *L, FILE *f, const char *name, + const char *impname) { + lua_pushstring(L, name); + *newfile(L) = f; + if (impname) { + lua_pushstring(L, impname); + lua_pushvalue(L, -2); + lua_settable(L, -6); /* metatable[impname] = file */ } + lua_settable(L, -3); /* io[name] = file */ } -static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) { +static int aux_close (lua_State *L) { + FILE *f = tofile(L, 1); if (f == stdin || f == stdout || f == stderr) - return 1; + return 0; /* file cannot be closed */ else { - lua_pushusertag(L, f, ctrl->iotag); - lua_settag(L, ctrl->closedtag); - return (CLOSEFILE(L, f) == 0); + int ok = (pclose(f) != -1) || (fclose(f) == 0); + if (ok) + *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ + return ok; } } static int io_close (lua_State *L) { - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - lua_pop(L, 1); /* remove upvalue */ - return pushresult(L, closefile(L, ctrl, getnonullfile(L, ctrl, 1))); + if (lua_isnone(L, 1)) { + lua_pushstring(L, IO_OUTPUT); + lua_rawget(L, lua_upvalueindex(1)); + } + return pushresult(L, aux_close(L), NULL); } -static int file_collect (lua_State *L) { - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - FILE *f = getnonullfile(L, ctrl, 1); - if (f != stdin && f != stdout && f != stderr) - CLOSEFILE(L, f); +static int io_gc (lua_State *L) { + FILE **f = topfile(L, 1); + if (*f != NULL) /* ignore closed files */ + aux_close(L); return 0; } -static int io_open (lua_State *L) { - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - FILE *f; - lua_pop(L, 1); /* remove upvalue */ - f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2)); - if (f) { - lua_pushusertag(L, f, ctrl->iotag); - return 1; - } +static int io_tostring (lua_State *L) { + char buff[32]; + FILE **f = topfile(L, 1); + if (*f == NULL) + strcpy(buff, "closed"); else - return pushresult(L, 0); + sprintf(buff, "%p", lua_touserdata(L, 1)); + lua_pushfstring(L, "file (%s)", buff); + return 1; } +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + FILE **pf = newfile(L); + *pf = fopen(filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} -static int io_fromto (lua_State *L, int inout, const char *mode) { - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - FILE *current; - lua_pop(L, 1); /* remove upvalue */ - if (lua_isnull(L, 1)) { - closefile(L, ctrl, getfilebyref(L, ctrl, inout)); - current = (inout == 0) ? stdin : stdout; - } - else if (lua_tag(L, 1) == ctrl->iotag) /* deprecated option */ - current = (FILE *)lua_touserdata(L, 1); - else { - const char *s = luaL_check_string(L, 1); - current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode); - } - return setreturn(L, ctrl, current, inout); + +static int io_popen (lua_State *L) { +#if !USE_POPEN + luaL_error(L, "`popen' not supported"); + return 0; +#else + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + FILE **pf = newfile(L); + *pf = popen(filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +#endif } -static int io_readfrom (lua_State *L) { - return io_fromto(L, INFILE, "r"); +static int io_tmpfile (lua_State *L) { + FILE **pf = newfile(L); + *pf = tmpfile(); + return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; } -static int io_writeto (lua_State *L) { - return io_fromto(L, OUTFILE, "w"); +static FILE *getiofile (lua_State *L, const char *name) { + lua_pushstring(L, name); + lua_rawget(L, lua_upvalueindex(1)); + return tofile(L, -1); } -static int io_appendto (lua_State *L) { - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - FILE *current; - lua_pop(L, 1); /* remove upvalue */ - current = fopen(luaL_check_string(L, 1), "a"); - return setreturn(L, ctrl, current, OUTFILE); +static int g_iofile (lua_State *L, const char *name, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + lua_pushstring(L, name); + if (filename) { + FILE **pf = newfile(L); + *pf = fopen(filename, mode); + if (*pf == NULL) { + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + luaL_argerror(L, 1, lua_tostring(L, -1)); + } + } + else { + tofile(L, 1); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_rawset(L, lua_upvalueindex(1)); + } + /* return current value */ + lua_pushstring(L, name); + lua_rawget(L, lua_upvalueindex(1)); + return 1; } +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} -/* -** {====================================================== -** READ -** ======================================================= -*/ +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} -#ifdef LUA_COMPAT_READPATTERN +static int io_readline (lua_State *L); -/* -** We cannot lookahead without need, because this can lock stdin. -** This flag signals when we need to read a next char. -*/ -#define NEED_OTHER (EOF-1) /* just some flag different from EOF */ +static void aux_lines (lua_State *L, int idx, int close) { + lua_pushliteral(L, FILEHANDLE); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, idx); + lua_pushboolean(L, close); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 3); +} -static int read_pattern (lua_State *L, FILE *f, const char *p) { - int inskip = 0; /* {skip} level */ - int c = NEED_OTHER; - luaL_Buffer b; - luaL_buffinit(L, &b); - while (*p != '\0') { - switch (*p) { - case '{': - inskip++; - p++; - continue; - case '}': - if (!inskip) lua_error(L, "unbalanced braces in read pattern"); - inskip--; - p++; - continue; - default: { - const char *ep = luaI_classend(L, p); /* get what is next */ - int m; /* match result */ - if (c == NEED_OTHER) c = getc(f); - m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); - if (m) { - if (!inskip) luaL_putchar(&b, c); - c = NEED_OTHER; - } - switch (*ep) { - case '+': /* repetition (1 or more) */ - if (!m) goto break_while; /* pattern fails? */ - /* else go through */ - case '*': /* repetition (0 or more) */ - while (m) { /* reads the same item until it fails */ - c = getc(f); - m = (c==EOF) ? 0 : luaI_singlematch(c, p, ep); - if (m && !inskip) luaL_putchar(&b, c); - } - /* go through to continue reading the pattern */ - case '?': /* optional */ - p = ep+1; /* continues reading the pattern */ - continue; - default: - if (!m) goto break_while; /* pattern fails? */ - p = ep; /* else continues reading the pattern */ - } - } - } - } break_while: - if (c != NEED_OTHER) ungetc(c, f); - luaL_pushresult(&b); /* close buffer */ - return (*p == '\0'); + +static int f_lines (lua_State *L) { + tofile(L, 1); /* check that it's a valid file handle */ + aux_lines(L, 1, 0); + return 1; } -#else -#define read_pattern(L, f, p) (lua_error(L, "read patterns are deprecated"), 0) +static int io_lines (lua_State *L) { + if (lua_isnoneornil(L, 1)) { /* no arguments? */ + lua_pushstring(L, IO_INPUT); + lua_rawget(L, lua_upvalueindex(1)); /* will iterate over default input */ + return f_lines(L); + } + else { + const char *filename = luaL_checkstring(L, 1); + FILE **pf = newfile(L); + *pf = fopen(filename, "r"); + luaL_argcheck(L, *pf, 1, strerror(errno)); + aux_lines(L, lua_gettop(L), 1); + return 1; + } +} + -#endif +/* +** {====================================================== +** READ +** ======================================================= +*/ static int read_number (lua_State *L, FILE *f) { - double d; - if (fscanf(f, "%lf", &d) == 1) { + lua_Number d; + if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { lua_pushnumber(L, d); return 1; } @@ -304,175 +311,167 @@ static int read_number (lua_State *L, FILE *f) { } -static int read_word (lua_State *L, FILE *f) { - int c; - luaL_Buffer b; - luaL_buffinit(L, &b); - do { c = fgetc(f); } while (isspace(c)); /* skip spaces */ - while (c != EOF && !isspace(c)) { - luaL_putchar(&b, c); - c = fgetc(f); - } +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); ungetc(c, f); - luaL_pushresult(&b); /* close buffer */ - return (lua_strlen(L, -1) > 0); + lua_pushlstring(L, NULL, 0); + return (c != EOF); } static int read_line (lua_State *L, FILE *f) { - int n = 0; luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { + size_t l; char *p = luaL_prepbuffer(&b); - if (!fgets(p, LUAL_BUFFERSIZE, f)) /* read fails? */ - break; - n = strlen(p); - if (p[n-1] != '\n') - luaL_addsize(&b, n); - else { - luaL_addsize(&b, n-1); /* do not add the `\n' */ - break; + if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ + luaL_pushresult(&b); /* close buffer */ + return (lua_strlen(L, -1) > 0); /* check whether read something */ } - } - luaL_pushresult(&b); /* close buffer */ - return (n > 0); /* read something? */ -} - - -static void read_file (lua_State *L, FILE *f) { - size_t len = 0; - size_t size = BUFSIZ; - char *buffer = NULL; - for (;;) { - char *newbuffer = (char *)realloc(buffer, size); - if (newbuffer == NULL) { - free(buffer); - lua_error(L, "not enough memory to read a file"); + l = strlen(p); + if (p[l-1] != '\n') + luaL_addsize(&b, l); + else { + luaL_addsize(&b, l - 1); /* do not include `eol' */ + luaL_pushresult(&b); /* close buffer */ + return 1; /* read at least an `eol' */ } - buffer = newbuffer; - len += fread(buffer+len, sizeof(char), size-len, f); - if (len < size) break; /* did not read all it could */ - size *= 2; } - lua_pushlstring(L, buffer, len); - free(buffer); } static int read_chars (lua_State *L, FILE *f, size_t n) { - char *buffer; - size_t n1; - char statbuff[BUFSIZ]; - if (n <= BUFSIZ) - buffer = statbuff; - else { - buffer = (char *)malloc(n); - if (buffer == NULL) - lua_error(L, "not enough memory to read a file"); - } - n1 = fread(buffer, sizeof(char), n, f); - lua_pushlstring(L, buffer, n1); - if (buffer != statbuff) free(buffer); - return (n1 > 0 || n == 0); + size_t rlen; /* how much to read */ + size_t nr; /* number of chars actually read */ + luaL_Buffer b; + luaL_buffinit(L, &b); + rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ + do { + char *p = luaL_prepbuffer(&b); + if (rlen > n) rlen = n; /* cannot read more than asked */ + nr = fread(p, sizeof(char), rlen, f); + luaL_addsize(&b, nr); + n -= nr; /* still have to read `n' chars */ + } while (n > 0 && nr == rlen); /* until end of count or eof */ + luaL_pushresult(&b); /* close buffer */ + return (n == 0 || lua_strlen(L, -1) > 0); } -static int io_read (lua_State *L) { - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - int lastarg = lua_gettop(L) - 1; - int firstarg = 1; - FILE *f = gethandle(L, ctrl, firstarg); +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int success; int n; - if (f) firstarg++; - else f = getfilebyref(L, ctrl, INFILE); /* get _INPUT */ - lua_pop(L, 1); - if (firstarg > lastarg) { /* no arguments? */ - lua_settop(L, 0); /* erase upvalue and other eventual garbage */ - firstarg = lastarg = 1; /* correct indices */ - lua_pushstring(L, "*l"); /* push default argument */ + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f); + n = first+1; /* to return 1 result */ } - else /* ensure stack space for all results and for auxlib's buffer */ - luaL_checkstack(L, lastarg-firstarg+1+LUA_MINSTACK, "too many arguments"); - for (n = firstarg; n<=lastarg; n++) { - int success; - if (lua_isnumber(L, n)) - success = read_chars(L, f, (size_t)lua_tonumber(L, n)); - else { - const char *p = luaL_check_string(L, n); - if (p[0] != '*') - success = read_pattern(L, f, p); /* deprecated! */ + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)lua_tonumber(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } else { + const char *p = lua_tostring(L, n); + luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'n': /* number */ - if (!read_number(L, f)) goto endloop; /* read fails */ - continue; /* number is already pushed; avoid the "pushstring" */ + success = read_number(L, f); + break; case 'l': /* line */ success = read_line(L, f); break; case 'a': /* file */ - read_file(L, f); + read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = 1; /* always success */ break; case 'w': /* word */ - success = read_word(L, f); - break; + return luaL_error(L, "obsolete option `*w' to `read'"); default: - luaL_argerror(L, n, "invalid format"); - success = 0; /* to avoid warnings */ + return luaL_argerror(L, n, "invalid format"); } } } - if (!success) { - lua_pop(L, 1); /* remove last result */ - break; /* read fails */ + } + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L, 1), 2); +} + + +static int io_readline (lua_State *L) { + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2)); + if (f == NULL) /* file is already closed? */ + luaL_error(L, "file is already closed"); + if (read_line(L, f)) return 1; + else { /* EOF */ + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(2)); + aux_close(L); /* close it */ } - } endloop: - return n - firstarg; + return 0; + } } /* }====================================================== */ -static int io_write (lua_State *L) { - int lastarg = lua_gettop(L) - 1; - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - int arg = 1; +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - 1; int status = 1; - FILE *f = gethandle(L, ctrl, arg); - if (f) arg++; - else f = getfilebyref(L, ctrl, OUTFILE); /* get _OUTPUT */ - for (; arg <= lastarg; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { /* LUA_NUMBER */ + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ - status = status && fprintf(f, "%.16g", lua_tonumber(L, arg)) > 0; + status = status && + fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; } else { size_t l; - const char *s = luaL_check_lstr(L, arg, &l); + const char *s = luaL_checklstring(L, arg, &l); status = status && (fwrite(s, sizeof(char), l, f) == l); } } - pushresult(L, status); - return 1; + return pushresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); } -static int io_seek (lua_State *L) { +static int f_write (lua_State *L) { + return g_write(L, tofile(L, 1), 2); +} + + +static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - FILE *f; - int op; - long offset; - lua_pop(L, 1); /* remove upvalue */ - f = getnonullfile(L, ctrl, 1); - op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames); - offset = luaL_opt_long(L, 3, 0); - luaL_arg_check(L, op != -1, 2, "invalid mode"); + FILE *f = tofile(L, 1); + int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); + long offset = luaL_optlong(L, 3, 0); + luaL_argcheck(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) - return pushresult(L, 0); /* error */ + return pushresult(L, 0, NULL); /* error */ else { lua_pushnumber(L, ftell(f)); return 1; @@ -481,12 +480,51 @@ static int io_seek (lua_State *L) { static int io_flush (lua_State *L) { - IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1); - FILE *f; - lua_pop(L, 1); /* remove upvalue */ - f = gethandle(L, ctrl, 1); - luaL_arg_check(L, f || lua_isnull(L, 1), 1, "invalid file handle"); - return pushresult(L, fflush(f) == 0); + return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return pushresult(L, fflush(tofile(L, 1)) == 0, NULL); +} + + +static const luaL_reg iolib[] = { + {"input", io_input}, + {"output", io_output}, + {"lines", io_lines}, + {"close", io_close}, + {"flush", io_flush}, + {"open", io_open}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +static const luaL_reg flib[] = { + {"flush", f_flush}, + {"read", f_read}, + {"lines", f_lines}, + {"seek", f_seek}, + {"write", f_write}, + {"close", io_close}, + {"__gc", io_gc}, + {"__tostring", io_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ + /* file methods */ + lua_pushliteral(L, "__index"); + lua_pushvalue(L, -2); /* push metatable */ + lua_rawset(L, -3); /* metatable.__index = metatable */ + luaL_openlib(L, NULL, flib, 0); } /* }====================================================== */ @@ -499,220 +537,214 @@ static int io_flush (lua_State *L) { */ static int io_execute (lua_State *L) { - lua_pushnumber(L, system(luaL_check_string(L, 1))); + lua_pushnumber(L, system(luaL_checkstring(L, 1))); return 1; } static int io_remove (lua_State *L) { - return pushresult(L, remove(luaL_check_string(L, 1)) == 0); + const char *filename = luaL_checkstring(L, 1); + return pushresult(L, remove(filename) == 0, filename); } static int io_rename (lua_State *L) { - return pushresult(L, rename(luaL_check_string(L, 1), - luaL_check_string(L, 2)) == 0); + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return pushresult(L, rename(fromname, toname) == 0, fromname); } static int io_tmpname (lua_State *L) { - lua_pushstring(L, tmpnam(NULL)); +#if !USE_TMPNAME + luaL_error(L, "`tmpname' not supported"); + return 0; +#else + char buff[L_tmpnam]; + if (tmpnam(buff) != buff) + return luaL_error(L, "unable to generate a unique filename in `tmpname'"); + lua_pushstring(L, buff); return 1; +#endif } - static int io_getenv (lua_State *L) { - lua_pushstring(L, getenv(luaL_check_string(L, 1))); /* if NULL push nil */ + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ return 1; } static int io_clock (lua_State *L) { - lua_pushnumber(L, ((double)clock())/CLOCKS_PER_SEC); + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); return 1; } +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushstring(L, key); + lua_pushnumber(L, value); + lua_rawset(L, -3); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + lua_pushstring(L, key); + lua_pushboolean(L, value); + lua_rawset(L, -3); +} + +static int getboolfield (lua_State *L, const char *key) { + int res; + lua_pushstring(L, key); + lua_gettable(L, -2); + res = lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d) { + int res; + lua_pushstring(L, key); + lua_gettable(L, -2); + if (lua_isnumber(L, -1)) + res = (int)(lua_tonumber(L, -1)); + else { + if (d == -2) + return luaL_error(L, "field `%s' missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + static int io_date (lua_State *L) { - char b[256]; - const char *s = luaL_opt_string(L, 1, "%c"); + const char *s = luaL_optstring(L, 1, "%c"); + time_t t = (time_t)(luaL_optnumber(L, 2, -1)); struct tm *stm; - time_t t; - time(&t); stm = localtime(&t); - if (strftime(b, sizeof(b), s, stm)) - lua_pushstring(L, b); + if (t == (time_t)(-1)) /* no time given? */ + t = time(NULL); /* use current time */ + if (*s == '!') { /* UTC? */ + stm = gmtime(&t); + s++; /* skip `!' */ + } else - lua_error(L, "invalid `date' format"); + stm = localtime(&t); + if (stm == NULL) /* invalid date? */ + lua_pushnil(L); + else if (strcmp(s, "*t") == 0) { + lua_newtable(L); + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon+1); + setfield(L, "year", stm->tm_year+1900); + setfield(L, "wday", stm->tm_wday+1); + setfield(L, "yday", stm->tm_yday+1); + setboolfield(L, "isdst", stm->tm_isdst); + } + else { + char b[256]; + if (strftime(b, sizeof(b), s, stm)) + lua_pushstring(L, b); + else + return luaL_error(L, "`date' format too long"); + } return 1; } -static int setloc (lua_State *L) { - static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, - LC_NUMERIC, LC_TIME}; - static const char *const catnames[] = {"all", "collate", "ctype", "monetary", - "numeric", "time", NULL}; - int op = luaL_findstring(luaL_opt_string(L, 2, "all"), catnames); - luaL_arg_check(L, op != -1, 2, "invalid option"); - lua_pushstring(L, setlocale(cat[op], luaL_check_string(L, 1))); +static int io_time (lua_State *L) { + if (lua_isnoneornil(L, 1)) /* called without args? */ + lua_pushnumber(L, time(NULL)); /* return current time */ + else { + time_t t; + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0); + ts.tm_min = getfield(L, "min", 0); + ts.tm_hour = getfield(L, "hour", 12); + ts.tm_mday = getfield(L, "day", -2); + ts.tm_mon = getfield(L, "month", -2) - 1; + ts.tm_year = getfield(L, "year", -2) - 1900; + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + if (t == (time_t)(-1)) + lua_pushnil(L); + else + lua_pushnumber(L, t); + } return 1; } -static int io_exit (lua_State *L) { - exit(luaL_opt_int(L, 1, EXIT_SUCCESS)); - return 0; /* to avoid warnings */ +static int io_difftime (lua_State *L) { + lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), + (time_t)(luaL_optnumber(L, 2, 0)))); + return 1; } /* }====================================================== */ - -static int io_debug (lua_State *L) { - for (;;) { - char buffer[250]; - fprintf(stderr, "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0 || - strcmp(buffer, "cont\n") == 0) - return 0; - lua_dostring(L, buffer); - lua_settop(L, 0); /* remove eventual returns */ - } +static int io_setloc (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = lua_tostring(L, 1); + int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames); + luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); + luaL_argcheck(L, op != -1, 2, "invalid option"); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; } -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ - -static int errorfb (lua_State *L) { - int level = 1; /* skip level 0 (it's this function) */ - int firstpart = 1; /* still before eventual `...' */ - lua_Debug ar; - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addstring(&b, "error: "); - luaL_addstring(&b, luaL_check_string(L, 1)); - luaL_addstring(&b, "\n"); - while (lua_getstack(L, level++, &ar)) { - char buff[120]; /* enough to fit following `sprintf's */ - if (level == 2) - luaL_addstring(&b, "stack traceback:\n"); - else if (level > LEVELS1 && firstpart) { - /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L, level+LEVELS2, &ar)) - level--; /* keep going */ - else { - luaL_addstring(&b, " ...\n"); /* too many levels */ - while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ - level++; - } - firstpart = 0; - continue; - } - sprintf(buff, "%4d: ", level-1); - luaL_addstring(&b, buff); - lua_getinfo(L, "Snl", &ar); - switch (*ar.namewhat) { - case 'g': case 'l': /* global, local */ - sprintf(buff, "function `%.50s'", ar.name); - break; - case 'f': /* field */ - sprintf(buff, "method `%.50s'", ar.name); - break; - case 't': /* tag method */ - sprintf(buff, "`%.50s' tag method", ar.name); - break; - default: { - if (*ar.what == 'm') /* main? */ - sprintf(buff, "main of %.70s", ar.short_src); - else if (*ar.what == 'C') /* C function? */ - sprintf(buff, "%.70s", ar.short_src); - else - sprintf(buff, "function <%d:%.70s>", ar.linedefined, ar.short_src); - ar.source = NULL; /* do not print source again */ - } - } - luaL_addstring(&b, buff); - if (ar.currentline > 0) { - sprintf(buff, " at line %d", ar.currentline); - luaL_addstring(&b, buff); - } - if (ar.source) { - sprintf(buff, " [%.70s]", ar.short_src); - luaL_addstring(&b, buff); - } - luaL_addstring(&b, "\n"); - } - luaL_pushresult(&b); - lua_getglobal(L, LUA_ALERT); - if (lua_isfunction(L, -1)) { /* avoid loop if _ALERT is not defined */ - lua_pushvalue(L, -2); /* error message */ - lua_rawcall(L, 1, 0); - } - return 0; +static int io_exit (lua_State *L) { + exit(luaL_optint(L, 1, EXIT_SUCCESS)); + return 0; /* to avoid warnings */ } - - -static const struct luaL_reg iolib[] = { - {LUA_ERRORMESSAGE, errorfb}, +static const luaL_reg syslib[] = { {"clock", io_clock}, - {"date", io_date}, - {"debug", io_debug}, - {"execute", io_execute}, - {"exit", io_exit}, - {"getenv", io_getenv}, - {"remove", io_remove}, - {"rename", io_rename}, - {"setlocale", setloc}, - {"tmpname", io_tmpname} + {"date", io_date}, + {"difftime", io_difftime}, + {"execute", io_execute}, + {"exit", io_exit}, + {"getenv", io_getenv}, + {"remove", io_remove}, + {"rename", io_rename}, + {"setlocale", io_setloc}, + {"time", io_time}, + {"tmpname", io_tmpname}, + {NULL, NULL} }; +/* }====================================================== */ -static const struct luaL_reg iolibtag[] = { - {"appendto", io_appendto}, - {"closefile", io_close}, - {"flush", io_flush}, - {"openfile", io_open}, - {"read", io_read}, - {"readfrom", io_readfrom}, - {"seek", io_seek}, - {"write", io_write}, - {"writeto", io_writeto} -}; -static void openwithcontrol (lua_State *L) { - IOCtrl *ctrl = (IOCtrl *)lua_newuserdata(L, sizeof(IOCtrl)); - unsigned int i; - ctrl->iotag = lua_newtag(L); - ctrl->closedtag = lua_newtag(L); - for (i=0; iref[INFILE] = lua_ref(L, 1); - lua_pushstring(L, filenames[OUTFILE]); - ctrl->ref[OUTFILE] = lua_ref(L, 1); - /* predefined file handles */ - setfile(L, ctrl, stdin, INFILE); - setfile(L, ctrl, stdout, OUTFILE); - setfilebyname(L, ctrl, stdin, "_STDIN"); - setfilebyname(L, ctrl, stdout, "_STDOUT"); - setfilebyname(L, ctrl, stderr, "_STDERR"); - /* close files when collected */ - lua_pushcclosure(L, file_collect, 1); /* pops `ctrl' from stack */ - lua_settagmethod(L, ctrl->iotag, "gc"); -} - - -LUALIB_API void lua_iolibopen (lua_State *L) { - luaL_openl(L, iolib); - openwithcontrol(L); +LUALIB_API int luaopen_io (lua_State *L) { + luaL_openlib(L, LUA_OSLIBNAME, syslib, 0); + createmeta(L); + lua_pushvalue(L, -1); + luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); + /* put predefined file handles into `io' table */ + registerfile(L, stdin, "stdin", IO_INPUT); + registerfile(L, stdout, "stdout", IO_OUTPUT); + registerfile(L, stderr, "stderr", NULL); + return 1; } diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c index c062cf4975..f074a56ee7 100644 --- a/src/lib/lmathlib.c +++ b/src/lib/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.32 2000/10/31 13:10:24 roberto Exp $ +** $Id: lmathlib.c,v 1.56 2003/03/11 12:30:37 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -8,6 +8,8 @@ #include #include +#define lmathlib_c + #include "lua.h" #include "lauxlib.h" @@ -21,117 +23,117 @@ /* -** If you want Lua to operate in radians (instead of degrees), -** define RADIANS +** If you want Lua to operate in degrees (instead of radians), +** define USE_DEGREES */ -#ifdef RADIANS -#define FROMRAD(a) (a) -#define TORAD(a) (a) -#else +#ifdef USE_DEGREES #define FROMRAD(a) ((a)/RADIANS_PER_DEGREE) #define TORAD(a) ((a)*RADIANS_PER_DEGREE) +#else +#define FROMRAD(a) (a) +#define TORAD(a) (a) #endif static int math_abs (lua_State *L) { - lua_pushnumber(L, fabs(luaL_check_number(L, 1))); + lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { - lua_pushnumber(L, sin(TORAD(luaL_check_number(L, 1)))); + lua_pushnumber(L, sin(TORAD(luaL_checknumber(L, 1)))); return 1; } static int math_cos (lua_State *L) { - lua_pushnumber(L, cos(TORAD(luaL_check_number(L, 1)))); + lua_pushnumber(L, cos(TORAD(luaL_checknumber(L, 1)))); return 1; } static int math_tan (lua_State *L) { - lua_pushnumber(L, tan(TORAD(luaL_check_number(L, 1)))); + lua_pushnumber(L, tan(TORAD(luaL_checknumber(L, 1)))); return 1; } static int math_asin (lua_State *L) { - lua_pushnumber(L, FROMRAD(asin(luaL_check_number(L, 1)))); + lua_pushnumber(L, FROMRAD(asin(luaL_checknumber(L, 1)))); return 1; } static int math_acos (lua_State *L) { - lua_pushnumber(L, FROMRAD(acos(luaL_check_number(L, 1)))); + lua_pushnumber(L, FROMRAD(acos(luaL_checknumber(L, 1)))); return 1; } static int math_atan (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan(luaL_check_number(L, 1)))); + lua_pushnumber(L, FROMRAD(atan(luaL_checknumber(L, 1)))); return 1; } static int math_atan2 (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan2(luaL_check_number(L, 1), luaL_check_number(L, 2)))); + lua_pushnumber(L, FROMRAD(atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)))); return 1; } static int math_ceil (lua_State *L) { - lua_pushnumber(L, ceil(luaL_check_number(L, 1))); + lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { - lua_pushnumber(L, floor(luaL_check_number(L, 1))); + lua_pushnumber(L, floor(luaL_checknumber(L, 1))); return 1; } static int math_mod (lua_State *L) { - lua_pushnumber(L, fmod(luaL_check_number(L, 1), luaL_check_number(L, 2))); + lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_sqrt (lua_State *L) { - lua_pushnumber(L, sqrt(luaL_check_number(L, 1))); + lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { - lua_pushnumber(L, pow(luaL_check_number(L, 1), luaL_check_number(L, 2))); + lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_log (lua_State *L) { - lua_pushnumber(L, log(luaL_check_number(L, 1))); + lua_pushnumber(L, log(luaL_checknumber(L, 1))); return 1; } static int math_log10 (lua_State *L) { - lua_pushnumber(L, log10(luaL_check_number(L, 1))); + lua_pushnumber(L, log10(luaL_checknumber(L, 1))); return 1; } static int math_exp (lua_State *L) { - lua_pushnumber(L, exp(luaL_check_number(L, 1))); + lua_pushnumber(L, exp(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { - lua_pushnumber(L, luaL_check_number(L, 1)/RADIANS_PER_DEGREE); + lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); return 1; } static int math_rad (lua_State *L) { - lua_pushnumber(L, luaL_check_number(L, 1)*RADIANS_PER_DEGREE); + lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); return 1; } static int math_frexp (lua_State *L) { int e; - lua_pushnumber(L, frexp(luaL_check_number(L, 1), &e)); + lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); lua_pushnumber(L, e); return 2; } static int math_ldexp (lua_State *L) { - lua_pushnumber(L, ldexp(luaL_check_number(L, 1), luaL_check_int(L, 2))); + lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); return 1; } @@ -139,10 +141,10 @@ static int math_ldexp (lua_State *L) { static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ - double dmin = luaL_check_number(L, 1); + lua_Number dmin = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { - double d = luaL_check_number(L, i); + lua_Number d = luaL_checknumber(L, i); if (d < dmin) dmin = d; } @@ -153,10 +155,10 @@ static int math_min (lua_State *L) { static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ - double dmax = luaL_check_number(L, 1); + lua_Number dmax = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { - double d = luaL_check_number(L, i); + lua_Number d = luaL_checknumber(L, i); if (d > dmax) dmax = d; } @@ -166,73 +168,79 @@ static int math_max (lua_State *L) { static int math_random (lua_State *L) { - /* the '%' avoids the (rare) case of r==1, and is needed also because on - some systems (SunOS!) "rand()" may return a value larger than RAND_MAX */ - double r = (double)(rand()%RAND_MAX) / (double)RAND_MAX; + /* the `%' avoids the (rare) case of r==1, and is needed also because on + some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ + lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ lua_pushnumber(L, r); /* Number between 0 and 1 */ break; } case 1: { /* only upper limit */ - int u = luaL_check_int(L, 1); - luaL_arg_check(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, (int)(r*u)+1); /* integer between 1 and `u' */ + int u = luaL_checkint(L, 1); + luaL_argcheck(L, 1<=u, 1, "interval is empty"); + lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ - int l = luaL_check_int(L, 1); - int u = luaL_check_int(L, 2); - luaL_arg_check(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, (int)(r*(u-l+1))+l); /* integer between `l' and `u' */ + int l = luaL_checkint(L, 1); + int u = luaL_checkint(L, 2); + luaL_argcheck(L, l<=u, 2, "interval is empty"); + lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */ break; } - default: lua_error(L, "wrong number of arguments"); + default: return luaL_error(L, "wrong number of arguments"); } return 1; } static int math_randomseed (lua_State *L) { - srand(luaL_check_int(L, 1)); + srand(luaL_checkint(L, 1)); return 0; } -static const struct luaL_reg mathlib[] = { -{"abs", math_abs}, -{"sin", math_sin}, -{"cos", math_cos}, -{"tan", math_tan}, -{"asin", math_asin}, -{"acos", math_acos}, -{"atan", math_atan}, -{"atan2", math_atan2}, -{"ceil", math_ceil}, -{"floor", math_floor}, -{"mod", math_mod}, -{"frexp", math_frexp}, -{"ldexp", math_ldexp}, -{"sqrt", math_sqrt}, -{"min", math_min}, -{"max", math_max}, -{"log", math_log}, -{"log10", math_log10}, -{"exp", math_exp}, -{"deg", math_deg}, -{"rad", math_rad}, -{"random", math_random}, -{"randomseed", math_randomseed} +static const luaL_reg mathlib[] = { + {"abs", math_abs}, + {"sin", math_sin}, + {"cos", math_cos}, + {"tan", math_tan}, + {"asin", math_asin}, + {"acos", math_acos}, + {"atan", math_atan}, + {"atan2", math_atan2}, + {"ceil", math_ceil}, + {"floor", math_floor}, + {"mod", math_mod}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"sqrt", math_sqrt}, + {"min", math_min}, + {"max", math_max}, + {"log", math_log}, + {"log10", math_log10}, + {"exp", math_exp}, + {"deg", math_deg}, + {"pow", math_pow}, + {"rad", math_rad}, + {"random", math_random}, + {"randomseed", math_randomseed}, + {NULL, NULL} }; + /* ** Open math library */ -LUALIB_API void lua_mathlibopen (lua_State *L) { - luaL_openl(L, mathlib); - lua_pushcfunction(L, math_pow); - lua_settagmethod(L, LUA_TNUMBER, "pow"); +LUALIB_API int luaopen_math (lua_State *L) { + luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); + lua_pushliteral(L, "pi"); lua_pushnumber(L, PI); - lua_setglobal(L, "PI"); + lua_settable(L, -3); + lua_pushliteral(L, "__pow"); + lua_pushcfunction(L, math_pow); + lua_settable(L, LUA_GLOBALSINDEX); + return 1; } diff --git a/src/lib/loadlib.c b/src/lib/loadlib.c new file mode 100644 index 0000000000..ac4d697a68 --- /dev/null +++ b/src/lib/loadlib.c @@ -0,0 +1,205 @@ +/* +** $Id: loadlib.c,v 1.4 2003/04/07 20:11:53 roberto Exp $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +* +* This Lua library exports a single function, called loadlib, which is +* called from Lua as loadlib(lib,init), where lib is the full name of the +* library to be loaded (including the complete path) and init is the name +* of a function to be called after the library is loaded. Typically, this +* function will register other functions, thus making the complete library +* available to Lua. The init function is *not* automatically called by +* loadlib. Instead, loadlib returns the init function as a Lua function +* that the client can call when it thinks is appropriate. In the case of +* errors, loadlib returns nil and two strings describing the error. +* The first string is supplied by the operating system; it should be +* informative and useful for error messages. The second string is "open", +* "init", or "absent" to identify the error and is meant to be used for +* making decisions without having to look into the first string (whose +* format is system-dependent). +* +* This module contains an implementation of loadlib for Unix systems that +* have dlfcn, an implementation for Windows, and a stub for other systems. +* See the list at the end of this file for some links to available +* implementations of dlfcn and interfaces to other native dynamic loaders +* on top of which loadlib could be implemented. +* +*/ + +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" + + +#undef LOADLIB + + +#ifdef USE_DLOPEN +#define LOADLIB +/* +* This is an implementation of loadlib based on the dlfcn interface. +* The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +* NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +* as an emulation layer on top of native functions. +*/ + +#include + +static int loadlib(lua_State *L) +{ + const char *path=luaL_checkstring(L,1); + const char *init=luaL_checkstring(L,2); + void *lib=dlopen(path,RTLD_NOW); + if (lib!=NULL) + { + lua_CFunction f=(lua_CFunction) dlsym(lib,init); + if (f!=NULL) + { + lua_pushlightuserdata(L,lib); + lua_pushcclosure(L,f,1); + return 1; + } + } + /* else return appropriate error messages */ + lua_pushnil(L); + lua_pushstring(L,dlerror()); + lua_pushstring(L,(lib!=NULL) ? "init" : "open"); + if (lib!=NULL) dlclose(lib); + return 3; +} + +#endif + + + +/* +** In Windows, default is to use dll; otherwise, default is not to use dll +*/ +#ifndef USE_DLL +#ifdef _WIN32 +#define USE_DLL 1 +#else +#define USE_DLL 0 +#endif +#endif + + +#if USE_DLL +#define LOADLIB +/* +* This is an implementation of loadlib for Windows using native functions. +*/ + +#include + +static void pusherror(lua_State *L) +{ + int error=GetLastError(); + char buffer[128]; + if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + 0, error, 0, buffer, sizeof(buffer), 0)) + lua_pushstring(L,buffer); + else + lua_pushfstring(L,"system error %d\n",error); +} + +static int loadlib(lua_State *L) +{ + const char *path=luaL_checkstring(L,1); + const char *init=luaL_checkstring(L,2); + HINSTANCE lib=LoadLibrary(path); + if (lib!=NULL) + { + lua_CFunction f=(lua_CFunction) GetProcAddress(lib,init); + if (f!=NULL) + { + lua_pushlightuserdata(L,lib); + lua_pushcclosure(L,f,1); + return 1; + } + } + lua_pushnil(L); + pusherror(L); + lua_pushstring(L,(lib!=NULL) ? "init" : "open"); + if (lib!=NULL) FreeLibrary(lib); + return 3; +} + +#endif + + + +#ifndef LOADLIB +/* Fallback for other systems */ + +/* +** Those systems support dlopen, so they should have defined USE_DLOPEN. +** The default (no)implementation gives them a special error message. +*/ +#ifdef linux +#define LOADLIB +#endif + +#ifdef sun +#define LOADLIB +#endif + +#ifdef sgi +#define LOADLIB +#endif + +#ifdef BSD +#define LOADLIB +#endif + +#ifdef _WIN32 +#define LOADLIB +#endif + +#ifdef LOADLIB +#undef LOADLIB +#define LOADLIB "`loadlib' not installed (check your Lua configuration)" +#else +#define LOADLIB "`loadlib' not supported" +#endif + +static int loadlib(lua_State *L) +{ + lua_pushnil(L); + lua_pushliteral(L,LOADLIB); + lua_pushliteral(L,"absent"); + return 3; +} +#endif + +LUALIB_API int luaopen_loadlib (lua_State *L) +{ + lua_register(L,"loadlib",loadlib); + return 0; +} + +/* +* Here are some links to available implementations of dlfcn and +* interfaces to other native dynamic loaders on top of which loadlib +* could be implemented. Please send contributions and corrections to us. +* +* AIX +* Starting with AIX 4.2, dlfcn is included in the base OS. +* There is also an emulation package available. +* http://www.faqs.org/faqs/aix-faq/part4/section-21.html +* +* HPUX +* HPUX 11 has dlfcn. For HPUX 10 use shl_*. +* http://www.geda.seul.org/mailinglist/geda-dev37/msg00094.html +* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html +* +* Macintosh, Windows +* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html +* +* Mac OS X/Darwin +* http://www.opendarwin.org/projects/dlcompat/ +* +* GLIB has wrapper code for BeOS, OS2, Unix and Windows +* http://cvs.gnome.org/lxr/source/glib/gmodule/ +* +*/ diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index 8f286982ad..8752e3aba3 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.56 2000/10/27 16:15:53 roberto Exp $ +** $Id: lstrlib.c,v 1.98 2003/04/03 13:35:34 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -11,37 +11,47 @@ #include #include +#define lstrlib_c + #include "lua.h" #include "lauxlib.h" #include "lualib.h" +/* macro to `unsign' a character */ +#ifndef uchar +#define uchar(c) ((unsigned char)(c)) +#endif + + +typedef long sint32; /* a signed version for size_t */ + static int str_len (lua_State *L) { size_t l; - luaL_check_lstr(L, 1, &l); - lua_pushnumber(L, l); + luaL_checklstring(L, 1, &l); + lua_pushnumber(L, (lua_Number)l); return 1; } -static long posrelat (long pos, size_t len) { +static sint32 posrelat (sint32 pos, size_t len) { /* relative string position: negative means back from end */ - return (pos>=0) ? pos : (long)len+pos+1; + return (pos>=0) ? pos : (sint32)len+pos+1; } static int str_sub (lua_State *L) { size_t l; - const char *s = luaL_check_lstr(L, 1, &l); - long start = posrelat(luaL_check_long(L, 2), l); - long end = posrelat(luaL_opt_long(L, 3, -1), l); + const char *s = luaL_checklstring(L, 1, &l); + sint32 start = posrelat(luaL_checklong(L, 2), l); + sint32 end = posrelat(luaL_optlong(L, 3, -1), l); if (start < 1) start = 1; - if (end > (long)l) end = l; + if (end > (sint32)l) end = (sint32)l; if (start <= end) lua_pushlstring(L, s+start-1, end-start+1); - else lua_pushstring(L, ""); + else lua_pushliteral(L, ""); return 1; } @@ -50,10 +60,10 @@ static int str_lower (lua_State *L) { size_t l; size_t i; luaL_Buffer b; - const char *s = luaL_check_lstr(L, 1, &l); + const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; i 0) luaL_addlstring(&b, s, l); @@ -86,10 +96,11 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; - const char *s = luaL_check_lstr(L, 1, &l); - long pos = posrelat(luaL_opt_long(L, 2, 1), l); - luaL_arg_check(L, 0 l) /* index out of range? */ + return 0; /* no answer */ + lua_pushnumber(L, uchar(s[pos-1])); return 1; } @@ -100,15 +111,33 @@ static int str_char (lua_State *L) { luaL_Buffer b; luaL_buffinit(L, &b); for (i=1; i<=n; i++) { - int c = luaL_check_int(L, i); - luaL_arg_check(L, (unsigned char)c == c, i, "invalid value"); - luaL_putchar(&b, (unsigned char)c); + int c = luaL_checkint(L, i); + luaL_argcheck(L, uchar(c) == c, i, "invalid value"); + luaL_putchar(&b, uchar(c)); } luaL_pushresult(&b); return 1; } +static int writer (lua_State *L, const void* b, size_t size, void* B) { + (void)L; + luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); + return 1; +} + + +static int str_dump (lua_State *L) { + luaL_Buffer b; + luaL_checktype(L, 1, LUA_TFUNCTION); + luaL_buffinit(L,&b); + if (!lua_dump(L, writer, &b)) + luaL_error(L, "unable to dump given function"); + luaL_pushresult(&b); + return 1; +} + + /* ** {====================================================== @@ -121,51 +150,61 @@ static int str_char (lua_State *L) { #endif -struct Capture { - const char *src_end; /* end ('\0') of source string */ +#define CAP_UNFINISHED (-1) +#define CAP_POSITION (-2) + +typedef struct MatchState { + const char *src_init; /* init of source string */ + const char *src_end; /* end (`\0') of source string */ + lua_State *L; int level; /* total number of captures (finished or unfinished) */ struct { const char *init; - long len; /* -1 signals unfinished capture */ + sint32 len; } capture[MAX_CAPTURES]; -}; +} MatchState; #define ESC '%' #define SPECIALS "^$*+?.([%-" -static int check_capture (lua_State *L, int l, struct Capture *cap) { +static int check_capture (MatchState *ms, int l) { l -= '1'; - if (!(0 <= l && l < cap->level && cap->capture[l].len != -1)) - lua_error(L, "invalid capture index"); + if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index"); return l; } -static int capture_to_close (lua_State *L, struct Capture *cap) { - int level = cap->level; +static int capture_to_close (MatchState *ms) { + int level = ms->level; for (level--; level>=0; level--) - if (cap->capture[level].len == -1) return level; - lua_error(L, "invalid pattern capture"); - return 0; /* to avoid warnings */ + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); } -const char *luaI_classend (lua_State *L, const char *p) { +static const char *luaI_classend (MatchState *ms, const char *p) { switch (*p++) { - case ESC: - if (*p == '\0') lua_error(L, "malformed pattern (ends with `%')"); + case ESC: { + if (*p == '\0') + luaL_error(ms->L, "malformed pattern (ends with `%')"); return p+1; - case '[': + } + case '[': { if (*p == '^') p++; - do { /* look for a ']' */ - if (*p == '\0') lua_error(L, "malformed pattern (missing `]')"); - if (*(p++) == ESC && *p != '\0') p++; /* skip escapes (e.g. '%]') */ + do { /* look for a `]' */ + if (*p == '\0') + luaL_error(ms->L, "malformed pattern (missing `]')"); + if (*(p++) == ESC && *p != '\0') + p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; - default: + } + default: { return p; + } } } @@ -182,66 +221,59 @@ static int match_class (int c, int cl) { case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == '\0'); break; + case 'z' : res = (c == 0); break; default: return (cl == c); } return (islower(cl) ? res : !res); } - -static int matchbracketclass (int c, const char *p, const char *endclass) { +static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; - p++; /* skip the '^' */ + p++; /* skip the `^' */ } - while (++p < endclass) { + while (++p < ec) { if (*p == ESC) { p++; - if (match_class(c, (unsigned char)*p)) + if (match_class(c, *p)) return sig; } - else if ((*(p+1) == '-') && (p+2 < endclass)) { + else if ((*(p+1) == '-') && (p+2 < ec)) { p+=2; - if ((int)(unsigned char)*(p-2) <= c && c <= (int)(unsigned char)*p) + if (uchar(*(p-2)) <= c && c <= uchar(*p)) return sig; } - else if ((int)(unsigned char)*p == c) return sig; + else if (uchar(*p) == c) return sig; } return !sig; } - -int luaI_singlematch (int c, const char *p, const char *ep) { +static int luaI_singlematch (int c, const char *p, const char *ep) { switch (*p) { - case '.': /* matches any char */ - return 1; - case ESC: - return match_class(c, (unsigned char)*(p+1)); - case '[': - return matchbracketclass(c, p, ep-1); - default: - return ((unsigned char)*p == c); + case '.': return 1; /* matches any char */ + case ESC: return match_class(c, *(p+1)); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); } } -static const char *match (lua_State *L, const char *s, const char *p, - struct Capture *cap); +static const char *match (MatchState *ms, const char *s, const char *p); -static const char *matchbalance (lua_State *L, const char *s, const char *p, - struct Capture *cap) { +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { if (*p == 0 || *(p+1) == 0) - lua_error(L, "unbalanced pattern"); + luaL_error(ms->L, "unbalanced pattern"); if (*s != *p) return NULL; else { int b = *p; int e = *(p+1); int cont = 1; - while (++s < cap->src_end) { + while (++s < ms->src_end) { if (*s == e) { if (--cont == 0) return s+1; } @@ -252,14 +284,14 @@ static const char *matchbalance (lua_State *L, const char *s, const char *p, } -static const char *max_expand (lua_State *L, const char *s, const char *p, - const char *ep, struct Capture *cap) { - long i = 0; /* counts maximum expand for item */ - while ((s+i)src_end && luaI_singlematch((unsigned char)*(s+i), p, ep)) +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + sint32 i = 0; /* counts maximum expand for item */ + while ((s+i)src_end && luaI_singlematch(uchar(*(s+i)), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { - const char *res = match(L, (s+i), ep+1, cap); + const char *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } @@ -267,100 +299,126 @@ static const char *max_expand (lua_State *L, const char *s, const char *p, } -static const char *min_expand (lua_State *L, const char *s, const char *p, - const char *ep, struct Capture *cap) { +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { for (;;) { - const char *res = match(L, s, ep+1, cap); + const char *res = match(ms, s, ep+1); if (res != NULL) return res; - else if (ssrc_end && luaI_singlematch((unsigned char)*s, p, ep)) + else if (ssrc_end && luaI_singlematch(uchar(*s), p, ep)) s++; /* try with one more repetition */ else return NULL; } } -static const char *start_capture (lua_State *L, const char *s, const char *p, - struct Capture *cap) { +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { const char *res; - int level = cap->level; - if (level >= MAX_CAPTURES) lua_error(L, "too many captures"); - cap->capture[level].init = s; - cap->capture[level].len = -1; - cap->level = level+1; - if ((res=match(L, s, p+1, cap)) == NULL) /* match failed? */ - cap->level--; /* undo capture */ + int level = ms->level; + if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ return res; } -static const char *end_capture (lua_State *L, const char *s, const char *p, - struct Capture *cap) { - int l = capture_to_close(L, cap); +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); const char *res; - cap->capture[l].len = s - cap->capture[l].init; /* close capture */ - if ((res = match(L, s, p+1, cap)) == NULL) /* match failed? */ - cap->capture[l].len = -1; /* undo capture */ + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ return res; } -static const char *match_capture (lua_State *L, const char *s, int level, - struct Capture *cap) { - int l = check_capture(L, level, cap); - size_t len = cap->capture[l].len; - if ((size_t)(cap->src_end-s) >= len && - memcmp(cap->capture[l].init, s, len) == 0) +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) return s+len; else return NULL; } -static const char *match (lua_State *L, const char *s, const char *p, - struct Capture *cap) { +static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ switch (*p) { - case '(': /* start capture */ - return start_capture(L, s, p, cap); - case ')': /* end capture */ - return end_capture(L, s, p, cap); - case ESC: /* may be %[0-9] or %b */ - if (isdigit((unsigned char)(*(p+1)))) { /* capture? */ - s = match_capture(L, s, *(p+1), cap); - if (s == NULL) return NULL; - p+=2; goto init; /* else return match(L, s, p+2, cap) */ - } - else if (*(p+1) == 'b') { /* balanced string? */ - s = matchbalance(L, s, p+2, cap); - if (s == NULL) return NULL; - p+=4; goto init; /* else return match(L, s, p+4, cap); */ + case '(': { /* start capture */ + if (*(p+1) == ')') /* position capture? */ + return start_capture(ms, s, p+2, CAP_POSITION); + else + return start_capture(ms, s, p+1, CAP_UNFINISHED); + } + case ')': { /* end capture */ + return end_capture(ms, s, p+1); + } + case ESC: { + switch (*(p+1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p+2); + if (s == NULL) return NULL; + p+=4; goto init; /* else return match(ms, s, p+4); */ + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing `[' after `%%f' in pattern"); + ep = luaI_classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s-1); + if (matchbracketclass(uchar(previous), p, ep-1) || + !matchbracketclass(uchar(*s), p, ep-1)) return NULL; + p=ep; goto init; /* else return match(ms, s, ep); */ + } + default: { + if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ + s = match_capture(ms, s, *(p+1)); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(ms, s, p+2) */ + } + goto dflt; /* case default */ + } } - else goto dflt; /* case default */ - case '\0': /* end of pattern */ + } + case '\0': { /* end of pattern */ return s; /* match succeeded */ - case '$': - if (*(p+1) == '\0') /* is the '$' the last char in pattern? */ - return (s == cap->src_end) ? s : NULL; /* check end of string */ + } + case '$': { + if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + return (s == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; + } default: dflt: { /* it is a pattern item */ - const char *ep = luaI_classend(L, p); /* points to what is next */ - int m = ssrc_end && luaI_singlematch((unsigned char)*s, p, ep); + const char *ep = luaI_classend(ms, p); /* points to what is next */ + int m = ssrc_end && luaI_singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; - if (m && ((res=match(L, s+1, ep+1, cap)) != NULL)) + if (m && ((res=match(ms, s+1, ep+1)) != NULL)) return res; - p=ep+1; goto init; /* else return match(L, s, ep+1, cap); */ + p=ep+1; goto init; /* else return match(ms, s, ep+1); */ + } + case '*': { /* 0 or more repetitions */ + return max_expand(ms, s, p, ep); + } + case '+': { /* 1 or more repetitions */ + return (m ? max_expand(ms, s+1, p, ep) : NULL); + } + case '-': { /* 0 or more repetitions (minimum) */ + return min_expand(ms, s, p, ep); } - case '*': /* 0 or more repetitions */ - return max_expand(L, s, p, ep, cap); - case '+': /* 1 or more repetitions */ - return (m ? max_expand(L, s+1, p, ep, cap) : NULL); - case '-': /* 0 or more repetitions (minimum) */ - return min_expand(L, s, p, ep, cap); - default: + default: { if (!m) return NULL; - s++; p=ep; goto init; /* else return match(L, s+1, ep, cap); */ + s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ + } } } } @@ -369,7 +427,7 @@ static const char *match (lua_State *L, const char *s, const char *p, static const char *lmemfind (const char *s1, size_t l1, - const char *s2, size_t l2) { + const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ else if (l2 > l1) return NULL; /* avoids a negative `l1' */ else { @@ -390,54 +448,109 @@ static const char *lmemfind (const char *s1, size_t l1, } -static int push_captures (lua_State *L, struct Capture *cap) { +static void push_onecapture (MatchState *ms, int i) { + int l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1)); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { int i; - luaL_checkstack(L, cap->level, "too many captures"); - for (i=0; ilevel; i++) { - int l = cap->capture[i].len; - if (l == -1) lua_error(L, "unfinished capture"); - lua_pushlstring(L, cap->capture[i].init, l); + luaL_checkstack(ms->L, ms->level, "too many captures"); + if (ms->level == 0 && s) { /* no explicit captures? */ + lua_pushlstring(ms->L, s, e-s); /* return whole match */ + return 1; + } + else { /* return all captures */ + for (i=0; ilevel; i++) + push_onecapture(ms, i); + return ms->level; /* number of strings pushed */ } - return cap->level; /* number of strings pushed */ } static int str_find (lua_State *L) { size_t l1, l2; - const char *s = luaL_check_lstr(L, 1, &l1); - const char *p = luaL_check_lstr(L, 2, &l2); - long init = posrelat(luaL_opt_long(L, 3, 1), l1) - 1; - struct Capture cap; - luaL_arg_check(L, 0 <= init && (size_t)init <= l1, 3, "out of range"); - if (lua_gettop(L) > 3 || /* extra argument? */ + const char *s = luaL_checklstring(L, 1, &l1); + const char *p = luaL_checklstring(L, 2, &l2); + sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1; + if (init < 0) init = 0; + else if ((size_t)(init) > l1) init = (sint32)l1; + if (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ + /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { - lua_pushnumber(L, s2-s+1); - lua_pushnumber(L, s2-s+l2); + lua_pushnumber(L, (lua_Number)(s2-s+1)); + lua_pushnumber(L, (lua_Number)(s2-s+l2)); return 2; } } else { + MatchState ms; int anchor = (*p == '^') ? (p++, 1) : 0; const char *s1=s+init; - cap.src_end = s+l1; + ms.L = L; + ms.src_init = s; + ms.src_end = s+l1; do { const char *res; - cap.level = 0; - if ((res=match(L, s1, p, &cap)) != NULL) { - lua_pushnumber(L, s1-s+1); /* start */ - lua_pushnumber(L, res-s); /* end */ - return push_captures(L, &cap) + 2; + ms.level = 0; + if ((res=match(&ms, s1, p)) != NULL) { + lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */ + lua_pushnumber(L, (lua_Number)(res-s)); /* end */ + return push_captures(&ms, NULL, 0) + 2; } - } while (s1++L; if (lua_isstring(L, 3)) { const char *news = lua_tostring(L, 3); size_t l = lua_strlen(L, 3); @@ -447,11 +560,12 @@ static void add_s (lua_State *L, luaL_Buffer *b, struct Capture *cap) { luaL_putchar(b, news[i]); else { i++; /* skip ESC */ - if (!isdigit((unsigned char)news[i])) + if (!isdigit(uchar(news[i]))) luaL_putchar(b, news[i]); else { - int level = check_capture(L, news[i], cap); - luaL_addlstring(b, cap->capture[level].init, cap->capture[level].len); + int level = check_capture(ms, news[i]); + push_onecapture(ms, level); + luaL_addvalue(b); /* add capture to accumulated result */ } } } @@ -459,8 +573,8 @@ static void add_s (lua_State *L, luaL_Buffer *b, struct Capture *cap) { else { /* is a function */ int n; lua_pushvalue(L, 3); - n = push_captures(L, cap); - lua_rawcall(L, n, 1); + n = push_captures(ms, s, e); + lua_call(L, n, 1); if (lua_isstring(L, -1)) luaL_addvalue(b); /* add return to accumulated result */ else @@ -471,124 +585,155 @@ static void add_s (lua_State *L, luaL_Buffer *b, struct Capture *cap) { static int str_gsub (lua_State *L) { size_t srcl; - const char *src = luaL_check_lstr(L, 1, &srcl); - const char *p = luaL_check_string(L, 2); - int max_s = luaL_opt_int(L, 4, srcl+1); + const char *src = luaL_checklstring(L, 1, &srcl); + const char *p = luaL_checkstring(L, 2); + int max_s = luaL_optint(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; - struct Capture cap; + MatchState ms; luaL_Buffer b; - luaL_arg_check(L, + luaL_argcheck(L, lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), 3, "string or function expected"); luaL_buffinit(L, &b); - cap.src_end = src+srcl; + ms.L = L; + ms.src_init = src; + ms.src_end = src+srcl; while (n < max_s) { const char *e; - cap.level = 0; - e = match(L, src, p, &cap); + ms.level = 0; + e = match(&ms, src, p); if (e) { n++; - add_s(L, &b, &cap); + add_s(&ms, &b, src, e); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ - else if (src < cap.src_end) + else if (src < ms.src_end) luaL_putchar(&b, *src++); else break; if (anchor) break; } - luaL_addlstring(&b, src, cap.src_end-src); + luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); - lua_pushnumber(L, n); /* number of substitutions */ + lua_pushnumber(L, (lua_Number)n); /* number of substitutions */ return 2; } /* }====================================================== */ +/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ +#define MAX_ITEM 512 +/* maximum size of each format specification (such as '%-099.99d') */ +#define MAX_FORMAT 20 + + static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; - const char *s = luaL_check_lstr(L, arg, &l); + const char *s = luaL_checklstring(L, arg, &l); luaL_putchar(b, '"'); while (l--) { switch (*s) { - case '"': case '\\': case '\n': + case '"': case '\\': case '\n': { luaL_putchar(b, '\\'); luaL_putchar(b, *s); break; - case '\0': luaL_addlstring(b, "\\000", 4); break; - default: luaL_putchar(b, *s); + } + case '\0': { + luaL_addlstring(b, "\\000", 4); + break; + } + default: { + luaL_putchar(b, *s); + break; + } } s++; } luaL_putchar(b, '"'); } -/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ -#define MAX_ITEM 512 -/* maximum size of each format specification (such as '%-099.99d') */ -#define MAX_FORMAT 20 + +static const char *scanformat (lua_State *L, const char *strfrmt, + char *form, int *hasprecision) { + const char *p = strfrmt; + while (strchr("-+ #0", *p)) p++; /* skip flags */ + if (isdigit(uchar(*p))) p++; /* skip width */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + if (*p == '.') { + p++; + *hasprecision = 1; + if (isdigit(uchar(*p))) p++; /* skip precision */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + } + if (isdigit(uchar(*p))) + luaL_error(L, "invalid format (width or precision too long)"); + if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */ + luaL_error(L, "invalid format (too long)"); + form[0] = '%'; + strncpy(form+1, strfrmt, p-strfrmt+1); + form[p-strfrmt+2] = 0; + return p; +} + static int str_format (lua_State *L) { int arg = 1; - const char *strfrmt = luaL_check_string(L, arg); + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; luaL_Buffer b; luaL_buffinit(L, &b); - while (*strfrmt) { + while (strfrmt < strfrmt_end) { if (*strfrmt != '%') luaL_putchar(&b, *strfrmt++); else if (*++strfrmt == '%') luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ - struct Capture cap; - char form[MAX_FORMAT]; /* to store the format ('%...') */ + char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ - const char *initf = strfrmt; - form[0] = '%'; - if (isdigit((unsigned char)*initf) && *(initf+1) == '$') { - arg = *initf - '0'; - initf += 2; /* skip the 'n$' */ - } + int hasprecision = 0; + if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$') + return luaL_error(L, "obsolete option (d$) to `format'"); arg++; - cap.src_end = strfrmt+strlen(strfrmt)+1; - cap.level = 0; - strfrmt = match(L, initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); - if (cap.capture[0].len > 2 || cap.capture[1].len > 2 || /* < 100? */ - strfrmt-initf > MAX_FORMAT-2) - lua_error(L, "invalid format (width or precision too long)"); - strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */ - form[strfrmt-initf+2] = 0; + strfrmt = scanformat(L, strfrmt, form, &hasprecision); switch (*strfrmt++) { - case 'c': case 'd': case 'i': - sprintf(buff, form, luaL_check_int(L, arg)); + case 'c': case 'd': case 'i': { + sprintf(buff, form, luaL_checkint(L, arg)); break; - case 'o': case 'u': case 'x': case 'X': - sprintf(buff, form, (unsigned int)luaL_check_number(L, arg)); + } + case 'o': case 'u': case 'x': case 'X': { + sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg))); break; - case 'e': case 'E': case 'f': case 'g': case 'G': - sprintf(buff, form, luaL_check_number(L, arg)); + } + case 'e': case 'E': case 'f': + case 'g': case 'G': { + sprintf(buff, form, luaL_checknumber(L, arg)); break; - case 'q': + } + case 'q': { luaI_addquoted(L, &b, arg); - continue; /* skip the "addsize" at the end */ + continue; /* skip the `addsize' at the end */ + } case 's': { size_t l; - const char *s = luaL_check_lstr(L, arg, &l); - if (cap.capture[1].len == 0 && l >= 100) { + const char *s = luaL_checklstring(L, arg, &l); + if (!hasprecision && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ lua_pushvalue(L, arg); luaL_addvalue(&b); - continue; /* skip the "addsize" at the end */ + continue; /* skip the `addsize' at the end */ } else { sprintf(buff, form, s); break; } } - default: /* also treat cases 'pnLlh' */ - lua_error(L, "invalid option in `format'"); + default: { /* also treat cases `pnLlh' */ + return luaL_error(L, "invalid option to `format'"); + } } luaL_addlstring(&b, buff, strlen(buff)); } @@ -598,24 +743,28 @@ static int str_format (lua_State *L) { } -static const struct luaL_reg strlib[] = { -{"strlen", str_len}, -{"strsub", str_sub}, -{"strlower", str_lower}, -{"strupper", str_upper}, -{"strchar", str_char}, -{"strrep", str_rep}, -{"ascii", str_byte}, /* for compatibility with 3.0 and earlier */ -{"strbyte", str_byte}, -{"format", str_format}, -{"strfind", str_find}, -{"gsub", str_gsub} +static const luaL_reg strlib[] = { + {"len", str_len}, + {"sub", str_sub}, + {"lower", str_lower}, + {"upper", str_upper}, + {"char", str_char}, + {"rep", str_rep}, + {"byte", str_byte}, + {"format", str_format}, + {"dump", str_dump}, + {"find", str_find}, + {"gfind", gfind}, + {"gsub", str_gsub}, + {NULL, NULL} }; /* ** Open string library */ -LUALIB_API void lua_strlibopen (lua_State *L) { - luaL_openl(L, strlib); +LUALIB_API int luaopen_string (lua_State *L) { + luaL_openlib(L, LUA_STRLIBNAME, strlib, 0); + return 1; } + diff --git a/src/lib/ltablib.c b/src/lib/ltablib.c new file mode 100644 index 0000000000..c9bb2d1b7e --- /dev/null +++ b/src/lib/ltablib.c @@ -0,0 +1,250 @@ +/* +** $Id: ltablib.c,v 1.21 2003/04/03 13:35:34 roberto Exp $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + + +#include + +#define ltablib_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) + + +static int luaB_foreachi (lua_State *L) { + int i; + int n = aux_getn(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + for (i=1; i<=n; i++) { + lua_pushvalue(L, 2); /* function */ + lua_pushnumber(L, (lua_Number)i); /* 1st argument */ + lua_rawgeti(L, 1, i); /* 2nd argument */ + lua_call(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 1); /* remove nil result */ + } + return 0; +} + + +static int luaB_foreach (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushnil(L); /* first key */ + for (;;) { + if (lua_next(L, 1) == 0) + return 0; + lua_pushvalue(L, 2); /* function */ + lua_pushvalue(L, -3); /* key */ + lua_pushvalue(L, -3); /* value */ + lua_call(L, 2, 1); + if (!lua_isnil(L, -1)) + return 1; + lua_pop(L, 2); /* remove value and result */ + } +} + + +static int luaB_getn (lua_State *L) { + lua_pushnumber(L, (lua_Number)aux_getn(L, 1)); + return 1; +} + + +static int luaB_setn (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_setn(L, 1, luaL_checkint(L, 2)); + return 0; +} + + +static int luaB_tinsert (lua_State *L) { + int v = lua_gettop(L); /* number of arguments */ + int n = aux_getn(L, 1) + 1; + int pos; /* where to insert new element */ + if (v == 2) /* called with only 2 arguments */ + pos = n; /* insert new element at the end */ + else { + pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + if (pos > n) n = pos; /* `grow' array if necessary */ + v = 3; /* function may be called with more than 3 args */ + } + luaL_setn(L, 1, n); /* new size */ + while (--n >= pos) { /* move up elements */ + lua_rawgeti(L, 1, n); + lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ + } + lua_pushvalue(L, v); + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int luaB_tremove (lua_State *L) { + int n = aux_getn(L, 1); + int pos = luaL_optint(L, 2, n); + if (n <= 0) return 0; /* table is `empty' */ + luaL_setn(L, 1, n-1); /* t.n = n-1 */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos= P */ + while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i>u) luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* repeat --j until a[j] <= P */ + while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j -#include #include +#define llex_c + #include "lua.h" +#include "ldo.h" #include "llex.h" -#include "lmem.h" #include "lobject.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" -#include "ltable.h" -#include "luadebug.h" #include "lzio.h" @@ -29,16 +28,22 @@ /* ORDER RESERVED */ static const char *const token2string [] = { - "and", "break", "do", "else", "elseif", "end", "for", - "function", "if", "local", "nil", "not", "or", "repeat", "return", "then", - "until", "while", "", "..", "...", "==", ">=", "<=", "~=", "", "", ""}; + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", "*name", + "..", "...", "==", ">=", "<=", "~=", + "*number", "*string", "" +}; void luaX_init (lua_State *L) { int i; for (i=0; imarked = (unsigned char)(RESERVEDMARK+i); /* reserved word */ + luaS_fix(ts); /* reserved words are never collected */ + lua_assert(strlen(token2string[i])+1 <= TOKEN_LEN); + ts->tsv.reserved = cast(lu_byte, i+1); /* reserved word */ } } @@ -48,50 +53,64 @@ void luaX_init (lua_State *L) { void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) { if (val > limit) { - char buff[100]; - sprintf(buff, "too many %.50s (limit=%d)", msg, limit); - luaX_error(ls, buff, ls->t.token); + msg = luaO_pushfstring(ls->L, "too many %s (limit=%d)", msg, limit); + luaX_syntaxerror(ls, msg); } } -void luaX_syntaxerror (LexState *ls, const char *s, const char *token) { +void luaX_errorline (LexState *ls, const char *s, const char *token, int line) { + lua_State *L = ls->L; char buff[MAXSRC]; - luaO_chunkid(buff, ls->source->str, sizeof(buff)); - luaO_verror(ls->L, "%.99s;\n last token read: `%.30s' at line %d in %.80s", - s, token, ls->linenumber, buff); + luaO_chunkid(buff, getstr(ls->source), MAXSRC); + luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, line, s, token); + luaD_throw(L, LUA_ERRSYNTAX); } -void luaX_error (LexState *ls, const char *s, int token) { - char buff[TOKEN_LEN]; - luaX_token2str(token, buff); - if (buff[0] == '\0') - luaX_syntaxerror(ls, s, ls->L->Mbuffer); - else - luaX_syntaxerror(ls, s, buff); +static void luaX_error (LexState *ls, const char *s, const char *token) { + luaX_errorline(ls, s, token, ls->linenumber); +} + + +void luaX_syntaxerror (LexState *ls, const char *msg) { + const char *lasttoken; + switch (ls->t.token) { + case TK_NAME: + lasttoken = getstr(ls->t.seminfo.ts); + break; + case TK_STRING: + case TK_NUMBER: + lasttoken = luaZ_buffer(ls->buff); + break; + default: + lasttoken = luaX_token2str(ls, ls->t.token); + break; + } + luaX_error(ls, msg, lasttoken); } -void luaX_token2str (int token, char *s) { - if (token < 256) { - s[0] = (char)token; - s[1] = '\0'; +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { + lua_assert(token == (unsigned char)token); + return luaO_pushfstring(ls->L, "%c", token); } else - strcpy(s, token2string[token-FIRST_RESERVED]); + return token2string[token-FIRST_RESERVED]; } -static void luaX_invalidchar (LexState *ls, int c) { - char buff[8]; - sprintf(buff, "0x%02X", c); - luaX_syntaxerror(ls, "invalid control char", buff); +static void luaX_lexerror (LexState *ls, const char *s, int token) { + if (token == TK_EOS) + luaX_error(ls, s, luaX_token2str(ls, token)); + else + luaX_error(ls, s, luaZ_buffer(ls->buff)); } static void inclinenumber (LexState *LS) { - next(LS); /* skip '\n' */ + next(LS); /* skip `\n' */ ++LS->linenumber; luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk"); } @@ -122,159 +141,173 @@ void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { */ -/* use Mbuffer to store names, literal strings and numbers */ +/* use buffer to store names, literal strings and numbers */ + +/* extra space to allocate when growing buffer */ +#define EXTRABUFF 32 + +/* maximum number of chars that can be read without checking buffer size */ +#define MAXNOCHECK 5 -#define EXTRABUFF 128 -#define checkbuffer(L, n, len) if ((len)+(n) > L->Mbuffsize) \ - luaO_openspace(L, (len)+(n)+EXTRABUFF) +#define checkbuffer(LS, len) \ + if (((len)+MAXNOCHECK)*sizeof(char) > luaZ_sizebuffer((LS)->buff)) \ + luaZ_openspace((LS)->L, (LS)->buff, (len)+EXTRABUFF) -#define save(L, c, l) (L->Mbuffer[l++] = (char)c) -#define save_and_next(L, LS, l) (save(L, LS->current, l), next(LS)) +#define save(LS, c, l) \ + (luaZ_buffer((LS)->buff)[l++] = cast(char, c)) +#define save_and_next(LS, l) (save(LS, LS->current, l), next(LS)) -static const char *readname (LexState *LS) { - lua_State *L = LS->L; +static size_t readname (LexState *LS) { size_t l = 0; - checkbuffer(L, 10, l); + checkbuffer(LS, l); do { - checkbuffer(L, 10, l); - save_and_next(L, LS, l); + checkbuffer(LS, l); + save_and_next(LS, l); } while (isalnum(LS->current) || LS->current == '_'); - save(L, '\0', l); - return L->Mbuffer; + save(LS, '\0', l); + return l-1; } /* LUA_NUMBER */ -static void read_number (LexState *LS, int comma, SemInfo *seminfo) { - lua_State *L = LS->L; +static void read_numeral (LexState *LS, int comma, SemInfo *seminfo) { size_t l = 0; - checkbuffer(L, 10, l); - if (comma) save(L, '.', l); + checkbuffer(LS, l); + if (comma) save(LS, '.', l); while (isdigit(LS->current)) { - checkbuffer(L, 10, l); - save_and_next(L, LS, l); + checkbuffer(LS, l); + save_and_next(LS, l); } if (LS->current == '.') { - save_and_next(L, LS, l); + save_and_next(LS, l); if (LS->current == '.') { - save_and_next(L, LS, l); - save(L, '\0', l); - luaX_error(LS, "ambiguous syntax" - " (decimal point x string concatenation)", TK_NUMBER); + save_and_next(LS, l); + save(LS, '\0', l); + luaX_lexerror(LS, + "ambiguous syntax (decimal point x string concatenation)", + TK_NUMBER); } } while (isdigit(LS->current)) { - checkbuffer(L, 10, l); - save_and_next(L, LS, l); + checkbuffer(LS, l); + save_and_next(LS, l); } if (LS->current == 'e' || LS->current == 'E') { - save_and_next(L, LS, l); /* read 'E' */ + save_and_next(LS, l); /* read `E' */ if (LS->current == '+' || LS->current == '-') - save_and_next(L, LS, l); /* optional exponent sign */ + save_and_next(LS, l); /* optional exponent sign */ while (isdigit(LS->current)) { - checkbuffer(L, 10, l); - save_and_next(L, LS, l); + checkbuffer(LS, l); + save_and_next(LS, l); } } - save(L, '\0', l); - if (!luaO_str2d(L->Mbuffer, &seminfo->r)) - luaX_error(LS, "malformed number", TK_NUMBER); + save(LS, '\0', l); + if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r)) + luaX_lexerror(LS, "malformed number", TK_NUMBER); } static void read_long_string (LexState *LS, SemInfo *seminfo) { - lua_State *L = LS->L; int cont = 0; size_t l = 0; - checkbuffer(L, 10, l); - save(L, '[', l); /* save first '[' */ - save_and_next(L, LS, l); /* pass the second '[' */ + checkbuffer(LS, l); + save(LS, '[', l); /* save first `[' */ + save_and_next(LS, l); /* pass the second `[' */ + if (LS->current == '\n') /* string starts with a newline? */ + inclinenumber(LS); /* skip it */ for (;;) { - checkbuffer(L, 10, l); + checkbuffer(LS, l); switch (LS->current) { case EOZ: - save(L, '\0', l); - luaX_error(LS, "unfinished long string", TK_STRING); + save(LS, '\0', l); + luaX_lexerror(LS, (seminfo) ? "unfinished long string" : + "unfinished long comment", TK_EOS); break; /* to avoid warnings */ case '[': - save_and_next(L, LS, l); + save_and_next(LS, l); if (LS->current == '[') { cont++; - save_and_next(L, LS, l); + save_and_next(LS, l); } continue; case ']': - save_and_next(L, LS, l); + save_and_next(LS, l); if (LS->current == ']') { if (cont == 0) goto endloop; cont--; - save_and_next(L, LS, l); + save_and_next(LS, l); } continue; case '\n': - save(L, '\n', l); + save(LS, '\n', l); inclinenumber(LS); + if (!seminfo) l = 0; /* reset buffer to avoid wasting space */ continue; default: - save_and_next(L, LS, l); + save_and_next(LS, l); } } endloop: - save_and_next(L, LS, l); /* skip the second ']' */ - save(L, '\0', l); - seminfo->ts = luaS_newlstr(L, L->Mbuffer+2, l-5); + save_and_next(LS, l); /* skip the second `]' */ + save(LS, '\0', l); + if (seminfo) + seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 2, l - 5); } static void read_string (LexState *LS, int del, SemInfo *seminfo) { - lua_State *L = LS->L; size_t l = 0; - checkbuffer(L, 10, l); - save_and_next(L, LS, l); + checkbuffer(LS, l); + save_and_next(LS, l); while (LS->current != del) { - checkbuffer(L, 10, l); + checkbuffer(LS, l); switch (LS->current) { - case EOZ: case '\n': - save(L, '\0', l); - luaX_error(LS, "unfinished string", TK_STRING); + case EOZ: + save(LS, '\0', l); + luaX_lexerror(LS, "unfinished string", TK_EOS); + break; /* to avoid warnings */ + case '\n': + save(LS, '\0', l); + luaX_lexerror(LS, "unfinished string", TK_STRING); break; /* to avoid warnings */ case '\\': - next(LS); /* do not save the '\' */ + next(LS); /* do not save the `\' */ switch (LS->current) { - case 'a': save(L, '\a', l); next(LS); break; - case 'b': save(L, '\b', l); next(LS); break; - case 'f': save(L, '\f', l); next(LS); break; - case 'n': save(L, '\n', l); next(LS); break; - case 'r': save(L, '\r', l); next(LS); break; - case 't': save(L, '\t', l); next(LS); break; - case 'v': save(L, '\v', l); next(LS); break; - case '\n': save(L, '\n', l); inclinenumber(LS); break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - int c = 0; - int i = 0; - do { - c = 10*c + (LS->current-'0'); - next(LS); - } while (++i<3 && isdigit(LS->current)); - if (c != (unsigned char)c) { - save(L, '\0', l); - luaX_error(LS, "escape sequence too large", TK_STRING); + case 'a': save(LS, '\a', l); next(LS); break; + case 'b': save(LS, '\b', l); next(LS); break; + case 'f': save(LS, '\f', l); next(LS); break; + case 'n': save(LS, '\n', l); next(LS); break; + case 'r': save(LS, '\r', l); next(LS); break; + case 't': save(LS, '\t', l); next(LS); break; + case 'v': save(LS, '\v', l); next(LS); break; + case '\n': save(LS, '\n', l); inclinenumber(LS); break; + case EOZ: break; /* will raise an error next loop */ + default: { + if (!isdigit(LS->current)) + save_and_next(LS, l); /* handles \\, \", \', and \? */ + else { /* \xxx */ + int c = 0; + int i = 0; + do { + c = 10*c + (LS->current-'0'); + next(LS); + } while (++i<3 && isdigit(LS->current)); + if (c > UCHAR_MAX) { + save(LS, '\0', l); + luaX_lexerror(LS, "escape sequence too large", TK_STRING); + } + save(LS, c, l); } - save(L, c, l); - break; } - default: /* handles \\, \", \', and \? */ - save_and_next(L, LS, l); } break; default: - save_and_next(L, LS, l); + save_and_next(LS, l); } } - save_and_next(L, LS, l); /* skip delimiter */ - save(L, '\0', l); - seminfo->ts = luaS_newlstr(L, L->Mbuffer+1, l-3); + save_and_next(LS, l); /* skip delimiter */ + save(LS, '\0', l); + seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 1, l - 3); } @@ -282,58 +315,56 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) { for (;;) { switch (LS->current) { - case ' ': case '\t': case '\r': /* `\r' to avoid problems with DOS */ - next(LS); - continue; - - case '\n': + case '\n': { inclinenumber(LS); continue; - - case '$': - luaX_error(LS, "unexpected `$' (pragmas are no longer supported)", '$'); - break; - - case '-': + } + case '-': { next(LS); if (LS->current != '-') return '-'; - do { next(LS); } while (LS->current != '\n' && LS->current != EOZ); + /* else is a comment */ + next(LS); + if (LS->current == '[' && (next(LS), LS->current == '[')) + read_long_string(LS, NULL); /* long comment */ + else /* short comment */ + while (LS->current != '\n' && LS->current != EOZ) + next(LS); continue; - - case '[': + } + case '[': { next(LS); if (LS->current != '[') return '['; else { read_long_string(LS, seminfo); return TK_STRING; } - - case '=': + } + case '=': { next(LS); if (LS->current != '=') return '='; else { next(LS); return TK_EQ; } - - case '<': + } + case '<': { next(LS); if (LS->current != '=') return '<'; else { next(LS); return TK_LE; } - - case '>': + } + case '>': { next(LS); if (LS->current != '=') return '>'; else { next(LS); return TK_GE; } - - case '~': + } + case '~': { next(LS); if (LS->current != '=') return '~'; else { next(LS); return TK_NE; } - + } case '"': - case '\'': + case '\'': { read_string(LS, LS->current, seminfo); return TK_STRING; - - case '.': + } + case '.': { next(LS); if (LS->current == '.') { next(LS); @@ -345,36 +376,42 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) { } else if (!isdigit(LS->current)) return '.'; else { - read_number(LS, 1, seminfo); + read_numeral(LS, 1, seminfo); return TK_NUMBER; } - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - read_number(LS, 0, seminfo); - return TK_NUMBER; - - case EOZ: + } + case EOZ: { return TK_EOS; - - case '_': goto tname; - - default: - if (!isalpha(LS->current)) { - int c = LS->current; - if (iscntrl(c)) - luaX_invalidchar(LS, c); + } + default: { + if (isspace(LS->current)) { next(LS); - return c; + continue; + } + else if (isdigit(LS->current)) { + read_numeral(LS, 0, seminfo); + return TK_NUMBER; } - tname: { /* identifier or reserved word */ - TString *ts = luaS_new(LS->L, readname(LS)); - if (ts->marked >= RESERVEDMARK) /* reserved word? */ - return ts->marked-RESERVEDMARK+FIRST_RESERVED; + else if (isalpha(LS->current) || LS->current == '_') { + /* identifier or reserved word */ + size_t l = readname(LS); + TString *ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff), l); + if (ts->tsv.reserved > 0) /* reserved word? */ + return ts->tsv.reserved - 1 + FIRST_RESERVED; seminfo->ts = ts; return TK_NAME; } + else { + int c = LS->current; + if (iscntrl(c)) + luaX_error(LS, "invalid control char", + luaO_pushfstring(LS->L, "char(%d)", c)); + next(LS); + return c; /* single-char tokens (+ - / ...) */ + } + } } } } +#undef next diff --git a/src/llex.h b/src/llex.h index 3b37996086..740e3f6b31 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.31 2000/09/27 17:41:58 roberto Exp $ +** $Id: llex.h,v 1.47 2003/02/28 17:19:47 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -13,8 +13,8 @@ #define FIRST_RESERVED 257 -/* maximum length of a reserved word (+1 for final 0) */ -#define TOKEN_LEN 15 +/* maximum length of a reserved word */ +#define TOKEN_LEN (sizeof("function")/sizeof(char)) /* @@ -24,19 +24,20 @@ enum RESERVED { /* terminal symbols denoted by reserved words */ TK_AND = FIRST_RESERVED, TK_BREAK, - TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FOR, TK_FUNCTION, TK_IF, TK_LOCAL, - TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_UNTIL, TK_WHILE, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, TK_STRING, TK_EOS }; /* number of reserved words */ -#define NUM_RESERVED ((int)(TK_WHILE-FIRST_RESERVED+1)) +#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) typedef union { - Number r; + lua_Number r; TString *ts; } SemInfo; /* semantics information */ @@ -48,15 +49,17 @@ typedef struct Token { typedef struct LexState { - int current; /* current character */ + int current; /* current character (charint) */ + int linenumber; /* input line counter */ + int lastline; /* line of last token `consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ struct FuncState *fs; /* `FuncState' is private to the parser */ struct lua_State *L; - struct zio *z; /* input stream */ - int linenumber; /* input line counter */ - int lastline; /* line of last token `consumed' */ + ZIO *z; /* input stream */ + Mbuffer *buff; /* buffer for tokens */ TString *source; /* current source name */ + int nestlevel; /* level of nested non-terminals */ } LexState; @@ -64,9 +67,9 @@ void luaX_init (lua_State *L); void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source); int luaX_lex (LexState *LS, SemInfo *seminfo); void luaX_checklimit (LexState *ls, int val, int limit, const char *msg); -void luaX_syntaxerror (LexState *ls, const char *s, const char *token); -void luaX_error (LexState *ls, const char *s, int token); -void luaX_token2str (int token, char *s); +void luaX_syntaxerror (LexState *ls, const char *s); +void luaX_errorline (LexState *ls, const char *s, const char *token, int line); +const char *luaX_token2str (LexState *ls, int token); #endif diff --git a/src/llimits.h b/src/llimits.h index b3f5de47e3..343c922612 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,6 +1,6 @@ /* -** $Id: llimits.h,v 1.19 2000/10/26 12:47:05 roberto Exp $ -** Limits, basic types, and some other "installation-dependent" definitions +** $Id: llimits.h,v 1.52 2003/02/20 19:33:23 roberto Exp $ +** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -12,6 +12,8 @@ #include +#include "lua.h" + /* ** try to find number of bits in an integer @@ -32,25 +34,29 @@ /* -** Define the type `number' of Lua -** GREP LUA_NUMBER to change that +** the following types define integer types for values that may not +** fit in a `small int' (16 bits), but may waste space in a +** `large long' (64 bits). The current definitions should work in +** any machine, but may not be optimal. */ -#ifndef LUA_NUM_TYPE -#define LUA_NUM_TYPE double -#endif -typedef LUA_NUM_TYPE Number; +/* an unsigned integer to hold hash values */ +typedef unsigned int lu_hash; +/* its signed equivalent */ +typedef int ls_hash; -/* function to convert a Number to a string */ -#define NUMBER_FMT "%.16g" /* LUA_NUMBER */ -#define lua_number2str(s,n) sprintf((s), NUMBER_FMT, (n)) +/* an unsigned integer big enough to count the total memory used by Lua; */ +/* it should be at least as large as size_t */ +typedef unsigned long lu_mem; -/* function to convert a string to a Number */ -#define lua_str2number(s,p) strtod((s), (p)) +#define MAX_LUMEM ULONG_MAX +/* an integer big enough to count the number of strings in use */ +typedef long ls_nstr; -typedef unsigned long lint32; /* unsigned int with at least 32 bits */ +/* chars used as small naturals (so that `char' is reserved for characters) */ +typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) @@ -59,117 +65,93 @@ typedef unsigned long lint32; /* unsigned int with at least 32 bits */ #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ /* -** conversion of pointer to int (for hashing only) -** (the shift removes bits that are usually 0 because of alignment) +** conversion of pointer to integer +** this is for hashing only; there is no problem if the integer +** cannot hold the whole pointer value */ -#define IntPoint(p) (((unsigned long)(p)) >> 3) +#define IntPoint(p) ((lu_hash)(p)) + +/* type to ensure maximum alignment */ +#ifndef LUSER_ALIGNMENT_T +typedef union { double u; void *s; long l; } L_Umaxalign; +#else +typedef LUSER_ALIGNMENT_T L_Umaxalign; +#endif -#define MINPOWER2 4 /* minimum size for "growing" vectors */ +/* result of `usual argument conversion' over lua_Number */ +#ifndef LUA_UACNUMBER +typedef double l_uacNumber; +#else +typedef LUA_UACNUMBER l_uacNumber; +#endif -#ifndef DEFAULT_STACK_SIZE -#define DEFAULT_STACK_SIZE 1024 +#ifndef lua_assert +#define lua_assert(c) /* empty */ #endif +#ifndef check_exp +#define check_exp(c,e) (e) +#endif -/* type to ensure maximum alignment */ -union L_Umaxalign { double d; char *s; long l; }; + +#ifndef UNUSED +#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#endif + + +#ifndef cast +#define cast(t, exp) ((t)(exp)) +#endif /* ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) -** For a very small machine, you may change that to 2 bytes (and adjust -** the following limits accordingly) */ typedef unsigned long Instruction; -/* -** size and position of opcode arguments. -** For an instruction with 2 bytes, size is 16, and size_b can be 5 -** (accordingly, size_u will be 10, and size_a will be 5) -*/ -#define SIZE_INSTRUCTION 32 -#define SIZE_B 9 - -#define SIZE_OP 6 -#define SIZE_U (SIZE_INSTRUCTION-SIZE_OP) -#define POS_U SIZE_OP -#define POS_B SIZE_OP -#define SIZE_A (SIZE_INSTRUCTION-(SIZE_OP+SIZE_B)) -#define POS_A (SIZE_OP+SIZE_B) +/* maximum depth for calls (unsigned short) */ +#ifndef LUA_MAXCALLS +#define LUA_MAXCALLS 4096 +#endif /* -** limits for opcode arguments. -** we use (signed) int to manipulate most arguments, -** so they must fit in BITS_INT-1 bits (-1 for sign) +** maximum depth for C calls (unsigned short): Not too big, or may +** overflow the C stack... */ -#if SIZE_U < BITS_INT-1 -#define MAXARG_U ((1<>1) /* `S' is signed */ -#else -#define MAXARG_U MAX_INT -#define MAXARG_S MAX_INT -#endif -#if SIZE_A < BITS_INT-1 -#define MAXARG_A ((1< MAXARG_B -#undef MAXSTACK -#define MAXSTACK MAXARG_B -#endif -/* maximum number of local variables */ -#ifndef MAXLOCALS -#define MAXLOCALS 200 /* arbitrary limit (=MAXSTACK -#undef MAXLOCALS -#define MAXLOCALS (MAXSTACK-1) +/* maximum number of variables declared in a function */ +#ifndef MAXVARS +#define MAXVARS 200 /* arbitrary limit (MAXARG_B -#undef MAXUPVALUES -#define MAXUPVALUES MAXARG_B -#endif - - -/* maximum number of variables in the left side of an assignment */ -#ifndef MAXVARSLH -#define MAXVARSLH 100 /* arbitrary limit (=MULT_RET -#undef MAXVARSLH -#define MAXVARSLH (MULT_RET-1) +#define MAXUPVALUES 32 #endif @@ -177,27 +159,26 @@ typedef unsigned long Instruction; #ifndef MAXPARAMS #define MAXPARAMS 100 /* arbitrary limit (=MAXLOCALS -#undef MAXPARAMS -#define MAXPARAMS (MAXLOCALS-1) -#endif -/* number of list items to accumulate before a SETLIST instruction */ -#define LFIELDS_PER_FLUSH 64 -#if LFIELDS_PER_FLUSH>(MAXSTACK/4) -#undef LFIELDS_PER_FLUSH -#define LFIELDS_PER_FLUSH (MAXSTACK/4) +/* minimum size for the string table (must be power of 2) */ +#ifndef MINSTRTABSIZE +#define MINSTRTABSIZE 32 #endif -/* number of record items to accumulate before a SETMAP instruction */ -/* (each item counts 2 elements on the stack: an index and a value) */ -#define RFIELDS_PER_FLUSH (LFIELDS_PER_FLUSH/2) + +/* minimum size for string buffer */ +#ifndef LUA_MINBUFFER +#define LUA_MINBUFFER 32 +#endif -/* maximum lookback to find a real constant (for code generation) */ -#ifndef LOOKBACKNUMS -#define LOOKBACKNUMS 20 /* arbitrary constant */ +/* +** maximum number of syntactical nested non-terminals: Not too big, +** or may overflow the C stack... +*/ +#ifndef LUA_MAXPARSERLEVEL +#define LUA_MAXPARSERLEVEL 200 #endif diff --git a/src/lmem.c b/src/lmem.c index 03a804c9ca..f977770af0 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.39 2000/10/30 16:29:59 roberto Exp $ +** $Id: lmem.c,v 1.61 2002/12/04 17:38:31 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -7,8 +7,11 @@ #include +#define lmem_c + #include "lua.h" +#include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" @@ -16,135 +19,73 @@ - -#ifdef LUA_DEBUG /* -** {====================================================================== -** Controlled version for realloc. -** ======================================================================= +** definition for realloc function. It must assure that l_realloc(NULL, +** 0, x) allocates a new block (ANSI C assures that). (`os' is the old +** block size; some allocators may use that.) */ - - -#include -#include -#include - -#define realloc(b, s) debug_realloc(b, s) -#define malloc(b) debug_realloc(NULL, b) -#define free(b) debug_realloc(b, 0) - - -/* ensures maximum alignment for HEADER */ -#define HEADER (sizeof(union L_Umaxalign)) - -#define MARKSIZE 16 -#define MARK 0x55 /* 01010101 (a nice pattern) */ - - -#define blocksize(b) ((unsigned long *)((char *)(b) - HEADER)) - -unsigned long memdebug_numblocks = 0; -unsigned long memdebug_total = 0; -unsigned long memdebug_maxmem = 0; -unsigned long memdebug_memlimit = LONG_MAX; - - -static void *checkblock (void *block) { - unsigned long *b = blocksize(block); - unsigned long size = *b; - int i; - for (i=0;i memdebug_memlimit) - return NULL; /* to test memory allocation errors */ - else { - size_t realsize = HEADER+size+MARKSIZE; - char *newblock = (char *)(malloc)(realsize); /* alloc a new block */ - int i; - if (realsize < size) return NULL; /* overflow! */ - if (newblock == NULL) return NULL; - if (block) { - size_t oldsize = *blocksize(block); - if (oldsize > size) oldsize = size; - memcpy(newblock+HEADER, block, oldsize); - freeblock(block); /* erase (and check) old copy */ - } - memdebug_total += size; - if (memdebug_total > memdebug_maxmem) memdebug_maxmem = memdebug_total; - memdebug_numblocks++; - *(unsigned long *)newblock = size; - for (i=0;i= limit-inc) lua_error(L, errormsg); - if ((newn ^ nelems) <= nelems || /* still the same power-of-2 limit? */ - (nelems > 0 && newn < MINPOWER2)) /* or block already is MINPOWER2? */ - return block; /* do not need to reallocate */ - else /* it crossed a power-of-2 boundary; grow to next power */ - return luaM_realloc(L, block, luaO_power2(newn)*size); +#define MINSIZEARRAY 4 + + +void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, + int limit, const char *errormsg) { + void *newblock; + int newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + else if (*size >= limit/2) { /* cannot double it? */ + if (*size < limit - MINSIZEARRAY) /* try something smaller... */ + newsize = limit; /* still have at least MINSIZEARRAY free places */ + else luaG_runerror(L, errormsg); + } + newblock = luaM_realloc(L, block, + cast(lu_mem, *size)*cast(lu_mem, size_elems), + cast(lu_mem, newsize)*cast(lu_mem, size_elems)); + *size = newsize; /* update only when everything else is OK */ + return newblock; } /* ** generic allocation routine. */ -void *luaM_realloc (lua_State *L, void *block, lint32 size) { +void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) { + lua_assert((oldsize == 0) == (block == NULL)); if (size == 0) { - free(block); /* block may be NULL; that is OK for free */ - return NULL; + if (block != NULL) { + l_free(block, oldsize); + block = NULL; + } + else return NULL; /* avoid `nblocks' computations when oldsize==size==0 */ } else if (size >= MAX_SIZET) - lua_error(L, "memory allocation error: block too big"); - block = realloc(block, size); - if (block == NULL) { - if (L) - luaD_breakrun(L, LUA_ERRMEM); /* break run without error message */ - else return NULL; /* error before creating state! */ + luaG_runerror(L, "memory allocation error: block too big"); + else { + block = l_realloc(block, oldsize, size); + if (block == NULL) { + if (L) + luaD_throw(L, LUA_ERRMEM); + else return NULL; /* error before creating state! */ + } + } + if (L) { + lua_assert(G(L) != NULL && G(L)->nblocks > 0); + G(L)->nblocks -= oldsize; + G(L)->nblocks += size; } return block; } - diff --git a/src/lmem.h b/src/lmem.h index 9e7c829d71..1bb4fde0b2 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.16 2000/10/30 16:29:59 roberto Exp $ +** $Id: lmem.h,v 1.26 2002/05/01 20:40:42 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -13,29 +13,31 @@ #include "llimits.h" #include "lua.h" -void *luaM_realloc (lua_State *L, void *oldblock, lint32 size); -void *luaM_growaux (lua_State *L, void *block, size_t nelems, - int inc, size_t size, const char *errormsg, - size_t limit); +#define MEMERRMSG "not enough memory" -#define luaM_free(L, b) luaM_realloc(L, (b), 0) -#define luaM_malloc(L, t) luaM_realloc(L, NULL, (t)) -#define luaM_new(L, t) ((t *)luaM_malloc(L, sizeof(t))) -#define luaM_newvector(L, n,t) ((t *)luaM_malloc(L, (n)*(lint32)sizeof(t))) -#define luaM_growvector(L, v,nelems,inc,t,e,l) \ - ((v)=(t *)luaM_growaux(L, v,nelems,inc,sizeof(t),e,l)) +void *luaM_realloc (lua_State *L, void *oldblock, lu_mem oldsize, lu_mem size); -#define luaM_reallocvector(L, v,n,t) \ - ((v)=(t *)luaM_realloc(L, v,(n)*(lint32)sizeof(t))) +void *luaM_growaux (lua_State *L, void *block, int *size, int size_elem, + int limit, const char *errormsg); +#define luaM_free(L, b, s) luaM_realloc(L, (b), (s), 0) +#define luaM_freelem(L, b) luaM_realloc(L, (b), sizeof(*(b)), 0) +#define luaM_freearray(L, b, n, t) luaM_realloc(L, (b), \ + cast(lu_mem, n)*cast(lu_mem, sizeof(t)), 0) -#ifdef LUA_DEBUG -extern unsigned long memdebug_numblocks; -extern unsigned long memdebug_total; -extern unsigned long memdebug_maxmem; -extern unsigned long memdebug_memlimit; -#endif +#define luaM_malloc(L, t) luaM_realloc(L, NULL, 0, (t)) +#define luaM_new(L, t) cast(t *, luaM_malloc(L, sizeof(t))) +#define luaM_newvector(L, n,t) cast(t *, luaM_malloc(L, \ + cast(lu_mem, n)*cast(lu_mem, sizeof(t)))) + +#define luaM_growvector(L,v,nelems,size,t,limit,e) \ + if (((nelems)+1) > (size)) \ + ((v)=cast(t *, luaM_growaux(L,v,&(size),sizeof(t),limit,e))) + +#define luaM_reallocvector(L, v,oldn,n,t) \ + ((v)=cast(t *, luaM_realloc(L, v,cast(lu_mem, oldn)*cast(lu_mem, sizeof(t)), \ + cast(lu_mem, n)*cast(lu_mem, sizeof(t))))) #endif diff --git a/src/lobject.c b/src/lobject.c index e787fbe82a..9522b6e812 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,92 +1,162 @@ /* -** $Id: lobject.c,v 1.55 2000/10/20 16:36:32 roberto Exp $ +** $Id: lobject.c,v 1.97 2003/04/03 13:35:34 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include #include -#include #include #include +#define lobject_c + #include "lua.h" +#include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" +#include "lstring.h" +#include "lvm.h" +/* function to convert a string to a lua_Number */ +#ifndef lua_str2number +#define lua_str2number(s,p) strtod((s), (p)) +#endif -const TObject luaO_nilobject = {LUA_TNIL, {NULL}}; - - -const char *const luaO_typenames[] = { - "userdata", "nil", "number", "string", "table", "function" -}; +const TObject luaO_nilobject = {LUA_TNIL, {NULL}}; /* -** returns smaller power of 2 larger than `n' (minimum is MINPOWER2) +** converts an integer to a "floating point byte", represented as +** (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm) */ -lint32 luaO_power2 (lint32 n) { - lint32 p = MINPOWER2; - while (p<=n) p<<=1; - return p; +int luaO_int2fb (unsigned int x) { + int m = 0; /* mantissa */ + while (x >= (1<<3)) { + x = (x+1) >> 1; + m++; + } + return (m << 3) | cast(int, x); } -int luaO_equalObj (const TObject *t1, const TObject *t2) { - if (ttype(t1) != ttype(t2)) return 0; - switch (ttype(t1)) { - case LUA_TNUMBER: - return nvalue(t1) == nvalue(t2); - case LUA_TSTRING: case LUA_TUSERDATA: - return tsvalue(t1) == tsvalue(t2); - case LUA_TTABLE: - return hvalue(t1) == hvalue(t2); - case LUA_TFUNCTION: - return clvalue(t1) == clvalue(t2); - default: - LUA_ASSERT(ttype(t1) == LUA_TNIL, "invalid type"); - return 1; /* LUA_TNIL */ +int luaO_log2 (unsigned int x) { + static const lu_byte log_8[255] = { + 0, + 1,1, + 2,2,2,2, + 3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 + }; + if (x >= 0x00010000) { + if (x >= 0x01000000) return log_8[((x>>24) & 0xff) - 1]+24; + else return log_8[((x>>16) & 0xff) - 1]+16; + } + else { + if (x >= 0x00000100) return log_8[((x>>8) & 0xff) - 1]+8; + else if (x) return log_8[(x & 0xff) - 1]; + return -1; /* special `log' for 0 */ } } -char *luaO_openspace (lua_State *L, size_t n) { - if (n > L->Mbuffsize) { - luaM_reallocvector(L, L->Mbuffer, n, char); - L->nblocks += (n - L->Mbuffsize)*sizeof(char); - L->Mbuffsize = n; +int luaO_rawequalObj (const TObject *t1, const TObject *t2) { + if (ttype(t1) != ttype(t2)) return 0; + else switch (ttype(t1)) { + case LUA_TNIL: + return 1; + case LUA_TNUMBER: + return nvalue(t1) == nvalue(t2); + case LUA_TBOOLEAN: + return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ + case LUA_TLIGHTUSERDATA: + return pvalue(t1) == pvalue(t2); + default: + lua_assert(iscollectable(t1)); + return gcvalue(t1) == gcvalue(t2); } - return L->Mbuffer; } -int luaO_str2d (const char *s, Number *result) { /* LUA_NUMBER */ +int luaO_str2d (const char *s, lua_Number *result) { char *endptr; - Number res = lua_str2number(s, &endptr); + lua_Number res = lua_str2number(s, &endptr); if (endptr == s) return 0; /* no conversion */ - while (isspace((unsigned char)*endptr)) endptr++; + while (isspace((unsigned char)(*endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ *result = res; return 1; } -/* maximum length of a string format for `luaO_verror' */ -#define MAX_VERROR 280 -/* this function needs to handle only '%d' and '%.XXs' formats */ -void luaO_verror (lua_State *L, const char *fmt, ...) { +static void pushstr (lua_State *L, const char *str) { + setsvalue2s(L->top, luaS_new(L, str)); + incr_top(L); +} + + +/* this function handles only `%d', `%c', %f, and `%s' formats */ +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { + int n = 1; + pushstr(L, ""); + for (;;) { + const char *e = strchr(fmt, '%'); + if (e == NULL) break; + setsvalue2s(L->top, luaS_newlstr(L, fmt, e-fmt)); + incr_top(L); + switch (*(e+1)) { + case 's': + pushstr(L, va_arg(argp, char *)); + break; + case 'c': { + char buff[2]; + buff[0] = cast(char, va_arg(argp, int)); + buff[1] = '\0'; + pushstr(L, buff); + break; + } + case 'd': + setnvalue(L->top, cast(lua_Number, va_arg(argp, int))); + incr_top(L); + break; + case 'f': + setnvalue(L->top, cast(lua_Number, va_arg(argp, l_uacNumber))); + incr_top(L); + break; + case '%': + pushstr(L, "%"); + break; + default: lua_assert(0); + } + n += 2; + fmt = e+2; + } + pushstr(L, fmt); + luaV_concat(L, n+1, L->top - L->base - 1); + L->top -= n; + return svalue(L->top - 1); +} + + +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { + const char *msg; va_list argp; - char buff[MAX_VERROR]; /* to hold formatted message */ va_start(argp, fmt); - vsprintf(buff, fmt, argp); + msg = luaO_pushvfstring(L, fmt, argp); va_end(argp); - lua_error(L, buff); + return msg; } @@ -95,31 +165,31 @@ void luaO_chunkid (char *out, const char *source, int bufflen) { strncpy(out, source+1, bufflen); /* remove first char */ out[bufflen-1] = '\0'; /* ensures null termination */ } - else { + else { /* out = "source", or "...source" */ if (*source == '@') { int l; source++; /* skip the `@' */ - bufflen -= sizeof("file `...%s'"); + bufflen -= sizeof(" `...' "); l = strlen(source); + strcpy(out, ""); if (l>bufflen) { source += (l-bufflen); /* get last part of file name */ - sprintf(out, "file `...%.99s'", source); + strcat(out, "..."); } - else - sprintf(out, "file `%.99s'", source); + strcat(out, source); } - else { + else { /* out = [string "string"] */ int len = strcspn(source, "\n"); /* stop at first newline */ - bufflen -= sizeof("string \"%.*s...\""); + bufflen -= sizeof(" [string \"...\"] "); if (len > bufflen) len = bufflen; + strcpy(out, "[string \""); if (source[len] != '\0') { /* must truncate? */ - strcpy(out, "string \""); - out += strlen(out); - strncpy(out, source, len); - strcpy(out+len, "...\""); + strncat(out, source, len); + strcat(out, "..."); } else - sprintf(out, "string \"%.99s\"", source); + strcat(out, source); + strcat(out, "\"]"); } } } diff --git a/src/lobject.h b/src/lobject.h index cb232c770b..321a7e06c1 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.82 2000/10/30 17:49:19 roberto Exp $ +** $Id: lobject.h,v 1.159 2003/03/18 12:50:04 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -12,115 +12,222 @@ #include "lua.h" -#ifdef LUA_DEBUG -#undef NDEBUG -#include -#define LUA_INTERNALERROR(s) assert(((void)s,0)) -#define LUA_ASSERT(c,s) assert(((void)s,(c))) -#else -#define LUA_INTERNALERROR(s) /* empty */ -#define LUA_ASSERT(c,s) /* empty */ -#endif +/* tags for values visible from Lua */ +#define NUM_TAGS LUA_TTHREAD -#ifdef LUA_DEBUG -/* to avoid warnings, and make sure value is really unused */ -#define UNUSED(x) (x=0, (void)(x)) -#else -#define UNUSED(x) ((void)(x)) /* to avoid warnings */ -#endif +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO (NUM_TAGS+1) +#define LUA_TUPVAL (NUM_TAGS+2) + + +/* +** Union of all collectable objects +*/ +typedef union GCObject GCObject; -/* mark for closures active in the stack */ -#define LUA_TMARK 6 +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked -/* tags for values visible from Lua == first user-created tag */ -#define NUM_TAGS 6 +/* +** Common header in struct form +*/ +typedef struct GCheader { + CommonHeader; +} GCheader; -/* check whether `t' is a mark */ -#define is_T_MARK(t) ((t) == LUA_TMARK) +/* +** Union of all Lua values +*/ typedef union { - struct TString *ts; /* LUA_TSTRING, LUA_TUSERDATA */ - struct Closure *cl; /* LUA_TFUNCTION */ - struct Hash *a; /* LUA_TTABLE */ - struct CallInfo *i; /* LUA_TLMARK */ - Number n; /* LUA_TNUMBER */ + GCObject *gc; + void *p; + lua_Number n; + int b; } Value; -/* Macros to access values */ -#define ttype(o) ((o)->ttype) -#define nvalue(o) ((o)->value.n) -#define tsvalue(o) ((o)->value.ts) -#define clvalue(o) ((o)->value.cl) -#define hvalue(o) ((o)->value.a) -#define infovalue(o) ((o)->value.i) -#define svalue(o) (tsvalue(o)->str) - - +/* +** Lua values (or `tagged objects') +*/ typedef struct lua_TObject { - int ttype; + int tt; Value value; } TObject; +/* Macros to test type */ +#define ttisnil(o) (ttype(o) == LUA_TNIL) +#define ttisnumber(o) (ttype(o) == LUA_TNUMBER) +#define ttisstring(o) (ttype(o) == LUA_TSTRING) +#define ttistable(o) (ttype(o) == LUA_TTABLE) +#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) +#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) +#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) +#define ttisthread(o) (ttype(o) == LUA_TTHREAD) +#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) + +/* Macros to access values */ +#define ttype(o) ((o)->tt) +#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) +#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) +#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) +#define tsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#define uvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) +#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) +#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) +#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) + +#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) + +/* Macros to set values */ +#define setnvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TNUMBER; i_o->value.n=(x); } + +#define chgnvalue(obj,x) \ + check_exp(ttype(obj)==LUA_TNUMBER, (obj)->value.n=(x)) + +#define setpvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TLIGHTUSERDATA; i_o->value.p=(x); } + +#define setbvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TBOOLEAN; i_o->value.b=(x); } + +#define setsvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TSTRING; \ + i_o->value.gc=cast(GCObject *, (x)); \ + lua_assert(i_o->value.gc->gch.tt == LUA_TSTRING); } + +#define setuvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TUSERDATA; \ + i_o->value.gc=cast(GCObject *, (x)); \ + lua_assert(i_o->value.gc->gch.tt == LUA_TUSERDATA); } + +#define setthvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TTHREAD; \ + i_o->value.gc=cast(GCObject *, (x)); \ + lua_assert(i_o->value.gc->gch.tt == LUA_TTHREAD); } + +#define setclvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TFUNCTION; \ + i_o->value.gc=cast(GCObject *, (x)); \ + lua_assert(i_o->value.gc->gch.tt == LUA_TFUNCTION); } + +#define sethvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TTABLE; \ + i_o->value.gc=cast(GCObject *, (x)); \ + lua_assert(i_o->value.gc->gch.tt == LUA_TTABLE); } + +#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) + + + /* -** String headers for string table +** for internal debug only +*/ +#define checkconsistency(obj) \ + lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) + + +#define setobj(obj1,obj2) \ + { const TObject *o2=(obj2); TObject *o1=(obj1); \ + checkconsistency(o2); \ + o1->tt=o2->tt; o1->value = o2->value; } + + +/* +** different types of sets, according to destination */ +/* from stack to (same) stack */ +#define setobjs2s setobj +/* to stack (not from same stack) */ +#define setobj2s setobj +#define setsvalue2s setsvalue +/* from table to same table */ +#define setobjt2t setobj +/* to table */ +#define setobj2t setobj +/* to new object */ +#define setobj2n setobj +#define setsvalue2n setsvalue + +#define setttype(obj, tt) (ttype(obj) = (tt)) + + +#define iscollectable(o) (ttype(o) >= LUA_TSTRING) + + + +typedef TObject *StkId; /* index to stack elements */ + + /* -** most `malloc' libraries allocate memory in blocks of 8 bytes. TSPACK -** tries to make sizeof(TString) a multiple of this granularity, to reduce -** waste of space. +** String headers for string table */ -#define TSPACK ((int)sizeof(int)) - -typedef struct TString { - union { - struct { /* for strings */ - unsigned long hash; - int constindex; /* hint to reuse constants */ - } s; - struct { /* for userdata */ - int tag; - void *value; - } d; - } u; - size_t len; - struct TString *nexthash; /* chain for hash table */ - int marked; - char str[TSPACK]; /* variable length string!! must be the last field! */ +typedef union TString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + struct { + CommonHeader; + lu_byte reserved; + lu_hash hash; + size_t len; + } tsv; } TString; +#define getstr(ts) cast(const char *, (ts) + 1) +#define svalue(o) getstr(tsvalue(o)) + + + +typedef union Udata { + L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ + struct { + CommonHeader; + struct Table *metatable; + size_t len; + } uv; +} Udata; + + + + /* ** Function Prototypes */ typedef struct Proto { - Number *knum; /* Number numbers used by the function */ - int nknum; /* size of `knum' */ - struct TString **kstr; /* strings used by the function */ - int nkstr; /* size of `kstr' */ - struct Proto **kproto; /* functions defined inside the function */ - int nkproto; /* size of `kproto' */ + CommonHeader; + TObject *k; /* constants used by the function */ Instruction *code; - int ncode; /* size of `code'; when 0 means an incomplete `Proto' */ - short numparams; - short is_vararg; - short maxstacksize; - short marked; - struct Proto *next; - /* debug information */ + struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ - int nlineinfo; /* size of `lineinfo' */ - int nlocvars; struct LocVar *locvars; /* information about local variables */ - int lineDefined; + TString **upvalues; /* upvalue names */ TString *source; + int sizeupvalues; + int sizek; /* size of `k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of `p' */ + int sizelocvars; + int lineDefined; + GCObject *gclist; + lu_byte nups; /* number of upvalues */ + lu_byte numparams; + lu_byte is_vararg; + lu_byte maxstacksize; } Proto; @@ -131,73 +238,98 @@ typedef struct LocVar { } LocVar; + +/* +** Upvalues +*/ + +typedef struct UpVal { + CommonHeader; + TObject *v; /* points to stack or to its own value */ + TObject value; /* the value (when closed) */ +} UpVal; + + /* ** Closures */ -typedef struct Closure { - union { - lua_CFunction c; /* C functions */ - struct Proto *l; /* Lua functions */ - } f; - struct Closure *next; - struct Closure *mark; /* marked closures (point to itself when not marked) */ - short isC; /* 0 for Lua functions, 1 for C functions */ - short nupvalues; + +#define ClosureHeader \ + CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; TObject upvalue[1]; +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + TObject g; /* global table for this closure */ + UpVal *upvals[1]; +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; } Closure; -#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->isC) +#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) +#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) + +/* +** Tables +*/ typedef struct Node { - TObject key; - TObject val; + TObject i_key; + TObject i_val; struct Node *next; /* for chaining */ } Node; -typedef struct Hash { + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<

    mark != (x)) /* -** informations about a call (for debugging) +** `module' operation for hashing (size is always a power of 2) */ -typedef struct CallInfo { - struct Closure *func; /* function being called */ - const Instruction **pc; /* current pc of called function */ - int lastpc; /* last pc traced */ - int line; /* current line */ - int refi; /* current index in `lineinfo' */ -} CallInfo; +#define lmod(s,size) \ + check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))) -extern const TObject luaO_nilobject; -extern const char *const luaO_typenames[]; +#define twoto(x) (1<<(x)) +#define sizenode(t) (twoto((t)->lsizenode)) -#define luaO_typename(o) (luaO_typenames[ttype(o)]) +extern const TObject luaO_nilobject; -lint32 luaO_power2 (lint32 n); -char *luaO_openspace (lua_State *L, size_t n); +int luaO_log2 (unsigned int x); +int luaO_int2fb (unsigned int x); +#define fb2int(x) (((x) & 7) << ((x) >> 3)) -int luaO_equalObj (const TObject *t1, const TObject *t2); -int luaO_str2d (const char *s, Number *result); +int luaO_rawequalObj (const TObject *t1, const TObject *t2); +int luaO_str2d (const char *s, lua_Number *result); -void luaO_verror (lua_State *L, const char *fmt, ...); +const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); +const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); void luaO_chunkid (char *out, const char *source, int len); diff --git a/src/lopcodes.c b/src/lopcodes.c new file mode 100644 index 0000000000..993e426d35 --- /dev/null +++ b/src/lopcodes.c @@ -0,0 +1,102 @@ +/* +** $Id: lopcodes.c,v 1.22 2002/12/04 17:38:31 roberto Exp $ +** extracted automatically from lopcodes.h by mkprint.lua +** DO NOT EDIT +** See Copyright Notice in lua.h +*/ + + +#define lopcodes_c + +#include "lua.h" + +#include "lobject.h" +#include "lopcodes.h" + + +#ifdef LUA_OPNAMES + +const char *const luaP_opnames[] = { + "MOVE", + "LOADK", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETGLOBAL", + "GETTABLE", + "SETGLOBAL", + "SETUPVAL", + "SETTABLE", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "DIV", + "POW", + "UNM", + "NOT", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "TFORLOOP", + "TFORPREP", + "SETLIST", + "SETLISTO", + "CLOSE", + "CLOSURE" +}; + +#endif + +#define opmode(t,b,bk,ck,sa,k,m) (((t)<>1) /* `sBx' is signed */ +#else +#define MAXARG_Bx MAX_INT +#define MAXARG_sBx MAX_INT +#endif + + +#define MAXARG_A ((1<>POS_U)) -#define SETARG_U(i,u) ((i) = (((i)&MASK0(SIZE_U,POS_U)) | \ - ((Instruction)(u)<>POS_A)) +#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ + ((cast(Instruction, u)<>POS_B) & MASK1(SIZE_B,0))) +#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ + ((cast(Instruction, b)<>POS_C) & MASK1(SIZE_C,0))) +#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ + ((cast(Instruction, b)<>POS_Bx) & MASK1(SIZE_Bx,0))) +#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ + ((cast(Instruction, b)<>POS_A)) -#define SETARG_A(i,a) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ - ((Instruction)(a)<>POS_B) & MASK1(SIZE_B,0))) -#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ - ((Instruction)(b)< C) then R(A) := R(B) else pc++ */ -OP_ADD,/* - y x x+y */ -OP_ADDI,/* S x x+s */ -OP_SUB,/* - y x x-y */ -OP_MULT,/* - y x x*y */ -OP_DIV,/* - y x x/y */ -OP_POW,/* - y x x^y */ -OP_CONCAT,/* U v_u-v_1 v1..-..v_u */ -OP_MINUS,/* - x -x */ -OP_NOT,/* - x (x==nil)? 1 : nil */ +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ -OP_JMPNE,/* J y x - (x~=y)? PC+=s */ -OP_JMPEQ,/* J y x - (x==y)? PC+=s */ -OP_JMPLT,/* J y x - (xy)? PC+=s */ -OP_JMPGE,/* J y x - (x>=y)? PC+=s */ +OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) =) R(A)*/ +OP_CLOSURE/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ +} OpCode; -OP_LFORPREP,/* J */ -OP_LFORLOOP,/* J */ -OP_CLOSURE/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */ +#define NUM_OPCODES (cast(int, OP_CLOSURE+1)) + -} OpCode; -#define NUM_OPCODES ((int)OP_CLOSURE+1) +/*=========================================================================== + Notes: + (1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, + and can be 0: OP_CALL then sets `top' to last_result+1, so + next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. + + (2) In OP_RETURN, if (B == 0) then return up to `top' + + (3) For comparisons, B specifies what conditions the test should accept. + + (4) All `skips' (pc++) assume that next instruction is a jump +===========================================================================*/ -#define ISJUMP(o) (OP_JMPNE <= (o) && (o) <= OP_JMP) +/* +** masks for instruction properties +*/ +enum OpModeMask { + OpModeBreg = 2, /* B is a register */ + OpModeBrk, /* B is a register/constant */ + OpModeCrk, /* C is a register/constant */ + OpModesetA, /* instruction set register A */ + OpModeK, /* Bx is a constant */ + OpModeT /* operator is a test */ + +}; +extern const lu_byte luaP_opmodes[NUM_OPCODES]; -/* special code to fit a LUA_MULTRET inside an argB */ -#define MULT_RET 255 /* (<=MAXARG_B) */ -#if MULT_RET>MAXARG_B -#undef MULT_RET -#define MULT_RET MAXARG_B +#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) +#define testOpMode(m, b) (luaP_opmodes[m] & (1 << (b))) + + +#ifdef LUA_OPNAMES +extern const char *const luaP_opnames[]; /* opcode names */ #endif + +/* number of list items to accumulate before a SETLIST instruction */ +/* (must be a power of 2) */ +#define LFIELDS_PER_FLUSH 32 + + #endif diff --git a/src/lparser.c b/src/lparser.c index 67161c868e..c1323ecd2a 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,16 +1,18 @@ /* -** $Id: lparser.c,v 1.117 2000/11/29 11:57:42 roberto Exp $ -** LL(1) Parser and code generator for Lua +** $Id: lparser.c,v 1.208 2003/04/03 13:35:34 roberto Exp $ +** Lua Parser ** See Copyright Notice in lua.h */ -#include #include +#define lparser_c + #include "lua.h" #include "lcode.h" +#include "ldebug.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" @@ -21,35 +23,34 @@ #include "lstring.h" -/* -** Constructors descriptor: -** `n' indicates number of elements, and `k' signals whether -** it is a list constructor (k = 0) or a record constructor (k = 1) -** or empty (k = ';' or '}') -*/ -typedef struct Constdesc { - int n; - int k; -} Constdesc; -typedef struct Breaklabel { - struct Breaklabel *previous; /* chain */ - int breaklist; - int stacklevel; -} Breaklabel; +#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) + + +#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ + luaX_syntaxerror(ls, "too many syntax levels"); +#define leavelevel(ls) ((ls)->nestlevel--) +/* +** nodes for block list (list of active blocks) +*/ +typedef struct BlockCnt { + struct BlockCnt *previous; /* chain */ + int breaklist; /* list of jumps out of this loop */ + int nactvar; /* # active local variables outside the breakable structure */ + int upval; /* true if some variable in the block is an upvalue */ + int isbreakable; /* true if `block' is a loop */ +} BlockCnt; + /* ** prototypes for recursive non-terminal functions */ -static void body (LexState *ls, int needself, int line); static void chunk (LexState *ls); -static void constructor (LexState *ls); static void expr (LexState *ls, expdesc *v); -static void exp1 (LexState *ls); @@ -65,32 +66,18 @@ static void next (LexState *ls) { static void lookahead (LexState *ls) { - LUA_ASSERT(ls->lookahead.token == TK_EOS, "two look-aheads"); + lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo); } static void error_expected (LexState *ls, int token) { - char buff[100], t[TOKEN_LEN]; - luaX_token2str(token, t); - sprintf(buff, "`%.20s' expected", t); - luaK_error(ls, buff); + luaX_syntaxerror(ls, + luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token))); } -static void check (LexState *ls, int c) { - if (ls->t.token != c) - error_expected(ls, c); - next(ls); -} - - -static void check_condition (LexState *ls, int c, const char *msg) { - if (!c) luaK_error(ls, msg); -} - - -static int optional (LexState *ls, int c) { +static int testnext (LexState *ls, int c) { if (ls->t.token == c) { next(ls); return 1; @@ -99,40 +86,26 @@ static int optional (LexState *ls, int c) { } +static void check (LexState *ls, int c) { + if (!testnext(ls, c)) + error_expected(ls, c); +} + + +#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } + + + static void check_match (LexState *ls, int what, int who, int where) { - if (ls->t.token != what) { + if (!testnext(ls, what)) { if (where == ls->linenumber) error_expected(ls, what); else { - char buff[100]; - char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; - luaX_token2str(what, t_what); - luaX_token2str(who, t_who); - sprintf(buff, "`%.20s' expected (to close `%.20s' at line %d)", - t_what, t_who, where); - luaK_error(ls, buff); + luaX_syntaxerror(ls, luaO_pushfstring(ls->L, + "`%s' expected (to close `%s' at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } - next(ls); -} - - -static int string_constant (FuncState *fs, TString *s) { - Proto *f = fs->f; - int c = s->u.s.constindex; - if (c >= f->nkstr || f->kstr[c] != s) { - luaM_growvector(fs->L, f->kstr, f->nkstr, 1, TString *, - "constant table overflow", MAXARG_U); - c = f->nkstr++; - f->kstr[c] = s; - s->u.s.constindex = c; /* hint for next time */ - } - return c; -} - - -static void code_string (LexState *ls, TString *s) { - luaK_kstr(ls, string_constant(ls->fs, s)); } @@ -145,182 +118,224 @@ static TString *str_checkname (LexState *ls) { } -static int checkname (LexState *ls) { - return string_constant(ls->fs, str_checkname(ls)); +static void init_exp (expdesc *e, expkind k, int i) { + e->f = e->t = NO_JUMP; + e->k = k; + e->info = i; +} + + +static void codestring (LexState *ls, expdesc *e, TString *s) { + init_exp(e, VK, luaK_stringK(ls->fs, s)); +} + + +static void checkname(LexState *ls, expdesc *e) { + codestring(ls, e, str_checkname(ls)); } static int luaI_registerlocalvar (LexState *ls, TString *varname) { - Proto *f = ls->fs->f; - luaM_growvector(ls->L, f->locvars, f->nlocvars, 1, LocVar, "", MAX_INT); - f->locvars[f->nlocvars].varname = varname; - return f->nlocvars++; + FuncState *fs = ls->fs; + Proto *f = fs->f; + luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, + LocVar, MAX_INT, ""); + f->locvars[fs->nlocvars].varname = varname; + return fs->nlocvars++; } static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; - luaX_checklimit(ls, fs->nactloc+n+1, MAXLOCALS, "local variables"); - fs->actloc[fs->nactloc+n] = luaI_registerlocalvar(ls, name); + luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "local variables"); + fs->actvar[fs->nactvar+n] = luaI_registerlocalvar(ls, name); } static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - while (nvars--) - fs->f->locvars[fs->actloc[fs->nactloc++]].startpc = fs->pc; + fs->nactvar += nvars; + for (; nvars; nvars--) { + getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; + } } -static void removelocalvars (LexState *ls, int nvars) { +static void removevars (LexState *ls, int tolevel) { FuncState *fs = ls->fs; - while (nvars--) - fs->f->locvars[fs->actloc[--fs->nactloc]].endpc = fs->pc; + while (fs->nactvar > tolevel) + getlocvar(fs, --fs->nactvar).endpc = fs->pc; } static void new_localvarstr (LexState *ls, const char *name, int n) { - new_localvar(ls, luaS_newfixed(ls->L, name), n); + new_localvar(ls, luaS_new(ls->L, name), n); } -static int search_local (LexState *ls, TString *n, expdesc *var) { - FuncState *fs; - int level = 0; - for (fs=ls->fs; fs; fs=fs->prev) { - int i; - for (i=fs->nactloc-1; i >= 0; i--) { - if (n == fs->f->locvars[fs->actloc[i]].varname) { - var->k = VLOCAL; - var->u.index = i; - return level; - } - } - level++; /* `var' not found; check outer level */ - } - var->k = VGLOBAL; /* not found in any level; must be global */ - return -1; +static void create_local (LexState *ls, const char *name) { + new_localvarstr(ls, name, 0); + adjustlocalvars(ls, 1); } -static void singlevar (LexState *ls, TString *n, expdesc *var) { - int level = search_local(ls, n, var); - if (level >= 1) /* neither local (0) nor global (-1)? */ - luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); - else if (level == -1) /* global? */ - var->u.index = string_constant(ls->fs, n); +static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { + int i; + Proto *f = fs->f; + for (i=0; inups; i++) { + if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) { + lua_assert(fs->f->upvalues[i] == name); + return i; + } + } + /* new one */ + luaX_checklimit(fs->ls, f->nups + 1, MAXUPVALUES, "upvalues"); + luaM_growvector(fs->L, fs->f->upvalues, f->nups, fs->f->sizeupvalues, + TString *, MAX_INT, ""); + fs->f->upvalues[f->nups] = name; + fs->upvalues[f->nups] = *v; + return f->nups++; } -static int indexupvalue (LexState *ls, expdesc *v) { - FuncState *fs = ls->fs; +static int searchvar (FuncState *fs, TString *n) { int i; - for (i=0; inupvalues; i++) { - if (fs->upvalues[i].k == v->k && fs->upvalues[i].u.index == v->u.index) + for (i=fs->nactvar-1; i >= 0; i--) { + if (n == getlocvar(fs, i).varname) return i; } - /* new one */ - luaX_checklimit(ls, fs->nupvalues+1, MAXUPVALUES, "upvalues"); - fs->upvalues[fs->nupvalues] = *v; - return fs->nupvalues++; + return -1; /* not found */ } -static void pushupvalue (LexState *ls, TString *n) { - FuncState *fs = ls->fs; - expdesc v; - int level = search_local(ls, n, &v); - if (level == -1) { /* global? */ - if (fs->prev == NULL) - luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); - v.u.index = string_constant(fs->prev, n); +static void markupval (FuncState *fs, int level) { + BlockCnt *bl = fs->bl; + while (bl && bl->nactvar > level) bl = bl->previous; + if (bl) bl->upval = 1; +} + + +static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) /* no more levels? */ + init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ + else { + int v = searchvar(fs, n); /* look up at current level */ + if (v >= 0) { + init_exp(var, VLOCAL, v); + if (!base) + markupval(fs, v); /* local will be used as an upval */ + } + else { /* not found at current level; try upper one */ + singlevaraux(fs->prev, n, var, 0); + if (var->k == VGLOBAL) { + if (base) + var->info = luaK_stringK(fs, n); /* info points to global name */ + } + else { /* LOCAL or UPVAL */ + var->info = indexupvalue(fs, n, var); + var->k = VUPVAL; /* upvalue in this level */ + } + } } - else if (level != 1) - luaX_syntaxerror(ls, - "upvalue must be global or local to immediately outer scope", n->str); - luaK_code1(fs, OP_PUSHUPVALUE, indexupvalue(ls, &v)); } -static void adjust_mult_assign (LexState *ls, int nvars, int nexps) { +static TString *singlevar (LexState *ls, expdesc *var, int base) { + TString *varname = str_checkname(ls); + singlevaraux(ls->fs, varname, var, base); + return varname; +} + + +static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; - int diff = nexps - nvars; - if (nexps > 0 && luaK_lastisopen(fs)) { /* list ends in a function call */ - diff--; /* do not count function call itself */ - if (diff <= 0) { /* more variables than values? */ - luaK_setcallreturns(fs, -diff); /* function call provide extra values */ - diff = 0; /* no more difference */ + int extra = nvars - nexps; + if (e->k == VCALL) { + extra++; /* includes call itself */ + if (extra <= 0) extra = 0; + else luaK_reserveregs(fs, extra-1); + luaK_setcallreturns(fs, e, extra); /* call provides the difference */ + } + else { + if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) { + int reg = fs->freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); } - else /* more values than variables */ - luaK_setcallreturns(fs, 0); /* call should provide no value */ } - /* push or pop eventual difference between list lengths */ - luaK_adjuststack(fs, diff); } static void code_params (LexState *ls, int nparams, int dots) { FuncState *fs = ls->fs; adjustlocalvars(ls, nparams); - luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters"); - fs->f->numparams = fs->nactloc; /* `self' could be there already */ - fs->f->is_vararg = dots; - if (dots) { - new_localvarstr(ls, "arg", 0); - adjustlocalvars(ls, 1); - } - luaK_deltastack(fs, fs->nactloc); /* count parameters in the stack */ + luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters"); + fs->f->numparams = cast(lu_byte, fs->nactvar); + fs->f->is_vararg = cast(lu_byte, dots); + if (dots) + create_local(ls, "arg"); + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } -static void enterbreak (FuncState *fs, Breaklabel *bl) { - bl->stacklevel = fs->stacklevel; +static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { bl->breaklist = NO_JUMP; + bl->isbreakable = isbreakable; + bl->nactvar = fs->nactvar; + bl->upval = 0; bl->previous = fs->bl; fs->bl = bl; + lua_assert(fs->freereg == fs->nactvar); } -static void leavebreak (FuncState *fs, Breaklabel *bl) { +static void leaveblock (FuncState *fs) { + BlockCnt *bl = fs->bl; fs->bl = bl->previous; - LUA_ASSERT(bl->stacklevel == fs->stacklevel, "wrong levels"); - luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs)); + removevars(fs->ls, bl->nactvar); + if (bl->upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + lua_assert(bl->nactvar == fs->nactvar); + fs->freereg = fs->nactvar; /* free registers */ + luaK_patchtohere(fs, bl->breaklist); } -static void pushclosure (LexState *ls, FuncState *func) { +static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { FuncState *fs = ls->fs; Proto *f = fs->f; int i; - for (i=0; inupvalues; i++) - luaK_tostack(ls, &func->upvalues[i], 1); - luaM_growvector(ls->L, f->kproto, f->nkproto, 1, Proto *, - "constant table overflow", MAXARG_A); - f->kproto[f->nkproto++] = func->f; - luaK_code2(fs, OP_CLOSURE, f->nkproto-1, func->nupvalues); + luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, + MAXARG_Bx, "constant table overflow"); + f->p[fs->np++] = func->f; + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); + for (i=0; if->nups; i++) { + OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); + } } static void open_func (LexState *ls, FuncState *fs) { Proto *f = luaF_newproto(ls->L); + fs->f = f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; fs->L = ls->L; ls->fs = fs; - fs->stacklevel = 0; - fs->nactloc = 0; - fs->nupvalues = 0; - fs->bl = NULL; - fs->f = f; - f->source = ls->source; fs->pc = 0; fs->lasttarget = 0; - fs->lastline = 0; - fs->jlt = NO_JUMP; - f->code = NULL; - f->maxstacksize = 0; - f->numparams = 0; /* default for main chunk */ - f->is_vararg = 0; /* default for main chunk */ + fs->jpc = NO_JUMP; + fs->freereg = 0; + fs->nk = 0; + fs->h = luaH_new(ls->L, 0, 0); + fs->np = 0; + fs->nlocvars = 0; + fs->nactvar = 0; + fs->bl = NULL; + f->source = ls->source; + f->maxstacksize = 2; /* registers 0/1 are always valid */ } @@ -328,33 +343,40 @@ static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; - luaK_code0(fs, OP_END); - luaK_getlabel(fs); /* close eventual list of pending jumps */ - luaM_reallocvector(L, f->code, fs->pc, Instruction); - luaM_reallocvector(L, f->kstr, f->nkstr, TString *); - luaM_reallocvector(L, f->knum, f->nknum, Number); - luaM_reallocvector(L, f->kproto, f->nkproto, Proto *); - removelocalvars(ls, fs->nactloc); - luaM_reallocvector(L, f->locvars, f->nlocvars, LocVar); - luaM_reallocvector(L, f->lineinfo, f->nlineinfo+1, int); - f->lineinfo[f->nlineinfo++] = MAX_INT; /* end flag */ - luaF_protook(L, f, fs->pc); /* proto is ok now */ + removevars(ls, 0); + luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ + luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); + f->sizecode = fs->pc; + luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); + f->sizelineinfo = fs->pc; + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject); + f->sizek = fs->nk; + luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); + f->sizep = fs->np; + luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + f->sizelocvars = fs->nlocvars; + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); + f->sizeupvalues = f->nups; + lua_assert(luaG_checkcode(f)); + lua_assert(fs->bl == NULL); ls->fs = fs->prev; - LUA_ASSERT(fs->bl == NULL, "wrong list end"); } -Proto *luaY_parser (lua_State *L, ZIO *z) { +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { struct LexState lexstate; struct FuncState funcstate; + lexstate.buff = buff; + lexstate.nestlevel = 0; luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); open_func(&lexstate, &funcstate); next(&lexstate); /* read first token */ chunk(&lexstate); check_condition(&lexstate, (lexstate.t.token == TK_EOS), " expected"); close_func(&lexstate); - LUA_ASSERT(funcstate.prev == NULL, "wrong list end"); - LUA_ASSERT(funcstate.nupvalues == 0, "no upvalues in main"); + lua_assert(funcstate.prev == NULL); + lua_assert(funcstate.f->nups == 0); + lua_assert(lexstate.nestlevel == 0); return funcstate.f; } @@ -365,235 +387,239 @@ Proto *luaY_parser (lua_State *L, ZIO *z) { /*============================================================*/ -static int explist1 (LexState *ls) { - /* explist1 -> expr { ',' expr } */ - int n = 1; /* at least one expression */ - expdesc v; - expr(ls, &v); - while (ls->t.token == ',') { - luaK_tostack(ls, &v, 1); /* gets only 1 value from previous expression */ - next(ls); /* skip comma */ - expr(ls, &v); - n++; - } - luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */ - return n; +static void luaY_field (LexState *ls, expdesc *v) { + /* field -> ['.' | ':'] NAME */ + FuncState *fs = ls->fs; + expdesc key; + luaK_exp2anyreg(fs, v); + next(ls); /* skip the dot or colon */ + checkname(ls, &key); + luaK_indexed(fs, v, &key); } -static void funcargs (LexState *ls, int slf) { +static void luaY_index (LexState *ls, expdesc *v) { + /* index -> '[' expr ']' */ + next(ls); /* skip the '[' */ + expr(ls, v); + luaK_exp2val(ls->fs, v); + check(ls, ']'); +} + + +/* +** {====================================================================== +** Rules for Constructors +** ======================================================================= +*/ + + +struct ConsControl { + expdesc v; /* last list item read */ + expdesc *t; /* table descriptor */ + int nh; /* total number of `record' elements */ + int na; /* total number of array elements */ + int tostore; /* number of array elements pending to be stored */ +}; + + +static void recfield (LexState *ls, struct ConsControl *cc) { + /* recfield -> (NAME | `['exp1`]') = exp1 */ FuncState *fs = ls->fs; - int slevel = fs->stacklevel - slf - 1; /* where is func in the stack */ - switch (ls->t.token) { - case '(': { /* funcargs -> '(' [ explist1 ] ')' */ - int line = ls->linenumber; - int nargs = 0; - next(ls); - if (ls->t.token != ')') /* arg list not empty? */ - nargs = explist1(ls); - check_match(ls, ')', '(', line); -#ifdef LUA_COMPAT_ARGRET - if (nargs > 0) /* arg list is not empty? */ - luaK_setcallreturns(fs, 1); /* last call returns only 1 value */ -#else - UNUSED(nargs); /* to avoid warnings */ -#endif - break; - } - case '{': { /* funcargs -> constructor */ - constructor(ls); - break; - } - case TK_STRING: { /* funcargs -> STRING */ - code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */ - next(ls); - break; - } - default: { - luaK_error(ls, "function arguments expected"); - break; - } + int reg = ls->fs->freereg; + expdesc key, val; + if (ls->t.token == TK_NAME) { + luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor"); + cc->nh++; + checkname(ls, &key); + } + else /* ls->t.token == '[' */ + luaY_index(ls, &key); + check(ls, '='); + luaK_exp2RK(fs, &key); + expr(ls, &val); + luaK_codeABC(fs, OP_SETTABLE, cc->t->info, luaK_exp2RK(fs, &key), + luaK_exp2RK(fs, &val)); + fs->freereg = reg; /* free registers */ +} + + +static void closelistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->v.k == VVOID) return; /* there is no list item */ + luaK_exp2nextreg(fs, &cc->v); + cc->v.k = VVOID; + if (cc->tostore == LFIELDS_PER_FLUSH) { + luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); /* flush */ + cc->tostore = 0; /* no more items pending */ + fs->freereg = cc->t->info + 1; /* free registers */ } - fs->stacklevel = slevel; /* call will remove function and arguments */ - luaK_code2(fs, OP_CALL, slevel, MULT_RET); } -static void var_or_func_tail (LexState *ls, expdesc *v) { - for (;;) { - switch (ls->t.token) { - case '.': { /* var_or_func_tail -> '.' NAME */ - next(ls); - luaK_tostack(ls, v, 1); /* `v' must be on stack */ - luaK_kstr(ls, checkname(ls)); - v->k = VINDEXED; - break; - } - case '[': { /* var_or_func_tail -> '[' exp1 ']' */ - next(ls); - luaK_tostack(ls, v, 1); /* `v' must be on stack */ - v->k = VINDEXED; - exp1(ls); - check(ls, ']'); +static void lastlistfield (FuncState *fs, struct ConsControl *cc) { + if (cc->tostore == 0) return; + if (cc->v.k == VCALL) { + luaK_setcallreturns(fs, &cc->v, LUA_MULTRET); + luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1); + } + else { + if (cc->v.k != VVOID) + luaK_exp2nextreg(fs, &cc->v); + luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); + } + fs->freereg = cc->t->info + 1; /* free registers */ +} + + +static void listfield (LexState *ls, struct ConsControl *cc) { + expr(ls, &cc->v); + luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor"); + cc->na++; + cc->tostore++; +} + + +static void constructor (LexState *ls, expdesc *t) { + /* constructor -> ?? */ + FuncState *fs = ls->fs; + int line = ls->linenumber; + int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); + struct ConsControl cc; + cc.na = cc.nh = cc.tostore = 0; + cc.t = t; + init_exp(t, VRELOCABLE, pc); + init_exp(&cc.v, VVOID, 0); /* no value (yet) */ + luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ + check(ls, '{'); + do { + lua_assert(cc.v.k == VVOID || cc.tostore > 0); + testnext(ls, ';'); /* compatibility only */ + if (ls->t.token == '}') break; + closelistfield(fs, &cc); + switch(ls->t.token) { + case TK_NAME: { /* may be listfields or recfields */ + lookahead(ls); + if (ls->lookahead.token != '=') /* expression? */ + listfield(ls, &cc); + else + recfield(ls, &cc); break; } - case ':': { /* var_or_func_tail -> ':' NAME funcargs */ - int name; - next(ls); - name = checkname(ls); - luaK_tostack(ls, v, 1); /* `v' must be on stack */ - luaK_code1(ls->fs, OP_PUSHSELF, name); - funcargs(ls, 1); - v->k = VEXP; - v->u.l.t = v->u.l.f = NO_JUMP; + case '[': { /* constructor_item -> recfield */ + recfield(ls, &cc); break; } - case '(': case TK_STRING: case '{': { /* var_or_func_tail -> funcargs */ - luaK_tostack(ls, v, 1); /* `v' must be on stack */ - funcargs(ls, 0); - v->k = VEXP; - v->u.l.t = v->u.l.f = NO_JUMP; + default: { /* constructor_part -> listfield */ + listfield(ls, &cc); break; } - default: return; /* should be follow... */ } - } -} - - -static void var_or_func (LexState *ls, expdesc *v) { - /* var_or_func -> ['%'] NAME var_or_func_tail */ - if (optional(ls, '%')) { /* upvalue? */ - pushupvalue(ls, str_checkname(ls)); - v->k = VEXP; - v->u.l.t = v->u.l.f = NO_JUMP; - } - else /* variable name */ - singlevar(ls, str_checkname(ls), v); - var_or_func_tail(ls, v); + } while (testnext(ls, ',') || testnext(ls, ';')); + check_match(ls, '}', '{', line); + lastlistfield(fs, &cc); + SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ + SETARG_C(fs->f->code[pc], luaO_log2(cc.nh)+1); /* set initial table size */ } +/* }====================================================================== */ -/* -** {====================================================================== -** Rules for Constructors -** ======================================================================= -*/ - -static void recfield (LexState *ls) { - /* recfield -> (NAME | '['exp1']') = exp1 */ - switch (ls->t.token) { - case TK_NAME: { - luaK_kstr(ls, checkname(ls)); - break; - } - case '[': { - next(ls); - exp1(ls); - check(ls, ']'); - break; - } - default: luaK_error(ls, " or `[' expected"); +static void parlist (LexState *ls) { + /* parlist -> [ param { `,' param } ] */ + int nparams = 0; + int dots = 0; + if (ls->t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls->t.token) { + case TK_DOTS: dots = 1; next(ls); break; + case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; + default: luaX_syntaxerror(ls, " or `...' expected"); + } + } while (!dots && testnext(ls, ',')); } - check(ls, '='); - exp1(ls); + code_params(ls, nparams, dots); } -static int recfields (LexState *ls) { - /* recfields -> recfield { ',' recfield } [','] */ - FuncState *fs = ls->fs; - int n = 1; /* at least one element */ - recfield(ls); - while (ls->t.token == ',') { - next(ls); - if (ls->t.token == ';' || ls->t.token == '}') - break; - recfield(ls); - n++; - if (n%RFIELDS_PER_FLUSH == 0) - luaK_code1(fs, OP_SETMAP, RFIELDS_PER_FLUSH); - } - luaK_code1(fs, OP_SETMAP, n%RFIELDS_PER_FLUSH); - return n; +static void body (LexState *ls, expdesc *e, int needself, int line) { + /* body -> `(' parlist `)' chunk END */ + FuncState new_fs; + open_func(ls, &new_fs); + new_fs.f->lineDefined = line; + check(ls, '('); + if (needself) + create_local(ls, "self"); + parlist(ls); + check(ls, ')'); + chunk(ls); + check_match(ls, TK_END, TK_FUNCTION, line); + close_func(ls); + pushclosure(ls, &new_fs, e); } -static int listfields (LexState *ls) { - /* listfields -> exp1 { ',' exp1 } [','] */ - FuncState *fs = ls->fs; - int n = 1; /* at least one element */ - exp1(ls); - while (ls->t.token == ',') { - next(ls); - if (ls->t.token == ';' || ls->t.token == '}') - break; - exp1(ls); +static int explist1 (LexState *ls, expdesc *v) { + /* explist1 -> expr { `,' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',')) { + luaK_exp2nextreg(ls->fs, v); + expr(ls, v); n++; - luaX_checklimit(ls, n/LFIELDS_PER_FLUSH, MAXARG_A, - "`item groups' in a list initializer"); - if (n%LFIELDS_PER_FLUSH == 0) - luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); } - luaK_code2(fs, OP_SETLIST, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); return n; } - -static void constructor_part (LexState *ls, Constdesc *cd) { +static void funcargs (LexState *ls, expdesc *f) { + FuncState *fs = ls->fs; + expdesc args; + int base, nparams; + int line = ls->linenumber; switch (ls->t.token) { - case ';': case '}': { /* constructor_part -> empty */ - cd->n = 0; - cd->k = ls->t.token; + case '(': { /* funcargs -> `(' [ explist1 ] `)' */ + if (line != ls->lastline) + luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); + next(ls); + if (ls->t.token == ')') /* arg list is empty? */ + args.k = VVOID; + else { + explist1(ls, &args); + luaK_setcallreturns(fs, &args, LUA_MULTRET); + } + check_match(ls, ')', '(', line); break; } - case TK_NAME: { /* may be listfields or recfields */ - lookahead(ls); - if (ls->lookahead.token != '=') /* expression? */ - goto case_default; - /* else go through to recfields */ - } - case '[': { /* constructor_part -> recfields */ - cd->n = recfields(ls); - cd->k = 1; /* record */ + case '{': { /* funcargs -> constructor */ + constructor(ls, &args); break; } - default: { /* constructor_part -> listfields */ - case_default: - cd->n = listfields(ls); - cd->k = 0; /* list */ + case TK_STRING: { /* funcargs -> STRING */ + codestring(ls, &args, ls->t.seminfo.ts); + next(ls); /* must use `seminfo' before `next' */ break; } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + return; + } } -} - - -static void constructor (LexState *ls) { - /* constructor -> '{' constructor_part [';' constructor_part] '}' */ - FuncState *fs = ls->fs; - int line = ls->linenumber; - int pc = luaK_code1(fs, OP_CREATETABLE, 0); - int nelems; - Constdesc cd; - check(ls, '{'); - constructor_part(ls, &cd); - nelems = cd.n; - if (optional(ls, ';')) { - Constdesc other_cd; - constructor_part(ls, &other_cd); - check_condition(ls, (cd.k != other_cd.k), "invalid constructor syntax"); - nelems += other_cd.n; + lua_assert(f->k == VNONRELOC); + base = f->info; /* base register for call */ + if (args.k == VCALL) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != VVOID) + luaK_exp2nextreg(fs, &args); /* close last argument */ + nparams = fs->freereg - (base+1); } - check_match(ls, '}', '{', line); - luaX_checklimit(ls, nelems, MAXARG_U, "elements in a table constructor"); - SETARG_U(fs->f->code[pc], nelems); /* set initial table size */ + init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); + luaK_fixline(fs, line); + fs->freereg = base+1; /* call remove function and arguments and leaves + (unless changed) one result */ } -/* }====================================================================== */ - @@ -604,58 +630,121 @@ static void constructor (LexState *ls) { */ -static void simpleexp (LexState *ls, expdesc *v) { - FuncState *fs = ls->fs; +static void prefixexp (LexState *ls, expdesc *v) { + /* prefixexp -> NAME | '(' expr ')' */ switch (ls->t.token) { - case TK_NUMBER: { /* simpleexp -> NUMBER */ - Number r = ls->t.seminfo.r; + case '(': { + int line = ls->linenumber; next(ls); - luaK_number(fs, r); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls->fs, v); + return; + } + case TK_NAME: { + singlevar(ls, v, 1); + return; + } +#ifdef LUA_COMPATUPSYNTAX + case '%': { /* for compatibility only */ + TString *varname; + int line = ls->linenumber; + next(ls); /* skip `%' */ + varname = singlevar(ls, v, 1); + if (v->k != VUPVAL) + luaX_errorline(ls, "global upvalues are obsolete", + getstr(varname), line); + return; + } +#endif + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + return; + } + } +} + + +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> + prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ + FuncState *fs = ls->fs; + prefixexp(ls, v); + for (;;) { + switch (ls->t.token) { + case '.': { /* field */ + luaY_field(ls, v); + break; + } + case '[': { /* `[' exp1 `]' */ + expdesc key; + luaK_exp2anyreg(fs, v); + luaY_index(ls, &key); + luaK_indexed(fs, v, &key); + break; + } + case ':': { /* `:' NAME funcargs */ + expdesc key; + next(ls); + checkname(ls, &key); + luaK_self(fs, v, &key); + funcargs(ls, v); + break; + } + case '(': case TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v); + break; + } + default: return; + } + } +} + + +static void simpleexp (LexState *ls, expdesc *v) { + /* simpleexp -> NUMBER | STRING | NIL | constructor | FUNCTION body + | primaryexp */ + switch (ls->t.token) { + case TK_NUMBER: { + init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r)); + next(ls); /* must use `seminfo' before `next' */ break; } - case TK_STRING: { /* simpleexp -> STRING */ - code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */ - next(ls); + case TK_STRING: { + codestring(ls, v, ls->t.seminfo.ts); + next(ls); /* must use `seminfo' before `next' */ break; } - case TK_NIL: { /* simpleexp -> NIL */ - luaK_adjuststack(fs, -1); + case TK_NIL: { + init_exp(v, VNIL, 0); next(ls); break; } - case '{': { /* simpleexp -> constructor */ - constructor(ls); + case TK_TRUE: { + init_exp(v, VTRUE, 0); + next(ls); break; } - case TK_FUNCTION: { /* simpleexp -> FUNCTION body */ + case TK_FALSE: { + init_exp(v, VFALSE, 0); next(ls); - body(ls, 0, ls->linenumber); break; } - case '(': { /* simpleexp -> '(' expr ')' */ - next(ls); - expr(ls, v); - check(ls, ')'); - return; + case '{': { /* constructor */ + constructor(ls, v); + break; } - case TK_NAME: case '%': { - var_or_func(ls, v); - return; + case TK_FUNCTION: { + next(ls); + body(ls, v, 0, ls->linenumber); + break; } default: { - luaK_error(ls, " expected"); - return; + primaryexp(ls, v); + break; } } - v->k = VEXP; - v->u.l.t = v->u.l.f = NO_JUMP; -} - - -static void exp1 (LexState *ls) { - expdesc v; - expr(ls, &v); - luaK_tostack(ls, &v, 1); } @@ -690,17 +779,17 @@ static BinOpr getbinopr (int op) { static const struct { - char left; /* left priority for each binary operator */ - char right; /* right priority */ + lu_byte left; /* left priority for each binary operator */ + lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {5, 5}, {5, 5}, {6, 6}, {6, 6}, /* arithmetic */ - {9, 8}, {4, 3}, /* power and concat (right associative) */ - {2, 2}, {2, 2}, /* equality */ - {2, 2}, {2, 2}, {2, 2}, {2, 2}, /* order */ - {1, 1}, {1, 1} /* logical */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, /* arithmetic */ + {10, 9}, {5, 4}, /* power and concat (right associative) */ + {3, 3}, {3, 3}, /* equality */ + {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ + {2, 2}, {1, 1} /* logical (and/or) */ }; -#define UNARY_PRIORITY 7 /* priority for unary operators */ +#define UNARY_PRIORITY 8 /* priority for unary operators */ /* @@ -709,25 +798,28 @@ static const struct { */ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { BinOpr op; - UnOpr uop = getunopr(ls->t.token); + UnOpr uop; + enterlevel(ls); + uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { next(ls); subexpr(ls, v, UNARY_PRIORITY); - luaK_prefix(ls, uop, v); + luaK_prefix(ls->fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && priority[op].left > limit) { + while (op != OPR_NOBINOPR && cast(int, priority[op].left) > limit) { expdesc v2; BinOpr nextop; next(ls); - luaK_infix(ls, op, v); + luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, priority[op].right); - luaK_posfix(ls, op, v, &v2); + nextop = subexpr(ls, &v2, cast(int, priority[op].right)); + luaK_posfix(ls->fs, op, v, &v2); op = nextop; } + leavelevel(ls); return op; /* return first untreated operator */ } @@ -739,6 +831,7 @@ static void expr (LexState *ls, expdesc *v) { /* }==================================================================== */ + /* ** {====================================================================== ** Rules for Statements @@ -759,61 +852,151 @@ static int block_follow (int token) { static void block (LexState *ls) { /* block -> chunk */ FuncState *fs = ls->fs; - int nactloc = fs->nactloc; + BlockCnt bl; + enterblock(fs, &bl, 0); chunk(ls); - luaK_adjuststack(fs, fs->nactloc - nactloc); /* remove local variables */ - removelocalvars(ls, fs->nactloc - nactloc); + lua_assert(bl.breaklist == NO_JUMP); + leaveblock(fs); } -static int assignment (LexState *ls, expdesc *v, int nvars) { - int left = 0; /* number of values left in the stack after assignment */ - luaX_checklimit(ls, nvars, MAXVARSLH, "variables in a multiple assignment"); - if (ls->t.token == ',') { /* assignment -> ',' NAME assignment */ - expdesc nv; - next(ls); - var_or_func(ls, &nv); - check_condition(ls, (nv.k != VEXP), "syntax error"); - left = assignment(ls, &nv, nvars+1); +/* +** structure to chain all variables in the left-hand side of an +** assignment +*/ +struct LHS_assign { + struct LHS_assign *prev; + expdesc v; /* variable (global, local, upvalue, or indexed) */ +}; + + +/* +** check whether, in an assignment to a local variable, the local variable +** is needed in a previous assignment (to a table). If so, save original +** local value in a safe place and use this safe copy in the previous +** assignment. +*/ +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { + FuncState *fs = ls->fs; + int extra = fs->freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh; lh = lh->prev) { + if (lh->v.k == VINDEXED) { + if (lh->v.info == v->info) { /* conflict? */ + conflict = 1; + lh->v.info = extra; /* previous assignment will use safe copy */ + } + if (lh->v.aux == v->info) { /* conflict? */ + conflict = 1; + lh->v.aux = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict) { + luaK_codeABC(fs, OP_MOVE, fs->freereg, v->info, 0); /* make copy */ + luaK_reserveregs(fs, 1); } - else { /* assignment -> '=' explist1 */ +} + + +static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { + expdesc e; + check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, + "syntax error"); + if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ + struct LHS_assign nv; + nv.prev = lh; + primaryexp(ls, &nv.v); + if (nv.v.k == VLOCAL) + check_conflict(ls, lh, &nv.v); + assignment(ls, &nv, nvars+1); + } + else { /* assignment -> `=' explist1 */ int nexps; check(ls, '='); - nexps = explist1(ls); - adjust_mult_assign(ls, nvars, nexps); - } - if (v->k != VINDEXED) - luaK_storevar(ls, v); - else { /* there may be garbage between table-index and value */ - luaK_code2(ls->fs, OP_SETTABLE, left+nvars+2, 1); - left += 2; + nexps = explist1(ls, &e); + if (nexps != nvars) { + adjust_assign(ls, nvars, nexps, &e); + if (nexps > nvars) + ls->fs->freereg -= nexps - nvars; /* remove extra values */ + } + else { + luaK_setcallreturns(ls->fs, &e, 1); /* close last expression */ + luaK_storevar(ls->fs, &lh->v, &e); + return; /* avoid default */ + } } - return left; + init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ + luaK_storevar(ls->fs, &lh->v, &e); } static void cond (LexState *ls, expdesc *v) { /* cond -> exp */ expr(ls, v); /* read condition */ - luaK_goiftrue(ls->fs, v, 0); + if (v->k == VNIL) v->k = VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls->fs, v); + luaK_patchtohere(ls->fs, v->t); } +/* +** The while statement optimizes its code by coding the condition +** after its body (and thus avoiding one jump in the loop). +*/ + +/* +** maximum size of expressions for optimizing `while' code +*/ +#ifndef MAXEXPWHILE +#define MAXEXPWHILE 100 +#endif + +/* +** the call `luaK_goiffalse' may grow the size of an expression by +** at most this: +*/ +#define EXTRAEXP 5 + static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ + Instruction codeexp[MAXEXPWHILE + EXTRAEXP]; + int lineexp; + int i; + int sizeexp; FuncState *fs = ls->fs; - int while_init = luaK_getlabel(fs); + int whileinit, blockinit, expinit; expdesc v; - Breaklabel bl; - enterbreak(fs, &bl); - next(ls); - cond(ls, &v); + BlockCnt bl; + next(ls); /* skip WHILE */ + whileinit = luaK_jump(fs); /* jump to condition (which will be moved) */ + expinit = luaK_getlabel(fs); + expr(ls, &v); /* parse condition */ + if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */ + lineexp = ls->linenumber; + luaK_goiffalse(fs, &v); + luaK_concat(fs, &v.f, fs->jpc); + fs->jpc = NO_JUMP; + sizeexp = fs->pc - expinit; /* size of expression code */ + if (sizeexp > MAXEXPWHILE) + luaX_syntaxerror(ls, "`while' condition too complex"); + for (i = 0; i < sizeexp; i++) /* save `exp' code */ + codeexp[i] = fs->f->code[expinit + i]; + fs->pc = expinit; /* remove `exp' code */ + enterblock(fs, &bl, 1); check(ls, TK_DO); + blockinit = luaK_getlabel(fs); block(ls); - luaK_patchlist(fs, luaK_jump(fs), while_init); - luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ + /* move `exp' back to code */ + if (v.t != NO_JUMP) v.t += fs->pc - expinit; + if (v.f != NO_JUMP) v.f += fs->pc - expinit; + for (i=0; ifs; int repeat_init = luaK_getlabel(fs); expdesc v; - Breaklabel bl; - enterbreak(fs, &bl); + BlockCnt bl; + enterblock(fs, &bl, 1); next(ls); block(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); cond(ls, &v); - luaK_patchlist(fs, v.u.l.f, repeat_init); - leavebreak(fs, &bl); + luaK_patchlist(fs, v.f, repeat_init); + leaveblock(fs); } -static void forbody (LexState *ls, int nvar, OpCode prepfor, OpCode loopfor) { - /* forbody -> DO block END */ +static int exp1 (LexState *ls) { + expdesc e; + int k; + expr(ls, &e); + k = e.k; + luaK_exp2nextreg(ls->fs, &e); + return k; +} + + +static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + BlockCnt bl; FuncState *fs = ls->fs; - int prep = luaK_code1(fs, prepfor, NO_JUMP); - int blockinit = luaK_getlabel(fs); + int prep, endfor; + adjustlocalvars(ls, nvars); /* scope for all variables */ check(ls, TK_DO); - adjustlocalvars(ls, nvar); /* scope for control variables */ + enterblock(fs, &bl, 1); /* loop block */ + prep = luaK_getlabel(fs); block(ls); - luaK_patchlist(fs, luaK_code1(fs, loopfor, NO_JUMP), blockinit); - luaK_patchlist(fs, prep, luaK_getlabel(fs)); - removelocalvars(ls, nvar); + luaK_patchtohere(fs, prep-1); + endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : + luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); + luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ + luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); + leaveblock(fs); } -static void fornum (LexState *ls, TString *varname) { - /* fornum -> NAME = exp1,exp1[,exp1] forbody */ +static void fornum (LexState *ls, TString *varname, int line) { + /* fornum -> NAME = exp1,exp1[,exp1] DO body */ FuncState *fs = ls->fs; + int base = fs->freereg; + new_localvar(ls, varname, 0); + new_localvarstr(ls, "(for limit)", 1); + new_localvarstr(ls, "(for step)", 2); check(ls, '='); exp1(ls); /* initial value */ check(ls, ','); exp1(ls); /* limit */ - if (optional(ls, ',')) + if (testnext(ls, ',')) exp1(ls); /* optional step */ - else - luaK_code1(fs, OP_PUSHINT, 1); /* default step */ - new_localvar(ls, varname, 0); - new_localvarstr(ls, "(limit)", 1); - new_localvarstr(ls, "(step)", 2); - forbody(ls, 3, OP_FORPREP, OP_FORLOOP); + else { /* default step = 1 */ + luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); + luaK_reserveregs(fs, 1); + } + luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); + luaK_jump(fs); + forbody(ls, base, line, 3, 1); } static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME,NAME IN exp1 forbody */ - TString *valname; - check(ls, ','); - valname = str_checkname(ls); - /* next test is dirty, but avoids `in' being a reserved word */ - check_condition(ls, - (ls->t.token == TK_NAME && ls->t.seminfo.ts == luaS_new(ls->L, "in")), - "`in' expected"); - next(ls); /* skip `in' */ - exp1(ls); /* table */ - new_localvarstr(ls, "(table)", 0); - new_localvar(ls, indexname, 1); - new_localvar(ls, valname, 2); - forbody(ls, 3, OP_LFORPREP, OP_LFORLOOP); + /* forlist -> NAME {,NAME} IN explist1 DO body */ + FuncState *fs = ls->fs; + expdesc e; + int nvars = 0; + int line; + int base = fs->freereg; + new_localvarstr(ls, "(for generator)", nvars++); + new_localvarstr(ls, "(for state)", nvars++); + new_localvar(ls, indexname, nvars++); + while (testnext(ls, ',')) + new_localvar(ls, str_checkname(ls), nvars++); + check(ls, TK_IN); + line = ls->linenumber; + adjust_assign(ls, nvars, explist1(ls, &e), &e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); + forbody(ls, base, line, nvars, 0); } @@ -887,17 +1092,17 @@ static void forstat (LexState *ls, int line) { /* forstat -> fornum | forlist */ FuncState *fs = ls->fs; TString *varname; - Breaklabel bl; - enterbreak(fs, &bl); + BlockCnt bl; + enterblock(fs, &bl, 0); /* block to control variable scope */ next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { - case '=': fornum(ls, varname); break; - case ',': forlist(ls, varname); break; - default: luaK_error(ls, "`=' or `,' expected"); + case '=': fornum(ls, varname, line); break; + case ',': case TK_IN: forlist(ls, varname); break; + default: luaX_syntaxerror(ls, "`=' or `in' expected"); } check_match(ls, TK_END, TK_FOR, line); - leavebreak(fs, &bl); + leaveblock(fs); } @@ -918,49 +1123,60 @@ static void ifstat (LexState *ls, int line) { test_then_block(ls, &v); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); + luaK_patchtohere(fs, v.f); test_then_block(ls, &v); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs)); - next(ls); /* skip ELSE */ + luaK_patchtohere(fs, v.f); + next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else - luaK_concat(fs, &escapelist, v.u.l.f); - luaK_patchlist(fs, escapelist, luaK_getlabel(fs)); + luaK_concat(fs, &escapelist, v.f); + luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); } +static void localfunc (LexState *ls) { + expdesc v, b; + new_localvar(ls, str_checkname(ls), 0); + init_exp(&v, VLOCAL, ls->fs->freereg++); + adjustlocalvars(ls, 1); + body(ls, &b, 0, ls->linenumber); + luaK_storevar(ls->fs, &v, &b); +} + + static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {',' NAME} ['=' explist1] */ + /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ int nvars = 0; int nexps; + expdesc e; do { - next(ls); /* skip LOCAL or ',' */ new_localvar(ls, str_checkname(ls), nvars++); - } while (ls->t.token == ','); - if (optional(ls, '=')) - nexps = explist1(ls); - else + } while (testnext(ls, ',')); + if (testnext(ls, '=')) + nexps = explist1(ls, &e); + else { + e.k = VVOID; nexps = 0; - adjust_mult_assign(ls, nvars, nexps); + } + adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME [':' NAME | '.' NAME] */ + /* funcname -> NAME {field} [`:' NAME] */ int needself = 0; - singlevar(ls, str_checkname(ls), v); - if (ls->t.token == ':' || ls->t.token == '.') { - needself = (ls->t.token == ':'); - next(ls); - luaK_tostack(ls, v, 1); - luaK_kstr(ls, checkname(ls)); - v->k = VINDEXED; + singlevar(ls, v, 1); + while (ls->t.token == '.') + luaY_field(ls, v); + if (ls->t.token == ':') { + needself = 1; + luaY_field(ls, v); } return needself; } @@ -969,26 +1185,26 @@ static int funcname (LexState *ls, expdesc *v) { static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int needself; - expdesc v; + expdesc v, b; next(ls); /* skip FUNCTION */ needself = funcname(ls, &v); - body(ls, needself, line); - luaK_storevar(ls, &v); + body(ls, &b, needself, line); + luaK_storevar(ls->fs, &v, &b); + luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ } -static void namestat (LexState *ls) { - /* stat -> func | ['%'] NAME assignment */ +static void exprstat (LexState *ls) { + /* stat -> func | assignment */ FuncState *fs = ls->fs; - expdesc v; - var_or_func(ls, &v); - if (v.k == VEXP) { /* stat -> func */ - check_condition(ls, luaK_lastisopen(fs), "syntax error"); /* an upvalue? */ - luaK_setcallreturns(fs, 0); /* call statement uses no results */ + struct LHS_assign v; + primaryexp(ls, &v.v); + if (v.v.k == VCALL) { /* stat -> func */ + luaK_setcallreturns(fs, &v.v, 0); /* call statement uses no results */ } - else { /* stat -> ['%'] NAME assignment */ - int left = assignment(ls, &v, 1); - luaK_adjuststack(fs, left); /* remove eventual garbage left on stack */ + else { /* stat -> assignment */ + v.prev = NULL; + assignment(ls, &v, 1); } } @@ -996,30 +1212,55 @@ static void namestat (LexState *ls) { static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = ls->fs; + expdesc e; + int first, nret; /* registers with returned values */ next(ls); /* skip RETURN */ - if (!block_follow(ls->t.token) && ls->t.token != ';') - explist1(ls); /* optional return values */ - luaK_code1(fs, OP_RETURN, ls->fs->nactloc); - fs->stacklevel = fs->nactloc; /* removes all temp values */ + if (block_follow(ls->t.token) || ls->t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist1(ls, &e); /* optional return values */ + if (e.k == VCALL) { + luaK_setcallreturns(fs, &e, LUA_MULTRET); + if (nret == 1) { /* tail call? */ + SET_OPCODE(getcode(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); + } + first = fs->nactvar; + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, &e); + else { + luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ + first = fs->nactvar; /* return all `active' values */ + lua_assert(nret == fs->freereg - first); + } + } + } + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); } static void breakstat (LexState *ls) { /* stat -> BREAK [NAME] */ FuncState *fs = ls->fs; - int currentlevel = fs->stacklevel; - Breaklabel *bl = fs->bl; - if (!bl) - luaK_error(ls, "no loop to break"); + BlockCnt *bl = fs->bl; + int upval = 0; next(ls); /* skip BREAK */ - luaK_adjuststack(fs, currentlevel - bl->stacklevel); + while (bl && !bl->isbreakable) { + upval |= bl->upval; + bl = bl->previous; + } + if (!bl) + luaX_syntaxerror(ls, "no loop to break"); + if (upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); - /* correct stack for compiler and symbolic execution */ - luaK_adjuststack(fs, bl->stacklevel - currentlevel); } -static int stat (LexState *ls) { +static int statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->t.token) { case TK_IF: { /* stat -> ifstat */ @@ -1044,16 +1285,16 @@ static int stat (LexState *ls) { repeatstat(ls, line); return 0; } - case TK_FUNCTION: { /* stat -> funcstat */ - funcstat(ls, line); + case TK_FUNCTION: { + funcstat(ls, line); /* stat -> funcstat */ return 0; } case TK_LOCAL: { /* stat -> localstat */ - localstat(ls); - return 0; - } - case TK_NAME: case '%': { /* stat -> namestat */ - namestat(ls); + next(ls); /* skip LOCAL */ + if (testnext(ls, TK_FUNCTION)) /* local function? */ + localfunc(ls); + else + localstat(ls); return 0; } case TK_RETURN: { /* stat -> retstat */ @@ -1065,60 +1306,24 @@ static int stat (LexState *ls) { return 1; /* must be last statement */ } default: { - luaK_error(ls, " expected"); + exprstat(ls); return 0; /* to avoid warnings */ } } } -static void parlist (LexState *ls) { - /* parlist -> [ param { ',' param } ] */ - int nparams = 0; - int dots = 0; - if (ls->t.token != ')') { /* is `parlist' not empty? */ - do { - switch (ls->t.token) { - case TK_DOTS: next(ls); dots = 1; break; - case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; - default: luaK_error(ls, " or `...' expected"); - } - } while (!dots && optional(ls, ',')); - } - code_params(ls, nparams, dots); -} - - -static void body (LexState *ls, int needself, int line) { - /* body -> '(' parlist ')' chunk END */ - FuncState new_fs; - open_func(ls, &new_fs); - new_fs.f->lineDefined = line; - check(ls, '('); - if (needself) { - new_localvarstr(ls, "self", 0); - adjustlocalvars(ls, 1); - } - parlist(ls); - check(ls, ')'); - chunk(ls); - check_match(ls, TK_END, TK_FUNCTION, line); - close_func(ls); - pushclosure(ls, &new_fs); -} - - -/* }====================================================================== */ - - static void chunk (LexState *ls) { - /* chunk -> { stat [';'] } */ + /* chunk -> { stat [`;'] } */ int islast = 0; + enterlevel(ls); while (!islast && !block_follow(ls->t.token)) { - islast = stat(ls); - optional(ls, ';'); - LUA_ASSERT(ls->fs->stacklevel == ls->fs->nactloc, - "stack size != # local vars"); + islast = statement(ls); + testnext(ls, ';'); + lua_assert(ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ } + leavelevel(ls); } +/* }====================================================================== */ diff --git a/src/lparser.h b/src/lparser.h index 445acea63f..d6aaaf0e7d 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,13 +1,15 @@ /* -** $Id: lparser.h,v 1.26 2000/10/09 13:47:46 roberto Exp $ -** LL(1) Parser and code generator for Lua +** $Id: lparser.h,v 1.47 2003/02/11 10:46:24 roberto Exp $ +** Lua Parser ** See Copyright Notice in lua.h */ #ifndef lparser_h #define lparser_h +#include "llimits.h" #include "lobject.h" +#include "ltable.h" #include "lzio.h" @@ -16,45 +18,54 @@ */ typedef enum { - VGLOBAL, - VLOCAL, - VINDEXED, - VEXP + VVOID, /* no value */ + VNIL, + VTRUE, + VFALSE, + VK, /* info = index of constant in `k' */ + VLOCAL, /* info = local register */ + VUPVAL, /* info = index of upvalue in `upvalues' */ + VGLOBAL, /* info = index of table; aux = index of global name in `k' */ + VINDEXED, /* info = table register; aux = index register (or `k') */ + VJMP, /* info = instruction pc */ + VRELOCABLE, /* info = instruction pc */ + VNONRELOC, /* info = result register */ + VCALL /* info = result register */ } expkind; typedef struct expdesc { expkind k; - union { - int index; /* VGLOBAL: `kstr' index of global name; VLOCAL: stack index */ - struct { - int t; /* patch list of `exit when true' */ - int f; /* patch list of `exit when false' */ - } l; - } u; + int info, aux; + int t; /* patch list of `exit when true' */ + int f; /* patch list of `exit when false' */ } expdesc; +struct BlockCnt; /* defined in lparser.c */ + /* state needed to generate code for a given function */ typedef struct FuncState { Proto *f; /* current function header */ + Table *h; /* table to find (and reuse) elements in `k' */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ struct lua_State *L; /* copy of the Lua state */ - int pc; /* next position to code */ + struct BlockCnt *bl; /* chain of current blocks */ + int pc; /* next position to code (equivalent to `ncode') */ int lasttarget; /* `pc' of last `jump target' */ - int jlt; /* list of jumps to `lasttarget' */ - short stacklevel; /* number of values on activation register */ - short nactloc; /* number of active local variables */ - short nupvalues; /* number of upvalues */ - int lastline; /* line where last `lineinfo' was generated */ - struct Breaklabel *bl; /* chain of breakable blocks */ + int jpc; /* list of pending jumps to `pc' */ + int freereg; /* first free register */ + int nk; /* number of elements in `k' */ + int np; /* number of elements in `p' */ + int nlocvars; /* number of elements in `locvars' */ + int nactvar; /* number of active local variables */ expdesc upvalues[MAXUPVALUES]; /* upvalues */ - int actloc[MAXLOCALS]; /* local-variable stack (indices to locvars) */ + int actvar[MAXVARS]; /* declared-variable stack */ } FuncState; -Proto *luaY_parser (lua_State *L, ZIO *z); +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff); #endif diff --git a/src/lstate.c b/src/lstate.c index 586c108586..b593658def 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,15 +1,19 @@ /* -** $Id: lstate.c,v 1.48 2000/10/30 16:29:59 roberto Exp $ +** $Id: lstate.c,v 1.123 2003/04/03 13:35:34 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ -#include +#include + +#define lstate_c #include "lua.h" +#include "ldebug.h" #include "ldo.h" +#include "lfunc.h" #include "lgc.h" #include "llex.h" #include "lmem.h" @@ -19,103 +23,198 @@ #include "ltm.h" -#ifdef LUA_DEBUG -static lua_State *lua_state = NULL; -void luaB_opentests (lua_State *L); +/* +** macro to allow the inclusion of user information in Lua state +*/ +#ifndef LUA_USERSTATE +#define EXTRASPACE 0 +#else +union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; +#define EXTRASPACE (sizeof(union UEXTRASPACE)) #endif + /* -** built-in implementation for ERRORMESSAGE. In a "correct" environment -** ERRORMESSAGE should have an external definition, and so this function -** would not be used. +** you can change this function through the official API: +** call `lua_setpanicf' */ -static int errormessage (lua_State *L) { - const char *s = lua_tostring(L, 1); - if (s == NULL) s = "(no message)"; - fprintf(stderr, "error: %s\n", s); +static int default_panic (lua_State *L) { + UNUSED(L); return 0; } +static lua_State *mallocstate (lua_State *L) { + lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE); + if (block == NULL) return NULL; + else { + block += EXTRASPACE; + return cast(lua_State *, block); + } +} + + +static void freestate (lua_State *L, lua_State *L1) { + luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE, + sizeof(lua_State) + EXTRASPACE); +} + + +static void stack_init (lua_State *L1, lua_State *L) { + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject); + L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + L1->top = L1->stack; + L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; + L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); + L1->ci = L1->base_ci; + L1->ci->state = CI_C; /* not a Lua function */ + setnilvalue(L1->top++); /* `function' entry for this `ci' */ + L1->base = L1->ci->base = L1->top; + L1->ci->top = L1->top + LUA_MINSTACK; + L1->size_ci = BASIC_CI_SIZE; + L1->end_ci = L1->base_ci + L1->size_ci; +} + + +static void freestack (lua_State *L, lua_State *L1) { + luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); + luaM_freearray(L, L1->stack, L1->stacksize, TObject); +} + + /* ** open parts that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { - int stacksize = *(int *)ud; - if (stacksize == 0) - stacksize = DEFAULT_STACK_SIZE; - else - stacksize += LUA_MINSTACK; - L->gt = luaH_new(L, 10); /* table of globals */ - luaD_init(L, stacksize); - luaS_init(L); - luaX_init(L); + /* create a new global state */ + global_State *g = luaM_new(NULL, global_State); + UNUSED(ud); + if (g == NULL) luaD_throw(L, LUA_ERRMEM); + L->l_G = g; + g->mainthread = L; + g->GCthreshold = 0; /* mark it as unfinished state */ + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(defaultmeta(L)); + setnilvalue(registry(L)); + luaZ_initbuffer(L, &g->buff); + g->panic = default_panic; + g->rootgc = NULL; + g->rootudata = NULL; + g->tmudata = NULL; + setnilvalue(gkey(g->dummynode)); + setnilvalue(gval(g->dummynode)); + g->dummynode->next = NULL; + g->nblocks = sizeof(lua_State) + sizeof(global_State); + stack_init(L, L); /* init stack */ + /* create default meta table with a dummy table, and then close the loop */ + defaultmeta(L)->tt = LUA_TTABLE; + sethvalue(defaultmeta(L), luaH_new(L, 0, 0)); + hvalue(defaultmeta(L))->metatable = hvalue(defaultmeta(L)); + sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */ + sethvalue(registry(L), luaH_new(L, 4, 4)); /* registry */ + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); - lua_newtable(L); - lua_ref(L, 1); /* create registry */ - lua_register(L, LUA_ERRORMESSAGE, errormessage); -#ifdef LUA_DEBUG - luaB_opentests(L); - if (lua_state == NULL) lua_state = L; /* keep first state to be opened */ -#endif - LUA_ASSERT(lua_gettop(L) == 0, "wrong API stack"); + luaX_init(L); + luaS_fix(luaS_newliteral(L, MEMERRMSG)); + g->GCthreshold = 4*G(L)->nblocks; } -LUA_API lua_State *lua_open (int stacksize) { - lua_State *L = luaM_new(NULL, lua_State); - if (L == NULL) return NULL; /* memory allocation error */ +static void preinit_state (lua_State *L) { L->stack = NULL; - L->strt.size = L->udt.size = 0; - L->strt.nuse = L->udt.nuse = 0; - L->strt.hash = NULL; - L->udt.hash = NULL; - L->Mbuffer = NULL; - L->Mbuffsize = 0; - L->rootproto = NULL; - L->rootcl = NULL; - L->roottable = NULL; - L->TMtable = NULL; - L->last_tag = -1; - L->refArray = NULL; - L->refSize = 0; - L->refFree = NONEXT; - L->nblocks = sizeof(lua_State); - L->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */ - L->callhook = NULL; - L->linehook = NULL; - L->allowhooks = 1; + L->stacksize = 0; L->errorJmp = NULL; - if (luaD_runprotected(L, f_luaopen, &stacksize) != 0) { - /* memory allocation error: free partial state */ - lua_close(L); - return NULL; + L->hook = NULL; + L->hookmask = L->hookinit = 0; + L->basehookcount = 0; + L->allowhook = 1; + resethookcount(L); + L->openupval = NULL; + L->size_ci = 0; + L->nCcalls = 0; + L->base_ci = L->ci = NULL; + L->errfunc = 0; + setnilvalue(gt(L)); +} + + +static void close_state (lua_State *L) { + luaF_close(L, L->stack); /* close all upvalues for this thread */ + if (G(L)) { /* close global state */ + luaC_sweep(L, 1); /* collect all elements */ + lua_assert(G(L)->rootgc == NULL); + lua_assert(G(L)->rootudata == NULL); + luaS_freeall(L); + luaZ_freebuffer(L, &G(L)->buff); + } + freestack(L, L); + if (G(L)) { + lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State)); + luaM_freelem(NULL, G(L)); + } + freestate(NULL, L); +} + + +lua_State *luaE_newthread (lua_State *L) { + lua_State *L1 = mallocstate(L); + luaC_link(L, valtogco(L1), LUA_TTHREAD); + preinit_state(L1); + L1->l_G = L->l_G; + stack_init(L1, L); /* init stack */ + setobj2n(gt(L1), gt(L)); /* share table of globals */ + return L1; +} + + +void luaE_freethread (lua_State *L, lua_State *L1) { + luaF_close(L1, L1->stack); /* close all upvalues for this thread */ + lua_assert(L1->openupval == NULL); + freestack(L, L1); + freestate(L, L1); +} + + +LUA_API lua_State *lua_open (void) { + lua_State *L = mallocstate(NULL); + if (L) { /* allocation OK? */ + L->tt = LUA_TTHREAD; + L->marked = 0; + L->next = L->gclist = NULL; + preinit_state(L); + L->l_G = NULL; + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } } - L->GCthreshold = 2*L->nblocks; + lua_userstateopen(L); return L; } +static void callallgcTM (lua_State *L, void *ud) { + UNUSED(ud); + luaC_callGCTM(L); /* call GC metamethods for all udata */ +} + + LUA_API void lua_close (lua_State *L) { - LUA_ASSERT(L != lua_state || lua_gettop(L) == 0, "garbage in C stack"); - luaC_collect(L, 1); /* collect all elements */ - LUA_ASSERT(L->rootproto == NULL, "list should be empty"); - LUA_ASSERT(L->rootcl == NULL, "list should be empty"); - LUA_ASSERT(L->roottable == NULL, "list should be empty"); - luaS_freeall(L); - if (L->stack) - L->nblocks -= (L->stack_last - L->stack + 1)*sizeof(TObject); - luaM_free(L, L->stack); - L->nblocks -= (L->last_tag+1)*sizeof(struct TM); - luaM_free(L, L->TMtable); - L->nblocks -= (L->refSize)*sizeof(struct Ref); - luaM_free(L, L->refArray); - L->nblocks -= (L->Mbuffsize)*sizeof(char); - luaM_free(L, L->Mbuffer); - LUA_ASSERT(L->nblocks == sizeof(lua_State), "wrong count for nblocks"); - luaM_free(L, L); - LUA_ASSERT(L != lua_state || memdebug_numblocks == 0, "memory leak!"); - LUA_ASSERT(L != lua_state || memdebug_total == 0,"memory leak!"); + lua_lock(L); + L = G(L)->mainthread; /* only the main thread can be closed */ + luaF_close(L, L->stack); /* close all upvalues for this thread */ + luaC_separateudata(L); /* separate udata that have GC metamethods */ + L->errfunc = 0; /* no error function during GC metamethods */ + do { /* repeat until no more errors */ + L->ci = L->base_ci; + L->base = L->top = L->ci->base; + L->nCcalls = 0; + } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); + lua_assert(G(L)->tmudata == NULL); + close_state(L); } diff --git a/src/lstate.h b/src/lstate.h index 0c8f552156..5422f1b196 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.41 2000/10/05 13:00:17 roberto Exp $ +** $Id: lstate.h,v 1.109 2003/02/27 11:52:30 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -7,71 +7,189 @@ #ifndef lstate_h #define lstate_h -#include "lobject.h" #include "lua.h" -#include "luadebug.h" - - -typedef TObject *StkId; /* index to stack elements */ +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" /* -** marks for Reference array +** macros for thread synchronization inside Lua core machine: +** all accesses to the global state and to global objects are synchronized. +** Because threads can read the stack of other threads +** (when running garbage collection), +** a thread must also synchronize any write-access to its own stack. +** Unsynchronized accesses are allowed only when reading its own stack, +** or when reading immutable fields from global objects +** (such as string values and udata values). */ -#define NONEXT -1 /* to end the free list */ -#define HOLD -2 -#define COLLECTED -3 -#define LOCK -4 +#ifndef lua_lock +#define lua_lock(L) ((void) 0) +#endif +#ifndef lua_unlock +#define lua_unlock(L) ((void) 0) +#endif + + +#ifndef lua_userstateopen +#define lua_userstateopen(l) +#endif -struct Ref { - TObject o; - int st; /* can be LOCK, HOLD, COLLECTED, or next (for free list) */ -}; struct lua_longjmp; /* defined in ldo.c */ -struct TM; /* defined in ltm.h */ + + +/* default meta table (both for tables and udata) */ +#define defaultmeta(L) (&G(L)->_defaultmeta) + +/* table of globals */ +#define gt(L) (&L->_gt) + +/* registry */ +#define registry(L) (&G(L)->_registry) + + +/* extra stack space to handle TM calls and some other extras */ +#define EXTRA_STACK 5 + + +#define BASIC_CI_SIZE 8 + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + typedef struct stringtable { + GCObject **hash; + ls_nstr nuse; /* number of elements */ int size; - lint32 nuse; /* number of elements */ - TString **hash; } stringtable; +/* +** informations about a call +*/ +typedef struct CallInfo { + StkId base; /* base for called function */ + StkId top; /* top for this function */ + int state; /* bit fields; see below */ + union { + struct { /* for Lua functions */ + const Instruction *savedpc; + const Instruction **pc; /* points to `pc' variable in `luaV_execute' */ + int tailcalls; /* number of tail calls lost under this entry */ + } l; + struct { /* for C functions */ + int dummy; /* just to avoid an empty struct */ + } c; + } u; +} CallInfo; + + +/* +** bit fields for `CallInfo.state' +*/ +#define CI_C (1<<0) /* 1 if function is a C function */ +/* 1 if (Lua) function has an active `luaV_execute' running it */ +#define CI_HASFRAME (1<<1) +/* 1 if Lua function is calling another Lua function (and therefore its + `pc' is being used by the other, and therefore CI_SAVEDPC is 1 too) */ +#define CI_CALLING (1<<2) +#define CI_SAVEDPC (1<<3) /* 1 if `savedpc' is updated */ +#define CI_YIELD (1<<4) /* 1 if thread is suspended */ + + +#define ci_func(ci) (clvalue((ci)->base - 1)) + +/* +** `global state', shared by all threads of this state +*/ +typedef struct global_State { + stringtable strt; /* hash table for strings */ + GCObject *rootgc; /* list of (almost) all collectable objects */ + GCObject *rootudata; /* (separated) list of all userdata */ + GCObject *tmudata; /* list of userdata to be GC */ + Mbuffer buff; /* temporary buffer for string concatentation */ + lu_mem GCthreshold; + lu_mem nblocks; /* number of `bytes' currently allocated */ + lua_CFunction panic; /* to be called in unprotected errors */ + TObject _registry; + TObject _defaultmeta; + struct lua_State *mainthread; + Node dummynode[1]; /* common node array for all empty tables */ + TString *tmname[TM_N]; /* array with tag-method names */ +} global_State; + + +/* +** `per thread' state +*/ struct lua_State { - /* thread-specific state */ + CommonHeader; StkId top; /* first free slot in the stack */ - StkId stack; /* stack base */ + StkId base; /* base of current function */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ int stacksize; - StkId Cbase; /* base for current C function */ + CallInfo *end_ci; /* points after end of ci array*/ + CallInfo *base_ci; /* array of CallInfo's */ + unsigned short size_ci; /* size of array `base_ci' */ + unsigned short nCcalls; /* number of nested C calls */ + lu_byte hookmask; + lu_byte allowhook; + lu_byte hookinit; + int basehookcount; + int hookcount; + lua_Hook hook; + TObject _gt; /* table of globals */ + GCObject *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ - char *Mbuffer; /* global buffer */ - size_t Mbuffsize; /* size of Mbuffer */ - /* global state */ - Proto *rootproto; /* list of all prototypes */ - Closure *rootcl; /* list of all closures */ - Hash *roottable; /* list of all tables */ - stringtable strt; /* hash table for strings */ - stringtable udt; /* hash table for udata */ - Hash *gt; /* table for globals */ - struct TM *TMtable; /* table for tag methods */ - int last_tag; /* last used tag in TMtable */ - struct Ref *refArray; /* locked objects */ - int refSize; /* size of refArray */ - int refFree; /* list of free positions in refArray */ - unsigned long GCthreshold; - unsigned long nblocks; /* number of `bytes' currently allocated */ - lua_Hook callhook; - lua_Hook linehook; - int allowhooks; + ptrdiff_t errfunc; /* current error handling function (stack index) */ +}; + + +#define G(L) (L->l_G) + + +/* +** Union of all collectable objects +*/ +union GCObject { + GCheader gch; + union TString ts; + union Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct UpVal uv; + struct lua_State th; /* thread */ }; +/* macros to convert a GCObject into a specific value */ +#define gcotots(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define gcotou(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) +#define gcotocl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) +#define gcotoh(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gcotop(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) +#define gcotouv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define ngcotouv(o) \ + check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define gcototh(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) + +/* macro to convert any value into a GCObject */ +#define valtogco(v) (cast(GCObject *, (v))) + + +lua_State *luaE_newthread (lua_State *L); +void luaE_freethread (lua_State *L, lua_State *L1); + #endif diff --git a/src/lstring.c b/src/lstring.c index a415a7d3fd..8cbddbd218 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.45a 2000/10/30 17:49:19 roberto Exp $ +** $Id: lstring.c,v 1.78 2002/12/04 17:38:31 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -7,6 +7,8 @@ #include +#define lstring_c + #include "lua.h" #include "lmem.h" @@ -15,141 +17,86 @@ #include "lstring.h" -/* -** type equivalent to TString, but with maximum alignment requirements -*/ -union L_UTString { - TString ts; - union L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ -}; - - - -void luaS_init (lua_State *L) { - L->strt.hash = luaM_newvector(L, 1, TString *); - L->udt.hash = luaM_newvector(L, 1, TString *); - L->nblocks += 2*sizeof(TString *); - L->strt.size = L->udt.size = 1; - L->strt.nuse = L->udt.nuse = 0; - L->strt.hash[0] = L->udt.hash[0] = NULL; -} - void luaS_freeall (lua_State *L) { - LUA_ASSERT(L->strt.nuse==0, "non-empty string table"); - L->nblocks -= (L->strt.size + L->udt.size)*sizeof(TString *); - luaM_free(L, L->strt.hash); - LUA_ASSERT(L->udt.nuse==0, "non-empty udata table"); - luaM_free(L, L->udt.hash); -} - - -static unsigned long hash_s (const char *s, size_t l) { - unsigned long h = l; /* seed */ - size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ - for (; l>=step; l-=step) - h = h ^ ((h<<5)+(h>>2)+(unsigned char)*(s++)); - return h; + lua_assert(G(L)->strt.nuse==0); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); } -void luaS_resize (lua_State *L, stringtable *tb, int newsize) { - TString **newhash = luaM_newvector(L, newsize, TString *); +void luaS_resize (lua_State *L, int newsize) { + GCObject **newhash = luaM_newvector(L, newsize, GCObject *); + stringtable *tb = &G(L)->strt; int i; for (i=0; isize; i++) { - TString *p = tb->hash[i]; + GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ - TString *next = p->nexthash; /* save next */ - unsigned long h = (tb == &L->strt) ? p->u.s.hash : IntPoint(p->u.d.value); - int h1 = h&(newsize-1); /* new position */ - LUA_ASSERT(h%newsize == (h&(newsize-1)), - "a&(x-1) == a%x, for x power of 2"); - p->nexthash = newhash[h1]; /* chain it in new position */ + GCObject *next = p->gch.next; /* save next */ + lu_hash h = gcotots(p)->tsv.hash; + int h1 = lmod(h, newsize); /* new position */ + lua_assert(cast(int, h%newsize) == lmod(h, newsize)); + p->gch.next = newhash[h1]; /* chain it */ newhash[h1] = p; p = next; } } - luaM_free(L, tb->hash); - L->nblocks += (newsize - tb->size)*sizeof(TString *); + luaM_freearray(L, tb->hash, tb->size, TString *); tb->size = newsize; tb->hash = newhash; } -static void newentry (lua_State *L, stringtable *tb, TString *ts, int h) { - ts->nexthash = tb->hash[h]; /* chain new entry */ - tb->hash[h] = ts; +static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { + TString *ts = cast(TString *, luaM_malloc(L, sizestring(l))); + stringtable *tb; + ts->tsv.len = l; + ts->tsv.hash = h; + ts->tsv.marked = 0; + ts->tsv.tt = LUA_TSTRING; + ts->tsv.reserved = 0; + memcpy(ts+1, str, l*sizeof(char)); + ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + tb = &G(L)->strt; + h = lmod(h, tb->size); + ts->tsv.next = tb->hash[h]; /* chain new entry */ + tb->hash[h] = valtogco(ts); tb->nuse++; - if (tb->nuse > (lint32)tb->size && tb->size < MAX_INT/2) /* too crowded? */ - luaS_resize(L, tb, tb->size*2); -} - - - -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - unsigned long h = hash_s(str, l); - int h1 = h & (L->strt.size-1); - TString *ts; - for (ts = L->strt.hash[h1]; ts; ts = ts->nexthash) { - if (ts->len == l && (memcmp(str, ts->str, l) == 0)) - return ts; - } - /* not found */ - ts = (TString *)luaM_malloc(L, sizestring(l)); - ts->marked = 0; - ts->nexthash = NULL; - ts->len = l; - ts->u.s.hash = h; - ts->u.s.constindex = 0; - memcpy(ts->str, str, l); - ts->str[l] = 0; /* ending 0 */ - L->nblocks += sizestring(l); - newentry(L, &L->strt, ts, h1); /* insert it on table */ - return ts; -} - - -TString *luaS_newudata (lua_State *L, size_t s, void *udata) { - union L_UTString *uts = (union L_UTString *)luaM_malloc(L, - (lint32)sizeof(union L_UTString)+s); - TString *ts = &uts->ts; - ts->marked = 0; - ts->nexthash = NULL; - ts->len = s; - ts->u.d.tag = 0; - ts->u.d.value = (s > 0) ? uts+1 : udata; - L->nblocks += sizestring(s); - /* insert it on table */ - newentry(L, &L->udt, ts, IntPoint(ts->u.d.value) & (L->udt.size-1)); + if (tb->nuse > cast(ls_nstr, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ return ts; } -TString *luaS_createudata (lua_State *L, void *udata, int tag) { - int h1 = IntPoint(udata) & (L->udt.size-1); - TString *ts; - for (ts = L->udt.hash[h1]; ts; ts = ts->nexthash) { - if (udata == ts->u.d.value && (tag == ts->u.d.tag || tag == LUA_ANYTAG)) +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + GCObject *o; + lu_hash h = (lu_hash)l; /* seed */ + size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ + size_t l1; + for (l1=l; l1>=step; l1-=step) /* compute hash */ + h = h ^ ((h<<5)+(h>>2)+(unsigned char)(str[l1-1])); + for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; + o != NULL; + o = o->gch.next) { + TString *ts = gcotots(o); + if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) return ts; } - /* not found */ - ts = luaS_newudata(L, 0, udata); - if (tag != LUA_ANYTAG) - ts->u.d.tag = tag; - return ts; + return newlstr(L, str, l, h); /* not found */ } -TString *luaS_new (lua_State *L, const char *str) { - return luaS_newlstr(L, str, strlen(str)); -} - - -TString *luaS_newfixed (lua_State *L, const char *str) { - TString *ts = luaS_new(L, str); - if (ts->marked == 0) ts->marked = FIXMARK; /* avoid GC */ - return ts; +Udata *luaS_newudata (lua_State *L, size_t s) { + Udata *u; + u = cast(Udata *, luaM_malloc(L, sizeudata(s))); + u->uv.marked = (1<<1); /* is not finalized */ + u->uv.tt = LUA_TUSERDATA; + u->uv.len = s; + u->uv.metatable = hvalue(defaultmeta(L)); + /* chain it on udata list */ + u->uv.next = G(L)->rootudata; + G(L)->rootudata = valtogco(u); + return u; } diff --git a/src/lstring.h b/src/lstring.h index 67ede68d5a..be5a1e3767 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.24 2000/10/30 17:49:19 roberto Exp $ +** $Id: lstring.h,v 1.37 2002/08/16 14:45:55 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -12,26 +12,22 @@ #include "lstate.h" -/* -** any TString with mark>=FIXMARK is never collected. -** Marks>=RESERVEDMARK are used to identify reserved words. -*/ -#define FIXMARK 2 -#define RESERVEDMARK 3 +#define sizestring(l) (cast(lu_mem, sizeof(union TString))+ \ + (cast(lu_mem, l)+1)*sizeof(char)) + +#define sizeudata(l) (cast(lu_mem, sizeof(union Udata))+(l)) -#define sizestring(l) ((long)sizeof(TString) + \ - ((long)(l+1)-TSPACK)*(long)sizeof(char)) +#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) +#define luaS_fix(s) ((s)->tsv.marked |= (1<<4)) -void luaS_init (lua_State *L); -void luaS_resize (lua_State *L, stringtable *tb, int newsize); -TString *luaS_newudata (lua_State *L, size_t s, void *udata); -TString *luaS_createudata (lua_State *L, void *udata, int tag); +void luaS_resize (lua_State *L, int newsize); +Udata *luaS_newudata (lua_State *L, size_t s); void luaS_freeall (lua_State *L); TString *luaS_newlstr (lua_State *L, const char *str, size_t l); -TString *luaS_new (lua_State *L, const char *str); -TString *luaS_newfixed (lua_State *L, const char *str); #endif diff --git a/src/ltable.c b/src/ltable.c index b28712d90d..0c64adb10a 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,13 +1,17 @@ /* -** $Id: ltable.c,v 1.58 2000/10/26 12:47:05 roberto Exp $ +** $Id: ltable.c,v 1.132 2003/04/03 13:35:34 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ /* -** Implementation of tables (aka arrays, objects, or hash tables); -** uses a mix of chained scatter table with Brent's variation. +** Implementation of tables (aka arrays, objects, or hash tables). +** Tables keep its elements in two parts: an array part and a hash part. +** Non-negative integer keys are all candidates to be kept in the array +** part. The actual size of the array is the largest `n' such that at +** least half the slots between 0 and n are in use. +** Hash uses a mix of chained scatter table with Brent's variation. ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the `original' position that its hash gives ** to it), then the colliding element is in its own main position. @@ -17,21 +21,74 @@ ** performance penalties. */ +#include + +#define ltable_c #include "lua.h" +#include "ldebug.h" +#include "ldo.h" +#include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" -#include "lstring.h" #include "ltable.h" -#define gcsize(L, n) (sizeof(Hash)+(n)*sizeof(Node)) +/* +** max size of array part is 2^MAXBITS +*/ +#if BITS_INT > 26 +#define MAXBITS 24 +#else +#define MAXBITS (BITS_INT-2) +#endif + +/* check whether `x' < 2^MAXBITS */ +#define toobig(x) ((((x)-1) >> MAXBITS) != 0) +/* function to convert a lua_Number to int (with any rounding method) */ +#ifndef lua_number2int +#define lua_number2int(i,n) ((i)=(int)(n)) +#endif -#define TagDefault LUA_TTABLE + +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) + +#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#define hashboolean(t,p) hashpow2(t, p) + + +/* +** for some types, it is better to avoid modulus by power of 2, as +** they tend to have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + +#define hashpointer(t,p) hashmod(t, IntPoint(p)) + + +/* +** number of ints inside a lua_Number +*/ +#define numints cast(int, sizeof(lua_Number)/sizeof(int)) + + +/* +** hash for lua_Numbers +*/ +static Node *hashnum (const Table *t, lua_Number n) { + unsigned int a[numints]; + int i; + n += 1; /* normalize number (avoid -0) */ + lua_assert(sizeof(a) <= sizeof(n)); + memcpy(a, &n, sizeof(a)); + for (i = 1; i < numints; i++) a[0] += a[i]; + return hashmod(t, cast(lu_hash, a[0])); +} @@ -39,226 +96,299 @@ ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ -Node *luaH_mainposition (const Hash *t, const TObject *key) { - unsigned long h; +Node *luaH_mainposition (const Table *t, const TObject *key) { switch (ttype(key)) { case LUA_TNUMBER: - h = (unsigned long)(long)nvalue(key); - break; + return hashnum(t, nvalue(key)); case LUA_TSTRING: - h = tsvalue(key)->u.s.hash; - break; - case LUA_TUSERDATA: - h = IntPoint(tsvalue(key)); - break; - case LUA_TTABLE: - h = IntPoint(hvalue(key)); - break; - case LUA_TFUNCTION: - h = IntPoint(clvalue(key)); - break; + return hashstr(t, tsvalue(key)); + case LUA_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case LUA_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); default: - return NULL; /* invalid key */ + return hashpointer(t, gcvalue(key)); } - LUA_ASSERT(h%(unsigned int)t->size == (h&((unsigned int)t->size-1)), - "a&(x-1) == a%x, for x power of 2"); - return &t->node[h&(t->size-1)]; } -static const TObject *luaH_getany (lua_State *L, const Hash *t, - const TObject *key) { - Node *n = luaH_mainposition(t, key); - if (!n) - lua_error(L, "table index is nil"); - else do { - if (luaO_equalObj(key, &n->key)) - return &n->val; - n = n->next; - } while (n); - return &luaO_nilobject; /* key not found */ +/* +** returns the index for `key' if `key' is an appropriate key to live in +** the array part of the table, -1 otherwise. +*/ +static int arrayindex (const TObject *key) { + if (ttisnumber(key)) { + int k; + lua_number2int(k, (nvalue(key))); + if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k)) + return k; + } + return -1; /* `key' did not match some condition */ } -/* specialized version for numbers */ -const TObject *luaH_getnum (const Hash *t, Number key) { - Node *n = &t->node[(unsigned long)(long)key&(t->size-1)]; - do { - if (ttype(&n->key) == LUA_TNUMBER && nvalue(&n->key) == key) - return &n->val; - n = n->next; - } while (n); - return &luaO_nilobject; /* key not found */ +/* +** returns the index of a `key' for table traversals. First goes all +** elements in the array part, then elements in the hash part. The +** beginning and end of a traversal are signalled by -1. +*/ +static int luaH_index (lua_State *L, Table *t, StkId key) { + int i; + if (ttisnil(key)) return -1; /* first iteration */ + i = arrayindex(key); + if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */ + return i-1; /* yes; that's the index (corrected to C) */ + } + else { + const TObject *v = luaH_get(t, key); + if (v == &luaO_nilobject) + luaG_runerror(L, "invalid key for `next'"); + i = cast(int, (cast(const lu_byte *, v) - + cast(const lu_byte *, gval(gnode(t, 0)))) / sizeof(Node)); + return i + t->sizearray; /* hash elements are numbered after array ones */ + } } -/* specialized version for strings */ -const TObject *luaH_getstr (const Hash *t, TString *key) { - Node *n = &t->node[key->u.s.hash&(t->size-1)]; - do { - if (ttype(&n->key) == LUA_TSTRING && tsvalue(&n->key) == key) - return &n->val; - n = n->next; - } while (n); - return &luaO_nilobject; /* key not found */ +int luaH_next (lua_State *L, Table *t, StkId key) { + int i = luaH_index(L, t, key); /* find original element */ + for (i++; i < t->sizearray; i++) { /* try first array part */ + if (!ttisnil(&t->array[i])) { /* a non-nil value? */ + setnvalue(key, cast(lua_Number, i+1)); + setobj2s(key+1, &t->array[i]); + return 1; + } + } + for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ + if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + setobj2s(key, gkey(gnode(t, i))); + setobj2s(key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ } -const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key) { - switch (ttype(key)) { - case LUA_TNUMBER: return luaH_getnum(t, nvalue(key)); - case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); - default: return luaH_getany(L, t, key); +/* +** {============================================================= +** Rehash +** ============================================================== +*/ + + +static void computesizes (int nums[], int ntotal, int *narray, int *nhash) { + int i; + int a = nums[0]; /* number of elements smaller than 2^i */ + int na = a; /* number of elements to go to array part */ + int n = (na == 0) ? -1 : 0; /* (log of) optimal size for array part */ + for (i = 1; a < *narray && *narray >= twoto(i-1); i++) { + if (nums[i] > 0) { + a += nums[i]; + if (a >= twoto(i-1)) { /* more than half elements in use? */ + n = i; + na = a; + } + } } + lua_assert(na <= *narray && *narray <= ntotal); + *nhash = ntotal - na; + *narray = (n == -1) ? 0 : twoto(n); + lua_assert(na <= *narray && na >= *narray/2); } -Node *luaH_next (lua_State *L, const Hash *t, const TObject *key) { - int i; - if (ttype(key) == LUA_TNIL) - i = 0; /* first iteration */ - else { - const TObject *v = luaH_get(L, t, key); - if (v == &luaO_nilobject) - lua_error(L, "invalid key for `next'"); - i = (int)(((const char *)v - - (const char *)(&t->node[0].val)) / sizeof(Node)) + 1; +static void numuse (const Table *t, int *narray, int *nhash) { + int nums[MAXBITS+1]; + int i, lg; + int totaluse = 0; + /* count elements in array part */ + for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ + int ttlg = twoto(lg); /* 2^lg */ + if (ttlg > t->sizearray) { + ttlg = t->sizearray; + if (i >= ttlg) break; + } + nums[lg] = 0; + for (; iarray[i])) { + nums[lg]++; + totaluse++; + } + } } - for (; isize; i++) { - Node *n = node(t, i); - if (ttype(val(n)) != LUA_TNIL) - return n; + for (; lg<=MAXBITS; lg++) nums[lg] = 0; /* reset other counts */ + *narray = totaluse; /* all previous uses were in array part */ + /* count elements in hash part */ + i = sizenode(t); + while (i--) { + Node *n = &t->node[i]; + if (!ttisnil(gval(n))) { + int k = arrayindex(gkey(n)); + if (k >= 0) { /* is `key' an appropriate array index? */ + nums[luaO_log2(k-1)+1]++; /* count as such */ + (*narray)++; + } + totaluse++; + } } - return NULL; /* no more elements */ + computesizes(nums, totaluse, narray, nhash); } -/* -** try to remove a key without value from a table. To avoid problems with -** hash, change `key' for a number with the same hash. -*/ -void luaH_remove (Hash *t, TObject *key) { - if (ttype(key) == LUA_TNUMBER || - (ttype(key) == LUA_TSTRING && tsvalue(key)->len <= 30)) - return; /* do not remove numbers nor small strings */ +static void setarrayvector (lua_State *L, Table *t, int size) { + int i; + luaM_reallocvector(L, t->array, t->sizearray, size, TObject); + for (i=t->sizearray; iarray[i]); + t->sizearray = size; +} + + +static void setnodevector (lua_State *L, Table *t, int lsize) { + int i; + int size = twoto(lsize); + if (lsize > MAXBITS) + luaG_runerror(L, "table overflow"); + if (lsize == 0) { /* no elements to hash part? */ + t->node = G(L)->dummynode; /* use common `dummynode' */ + lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */ + lua_assert(ttisnil(gval(t->node))); + lua_assert(t->node->next == NULL); /* (`dummynode' must be empty) */ + } else { - /* try to find a number `n' with the same hash as `key' */ - Node *mp = luaH_mainposition(t, key); - int n = mp - &t->node[0]; - /* make sure `n' is not in `t' */ - while (luaH_getnum(t, n) != &luaO_nilobject) { - if (n >= MAX_INT - t->size) - return; /* give up; (to avoid overflow) */ - n += t->size; + t->node = luaM_newvector(L, size, Node); + for (i=0; inode[i].next = NULL; + setnilvalue(gkey(gnode(t, i))); + setnilvalue(gval(gnode(t, i))); } - ttype(key) = LUA_TNUMBER; - nvalue(key) = n; - LUA_ASSERT(luaH_mainposition(t, key) == mp, "cannot change hash"); } + t->lsizenode = cast(lu_byte, lsize); + t->firstfree = gnode(t, size-1); /* first free position to be used */ } -static void setnodevector (lua_State *L, Hash *t, lint32 size) { +static void resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; - if (size > MAX_INT) - lua_error(L, "table overflow"); - t->node = luaM_newvector(L, size, Node); - for (i=0; i<(int)size; i++) { - ttype(&t->node[i].key) = ttype(&t->node[i].val) = LUA_TNIL; - t->node[i].next = NULL; + int oldasize = t->sizearray; + int oldhsize = t->lsizenode; + Node *nold; + Node temp[1]; + if (oldhsize) + nold = t->node; /* save old hash ... */ + else { /* old hash is `dummynode' */ + lua_assert(t->node == G(L)->dummynode); + temp[0] = t->node[0]; /* copy it to `temp' */ + nold = temp; + setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */ + setnilvalue(gval(G(L)->dummynode)); + lua_assert(G(L)->dummynode->next == NULL); + } + if (nasize > oldasize) /* array part must grow? */ + setarrayvector(L, t, nasize); + /* create new hash part with appropriate size */ + setnodevector(L, t, nhsize); + /* re-insert elements */ + if (nasize < oldasize) { /* array part must shrink? */ + t->sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; iarray[i])) + setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]); + } + /* shrink array */ + luaM_reallocvector(L, t->array, oldasize, nasize, TObject); } - L->nblocks += gcsize(L, size) - gcsize(L, t->size); - t->size = size; - t->firstfree = &t->node[size-1]; /* first free position to be used */ + /* re-insert elements in hash part */ + for (i = twoto(oldhsize) - 1; i >= 0; i--) { + Node *old = nold+i; + if (!ttisnil(gval(old))) + setobjt2t(luaH_set(L, t, gkey(old)), gval(old)); + } + if (oldhsize) + luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ } -Hash *luaH_new (lua_State *L, int size) { - Hash *t = luaM_new(L, Hash); - t->htag = TagDefault; - t->next = L->roottable; - L->roottable = t; - t->mark = t; - t->size = 0; - L->nblocks += gcsize(L, 0); - t->node = NULL; - setnodevector(L, t, luaO_power2(size)); - return t; +static void rehash (lua_State *L, Table *t) { + int nasize, nhsize; + numuse(t, &nasize, &nhsize); /* compute new sizes for array and hash parts */ + resize(L, t, nasize, luaO_log2(nhsize)+1); } -void luaH_free (lua_State *L, Hash *t) { - L->nblocks -= gcsize(L, t->size); - luaM_free(L, t->node); - luaM_free(L, t); + +/* +** }============================================================= +*/ + + +Table *luaH_new (lua_State *L, int narray, int lnhash) { + Table *t = luaM_new(L, Table); + luaC_link(L, valtogco(t), LUA_TTABLE); + t->metatable = hvalue(defaultmeta(L)); + t->flags = cast(lu_byte, ~0); + /* temporary values (kept only if some malloc fails) */ + t->array = NULL; + t->sizearray = 0; + t->lsizenode = 0; + t->node = NULL; + setarrayvector(L, t, narray); + setnodevector(L, t, lnhash); + return t; } -static int numuse (const Hash *t) { - Node *v = t->node; - int size = t->size; - int realuse = 0; - int i; - for (i=0; ilsizenode) + luaM_freearray(L, t->node, sizenode(t), Node); + luaM_freearray(L, t->array, t->sizearray, TObject); + luaM_freelem(L, t); } -static void rehash (lua_State *L, Hash *t) { - int oldsize = t->size; - Node *nold = t->node; - int nelems = numuse(t); - int i; - LUA_ASSERT(nelems<=oldsize, "wrong count"); - if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */ - setnodevector(L, t, (lint32)oldsize*2); - else if (nelems <= oldsize/4 && /* less than 1/4? */ - oldsize > MINPOWER2) - setnodevector(L, t, oldsize/2); - else - setnodevector(L, t, oldsize); - for (i=0; ival) != LUA_TNIL) - *luaH_set(L, t, &old->key) = old->val; +#if 0 +/* +** try to remove an element from a hash table; cannot move any element +** (because gc can call `remove' during a table traversal) +*/ +void luaH_remove (Table *t, Node *e) { + Node *mp = luaH_mainposition(t, gkey(e)); + if (e != mp) { /* element not in its main position? */ + while (mp->next != e) mp = mp->next; /* find previous */ + mp->next = e->next; /* remove `e' from its list */ + } + else { + if (e->next != NULL) ?? } - luaM_free(L, nold); /* free old array */ + lua_assert(ttisnil(gval(node))); + setnilvalue(gkey(e)); /* clear node `e' */ + e->next = NULL; } +#endif /* -** inserts a key into a hash table; first, check whether key is -** already present; if not, check whether key's main position is free; -** if not, check whether colliding node is in its main position or not; -** if it is not, move colliding node to an empty place and put new key -** in its main position; otherwise (colliding node is in its main position), -** new key goes to an empty position. +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. */ -TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) { +static TObject *newkey (lua_State *L, Table *t, const TObject *key) { + TObject *val; Node *mp = luaH_mainposition(t, key); - Node *n = mp; - if (!mp) - lua_error(L, "table index is nil"); - do { /* check whether `key' is somewhere in the chain */ - if (luaO_equalObj(key, &n->key)) - return &n->val; /* that's all */ - else n = n->next; - } while (n); - /* `key' not found; must insert it */ - if (ttype(&mp->key) != LUA_TNIL) { /* main position is not free? */ - Node *othern; /* main position of colliding node */ - n = t->firstfree; /* get a free place */ - /* is colliding node out of its main position? (can only happens if - its position is after "firstfree") */ - if (mp > n && (othern=luaH_mainposition(t, &mp->key)) != mp) { + if (!ttisnil(gval(mp))) { /* main position is not free? */ + Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */ + Node *n = t->firstfree; /* get a free place */ + if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (othern->next != mp) othern = othern->next; /* find previous */ othern->next = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ mp->next = NULL; /* now `mp' is free */ + setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ @@ -267,37 +397,113 @@ TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) { mp = n; } } - mp->key = *key; + setobj2t(gkey(mp), key); /* write barrier */ + lua_assert(ttisnil(gval(mp))); for (;;) { /* correct `firstfree' */ - if (ttype(&t->firstfree->key) == LUA_TNIL) - return &mp->val; /* OK; table still has a free place */ + if (ttisnil(gkey(t->firstfree))) + return gval(mp); /* OK; table still has a free place */ else if (t->firstfree == t->node) break; /* cannot decrement from here */ else (t->firstfree)--; } - rehash(L, t); /* no more free places */ - return luaH_set(L, t, key); /* `rehash' invalidates this insertion */ + /* no more free places; must create one */ + setbvalue(gval(mp), 0); /* avoid new key being removed */ + rehash(L, t); /* grow table */ + val = cast(TObject *, luaH_get(t, key)); /* get new position */ + lua_assert(ttisboolean(val)); + setnilvalue(val); + return val; +} + + +/* +** generic search function +*/ +static const TObject *luaH_getany (Table *t, const TObject *key) { + if (ttisnil(key)) return &luaO_nilobject; + else { + Node *n = luaH_mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ + else n = n->next; + } while (n); + return &luaO_nilobject; + } } -TObject *luaH_setint (lua_State *L, Hash *t, int key) { - TObject index; - ttype(&index) = LUA_TNUMBER; - nvalue(&index) = key; - return luaH_set(L, t, &index); +/* +** search function for integers +*/ +const TObject *luaH_getnum (Table *t, int key) { + if (1 <= key && key <= t->sizearray) + return &t->array[key-1]; + else { + lua_Number nk = cast(lua_Number, key); + Node *n = hashnum(t, nk); + do { /* check whether `key' is somewhere in the chain */ + if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk) + return gval(n); /* that's it */ + else n = n->next; + } while (n); + return &luaO_nilobject; + } } -void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val) { - TObject *value, index; - ttype(&index) = LUA_TSTRING; - tsvalue(&index) = key; - value = luaH_set(L, t, &index); - ttype(value) = LUA_TNUMBER; - nvalue(value) = val; +/* +** search function for strings +*/ +const TObject *luaH_getstr (Table *t, TString *key) { + Node *n = hashstr(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key) + return gval(n); /* that's it */ + else n = n->next; + } while (n); + return &luaO_nilobject; } -const TObject *luaH_getglobal (lua_State *L, const char *name) { - return luaH_getstr(L->gt, luaS_new(L, name)); +/* +** main search function +*/ +const TObject *luaH_get (Table *t, const TObject *key) { + switch (ttype(key)) { + case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); + case LUA_TNUMBER: { + int k; + lua_number2int(k, (nvalue(key))); + if (cast(lua_Number, k) == nvalue(key)) /* is an integer index? */ + return luaH_getnum(t, k); /* use specialized version */ + /* else go through */ + } + default: return luaH_getany(t, key); + } +} + + +TObject *luaH_set (lua_State *L, Table *t, const TObject *key) { + const TObject *p = luaH_get(t, key); + t->flags = 0; + if (p != &luaO_nilobject) + return cast(TObject *, p); + else { + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisnumber(key) && nvalue(key) != nvalue(key)) + luaG_runerror(L, "table index is NaN"); + return newkey(L, t, key); + } +} + + +TObject *luaH_setnum (lua_State *L, Table *t, int key) { + const TObject *p = luaH_getnum(t, key); + if (p != &luaO_nilobject) + return cast(TObject *, p); + else { + TObject k; + setnvalue(&k, cast(lua_Number, key)); + return newkey(L, t, &k); + } } diff --git a/src/ltable.h b/src/ltable.h index 8ee41a81af..3d4d753c3c 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 1.24 2000/08/31 14:08:27 roberto Exp $ +** $Id: ltable.h,v 1.44 2003/03/18 12:50:04 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -10,25 +10,22 @@ #include "lobject.h" -#define node(t,i) (&(t)->node[i]) -#define key(n) (&(n)->key) -#define val(n) (&(n)->val) +#define gnode(t,i) (&(t)->node[i]) +#define gkey(n) (&(n)->i_key) +#define gval(n) (&(n)->i_val) -Hash *luaH_new (lua_State *L, int nhash); -void luaH_free (lua_State *L, Hash *t); -const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key); -const TObject *luaH_getnum (const Hash *t, Number key); -const TObject *luaH_getstr (const Hash *t, TString *key); -void luaH_remove (Hash *t, TObject *key); -TObject *luaH_set (lua_State *L, Hash *t, const TObject *key); -Node * luaH_next (lua_State *L, const Hash *t, const TObject *r); -TObject *luaH_setint (lua_State *L, Hash *t, int key); -void luaH_setstrnum (lua_State *L, Hash *t, TString *key, Number val); -unsigned long luaH_hash (lua_State *L, const TObject *key); -const TObject *luaH_getglobal (lua_State *L, const char *name); + +const TObject *luaH_getnum (Table *t, int key); +TObject *luaH_setnum (lua_State *L, Table *t, int key); +const TObject *luaH_getstr (Table *t, TString *key); +const TObject *luaH_get (Table *t, const TObject *key); +TObject *luaH_set (lua_State *L, Table *t, const TObject *key); +Table *luaH_new (lua_State *L, int narray, int lnhash); +void luaH_free (lua_State *L, Table *t); +int luaH_next (lua_State *L, Table *t, StkId key); /* exported only for debugging */ -Node *luaH_mainposition (const Hash *t, const TObject *key); +Node *luaH_mainposition (const Table *t, const TObject *key); #endif diff --git a/src/ltests.c b/src/ltests.c index c27c7c8172..649b14e0d4 100644 --- a/src/ltests.c +++ b/src/ltests.c @@ -1,15 +1,17 @@ /* -** $Id: ltests.c,v 1.54 2000/10/31 13:10:24 roberto Exp $ +** $Id: ltests.c,v 1.158 2003/04/07 14:35:00 roberto Exp $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ #include +#include #include #include #include +#define ltests_c #include "lua.h" @@ -24,12 +26,9 @@ #include "lstate.h" #include "lstring.h" #include "ltable.h" -#include "luadebug.h" #include "lualib.h" -void luaB_opentests (lua_State *L); - /* ** The whole module only makes sense with LUA_DEBUG on @@ -37,14 +36,117 @@ void luaB_opentests (lua_State *L); #ifdef LUA_DEBUG +#define lua_pushintegral(L,i) lua_pushnumber(L, cast(lua_Number, (i))) + + +static lua_State *lua_state = NULL; + +int islocked = 0; + + +#define func_at(L,k) (L->ci->base+(k) - 1) + static void setnameval (lua_State *L, const char *name, int val) { lua_pushstring(L, name); - lua_pushnumber(L, val); + lua_pushintegral(L, val); lua_settable(L, -3); } +/* +** {====================================================================== +** Controlled version for realloc. +** ======================================================================= +*/ + +#define MARK 0x55 /* 01010101 (a nice pattern) */ + +#ifndef EXTERNMEMCHECK +/* full memory check */ +#define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */ +#define MARKSIZE 16 /* size of marks after each block */ +#define blockhead(b) (cast(char *, b) - HEADER) +#define setsize(newblock, size) (*cast(size_t *, newblock) = size) +#define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b)))) +#define fillmem(mem,size) memset(mem, -MARK, size) +#else +/* external memory check: don't do it twice */ +#define HEADER 0 +#define MARKSIZE 0 +#define blockhead(b) (b) +#define setsize(newblock, size) /* empty */ +#define checkblocksize(b,size) (1) +#define fillmem(mem,size) /* empty */ +#endif + +unsigned long memdebug_numblocks = 0; +unsigned long memdebug_total = 0; +unsigned long memdebug_maxmem = 0; +unsigned long memdebug_memlimit = ULONG_MAX; + + +static void *checkblock (void *block, size_t size) { + void *b = blockhead(block); + int i; + for (i=0;i 0); + if (size == 0) { + freeblock(block, oldsize); + return NULL; + } + else if (size > oldsize && memdebug_total+size-oldsize > memdebug_memlimit) + return NULL; /* to test memory allocation errors */ + else { + void *newblock; + int i; + size_t realsize = HEADER+size+MARKSIZE; + size_t commonsize = (oldsize < size) ? oldsize : size; + if (realsize < size) return NULL; /* overflow! */ + newblock = malloc(realsize); /* alloc a new block */ + if (newblock == NULL) return NULL; + if (block) { + memcpy(cast(char *, newblock)+HEADER, block, commonsize); + freeblock(block, oldsize); /* erase (and check) old copy */ + } + /* initialize new part of the block with something `weird' */ + fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize); + memdebug_total += size; + if (memdebug_total > memdebug_maxmem) + memdebug_maxmem = memdebug_total; + memdebug_numblocks++; + setsize(newblock, size); + for (i=0;icode[pc]; OpCode o = GET_OPCODE(i); - const char *name = instrname[o]; - sprintf(buff, "%5d - ", luaG_getline(p->lineinfo, pc, 1, NULL)); - switch ((enum Mode)luaK_opproperties[o].mode) { - case iO: - sprintf(buff+8, "%-12s", name); - break; - case iU: - sprintf(buff+8, "%-12s%4u", name, GETARG_U(i)); + const char *name = luaP_opnames[o]; + int line = getline(p, pc); + sprintf(buff, "(%4d) %4d - ", line, pc); + switch (getOpMode(o)) { + case iABC: + sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name, + GETARG_A(i), GETARG_B(i), GETARG_C(i)); break; - case iS: - sprintf(buff+8, "%-12s%4d", name, GETARG_S(i)); + case iABx: + sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); break; - case iAB: - sprintf(buff+8, "%-12s%4d %4d", name, GETARG_A(i), GETARG_B(i)); + case iAsBx: + sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); break; } - lua_pushstring(L, buff); - return (o != OP_END); + return buff; } +#if 0 +void luaI_printcode (Proto *pt, int size) { + int pc; + for (pc=0; pcf.l; + p = clvalue(func_at(L, 1))->l.p; lua_newtable(L); setnameval(L, "maxstack", p->maxstacksize); setnameval(L, "numparams", p->numparams); - pc = 0; - do { - lua_pushnumber(L, pc+1); - res = pushop(L, p, pc++); + for (pc=0; pcsizecode; pc++) { + char buff[100]; + lua_pushintegral(L, pc+1); + lua_pushstring(L, buildop(p, pc, buff)); lua_settable(L, -3); - } while (res); + } return 1; } -static int liststrings (lua_State *L) { +static int listk (lua_State *L) { Proto *p; int i; - luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); - p = clvalue(luaA_index(L, 1))->f.l; + p = clvalue(func_at(L, 1))->l.p; lua_newtable(L); - for (i=0; inkstr; i++) { - lua_pushnumber(L, i+1); - lua_pushstring(L, p->kstr[i]->str); + for (i=0; isizek; i++) { + lua_pushintegral(L, i+1); + luaA_pushobject(L, p->k+i); lua_settable(L, -3); } return 1; @@ -127,12 +225,12 @@ static int liststrings (lua_State *L) { static int listlocals (lua_State *L) { Proto *p; - int pc = luaL_check_int(L, 2) - 1; + int pc = luaL_checkint(L, 2) - 1; int i = 0; const char *name; - luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); - p = clvalue(luaA_index(L, 1))->f.l; + p = clvalue(func_at(L, 1))->l.p; while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) lua_pushstring(L, name); return i-1; @@ -142,96 +240,107 @@ static int listlocals (lua_State *L) { + static int get_limits (lua_State *L) { lua_newtable(L); setnameval(L, "BITS_INT", BITS_INT); setnameval(L, "LFPF", LFIELDS_PER_FLUSH); - setnameval(L, "MAXARG_A", MAXARG_A); - setnameval(L, "MAXARG_B", MAXARG_B); - setnameval(L, "MAXARG_S", MAXARG_S); - setnameval(L, "MAXARG_U", MAXARG_U); - setnameval(L, "MAXLOCALS", MAXLOCALS); + setnameval(L, "MAXVARS", MAXVARS); setnameval(L, "MAXPARAMS", MAXPARAMS); setnameval(L, "MAXSTACK", MAXSTACK); setnameval(L, "MAXUPVALUES", MAXUPVALUES); - setnameval(L, "MAXVARSLH", MAXVARSLH); - setnameval(L, "RFPF", RFIELDS_PER_FLUSH); - setnameval(L, "SIZE_A", SIZE_A); - setnameval(L, "SIZE_B", SIZE_B); - setnameval(L, "SIZE_OP", SIZE_OP); - setnameval(L, "SIZE_U", SIZE_U); return 1; } static int mem_query (lua_State *L) { - if (lua_isnull(L, 1)) { - lua_pushnumber(L, memdebug_total); - lua_pushnumber(L, memdebug_numblocks); - lua_pushnumber(L, memdebug_maxmem); + if (lua_isnone(L, 1)) { + lua_pushintegral(L, memdebug_total); + lua_pushintegral(L, memdebug_numblocks); + lua_pushintegral(L, memdebug_maxmem); return 3; } else { - memdebug_memlimit = luaL_check_int(L, 1); + memdebug_memlimit = luaL_checkint(L, 1); return 0; } } static int hash_query (lua_State *L) { - if (lua_isnull(L, 2)) { - luaL_arg_check(L, lua_tag(L, 1) == LUA_TSTRING, 1, "string expected"); - lua_pushnumber(L, tsvalue(luaA_index(L, 1))->u.s.hash); + if (lua_isnone(L, 2)) { + luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); + lua_pushintegral(L, tsvalue(func_at(L, 1))->tsv.hash); } else { - Hash *t; + TObject *o = func_at(L, 1); + Table *t; luaL_checktype(L, 2, LUA_TTABLE); - t = hvalue(luaA_index(L, 2)); - lua_pushnumber(L, luaH_mainposition(t, luaA_index(L, 1)) - t->node); + t = hvalue(func_at(L, 2)); + lua_pushintegral(L, luaH_mainposition(t, o) - t->node); } return 1; } +static int stacklevel (lua_State *L) { + unsigned long a = 0; + lua_pushintegral(L, (int)(L->top - L->stack)); + lua_pushintegral(L, (int)(L->stack_last - L->stack)); + lua_pushintegral(L, (int)(L->ci - L->base_ci)); + lua_pushintegral(L, (int)(L->end_ci - L->base_ci)); + lua_pushintegral(L, (unsigned long)&a); + return 5; +} + + static int table_query (lua_State *L) { - const Hash *t; - int i = luaL_opt_int(L, 2, -1); + const Table *t; + int i = luaL_optint(L, 2, -1); luaL_checktype(L, 1, LUA_TTABLE); - t = hvalue(luaA_index(L, 1)); + t = hvalue(func_at(L, 1)); if (i == -1) { - lua_pushnumber(L, t->size); - lua_pushnumber(L, t->firstfree - t->node); - return 2; + lua_pushintegral(L, t->sizearray); + lua_pushintegral(L, sizenode(t)); + lua_pushintegral(L, t->firstfree - t->node); } - else if (i < t->size) { - luaA_pushobject(L, &t->node[i].key); - luaA_pushobject(L, &t->node[i].val); - if (t->node[i].next) { - lua_pushnumber(L, t->node[i].next - t->node); - return 3; + else if (i < t->sizearray) { + lua_pushintegral(L, i); + luaA_pushobject(L, &t->array[i]); + lua_pushnil(L); + } + else if ((i -= t->sizearray) < sizenode(t)) { + if (!ttisnil(gval(gnode(t, i))) || + ttisnil(gkey(gnode(t, i))) || + ttisnumber(gkey(gnode(t, i)))) { + luaA_pushobject(L, gkey(gnode(t, i))); } else - return 2; + lua_pushstring(L, ""); + luaA_pushobject(L, gval(gnode(t, i))); + if (t->node[i].next) + lua_pushintegral(L, t->node[i].next - t->node); + else + lua_pushnil(L); } - return 0; + return 3; } static int string_query (lua_State *L) { - stringtable *tb = (*luaL_check_string(L, 1) == 's') ? &L->strt : &L->udt; - int s = luaL_opt_int(L, 2, 0) - 1; + stringtable *tb = &G(L)->strt; + int s = luaL_optint(L, 2, 0) - 1; if (s==-1) { - lua_pushnumber(L ,tb->nuse); - lua_pushnumber(L ,tb->size); + lua_pushintegral(L ,tb->nuse); + lua_pushintegral(L ,tb->size); return 2; } else if (s < tb->size) { - TString *ts; + GCObject *ts; int n = 0; - for (ts = tb->hash[s]; ts; ts = ts->nexthash) { - ttype(L->top) = LUA_TSTRING; - tsvalue(L->top) = ts; - incr_top; + for (ts = tb->hash[s]; ts; ts = ts->gch.next) { + setsvalue2s(L->top, gcotots(ts)); + incr_top(L); n++; } return n; @@ -241,111 +350,193 @@ static int string_query (lua_State *L) { static int tref (lua_State *L) { + int level = lua_gettop(L); + int lock = luaL_optint(L, 2, 1); luaL_checkany(L, 1); lua_pushvalue(L, 1); - lua_pushnumber(L, lua_ref(L, luaL_opt_int(L, 2, 1))); + lua_pushintegral(L, lua_ref(L, lock)); + assert(lua_gettop(L) == level+1); /* +1 for result */ return 1; } static int getref (lua_State *L) { - if (lua_getref(L, luaL_check_int(L, 1))) - return 1; - else - return 0; + int level = lua_gettop(L); + lua_getref(L, luaL_checkint(L, 1)); + assert(lua_gettop(L) == level+1); + return 1; } static int unref (lua_State *L) { - lua_unref(L, luaL_check_int(L, 1)); + int level = lua_gettop(L); + lua_unref(L, luaL_checkint(L, 1)); + assert(lua_gettop(L) == level); return 0; } +static int metatable (lua_State *L) { + luaL_checkany(L, 1); + if (lua_isnone(L, 2)) { + if (lua_getmetatable(L, 1) == 0) + lua_pushnil(L); + } + else { + lua_settop(L, 2); + luaL_checktype(L, 2, LUA_TTABLE); + lua_setmetatable(L, 1); + } + return 1; +} + + +static int upvalue (lua_State *L) { + int n = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + if (lua_isnone(L, 3)) { + const char *name = lua_getupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + return 2; + } + else { + const char *name = lua_setupvalue(L, 1, n); + lua_pushstring(L, name); + return 1; + } +} + + static int newuserdata (lua_State *L) { - if (lua_isnumber(L, 2)) - lua_pushusertag(L, (void *)luaL_check_int(L, 1), luaL_check_int(L, 2)); - else - lua_newuserdata(L, luaL_check_int(L, 1)); + size_t size = luaL_checkint(L, 1); + char *p = cast(char *, lua_newuserdata(L, size)); + while (size--) *p++ = '\0'; + return 1; +} + + +static int pushuserdata (lua_State *L) { + lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1))); return 1; } + static int udataval (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); - lua_pushnumber(L, (int)lua_touserdata(L, 1)); + lua_pushintegral(L, cast(int, lua_touserdata(L, 1))); + return 1; +} + + +static int doonnewstack (lua_State *L) { + lua_State *L1 = lua_newthread(L); + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + int status = luaL_loadbuffer(L1, s, l, s); + if (status == 0) + status = lua_pcall(L1, 0, 0, 0); + lua_pushintegral(L, status); + return 1; +} + + +static int s2d (lua_State *L) { + lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1))); + return 1; +} + +static int d2s (lua_State *L) { + double d = luaL_checknumber(L, 1); + lua_pushlstring(L, cast(char *, &d), sizeof(d)); return 1; } + static int newstate (lua_State *L) { - lua_State *L1 = lua_open(luaL_check_int(L, 1)); - if (L1) - lua_pushuserdata(L, L1); + lua_State *L1 = lua_open(); + if (L1) { + lua_userstateopen(L1); /* init lock */ + lua_pushintegral(L, (unsigned long)L1); + } else lua_pushnil(L); return 1; } + static int loadlib (lua_State *L) { - lua_State *L1 = (lua_State *)lua_touserdata(L, 1); - switch (*luaL_check_string(L, 2)) { - case 'm': lua_mathlibopen(L1); break; - case 's': lua_strlibopen(L1); break; - case 'i': lua_iolibopen(L1); break; - case 'd': lua_dblibopen(L1); break; - case 'b': lua_baselibopen(L1); break; - default: luaL_argerror(L, 2, "invalid option"); - } + static const luaL_reg libs[] = { + {"mathlibopen", luaopen_math}, + {"strlibopen", luaopen_string}, + {"iolibopen", luaopen_io}, + {"tablibopen", luaopen_table}, + {"dblibopen", luaopen_debug}, + {"baselibopen", luaopen_base}, + {NULL, NULL} + }; + lua_State *L1 = cast(lua_State *, + cast(unsigned long, luaL_checknumber(L, 1))); + lua_pushvalue(L1, LUA_GLOBALSINDEX); + luaL_openlib(L1, NULL, libs, 0); return 0; } static int closestate (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); - lua_close((lua_State *)lua_touserdata(L, 1)); + lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1))); + lua_close(L1); + lua_unlock(L); /* close cannot unlock that */ return 0; } static int doremote (lua_State *L) { - lua_State *L1; - const char *code = luaL_check_string(L, 2); + lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1))); + size_t lcode; + const char *code = luaL_checklstring(L, 2, &lcode); int status; - luaL_checktype(L, 1, LUA_TUSERDATA); - L1 = (lua_State *)lua_touserdata(L, 1); - status = lua_dostring(L1, code); + lua_settop(L1, 0); + status = luaL_loadbuffer(L1, code, lcode, code); + if (status == 0) + status = lua_pcall(L1, 0, LUA_MULTRET, 0); if (status != 0) { lua_pushnil(L); - lua_pushnumber(L, status); - return 2; + lua_pushintegral(L, status); + lua_pushstring(L, lua_tostring(L1, -1)); + return 3; } else { int i = 0; - while (!lua_isnull(L1, ++i)) + while (!lua_isnone(L1, ++i)) lua_pushstring(L, lua_tostring(L1, i)); + lua_pop(L1, i-1); return i-1; } } -static int settagmethod (lua_State *L) { - int tag = luaL_check_int(L, 1); - const char *event = luaL_check_string(L, 2); - luaL_checkany(L, 3); - lua_gettagmethod(L, tag, event); - lua_pushvalue(L, 3); - lua_settagmethod(L, tag, event); + +static int log2_aux (lua_State *L) { + lua_pushintegral(L, luaO_log2(luaL_checkint(L, 1))); return 1; } -static int pushbool (lua_State *L, int b) { - if (b) lua_pushnumber(L, 1); - else lua_pushnil(L); - return 1; +static int int2fb_aux (lua_State *L) { + int b = luaO_int2fb(luaL_checkint(L, 1)); + lua_pushintegral(L, b); + lua_pushintegral(L, fb2int(b)); + return 2; } -static int equal (lua_State *L) { - return pushbool(L, lua_equal(L, 1, 2)); + +static int test_do (lua_State *L) { + const char *p = luaL_checkstring(L, 1); + if (*p == '@') + lua_dofile(L, p+1); + else + lua_dostring(L, p); + return lua_gettop(L); } - + /* ** {====================================================== -** function to test the API with C. It interprets a kind of "assembler" +** function to test the API with C. It interprets a kind of assembler ** language with calls to the API, so the test can be driven by Lua code ** ======================================================= */ @@ -356,12 +547,12 @@ static void skip (const char **pc) { while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; } -static int getnum (lua_State *L, const char **pc) { +static int getnum_aux (lua_State *L, const char **pc) { int res = 0; int sig = 1; skip(pc); if (**pc == '.') { - res = (int)lua_tonumber(L, -1); + res = cast(int, lua_tonumber(L, -1)); lua_pop(L, 1); (*pc)++; return res; @@ -370,11 +561,11 @@ static int getnum (lua_State *L, const char **pc) { sig = -1; (*pc)++; } - while (isdigit(**pc)) res = res*10 + (*(*pc)++) - '0'; + while (isdigit(cast(int, **pc))) res = res*10 + (*(*pc)++) - '0'; return sig*res; } -static const char *getname (char *buff, const char **pc) { +static const char *getname_aux (char *buff, const char **pc) { int i = 0; skip(pc); while (**pc != '\0' && !strchr(delimits, **pc)) @@ -386,51 +577,52 @@ static const char *getname (char *buff, const char **pc) { #define EQ(s1) (strcmp(s1, inst) == 0) -#define getnum ((getnum)(L, &pc)) -#define getname ((getname)(buff, &pc)) +#define getnum (getnum_aux(L, &pc)) +#define getname (getname_aux(buff, &pc)) static int testC (lua_State *L) { char buff[30]; - const char *pc = luaL_check_string(L, 1); + const char *pc = luaL_checkstring(L, 1); for (;;) { const char *inst = getname; if EQ("") return 0; else if EQ("isnumber") { - lua_pushnumber(L, lua_isnumber(L, getnum)); + lua_pushintegral(L, lua_isnumber(L, getnum)); } else if EQ("isstring") { - lua_pushnumber(L, lua_isstring(L, getnum)); + lua_pushintegral(L, lua_isstring(L, getnum)); } else if EQ("istable") { - lua_pushnumber(L, lua_istable(L, getnum)); + lua_pushintegral(L, lua_istable(L, getnum)); } else if EQ("iscfunction") { - lua_pushnumber(L, lua_iscfunction(L, getnum)); + lua_pushintegral(L, lua_iscfunction(L, getnum)); } else if EQ("isfunction") { - lua_pushnumber(L, lua_isfunction(L, getnum)); + lua_pushintegral(L, lua_isfunction(L, getnum)); } else if EQ("isuserdata") { - lua_pushnumber(L, lua_isuserdata(L, getnum)); + lua_pushintegral(L, lua_isuserdata(L, getnum)); + } + else if EQ("isudataval") { + lua_pushintegral(L, lua_islightuserdata(L, getnum)); } else if EQ("isnil") { - lua_pushnumber(L, lua_isnil(L, getnum)); + lua_pushintegral(L, lua_isnil(L, getnum)); } else if EQ("isnull") { - lua_pushnumber(L, lua_isnull(L, getnum)); + lua_pushintegral(L, lua_isnone(L, getnum)); } else if EQ("tonumber") { lua_pushnumber(L, lua_tonumber(L, getnum)); } else if EQ("tostring") { - lua_pushstring(L, lua_tostring(L, getnum)); - } - else if EQ("tonumber") { - lua_pushnumber(L, lua_tonumber(L, getnum)); + const char *s = lua_tostring(L, getnum); + lua_pushstring(L, s); } else if EQ("strlen") { - lua_pushnumber(L, lua_strlen(L, getnum)); + lua_pushintegral(L, lua_strlen(L, getnum)); } else if EQ("tocfunction") { lua_pushcfunction(L, lua_tocfunction(L, getnum)); @@ -439,7 +631,7 @@ static int testC (lua_State *L) { return getnum; } else if EQ("gettop") { - lua_pushnumber(L, lua_gettop(L)); + lua_pushintegral(L, lua_gettop(L)); } else if EQ("settop") { lua_settop(L, getnum); @@ -448,17 +640,35 @@ static int testC (lua_State *L) { lua_pop(L, getnum); } else if EQ("pushnum") { - lua_pushnumber(L, getnum); + lua_pushintegral(L, getnum); + } + else if EQ("pushnil") { + lua_pushnil(L); + } + else if EQ("pushbool") { + lua_pushboolean(L, getnum); + } + else if EQ("tobool") { + lua_pushintegral(L, lua_toboolean(L, getnum)); } else if EQ("pushvalue") { lua_pushvalue(L, getnum); } + else if EQ("pushcclosure") { + lua_pushcclosure(L, testC, getnum); + } + else if EQ("pushupvalues") { + lua_pushupvalues(L); + } else if EQ("remove") { lua_remove(L, getnum); } else if EQ("insert") { lua_insert(L, getnum); } + else if EQ("replace") { + lua_replace(L, getnum); + } else if EQ("gettable") { lua_gettable(L, getnum); } @@ -471,33 +681,53 @@ static int testC (lua_State *L) { else if EQ("concat") { lua_concat(L, getnum); } + else if EQ("lessthan") { + int a = getnum; + lua_pushboolean(L, lua_lessthan(L, a, getnum)); + } + else if EQ("equal") { + int a = getnum; + lua_pushboolean(L, lua_equal(L, a, getnum)); + } else if EQ("rawcall") { int narg = getnum; int nres = getnum; - lua_rawcall(L, narg, nres); + lua_call(L, narg, nres); } else if EQ("call") { int narg = getnum; int nres = getnum; - lua_call(L, narg, nres); + lua_pcall(L, narg, nres, 0); + } + else if EQ("loadstring") { + size_t sl; + const char *s = luaL_checklstring(L, getnum, &sl); + luaL_loadbuffer(L, s, sl, s); } - else if EQ("dostring") { - lua_dostring(L, luaL_check_string(L, getnum)); + else if EQ("loadfile") { + luaL_loadfile(L, luaL_checkstring(L, getnum)); } - else if EQ("settagmethod") { - int tag = getnum; - const char *event = getname; - lua_settagmethod(L, tag, event); + else if EQ("setmetatable") { + lua_setmetatable(L, getnum); } - else if EQ("gettagmethod") { - int tag = getnum; - const char *event = getname; - lua_gettagmethod(L, tag, event); + else if EQ("getmetatable") { + if (lua_getmetatable(L, getnum) == 0) + lua_pushnil(L); } else if EQ("type") { lua_pushstring(L, lua_typename(L, lua_type(L, getnum))); } - else luaL_verror(L, "unknown instruction %.30s", buff); + else if EQ("getn") { + int i = getnum; + lua_pushintegral(L, luaL_getn(L, i)); + } + else if EQ("setn") { + int i = getnum; + int n = cast(int, lua_tonumber(L, -1)); + luaL_setn(L, i, n); + lua_pop(L, 1); + } + else luaL_error(L, "unknown instruction %s", buff); } return 0; } @@ -505,39 +735,118 @@ static int testC (lua_State *L) { /* }====================================================== */ +/* +** {====================================================== +** tests for yield inside hooks +** ======================================================= +*/ + +static void yieldf (lua_State *L, lua_Debug *ar) { + lua_yield(L, 0); +} + +static int setyhook (lua_State *L) { + if (lua_isnoneornil(L, 1)) + lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + else { + const char *smask = luaL_checkstring(L, 1); + int count = luaL_optint(L, 2, 0); + int mask = 0; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + lua_sethook(L, yieldf, mask, count); + } + return 0; +} + + +static int coresume (lua_State *L) { + int status; + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "coroutine expected"); + status = lua_resume(co, 0); + if (status != 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + return 1; + } +} + +/* }====================================================== */ + + static const struct luaL_reg tests_funcs[] = { {"hash", hash_query}, {"limits", get_limits}, {"listcode", listcode}, - {"liststrings", liststrings}, + {"listk", listk}, {"listlocals", listlocals}, {"loadlib", loadlib}, + {"stacklevel", stacklevel}, {"querystr", string_query}, {"querytab", table_query}, + {"doit", test_do}, {"testC", testC}, {"ref", tref}, {"getref", getref}, {"unref", unref}, + {"d2s", d2s}, + {"s2d", s2d}, + {"metatable", metatable}, + {"upvalue", upvalue}, {"newuserdata", newuserdata}, + {"pushuserdata", pushuserdata}, {"udataval", udataval}, + {"doonnewstack", doonnewstack}, {"newstate", newstate}, {"closestate", closestate}, {"doremote", doremote}, - {"settagmethod", settagmethod}, - {"equal", equal}, - {"totalmem", mem_query} + {"log2", log2_aux}, + {"int2fb", int2fb_aux}, + {"totalmem", mem_query}, + {"resume", coresume}, + {"setyhook", setyhook}, + {NULL, NULL} }; -void luaB_opentests (lua_State *L) { - lua_newtable(L); - lua_getglobals(L); - lua_pushvalue(L, -2); - lua_setglobals(L); - luaL_openl(L, tests_funcs); /* open functions inside new table */ - lua_setglobals(L); /* restore old table of globals */ - lua_setglobal(L, "T"); /* set new table as global T */ +static void fim (void) { + if (!islocked) + lua_close(lua_state); + lua_assert(memdebug_numblocks == 0); + lua_assert(memdebug_total == 0); +} + + +static int l_panic (lua_State *L) { + UNUSED(L); + fprintf(stderr, "unable to recover; exiting\n"); + return 0; +} + + +int luaB_opentests (lua_State *L) { + lua_atpanic(L, l_panic); + lua_userstateopen(L); /* init lock */ + lua_state = L; /* keep first state to be opened */ + luaL_openlib(L, "T", tests_funcs, 0); + atexit(fim); + return 0; +} + + +#undef main +int main (int argc, char *argv[]) { + char *limit = getenv("MEMLIMIT"); + if (limit) + memdebug_memlimit = strtoul(limit, NULL, 10); + l_main(argc, argv); + return 0; } #endif diff --git a/src/ltm.c b/src/ltm.c index a20909a1b3..1b3e515e57 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,163 +1,70 @@ /* -** $Id: ltm.c,v 1.56 2000/10/31 13:10:24 roberto Exp $ +** $Id: ltm.c,v 1.106 2003/04/03 13:35:34 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ -#include #include +#define ltm_c + #include "lua.h" -#include "ldo.h" -#include "lmem.h" #include "lobject.h" #include "lstate.h" +#include "lstring.h" +#include "ltable.h" #include "ltm.h" -const char *const luaT_eventname[] = { /* ORDER TM */ - "gettable", "settable", "index", "getglobal", "setglobal", "add", "sub", - "mul", "div", "pow", "unm", "lt", "concat", "gc", "function", - "le", "gt", "ge", /* deprecated options!! */ - NULL -}; - - -static int findevent (const char *name) { - int i; - for (i=0; luaT_eventname[i]; i++) - if (strcmp(luaT_eventname[i], name) == 0) - return i; - return -1; /* name not found */ -} - - -static int luaI_checkevent (lua_State *L, const char *name, int t) { - int e = findevent(name); - if (e >= TM_N) - luaO_verror(L, "event `%.50s' is deprecated", name); - if (e == TM_GC && t == LUA_TTABLE) - luaO_verror(L, "event `gc' for tables is deprecated"); - if (e < 0) - luaO_verror(L, "`%.50s' is not a valid event name", name); - return e; -} - - -/* events in LUA_TNIL are all allowed, since this is used as a -* 'placeholder' for "default" fallbacks -*/ -/* ORDER LUA_T, ORDER TM */ -static const char luaT_validevents[NUM_TAGS][TM_N] = { - {1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TUSERDATA */ - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_TNIL */ - {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, /* LUA_TNUMBER */ - {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_TSTRING */ - {0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TTABLE */ - {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0} /* LUA_TFUNCTION */ +const char *const luaT_typenames[] = { + "nil", "boolean", "userdata", "number", + "string", "table", "function", "userdata", "thread" }; -int luaT_validevent (int t, int e) { /* ORDER LUA_T */ - return (t >= NUM_TAGS) ? 1 : luaT_validevents[t][e]; -} - - -static void init_entry (lua_State *L, int tag) { - int i; - for (i=0; iTMtable[tag].collected = NULL; -} - void luaT_init (lua_State *L) { - int t; - luaM_growvector(L, L->TMtable, 0, NUM_TAGS, struct TM, "", MAX_INT); - L->nblocks += NUM_TAGS*sizeof(struct TM); - L->last_tag = NUM_TAGS-1; - for (t=0; t<=L->last_tag; t++) - init_entry(L, t); -} - - -LUA_API int lua_newtag (lua_State *L) { - luaM_growvector(L, L->TMtable, L->last_tag, 1, struct TM, - "tag table overflow", MAX_INT); - L->nblocks += sizeof(struct TM); - L->last_tag++; - init_entry(L, L->last_tag); - return L->last_tag; -} - - -static void checktag (lua_State *L, int tag) { - if (!(0 <= tag && tag <= L->last_tag)) - luaO_verror(L, "%d is not a valid tag", tag); -} - -void luaT_realtag (lua_State *L, int tag) { - if (!validtag(tag)) - luaO_verror(L, "tag %d was not created by `newtag'", tag); -} - - -LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom) { - int e; - checktag(L, tagto); - checktag(L, tagfrom); - for (e=0; eu.d.tag; - case LUA_TTABLE: return hvalue(o)->htag; - default: return t; + static const char *const luaT_eventname[] = { /* ORDER TM */ + "__index", "__newindex", + "__gc", "__mode", "__eq", + "__add", "__sub", "__mul", "__div", + "__pow", "__unm", "__lt", "__le", + "__concat", "__call" + }; + int i; + for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); + luaS_fix(G(L)->tmname[i]); /* never collect these names */ } } -LUA_API void lua_gettagmethod (lua_State *L, int t, const char *event) { - int e; - e = luaI_checkevent(L, event, t); - checktag(L, t); - if (luaT_validevent(t, e) && luaT_gettm(L, t, e)) { - clvalue(L->top) = luaT_gettm(L, t, e); - ttype(L->top) = LUA_TFUNCTION; +/* +** function to be used with macro "fasttm": optimized for absence of +** tag methods +*/ +const TObject *luaT_gettm (Table *events, TMS event, TString *ename) { + const TObject *tm = luaH_getstr(events, ename); + lua_assert(event <= TM_EQ); + if (ttisnil(tm)) { /* no tag method? */ + events->flags |= cast(lu_byte, 1u<top) = LUA_TNIL; - incr_top; + else return tm; } -LUA_API void lua_settagmethod (lua_State *L, int t, const char *event) { - int e = luaI_checkevent(L, event, t); - checktag(L, t); - if (!luaT_validevent(t, e)) - luaO_verror(L, "cannot change `%.20s' tag method for type `%.20s'%.20s", - luaT_eventname[e], luaO_typenames[t], - (t == LUA_TTABLE || t == LUA_TUSERDATA) ? - " with default tag" : ""); - switch (ttype(L->top - 1)) { - case LUA_TNIL: - luaT_gettm(L, t, e) = NULL; - break; - case LUA_TFUNCTION: - luaT_gettm(L, t, e) = clvalue(L->top - 1); - break; +const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event) { + TString *ename = G(L)->tmname[event]; + switch (ttype(o)) { + case LUA_TTABLE: + return luaH_getstr(hvalue(o)->metatable, ename); + case LUA_TUSERDATA: + return luaH_getstr(uvalue(o)->uv.metatable, ename); default: - lua_error(L, "tag method must be a function (or nil)"); + return &luaO_nilobject; } - L->top--; } diff --git a/src/ltm.h b/src/ltm.h index 3bd8e82751..8eebfd3dc3 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 1.18 2000/10/05 13:00:17 roberto Exp $ +** $Id: ltm.h,v 1.41 2002/11/14 11:51:50 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -9,18 +9,18 @@ #include "lobject.h" -#include "lstate.h" + /* * WARNING: if you change the order of this enumeration, * grep "ORDER TM" */ typedef enum { - TM_GETTABLE = 0, - TM_SETTABLE, TM_INDEX, - TM_GETGLOBAL, - TM_SETGLOBAL, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_EQ, /* last tag method with `fast' access */ TM_ADD, TM_SUB, TM_MUL, @@ -28,32 +28,24 @@ typedef enum { TM_POW, TM_UNM, TM_LT, + TM_LE, TM_CONCAT, - TM_GC, - TM_FUNCTION, + TM_CALL, TM_N /* number of elements in the enum */ } TMS; -struct TM { - Closure *method[TM_N]; - TString *collected; /* list of garbage-collected udata with this tag */ -}; - - -#define luaT_gettm(L,tag,event) (L->TMtable[tag].method[event]) -#define luaT_gettmbyObj(L,o,e) (luaT_gettm((L),luaT_tag(o),(e))) - -#define validtag(t) (NUM_TAGS <= (t) && (t) <= L->last_tag) +#define gfasttm(g,et,e) \ + (((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) -extern const char *const luaT_eventname[]; +#define fasttm(l,et,e) gfasttm(G(l), et, e) +const TObject *luaT_gettm (Table *events, TMS event, TString *ename); +const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event); void luaT_init (lua_State *L); -void luaT_realtag (lua_State *L, int tag); -int luaT_tag (const TObject *o); -int luaT_validevent (int t, int e); /* used by compatibility module */ +extern const char *const luaT_typenames[]; #endif diff --git a/src/lua/Makefile b/src/lua/Makefile index 5b47161f22..aa52832f26 100644 --- a/src/lua/Makefile +++ b/src/lua/Makefile @@ -4,17 +4,16 @@ LUA= ../.. include $(LUA)/config -EXTRA_DEFS= $(POSIX) - +EXTRA_DEFS= $(USERCONF) OBJS= lua.o SRCS= lua.c T= $(BIN)/lua -all: $T +all: $T -$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) +$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a + $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) $(LIB)/liblua.a: cd ..; $(MAKE) diff --git a/src/lua/README b/src/lua/README index 832fb5bf78..febd229a58 100644 --- a/src/lua/README +++ b/src/lua/README @@ -2,39 +2,31 @@ This is lua, a sample Lua interpreter. It can be used as a batch interpreter and also interactively. There are man pages for it in both nroff and html in ../../doc. -Here are the options that it understands: +Usage: ./lua [options] [script [args]]. Available options are: - execute stdin as a file - -c close Lua when exiting -e stat execute string `stat' - -f name execute file `name' with remaining arguments in table `arg' - -i enter interactive mode with prompt - -q enter interactive mode without prompt - -sNUM set stack size to NUM (must be the first option) - -v print version information - a=b set global `a' to string `b' - name execute file `name' + -i enter interactive mode after executing `script' + -l name load and run library `name' + -v show version information + -- stop handling options -If no options are given, then it reads lines from stdin and executes them -as they are read -- so, each line must contain a complete statement. -To span a statement across several lines, end each line with a backslash '\'. +This interpreter is suitable for using Lua as a standalone language; it loads +all standard libraries. For a minimal interpreter, see ../../etc/min.c. -To change the prompt, set the global variable _PROMPT to whatever you want. -You can do this after calling the interpreter or on the command line with - lua _PROMPT="lua: " -i -for example. Note that you need "-i" in this case. +If your application simply exports new functions to Lua (which is common), +then you can use this interpreter (almost) unmodified, as follows: -You must be careful when using quotes on the command line because they are -usually handled by the shell. +* First, define a function + void myinit (lua_State *L) + in your own code. In this function, you should do whatever initializations + are needed by your application, typically exporting your functions to Lua. + (Of course, you can use any name instead of "myinit".) -This interpreter is good for using Lua as a standalone language. -For a minimal interpreter, see ../../etc/min.c. +* Then, #define lua_userinit(L) to be "openstdlibs(L)+myinit(L)". + Here, openstdlibs is a function in lua.c that opens all standard libraries. + If you don't need them, just don't call openstdlibs and open any standard + libraries that you do need in myinit. -If your application simply exports new functions to Lua (which is common), -then you can use this interpreter (almost) unmodified, as follows: -First, define a function - void myinit (lua_State *L) -in your own code. In this function, you should do whatever initializations -are needed by your application, typically exporting your functions to Lua. -Then, add a call "myinit(L)" in lua.c after the place marked - "add your libraries here" -Of course, you can use any name instead of "myinit". +* Finally, remember to link your C code when building lua. + +For other customizations, see ../../etc/config.c. diff --git a/src/lua/lua.c b/src/lua/lua.c index 2da857e1cb..28c84cb613 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.55 2000/10/20 16:36:32 roberto Exp $ +** $Id: lua.c,v 1.122 2003/04/03 13:34:42 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -10,313 +10,429 @@ #include #include +#define lua_c + #include "lua.h" -#include "luadebug.h" +#include "lauxlib.h" #include "lualib.h" -static lua_State *L = NULL; +/* +** generic extra include file +*/ +#ifdef LUA_USERCONFIG +#include LUA_USERCONFIG +#endif + + +/* +** definition of `isatty' +*/ +#ifdef _POSIX_C_SOURCE +#include +#define stdin_is_tty() isatty(0) +#else +#define stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + #ifndef PROMPT #define PROMPT "> " #endif -#ifdef _POSIX_SOURCE -#include -#else -static int isatty (int x) { return x==0; } /* assume stdin is a tty */ + +#ifndef PROMPT2 +#define PROMPT2 ">> " #endif +#ifndef PROGNAME +#define PROGNAME "lua" +#endif -/* -** global options -*/ -struct Options { - int toclose; - int stacksize; -}; +#ifndef lua_userinit +#define lua_userinit(L) openstdlibs(L) +#endif -typedef void (*handler)(int); /* type for signal actions */ +#ifndef LUA_EXTRALIBS +#define LUA_EXTRALIBS /* empty */ +#endif -static void laction (int i); +static lua_State *L = NULL; -static lua_Hook old_linehook = NULL; -static lua_Hook old_callhook = NULL; +static const char *progname = PROGNAME; -static void userinit (void) { - lua_baselibopen(L); - lua_iolibopen(L); - lua_strlibopen(L); - lua_mathlibopen(L); - lua_dblibopen(L); + +static const luaL_reg lualibs[] = { + {"base", luaopen_base}, + {"table", luaopen_table}, + {"io", luaopen_io}, + {"string", luaopen_string}, + {"math", luaopen_math}, + {"debug", luaopen_debug}, + {"loadlib", luaopen_loadlib}, /* add your libraries here */ -} + LUA_EXTRALIBS + {NULL, NULL} +}; -static handler lreset (void) { - return signal(SIGINT, laction); -} - -static void lstop (void) { - lua_setlinehook(L, old_linehook); - lua_setcallhook(L, old_callhook); - lreset(); - lua_error(L, "interrupted!"); +static void lstop (lua_State *l, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(l, NULL, 0, 0); + luaL_error(l, "interrupted!"); } static void laction (int i) { - (void)i; /* to avoid warnings */ - signal(SIGINT, SIG_DFL); /* if another SIGINT happens before lstop, + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ - old_linehook = lua_setlinehook(L, (lua_Hook)lstop); - old_callhook = lua_setcallhook(L, (lua_Hook)lstop); -} - - -static int ldo (int (*f)(lua_State *l, const char *), const char *name) { - int res; - handler h = lreset(); - int top = lua_gettop(L); - res = f(L, name); /* dostring | dofile */ - lua_settop(L, top); /* remove eventual results */ - signal(SIGINT, h); /* restore old action */ - /* Lua gives no message in such cases, so lua.c provides one */ - if (res == LUA_ERRMEM) { - fprintf(stderr, "lua: memory allocation error\n"); - } - else if (res == LUA_ERRERR) - fprintf(stderr, "lua: error in error message\n"); - return res; + lua_sethook(L, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } -static void print_message (void) { +static void print_usage (void) { fprintf(stderr, - "usage: lua [options]. Available options are:\n" + "usage: %s [options] [script [args]].\n" + "Available options are:\n" " - execute stdin as a file\n" - " -c close Lua when exiting\n" " -e stat execute string `stat'\n" - " -f name execute file `name' with remaining arguments in table `arg'\n" - " -i enter interactive mode with prompt\n" - " -q enter interactive mode without prompt\n" - " -sNUM set stack size to NUM (must be the first option)\n" - " -v print version information\n" - " a=b set global `a' to string `b'\n" - " name execute file `name'\n" -); + " -i enter interactive mode after executing `script'\n" + " -l name load and run library `name'\n" + " -v show version information\n" + " -- stop handling options\n" , + progname); } -static void print_version (void) { - printf("%.80s %.80s\n", LUA_VERSION, LUA_COPYRIGHT); +static void l_message (const char *pname, const char *msg) { + if (pname) fprintf(stderr, "%s: ", pname); + fprintf(stderr, "%s\n", msg); } -static void assign (char *arg) { - char *eq = strchr(arg, '='); - *eq = '\0'; /* spilt `arg' in two strings (name & value) */ - lua_pushstring(L, eq+1); - lua_setglobal(L, arg); +static int report (int status) { + const char *msg; + if (status) { + msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error with no message)"; + l_message(progname, msg); + lua_pop(L, 1); + } + return status; } -static void getargs (char *argv[]) { +static int lcall (int narg, int clear) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushliteral(L, "_TRACEBACK"); + lua_rawget(L, LUA_GLOBALSINDEX); /* get traceback function */ + lua_insert(L, base); /* put it under chunk and args */ + signal(SIGINT, laction); + status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); + signal(SIGINT, SIG_DFL); + lua_remove(L, base); /* remove traceback function */ + return status; +} + + +static void print_version (void) { + l_message(NULL, LUA_VERSION " " LUA_COPYRIGHT); +} + + +static void getargs (char *argv[], int n) { int i; lua_newtable(L); for (i=0; argv[i]; i++) { - /* arg[i] = argv[i] */ - lua_pushnumber(L, i); + lua_pushnumber(L, i - n); lua_pushstring(L, argv[i]); - lua_settable(L, -3); + lua_rawset(L, -3); } /* arg.n = maximum index in table `arg' */ - lua_pushstring(L, "n"); - lua_pushnumber(L, i-1); - lua_settable(L, -3); + lua_pushliteral(L, "n"); + lua_pushnumber(L, i-n-1); + lua_rawset(L, -3); } -static int l_getargs (lua_State *l) { - char **argv = (char **)lua_touserdata(l, -1); - getargs(argv); - return 1; +static int docall (int status) { + if (status == 0) status = lcall(0, 1); + return report(status); } -static int file_input (const char *argv) { - int result = ldo(lua_dofile, argv); - if (result) { - if (result == LUA_ERRFILE) { - fprintf(stderr, "lua: cannot execute file "); - perror(argv); - } - return EXIT_FAILURE; +static int file_input (const char *name) { + return docall(luaL_loadfile(L, name)); +} + + +static int dostring (const char *s, const char *name) { + return docall(luaL_loadbuffer(L, s, strlen(s), name)); +} + + +static int load_file (const char *name) { + lua_pushliteral(L, "require"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (!lua_isfunction(L, -1)) { /* no `require' defined? */ + lua_pop(L, 1); + return file_input(name); + } + else { + lua_pushstring(L, name); + return report(lcall(1, 1)); } - else - return EXIT_SUCCESS; } -/* maximum length of an input string */ +/* +** this macro can be used by some `history' system to save lines +** read in manual input +*/ +#ifndef lua_saveline +#define lua_saveline(L,line) /* empty */ +#endif + + +/* +** this macro defines a function to show the prompt and reads the +** next line for manual input +*/ +#ifndef lua_readline +#define lua_readline(L,prompt) readline(L,prompt) + +/* maximum length of an input line */ #ifndef MAXINPUT -#define MAXINPUT BUFSIZ +#define MAXINPUT 512 #endif -static void manual_input (int version, int prompt) { - int cont = 1; - if (version) print_version(); - while (cont) { - char buffer[MAXINPUT]; - int i = 0; - if (prompt) { - const char *s; - lua_getglobal(L, "_PROMPT"); - s = lua_tostring(L, -1); - if (!s) s = PROMPT; - fputs(s, stdout); - lua_pop(L, 1); /* remove global */ - } - for(;;) { - int c = getchar(); - if (c == EOF) { - cont = 0; - break; - } - else if (c == '\n') { - if (i>0 && buffer[i-1] == '\\') - buffer[i-1] = '\n'; - else break; - } - else if (i >= MAXINPUT-1) { - fprintf(stderr, "lua: input line too long\n"); - break; - } - else buffer[i++] = (char)c; + +static int readline (lua_State *l, const char *prompt) { + static char buffer[MAXINPUT]; + if (prompt) { + fputs(prompt, stdout); + fflush(stdout); + } + if (fgets(buffer, sizeof(buffer), stdin) == NULL) + return 0; /* read fails */ + else { + lua_pushstring(l, buffer); + return 1; + } +} + +#endif + + +static const char *get_prompt (int firstline) { + const char *p = NULL; + lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2"); + lua_rawget(L, LUA_GLOBALSINDEX); + p = lua_tostring(L, -1); + if (p == NULL) p = (firstline ? PROMPT : PROMPT2); + lua_pop(L, 1); /* remove global */ + return p; +} + + +static int incomplete (int status) { + if (status == LUA_ERRSYNTAX && + strstr(lua_tostring(L, -1), "near `'") != NULL) { + lua_pop(L, 1); + return 1; + } + else + return 0; +} + + +static int load_string (void) { + int status; + lua_settop(L, 0); + if (lua_readline(L, get_prompt(1)) == 0) /* no input? */ + return -1; + if (lua_tostring(L, -1)[0] == '=') { /* line starts with `=' ? */ + lua_pushfstring(L, "return %s", lua_tostring(L, -1)+1);/* `=' -> `return' */ + lua_remove(L, -2); /* remove original line */ + } + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(status)) break; /* cannot try to add lines? */ + if (lua_readline(L, get_prompt(0)) == 0) /* no more input? */ + return -1; + lua_concat(L, lua_gettop(L)); /* join lines */ + } + lua_saveline(L, lua_tostring(L, 1)); + lua_remove(L, 1); /* remove line */ + return status; +} + + +static void manual_input (void) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = load_string()) != -1) { + if (status == 0) status = lcall(0, 0); + report(status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, "error calling `print' (%s)", + lua_tostring(L, -1))); } - buffer[i] = '\0'; - ldo(lua_dostring, buffer); - lua_settop(L, 0); /* remove eventual results */ } - printf("\n"); + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + progname = oldprogname; } -static int handle_argv (char *argv[], struct Options *opt) { - if (opt->stacksize > 0) argv++; /* skip option `-s' (if present) */ - if (*argv == NULL) { /* no more arguments? */ - if (isatty(0)) { - manual_input(1, 1); +static int handle_argv (char *argv[], int *interactive) { + if (argv[1] == NULL) { /* no more arguments? */ + if (stdin_is_tty()) { + print_version(); + manual_input(); } else - ldo(lua_dofile, NULL); /* executes stdin as a file */ + file_input(NULL); /* executes stdin as a file */ } else { /* other arguments; loop over them */ int i; - for (i = 0; argv[i] != NULL; i++) { - if (argv[i][0] != '-') { /* not an option? */ - if (strchr(argv[i], '=')) - assign(argv[i]); - else - if (file_input(argv[i]) != EXIT_SUCCESS) - return EXIT_FAILURE; /* stop if file fails */ - } - else switch (argv[i][1]) { /* option */ - case 0: { - ldo(lua_dofile, NULL); /* executes stdin as a file */ - break; - } - case 'i': { - manual_input(0, 1); - break; - } - case 'q': { - manual_input(0, 0); - break; - } - case 'c': { - opt->toclose = 1; - break; + for (i = 1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') break; /* not an option? */ + switch (argv[i][1]) { /* option */ + case '-': { /* `--' */ + if (argv[i][2] != '\0') { + print_usage(); + return 1; } - case 'v': { - print_version(); - break; - } - case 'e': { - i++; - if (argv[i] == NULL) { - print_message(); - return EXIT_FAILURE; - } - if (ldo(lua_dostring, argv[i]) != 0) { - fprintf(stderr, "lua: error running argument `%.99s'\n", argv[i]); - return EXIT_FAILURE; - } - break; - } - case 'f': { - i++; - if (argv[i] == NULL) { - print_message(); - return EXIT_FAILURE; - } - getargs(argv+i); /* collect remaining arguments */ - lua_setglobal(L, "arg"); - return file_input(argv[i]); /* stop scanning arguments */ - } - case 's': { - fprintf(stderr, "lua: stack size (`-s') must be the first option\n"); - return EXIT_FAILURE; + i++; /* skip this argument */ + goto endloop; /* stop handling arguments */ + } + case '\0': { + file_input(NULL); /* executes stdin as a file */ + break; + } + case 'i': { + *interactive = 1; + break; + } + case 'v': { + print_version(); + break; + } + case 'e': { + const char *chunk = argv[i] + 2; + if (*chunk == '\0') chunk = argv[++i]; + if (chunk == NULL) { + print_usage(); + return 1; } - default: { - print_message(); - return EXIT_FAILURE; + if (dostring(chunk, "=") != 0) + return 1; + break; + } + case 'l': { + const char *filename = argv[i] + 2; + if (*filename == '\0') filename = argv[++i]; + if (filename == NULL) { + print_usage(); + return 1; } + if (load_file(filename)) + return 1; /* stop if file fails */ + break; + } + case 'c': { + l_message(progname, "option `-c' is deprecated"); + break; + } + case 's': { + l_message(progname, "option `-s' is deprecated"); + break; + } + default: { + print_usage(); + return 1; } + } + } endloop: + if (argv[i] != NULL) { + const char *filename = argv[i]; + getargs(argv, i); /* collect arguments */ + lua_setglobal(L, "arg"); + return file_input(filename); /* stop scanning arguments */ } } - return EXIT_SUCCESS; + return 0; } -static void getstacksize (int argc, char *argv[], struct Options *opt) { - if (argc >= 2 && argv[1][0] == '-' && argv[1][1] == 's') { - int stacksize = atoi(&argv[1][2]); - if (stacksize <= 0) { - fprintf(stderr, "lua: invalid stack size ('%.20s')\n", &argv[1][2]); - exit(EXIT_FAILURE); - } - opt->stacksize = stacksize; +static void openstdlibs (lua_State *l) { + const luaL_reg *lib = lualibs; + for (; lib->func; lib++) { + lib->func(l); /* open library */ + lua_settop(l, 0); /* discard any results */ } +} + + +static int handle_luainit (void) { + const char *init = getenv("LUA_INIT"); + if (init == NULL) return 0; /* status OK */ + else if (init[0] == '@') + return file_input(init+1); else - opt->stacksize = 0; /* no stack size */ + return dostring(init, "=LUA_INIT"); } -static void register_getargs (char *argv[]) { - lua_pushuserdata(L, argv); - lua_pushcclosure(L, l_getargs, 1); - lua_setglobal(L, "getargs"); +struct Smain { + int argc; + char **argv; + int status; +}; + + +static int pmain (lua_State *l) { + struct Smain *s = (struct Smain *)lua_touserdata(l, 1); + int status; + int interactive = 0; + if (s->argv[0] && s->argv[0][0]) progname = s->argv[0]; + L = l; + lua_userinit(l); /* open libraries */ + status = handle_luainit(); + if (status == 0) { + status = handle_argv(s->argv, &interactive); + if (status == 0 && interactive) manual_input(); + } + s->status = status; + return 0; } int main (int argc, char *argv[]) { - struct Options opt; int status; - opt.toclose = 0; - getstacksize(argc, argv, &opt); /* handle option `-s' */ - L = lua_open(opt.stacksize); /* create state */ - userinit(); /* open libraries */ - register_getargs(argv); /* create `getargs' function */ - status = handle_argv(argv+1, &opt); - if (opt.toclose) - lua_close(L); - return status; + struct Smain s; + lua_State *l = lua_open(); /* create state */ + if (l == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + s.argc = argc; + s.argv = argv; + status = lua_cpcall(l, &pmain, &s); + report(status); + lua_close(l); + return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/luac/Makefile b/src/luac/Makefile index 4517d82b4b..7a620826f3 100644 --- a/src/luac/Makefile +++ b/src/luac/Makefile @@ -4,20 +4,27 @@ LUA= ../.. include $(LUA)/config -INCS= -I$(INC) $(EXTRA_INCS) -I.. -OBJS= dump.o luac.o opt.o print.o stubs.o -SRCS= dump.c luac.c opt.c print.c stubs.c luac.h print.h +INCS= -I$(INC) -I.. $(EXTRA_INCS) +OBJS= luac.o print.o lopcodes.o +SRCS= luac.c print.c T= $(BIN)/luac -all: $T +all: $T -$T: $(OBJS) $(LIB)/liblua.a - $(CC) -o $@ $(OBJS) -L$(LIB) -llua +$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a + $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) + +# print.c needs opcode names from lopcodes.c +lopcodes.o: ../lopcodes.c ../lopcodes.h + $(CC) -o $@ -c $(CFLAGS) -DLUA_OPNAMES ../lopcodes.c $(LIB)/liblua.a: cd ..; $(MAKE) +$(LIB)/liblualib.a: + cd ../lib; $(MAKE) + clean: rm -f $(OBJS) $T diff --git a/src/luac/README b/src/luac/README index 8d8bb491d1..ada7bc4b3c 100644 --- a/src/luac/README +++ b/src/luac/README @@ -1,22 +1,18 @@ This is luac, the Lua compiler. There are man pages for it in both nroff and html in ../../doc. -luac translates Lua programs into binary files that can be loaded and executed -with lua_dofile in C or with dofile in Lua. +luac translates Lua programs into binary files that can be loaded latter. The main advantages of pre-compiling chunks are: faster loading, protecting source code from user changes, and off-line syntax error detection. luac can also be used to learn about the Lua virtual machine. -Here are the options that luac understands: - +Usage: /l/luac/luac [options] [filenames]. Available options are: - process stdin -l list - -o file output file (default is "luac.out") + -o name output to file `name' (default is "luac.out") -p parse only -s strip debug information - -t test code integrity -v show version information + -- stop handling options luac is also an example of how to use the internals of Lua (politely). -Finally, luac does not need the runtime code, and stubs.c makes sure it is not -linked into luac. This file also shows how to avoid linking the parser. diff --git a/src/luac/dump.c b/src/luac/dump.c deleted file mode 100644 index 149469ba11..0000000000 --- a/src/luac/dump.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -** $Id: dump.c,v 1.30 2000/10/31 16:57:23 lhf Exp $ -** save bytecodes to file -** See Copyright Notice in lua.h -*/ - -#include -#include -#include - -#include "luac.h" - -#define DumpVector(b,n,size,D) fwrite(b,size,n,D) -#define DumpBlock(b,size,D) fwrite(b,size,1,D) -#define DumpByte fputc - -static void DumpInt(int x, FILE* D) -{ - DumpBlock(&x,sizeof(x),D); -} - -static void DumpSize(size_t x, FILE* D) -{ - DumpBlock(&x,sizeof(x),D); -} - -static void DumpNumber(Number x, FILE* D) -{ - DumpBlock(&x,sizeof(x),D); -} - -static void DumpString(const TString* s, FILE* D) -{ - if (s==NULL || s->str==NULL) - DumpSize(0,D); - else - { - size_t size=s->len+1; /* include trailing '\0' */ - DumpSize(size,D); - DumpBlock(s->str,size,D); - } -} - -static void DumpCode(const Proto* tf, FILE* D) -{ - DumpInt(tf->ncode,D); - DumpVector(tf->code,tf->ncode,sizeof(*tf->code),D); -} - -static void DumpLocals(const Proto* tf, FILE* D) -{ - int i,n=tf->nlocvars; - DumpInt(n,D); - for (i=0; ilocvars[i].varname,D); - DumpInt(tf->locvars[i].startpc,D); - DumpInt(tf->locvars[i].endpc,D); - } -} - -static void DumpLines(const Proto* tf, FILE* D) -{ - DumpInt(tf->nlineinfo,D); - DumpVector(tf->lineinfo,tf->nlineinfo,sizeof(*tf->lineinfo),D); -} - -static void DumpFunction(const Proto* tf, FILE* D); - -static void DumpConstants(const Proto* tf, FILE* D) -{ - int i,n; - DumpInt(n=tf->nkstr,D); - for (i=0; ikstr[i],D); - DumpInt(tf->nknum,D); - DumpVector(tf->knum,tf->nknum,sizeof(*tf->knum),D); - DumpInt(n=tf->nkproto,D); - for (i=0; ikproto[i],D); -} - -static void DumpFunction(const Proto* tf, FILE* D) -{ - DumpString(tf->source,D); - DumpInt(tf->lineDefined,D); - DumpInt(tf->numparams,D); - DumpByte(tf->is_vararg,D); - DumpInt(tf->maxstacksize,D); - DumpLocals(tf,D); - DumpLines(tf,D); - DumpConstants(tf,D); - DumpCode(tf,D); - if (ferror(D)) - { - perror("luac: write error"); - exit(1); - } -} - -static void DumpHeader(FILE* D) -{ - DumpByte(ID_CHUNK,D); - fputs(SIGNATURE,D); - DumpByte(VERSION,D); - DumpByte(luaU_endianess(),D); - DumpByte(sizeof(int),D); - DumpByte(sizeof(size_t),D); - DumpByte(sizeof(Instruction),D); - DumpByte(SIZE_INSTRUCTION,D); - DumpByte(SIZE_OP,D); - DumpByte(SIZE_B,D); - DumpByte(sizeof(Number),D); - DumpNumber(TEST_NUMBER,D); -} - -void luaU_dumpchunk(const Proto* Main, FILE* D) -{ - DumpHeader(D); - DumpFunction(Main,D); -} diff --git a/src/luac/luac.c b/src/luac/luac.c index 8832de62d4..9ea23342da 100644 --- a/src/luac/luac.c +++ b/src/luac/luac.c @@ -1,6 +1,6 @@ /* -** $Id: luac.c,v 1.28 2000/11/06 20:06:27 lhf Exp $ -** lua compiler (saves bytecodes to files; also list binary files) +** $Id: luac.c,v 1.44 2003/04/07 20:34:20 lhf Exp $ +** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -8,78 +8,80 @@ #include #include -#include "lparser.h" -#include "lstate.h" -#include "lzio.h" -#include "luac.h" +#include "lua.h" +#include "lauxlib.h" -#define OUTPUT "luac.out" /* default output file */ +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstring.h" +#include "lundump.h" -static void usage(const char* message, const char* arg); -static int doargs(int argc, const char* argv[]); -static Proto* load(const char* filename); -static FILE* efopen(const char* name, const char* mode); -static void strip(Proto* tf); -static Proto* combine(Proto** P, int n); +#ifndef LUA_DEBUG +#define luaB_opentests(L) +#endif -lua_State* lua_state=NULL; /* lazy! */ +#ifndef PROGNAME +#define PROGNAME "luac" /* program name */ +#endif + +#define OUTPUT "luac.out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ static int stripping=0; /* strip debug information? */ -static int testing=0; /* test integrity? */ -static const char* output=OUTPUT; /* output file name */ +static char Output[]={ OUTPUT }; /* default output file name */ +static const char* output=Output; /* output file name */ +static const char* progname=PROGNAME; /* actual program name */ -#define IS(s) (strcmp(argv[i],s)==0) +static void fatal(const char* message) +{ + fprintf(stderr,"%s: %s\n",progname,message); + exit(EXIT_FAILURE); +} -int main(int argc, const char* argv[]) +static void cannot(const char* name, const char* what, const char* mode) { - Proto** P,*tf; - int i=doargs(argc,argv); - argc-=i; argv+=i; - if (argc<=0) usage("no input files given",NULL); - L=lua_open(0); - P=luaM_newvector(L,argc,Proto*); - for (i=0; il.p; } -static Proto* combine(Proto** P, int n) +static Proto* combine(lua_State* L, int n) { if (n==1) - return P[0]; + return toproto(L,-1); else { int i,pc=0; - Proto* tf=luaF_newproto(L); - tf->source=luaS_new(L,"=(luac)"); - tf->maxstacksize=1; - tf->kproto=P; - tf->nkproto=n; - tf->ncode=2*n+1; - tf->code=luaM_newvector(L,tf->ncode,Instruction); + Proto* f=luaF_newproto(L); + f->source=luaS_newliteral(L,"=(" PROGNAME ")"); + f->maxstacksize=1; + f->p=luaM_newvector(L,n,Proto*); + f->sizep=n; + f->sizecode=2*n+1; + f->code=luaM_newvector(L,f->sizecode,Instruction); for (i=0; icode[pc++]=CREATE_AB(OP_CLOSURE,i,0); - tf->code[pc++]=CREATE_AB(OP_CALL,0,0); + f->p[i]=toproto(L,i-n); + f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); + f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); } - tf->code[pc++]=OP_END; - return tf; + f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); + return f; } } -static void strip(Proto* tf) +static void strip(lua_State* L, Proto* f) { - int i,n=tf->nkproto; - tf->lineinfo=NULL; - tf->nlineinfo=0; - tf->source=luaS_new(L,"=(none)"); - tf->locvars=NULL; - tf->nlocvars=0; - for (i=0; ikproto[i]); + int i,n=f->sizep; + luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); + luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); + luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); + f->lineinfo=NULL; f->sizelineinfo=0; + f->locvars=NULL; f->sizelocvars=0; + f->upvalues=NULL; f->sizeupvalues=0; + f->source=luaS_newliteral(L,"=(none)"); + for (i=0; ip[i]); } -static FILE* efopen(const char* name, const char* mode) +static int writer(lua_State* L, const void* p, size_t size, void* u) { - FILE* f=fopen(name,mode); - if (f==NULL) - { - fprintf(stderr,"luac: cannot open %sput file ",*mode=='r' ? "in" : "out"); - perror(name); - exit(1); - } - return f; + UNUSED(L); + return fwrite(p,size,1,(FILE*)u)==1; } -void luaU_testchunk(const Proto* Main) +int main(int argc, char* argv[]) { - UNUSED(Main); - fprintf(stderr,"luac: -t not operational in this version\n"); - exit(1); + lua_State* L; + Proto* f; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given",NULL); + L=lua_open(); + luaB_opentests(L); + for (i=0; i -#include -#include - -#include "luac.h" - -static int MapConstant(Hash* t, int j, const TObject* key) -{ - const TObject* o=luaH_get(L,t,key); - if (ttype(o)==LUA_TNUMBER) - return (int) nvalue(o); - else - { - TObject val; - ttype(&val)=LUA_TNUMBER; - nvalue(&val)=j; - *luaH_set(L,t,key)=val; - LUA_ASSERT(j>=0,"MapConstant returns negative!"); - return j; - } -} - -static int MapConstants(Proto* tf, Hash* map) -{ - int i,j,k,n,m=0; - TObject o; - j=0; n=tf->nknum; ttype(&o)=LUA_TNUMBER; - for (i=0; iknum[i]; - k=MapConstant(map,j,&o); - if (k==j) j++; - } - m=j; - j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING; - for (i=0; ikstr[i]; - k=MapConstant(map,j,&o); - if (k==j) j++; - } - return m+j; -} - -static void PackConstants(Proto* tf, Hash* map) -{ - int i,j,k,n; - TObject o; -#ifdef DEBUG - printf("%p before pack nknum=%d nkstr=%d\n",tf,tf->nknum,tf->nkstr); -#endif - j=0; n=tf->nknum; ttype(&o)=LUA_TNUMBER; - for (i=0; iknum[i]; - k=MapConstant(map,-1,&o); - if (k==j) tf->knum[j++]=tf->knum[i]; - } - tf->nknum=j; - j=0; n=tf->nkstr; ttype(&o)=LUA_TSTRING; - for (i=0; ikstr[i]; - k=MapConstant(map,-1,&o); - if (k==j) tf->kstr[j++]=tf->kstr[i]; - } - tf->nkstr=j; -#ifdef DEBUG - printf("%p after pack nknum=%d nkstr=%d\n",tf,tf->nknum,tf->nkstr); -#endif -} - -static void OptConstants(Proto* tf) -{ - Instruction* p; - int n=tf->nknum+tf->nkstr; - Hash* map=luaH_new(L,n); - int m=MapConstants(tf,map); -#ifdef DEBUG - printf("%p n=%d m=%d %s\n",tf,n,m,(m==n)?"nothing to optimize":"yes!"); -#endif - if (m==n) return; - for (p=tf->code;; p++) - { - Instruction i=*p; - int op=GET_OPCODE(i); - switch (op) - { - TObject o; - int j,k; - case OP_PUSHNUM: case OP_PUSHNEGNUM: - j=GETARG_U(i); - ttype(&o)=LUA_TNUMBER; nvalue(&o)=tf->knum[j]; - k=MapConstant(map,-1,&o); - if (k!=j) *p=CREATE_U(op,k); - break; - case OP_PUSHSTRING: case OP_GETGLOBAL: case OP_GETDOTTED: - case OP_PUSHSELF: case OP_SETGLOBAL: - j=GETARG_U(i); - ttype(&o)=LUA_TSTRING; tsvalue(&o)=tf->kstr[j]; - k=MapConstant(map,-1,&o); - if (k!=j) *p=CREATE_U(op,k); - break; - case OP_END: - PackConstants(tf,map); - luaH_free(L,map); - return; - default: - break; - } - } -} - -#define OptFunction luaU_optchunk - -void OptFunction(Proto* tf) -{ - int i,n=tf->nkproto; - OptConstants(tf); - for (i=0; ikproto[i]); -} diff --git a/src/luac/print.c b/src/luac/print.c index 4ffc8b3d16..d0b5efb25b 100644 --- a/src/luac/print.c +++ b/src/luac/print.c @@ -1,31 +1,30 @@ /* -** $Id: print.c,v 1.32 2000/11/06 20:04:36 lhf Exp $ +** $Id: print.c,v 1.44 2003/04/07 20:34:20 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ #include -#include - -#include "luac.h" - -/* macros used in print.h, included in PrintCode */ -#define P_OP(x) printf("%-11s\t",x) -#define P_NONE -#define P_AB printf("%d %d",GETARG_A(i),GETARG_B(i)) -#define P_F printf("%d %d\t; %p",GETARG_A(i),GETARG_B(i),tf->kproto[GETARG_A(i)]) -#define P_J printf("%d\t; to %d",GETARG_S(i),GETARG_S(i)+at+1) -#define P_Q PrintString(tf,GETARG_U(i)) -#define P_K printf("%d\t; %s",GETARG_U(i),tf->kstr[GETARG_U(i)]->str) -#define P_L PrintLocal(tf,GETARG_U(i),at-1) -#define P_N printf("%d\t; " NUMBER_FMT,GETARG_U(i),tf->knum[GETARG_U(i)]) -#define P_S printf("%d",GETARG_S(i)) -#define P_U printf("%u",GETARG_U(i)) - -static void PrintString(const Proto* tf, int n) + +#if 0 +#define DEBUG_PRINT +#endif + +#ifndef LUA_OPNAMES +#define LUA_OPNAMES +#endif + +#include "ldebug.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lundump.h" + +#define Sizeof(x) ((int)sizeof(x)) +#define VOID(p) ((const void*)(p)) + +static void PrintString(const Proto* f, int n) { - const char* s=tf->kstr[n]->str; - printf("%d\t; ",n); + const char* s=svalue(&f->k[n]); putchar('"'); for (; *s; s++) { @@ -45,55 +44,174 @@ static void PrintString(const Proto* tf, int n) putchar('"'); } -static void PrintLocal(const Proto* tf, int n, int pc) +static void PrintConstant(const Proto* f, int i) { - const char* s=luaF_getlocalname(tf,n+1,pc); - printf("%u",n); - if (s!=NULL) printf("\t; %s",s); + const TObject* o=&f->k[i]; + switch (ttype(o)) + { + case LUA_TNUMBER: + printf(LUA_NUMBER_FMT,nvalue(o)); + break; + case LUA_TSTRING: + PrintString(f,i); + break; + case LUA_TNIL: + printf("nil"); + break; + default: /* cannot happen */ + printf("? type=%d",ttype(o)); + break; + } } -static void PrintCode(const Proto* tf) +static void PrintCode(const Proto* f) { - const Instruction* code=tf->code; - const Instruction* p=code; - for (;;) + const Instruction* code=f->code; + int pc,n=f->sizecode; + for (pc=0; pclineinfo,at-1,1,NULL); - printf("%6d\t",at); - if (line>=0) printf("[%d]\t",line); else printf("[-]\t"); - switch (GET_OPCODE(i)) { -#include "print.h" + Instruction i=code[pc]; + OpCode o=GET_OPCODE(i); + int a=GETARG_A(i); + int b=GETARG_B(i); + int c=GETARG_C(i); + int bc=GETARG_Bx(i); + int sbc=GETARG_sBx(i); + int line=getline(f,pc); +#if 0 + printf("%0*lX",Sizeof(i)*2,i); +#endif + printf("\t%d\t",pc+1); + if (line>0) printf("[%d]\t",line); else printf("[-]\t"); + printf("%-9s\t",luaP_opnames[o]); + switch (getOpMode(o)) + { + case iABC: printf("%d %d %d",a,b,c); break; + case iABx: printf("%d %d",a,bc); break; + case iAsBx: printf("%d %d",a,sbc); break; + } + switch (o) + { + case OP_LOADK: + printf("\t; "); PrintConstant(f,bc); + break; + case OP_GETUPVAL: + case OP_SETUPVAL: + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); + break; + case OP_GETGLOBAL: + case OP_SETGLOBAL: + printf("\t; %s",svalue(&f->k[bc])); + break; + case OP_GETTABLE: + case OP_SELF: + if (c>=MAXSTACK) { printf("\t; "); PrintConstant(f,c-MAXSTACK); } + break; + case OP_SETTABLE: + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_POW: + case OP_EQ: + case OP_LT: + case OP_LE: + if (b>=MAXSTACK || c>=MAXSTACK) + { + printf("\t; "); + if (b>=MAXSTACK) PrintConstant(f,b-MAXSTACK); else printf("-"); + printf(" "); + if (c>=MAXSTACK) PrintConstant(f,c-MAXSTACK); + } + break; + case OP_JMP: + case OP_FORLOOP: + case OP_TFORPREP: + printf("\t; to %d",sbc+pc+2); + break; + case OP_CLOSURE: + printf("\t; %p",VOID(f->p[bc])); + break; + default: + break; } printf("\n"); - if (i==OP_END) break; - p++; } } -#define IsMain(tf) (tf->lineDefined==0) +static const char* Source(const Proto* f) +{ + const char* s=getstr(f->source); + if (*s=='@' || *s=='=') + return s+1; + else if (*s==LUA_SIGNATURE[0]) + return "(bstring)"; + else + return "(string)"; +} + +#define IsMain(f) (f->lineDefined==0) #define SS(x) (x==1)?"":"s" #define S(x) x,SS(x) -static void PrintHeader(const Proto* tf) +static void PrintHeader(const Proto* f) +{ + printf("\n%s <%s:%d> (%d instruction%s, %d bytes at %p)\n", + IsMain(f)?"main":"function",Source(f),f->lineDefined, + S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); + printf("%d%s param%s, %d stack%s, %d upvalue%s, ", + f->numparams,f->is_vararg?"+":"",SS(f->numparams),S(f->maxstacksize), + S(f->nups)); + printf("%d local%s, %d constant%s, %d function%s\n", + S(f->sizelocvars),S(f->sizek),S(f->sizep)); +} + +#ifdef DEBUG_PRINT +static void PrintConstants(const Proto* f) +{ + int i,n=f->sizek; + printf("constants (%d) for %p:\n",n,VOID(f)); + for (i=0; incode),tf->ncode*Sizeof(Instruction),tf); - printf("%d%s param%s, %d stack%s, ", - tf->numparams,tf->is_vararg?"+":"",SS(tf->numparams),S(tf->maxstacksize)); - printf("%d local%s, %d string%s, %d number%s, %d function%s, %d line%s\n", - S(tf->nlocvars),S(tf->nkstr),S(tf->nknum),S(tf->nkproto),S(tf->nlineinfo)); + int i,n=f->sizelocvars; + printf("locals (%d) for %p:\n",n,VOID(f)); + for (i=0; ilocvars[i].varname),f->locvars[i].startpc,f->locvars[i].endpc); + } } -#define PrintFunction luaU_printchunk +static void PrintUpvalues(const Proto* f) +{ + int i,n=f->sizeupvalues; + printf("upvalues (%d) for %p:\n",n,VOID(f)); + if (f->upvalues==NULL) return; + for (i=0; iupvalues[i])); + } +} +#endif -void PrintFunction(const Proto* tf) +void luaU_print(const Proto* f) { - int i,n=tf->nkproto; - PrintHeader(tf); - PrintCode(tf); - for (i=0; ikproto[i]); + int i,n=f->sizep; + PrintHeader(f); + PrintCode(f); +#ifdef DEBUG_PRINT + PrintConstants(f); + PrintLocals(f); + PrintUpvalues(f); +#endif + for (i=0; ip[i]); } diff --git a/src/luac/print.h b/src/luac/print.h deleted file mode 100644 index 5f74e14959..0000000000 --- a/src/luac/print.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -** $Id: print.h,v 1.1 2000/11/06 20:03:12 lhf Exp $ -** extracted automatically from lopcodes.h by mkprint.lua -- DO NOT EDIT -** See Copyright Notice in lua.h -*/ - - case OP_END: P_OP("END"); P_NONE; break; - case OP_RETURN: P_OP("RETURN"); P_U; break; - case OP_CALL: P_OP("CALL"); P_AB; break; - case OP_TAILCALL: P_OP("TAILCALL"); P_AB; break; - case OP_PUSHNIL: P_OP("PUSHNIL"); P_U; break; - case OP_POP: P_OP("POP"); P_U; break; - case OP_PUSHINT: P_OP("PUSHINT"); P_S; break; - case OP_PUSHSTRING: P_OP("PUSHSTRING"); P_Q; break; - case OP_PUSHNUM: P_OP("PUSHNUM"); P_N; break; - case OP_PUSHNEGNUM: P_OP("PUSHNEGNUM"); P_N; break; - case OP_PUSHUPVALUE: P_OP("PUSHUPVALUE"); P_U; break; - case OP_GETLOCAL: P_OP("GETLOCAL"); P_L; break; - case OP_GETGLOBAL: P_OP("GETGLOBAL"); P_K; break; - case OP_GETTABLE: P_OP("GETTABLE"); P_NONE; break; - case OP_GETDOTTED: P_OP("GETDOTTED"); P_K; break; - case OP_GETINDEXED: P_OP("GETINDEXED"); P_L; break; - case OP_PUSHSELF: P_OP("PUSHSELF"); P_K; break; - case OP_CREATETABLE: P_OP("CREATETABLE"); P_U; break; - case OP_SETLOCAL: P_OP("SETLOCAL"); P_L; break; - case OP_SETGLOBAL: P_OP("SETGLOBAL"); P_K; break; - case OP_SETTABLE: P_OP("SETTABLE"); P_AB; break; - case OP_SETLIST: P_OP("SETLIST"); P_AB; break; - case OP_SETMAP: P_OP("SETMAP"); P_U; break; - case OP_ADD: P_OP("ADD"); P_NONE; break; - case OP_ADDI: P_OP("ADDI"); P_S; break; - case OP_SUB: P_OP("SUB"); P_NONE; break; - case OP_MULT: P_OP("MULT"); P_NONE; break; - case OP_DIV: P_OP("DIV"); P_NONE; break; - case OP_POW: P_OP("POW"); P_NONE; break; - case OP_CONCAT: P_OP("CONCAT"); P_U; break; - case OP_MINUS: P_OP("MINUS"); P_NONE; break; - case OP_NOT: P_OP("NOT"); P_NONE; break; - case OP_JMPNE: P_OP("JMPNE"); P_J; break; - case OP_JMPEQ: P_OP("JMPEQ"); P_J; break; - case OP_JMPLT: P_OP("JMPLT"); P_J; break; - case OP_JMPLE: P_OP("JMPLE"); P_J; break; - case OP_JMPGT: P_OP("JMPGT"); P_J; break; - case OP_JMPGE: P_OP("JMPGE"); P_J; break; - case OP_JMPT: P_OP("JMPT"); P_J; break; - case OP_JMPF: P_OP("JMPF"); P_J; break; - case OP_JMPONT: P_OP("JMPONT"); P_J; break; - case OP_JMPONF: P_OP("JMPONF"); P_J; break; - case OP_JMP: P_OP("JMP"); P_J; break; - case OP_PUSHNILJMP: P_OP("PUSHNILJMP"); P_NONE; break; - case OP_FORPREP: P_OP("FORPREP"); P_J; break; - case OP_FORLOOP: P_OP("FORLOOP"); P_J; break; - case OP_LFORPREP: P_OP("LFORPREP"); P_J; break; - case OP_LFORLOOP: P_OP("LFORLOOP"); P_J; break; - case OP_CLOSURE: P_OP("CLOSURE"); P_F; break; diff --git a/src/luac/stubs.c b/src/luac/stubs.c deleted file mode 100644 index 74f509eb26..0000000000 --- a/src/luac/stubs.c +++ /dev/null @@ -1,127 +0,0 @@ -/* -** $Id: stubs.c,v 1.20 2000/10/31 16:57:23 lhf Exp $ -** avoid runtime modules in luac -** See Copyright Notice in lua.h -*/ - -#include -#include - -#include "ldo.h" -#include "llex.h" -#include "luac.h" -#undef L - -#ifndef NOSTUBS - -const char luac_ident[] = "$luac: " LUA_VERSION " " LUA_COPYRIGHT " $\n" - "$Authors: " LUA_AUTHORS " $"; - -/* -* avoid lapi ldebug ldo lgc lstate ltm lvm -* use only lcode lfunc llex lmem lobject lparser lstring ltable lzio -*/ - -/* simplified from ldo.c */ -void lua_error (lua_State* L, const char* s) { - UNUSED(L); - if (s) fprintf(stderr,"luac: %s\n",s); - exit(1); -} - -/* simplified from ldo.c */ -void luaD_breakrun (lua_State *L, int errcode) { - UNUSED(errcode); - lua_error(L,"memory allocation error"); -} - -/* simplified from lstate.c */ -lua_State *lua_open (int stacksize) { - lua_State *L = luaM_new(NULL, lua_State); - if (L == NULL) return NULL; /* memory allocation error */ - L->stack = NULL; - L->strt.size = L->udt.size = 0; - L->strt.nuse = L->udt.nuse = 0; - L->strt.hash = NULL; - L->udt.hash = NULL; - L->Mbuffer = NULL; - L->Mbuffsize = 0; - L->rootproto = NULL; - L->rootcl = NULL; - L->roottable = NULL; - L->TMtable = NULL; - L->last_tag = -1; - L->refArray = NULL; - L->refSize = 0; - L->refFree = NONEXT; - L->nblocks = sizeof(lua_State); - L->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */ - L->callhook = NULL; - L->linehook = NULL; - L->allowhooks = 1; - L->errorJmp = NULL; - if (stacksize == 0) - stacksize = DEFAULT_STACK_SIZE; - else - stacksize += LUA_MINSTACK; - L->gt = luaH_new(L, 10); /* table of globals */ - luaS_init(L); - luaX_init(L); - L->GCthreshold = 2*L->nblocks; - return L; -} - -/* copied from ldebug.c */ -int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) { - int refi; - if (lineinfo == NULL || pc == -1) - return -1; /* no line info or function is not active */ - refi = prefi ? *prefi : 0; - if (lineinfo[refi] < 0) - refline += -lineinfo[refi++]; - LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); - while (lineinfo[refi] > pc) { - refline--; - refi--; - if (lineinfo[refi] < 0) - refline -= -lineinfo[refi--]; - LUA_ASSERT(lineinfo[refi] >= 0, "invalid line info"); - } - for (;;) { - int nextline = refline + 1; - int nextref = refi + 1; - if (lineinfo[nextref] < 0) - nextline += -lineinfo[nextref++]; - LUA_ASSERT(lineinfo[nextref] >= 0, "invalid line info"); - if (lineinfo[nextref] > pc) - break; - refline = nextline; - refi = nextref; - } - if (prefi) *prefi = refi; - return refline; -} - -/* -* the code below avoids the lexer and the parser (llex lparser lcode). -* it is useful if you only want to load binary files. -* this works for interpreters like lua.c too. -*/ - -#ifdef NOPARSER - -#include "llex.h" -#include "lparser.h" - -void luaX_init(lua_State *L) { - UNUSED(L); -} - -Proto *luaY_parser(lua_State *L, ZIO *z) { - UNUSED(z); - lua_error(L,"parser not loaded"); - return NULL; -} - -#endif -#endif diff --git a/src/lundump.c b/src/lundump.c index a8d0610675..151a8507cc 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,243 +1,285 @@ /* -** $Id: lundump.c,v 1.33 2000/10/31 16:57:23 lhf Exp $ -** load bytecodes from files +** $Id: lundump.c,v 1.49 2003/04/07 20:34:20 lhf Exp $ +** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ -#include -#include +#define lundump_c +#include "lua.h" + +#include "ldebug.h" #include "lfunc.h" #include "lmem.h" #include "lopcodes.h" #include "lstring.h" #include "lundump.h" +#include "lzio.h" -#define LoadByte ezgetc +#define LoadByte (lu_byte) ezgetc -static const char* ZNAME (ZIO* Z) -{ - const char* s=zname(Z); - return (*s=='@') ? s+1 : s; -} +typedef struct { + lua_State* L; + ZIO* Z; + Mbuffer* b; + int swap; + const char* name; +} LoadState; -static void unexpectedEOZ (lua_State* L, ZIO* Z) +static void unexpectedEOZ (LoadState* S) { - luaO_verror(L,"unexpected end of file in `%.99s'",ZNAME(Z)); + luaG_runerror(S->L,"unexpected end of file in %s",S->name); } -static int ezgetc (lua_State* L, ZIO* Z) +static int ezgetc (LoadState* S) { - int c=zgetc(Z); - if (c==EOZ) unexpectedEOZ(L,Z); + int c=zgetc(S->Z); + if (c==EOZ) unexpectedEOZ(S); return c; } -static void ezread (lua_State* L, ZIO* Z, void* b, int n) +static void ezread (LoadState* S, void* b, int n) { - int r=zread(Z,b,n); - if (r!=0) unexpectedEOZ(L,Z); + int r=luaZ_read(S->Z,b,n); + if (r!=0) unexpectedEOZ(S); } -static void LoadBlock (lua_State* L, void* b, size_t size, ZIO* Z, int swap) +static void LoadBlock (LoadState* S, void* b, size_t size) { - if (swap) + if (S->swap) { - char *p=(char *) b+size-1; + char* p=(char*) b+size-1; int n=size; - while (n--) *p--=(char)ezgetc(L,Z); + while (n--) *p--=(char)ezgetc(S); } else - ezread(L,Z,b,size); + ezread(S,b,size); } -static void LoadVector (lua_State* L, void* b, int m, size_t size, ZIO* Z, int swap) +static void LoadVector (LoadState* S, void* b, int m, size_t size) { - if (swap) + if (S->swap) { - char *q=(char *) b; + char* q=(char*) b; while (m--) { - char *p=q+size-1; + char* p=q+size-1; int n=size; - while (n--) *p--=(char)ezgetc(L,Z); + while (n--) *p--=(char)ezgetc(S); q+=size; } } else - ezread(L,Z,b,m*size); + ezread(S,b,m*size); } -static int LoadInt (lua_State* L, ZIO* Z, int swap) +static int LoadInt (LoadState* S) { int x; - LoadBlock(L,&x,sizeof(x),Z,swap); + LoadBlock(S,&x,sizeof(x)); + if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name); return x; } -static size_t LoadSize (lua_State* L, ZIO* Z, int swap) +static size_t LoadSize (LoadState* S) { size_t x; - LoadBlock(L,&x,sizeof(x),Z,swap); + LoadBlock(S,&x,sizeof(x)); return x; } -static Number LoadNumber (lua_State* L, ZIO* Z, int swap) +static lua_Number LoadNumber (LoadState* S) { - Number x; - LoadBlock(L,&x,sizeof(x),Z,swap); + lua_Number x; + LoadBlock(S,&x,sizeof(x)); return x; } -static TString* LoadString (lua_State* L, ZIO* Z, int swap) +static TString* LoadString (LoadState* S) { - size_t size=LoadSize(L,Z,swap); + size_t size=LoadSize(S); if (size==0) return NULL; else { - char* s=luaO_openspace(L,size); - LoadBlock(L,s,size,Z,0); - return luaS_newlstr(L,s,size-1); /* remove trailing '\0' */ + char* s=luaZ_openspace(S->L,S->b,size); + ezread(S,s,size); + return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ } } -static void LoadCode (lua_State* L, Proto* tf, ZIO* Z, int swap) +static void LoadCode (LoadState* S, Proto* f) { - int size=LoadInt(L,Z,swap); - tf->code=luaM_newvector(L,size,Instruction); - LoadVector(L,tf->code,size,sizeof(*tf->code),Z,swap); - if (tf->code[size-1]!=OP_END) luaO_verror(L,"bad code in `%.99s'",ZNAME(Z)); - luaF_protook(L,tf,size); + int size=LoadInt(S); + f->code=luaM_newvector(S->L,size,Instruction); + f->sizecode=size; + LoadVector(S,f->code,size,sizeof(*f->code)); } -static void LoadLocals (lua_State* L, Proto* tf, ZIO* Z, int swap) +static void LoadLocals (LoadState* S, Proto* f) { int i,n; - tf->nlocvars=n=LoadInt(L,Z,swap); - tf->locvars=luaM_newvector(L,n,LocVar); + n=LoadInt(S); + f->locvars=luaM_newvector(S->L,n,LocVar); + f->sizelocvars=n; for (i=0; ilocvars[i].varname=LoadString(L,Z,swap); - tf->locvars[i].startpc=LoadInt(L,Z,swap); - tf->locvars[i].endpc=LoadInt(L,Z,swap); + f->locvars[i].varname=LoadString(S); + f->locvars[i].startpc=LoadInt(S); + f->locvars[i].endpc=LoadInt(S); } } -static void LoadLines (lua_State* L, Proto* tf, ZIO* Z, int swap) +static void LoadLines (LoadState* S, Proto* f) { - int n; - tf->nlineinfo=n=LoadInt(L,Z,swap); - tf->lineinfo=luaM_newvector(L,n,int); - LoadVector(L,tf->lineinfo,n,sizeof(*tf->lineinfo),Z,swap); + int size=LoadInt(S); + f->lineinfo=luaM_newvector(S->L,size,int); + f->sizelineinfo=size; + LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo)); } -static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap); +static void LoadUpvalues (LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + if (n!=0 && n!=f->nups) + luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d", + S->name,n,f->nups); + f->upvalues=luaM_newvector(S->L,n,TString*); + f->sizeupvalues=n; + for (i=0; iupvalues[i]=LoadString(S); +} -static void LoadConstants (lua_State* L, Proto* tf, ZIO* Z, int swap) +static Proto* LoadFunction (LoadState* S, TString* p); + +static void LoadConstants (LoadState* S, Proto* f) { int i,n; - tf->nkstr=n=LoadInt(L,Z,swap); - tf->kstr=luaM_newvector(L,n,TString*); - for (i=0; ikstr[i]=LoadString(L,Z,swap); - tf->nknum=n=LoadInt(L,Z,swap); - tf->knum=luaM_newvector(L,n,Number); - LoadVector(L,tf->knum,n,sizeof(*tf->knum),Z,swap); - tf->nkproto=n=LoadInt(L,Z,swap); - tf->kproto=luaM_newvector(L,n,Proto*); + n=LoadInt(S); + f->k=luaM_newvector(S->L,n,TObject); + f->sizek=n; for (i=0; ikproto[i]=LoadFunction(L,Z,swap); + { + TObject* o=&f->k[i]; + int t=LoadByte(S); + switch (t) + { + case LUA_TNUMBER: + setnvalue(o,LoadNumber(S)); + break; + case LUA_TSTRING: + setsvalue2n(o,LoadString(S)); + break; + case LUA_TNIL: + setnilvalue(o); + break; + default: + luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name); + break; + } + } + n=LoadInt(S); + f->p=luaM_newvector(S->L,n,Proto*); + f->sizep=n; + for (i=0; ip[i]=LoadFunction(S,f->source); } -static Proto* LoadFunction (lua_State* L, ZIO* Z, int swap) +static Proto* LoadFunction (LoadState* S, TString* p) { - Proto* tf=luaF_newproto(L); - tf->source=LoadString(L,Z,swap); - tf->lineDefined=LoadInt(L,Z,swap); - tf->numparams=LoadInt(L,Z,swap); - tf->is_vararg=LoadByte(L,Z); - tf->maxstacksize=LoadInt(L,Z,swap); - LoadLocals(L,tf,Z,swap); - LoadLines(L,tf,Z,swap); - LoadConstants(L,tf,Z,swap); - LoadCode(L,tf,Z,swap); - return tf; + Proto* f=luaF_newproto(S->L); + f->source=LoadString(S); if (f->source==NULL) f->source=p; + f->lineDefined=LoadInt(S); + f->nups=LoadByte(S); + f->numparams=LoadByte(S); + f->is_vararg=LoadByte(S); + f->maxstacksize=LoadByte(S); + LoadLines(S,f); + LoadLocals(S,f); + LoadUpvalues(S,f); + LoadConstants(S,f); + LoadCode(S,f); +#ifndef TRUST_BINARIES + if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name); +#endif + return f; } -static void LoadSignature (lua_State* L, ZIO* Z) +static void LoadSignature (LoadState* S) { - const char* s=SIGNATURE; - while (*s!=0 && ezgetc(L,Z)==*s) + const char* s=LUA_SIGNATURE; + while (*s!=0 && ezgetc(S)==*s) ++s; - if (*s!=0) luaO_verror(L,"bad signature in `%.99s'",ZNAME(Z)); + if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name); } -static void TestSize (lua_State* L, int s, const char* what, ZIO* Z) +static void TestSize (LoadState* S, int s, const char* what) { - int r=ezgetc(L,Z); + int r=LoadByte(S); if (r!=s) - luaO_verror(L,"virtual machine mismatch in `%.99s':\n" - " %.20s is %d but read %d",ZNAME(Z),what,s,r); + luaG_runerror(S->L,"virtual machine mismatch in %s: " + "size of %s is %d but read %d",S->name,what,s,r); } -#define TESTSIZE(s) TestSize(L,s,#s,Z) -#define V(v) v/16,v%16 +#define TESTSIZE(s,w) TestSize(S,s,w) +#define V(v) v/16,v%16 -static int LoadHeader (lua_State* L, ZIO* Z) +static void LoadHeader (LoadState* S) { - int version,swap; - Number f=0,tf=TEST_NUMBER; - LoadSignature(L,Z); - version=ezgetc(L,Z); + int version; + lua_Number x,tx=TEST_NUMBER; + LoadSignature(S); + version=LoadByte(S); if (version>VERSION) - luaO_verror(L,"`%.99s' too new:\n" - " read version %d.%d; expected at most %d.%d", - ZNAME(Z),V(version),V(VERSION)); - if (versionL,"%s too new: " + "read version %d.%d; expected at most %d.%d", + S->name,V(version),V(VERSION)); + if (versionL,"%s too old: " + "read version %d.%d; expected at least %d.%d", + S->name,V(version),V(VERSION0)); + S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */ + TESTSIZE(sizeof(int),"int"); + TESTSIZE(sizeof(size_t), "size_t"); + TESTSIZE(sizeof(Instruction), "Instruction"); + TESTSIZE(SIZE_OP, "OP"); + TESTSIZE(SIZE_A, "A"); + TESTSIZE(SIZE_B, "B"); + TESTSIZE(SIZE_C, "C"); + TESTSIZE(sizeof(lua_Number), "number"); + x=LoadNumber(S); + if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */ + luaG_runerror(S->L,"unknown number format in %s",S->name); +} + +static Proto* LoadChunk (LoadState* S) +{ + LoadHeader(S); + return LoadFunction(S,NULL); } /* -** load one chunk from a file or buffer -** return main if ok and NULL at EOF +** load precompiled chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z) +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff) { - Proto* tf=NULL; - int c=zgetc(Z); - if (c==ID_CHUNK) - tf=LoadChunk(L,Z); - c=zgetc(Z); - if (c!=EOZ) - luaO_verror(L,"`%.99s' apparently contains more than one chunk",ZNAME(Z)); - return tf; + LoadState S; + const char* s=zname(Z); + if (*s=='@' || *s=='=') + S.name=s+1; + else if (*s==LUA_SIGNATURE[0]) + S.name="binary string"; + else + S.name=s; + S.L=L; + S.Z=Z; + S.b=buff; + return LoadChunk(&S); } /* ** find byte order */ -int luaU_endianess (void) +int luaU_endianness (void) { int x=1; return *(char*)&x; diff --git a/src/lundump.h b/src/lundump.h index 446d2de9c3..c7e6959b30 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.21 2000/10/31 16:57:23 lhf Exp $ +** $Id: lundump.h,v 1.30 2003/04/07 20:34:20 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -10,26 +10,25 @@ #include "lobject.h" #include "lzio.h" -/* load one chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z); +/* load one chunk; from lundump.c */ +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff); -/* find byte order */ -int luaU_endianess (void); +/* find byte order; from lundump.c */ +int luaU_endianness (void); -/* definitions for headers of binary files */ -#define VERSION 0x40 /* last format change was in 4.0 */ -#define VERSION0 0x40 /* last major change was in 4.0 */ -#define ID_CHUNK 27 /* binary files start with ESC... */ -#define SIGNATURE "Lua" /* ...followed by this signature */ +/* dump one chunk; from ldump.c */ +void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data); + +/* print one chunk; from print.c */ +void luaU_print (const Proto* Main); -/* formats for error messages */ -#define SOURCE_FMT "<%d:%.99s>" -#define SOURCE tf->lineDefined,tf->source->str -#define IN_FMT " in %p " SOURCE_FMT -#define IN tf,SOURCE +/* definitions for headers of binary files */ +#define LUA_SIGNATURE "\033Lua" /* binary files start with "Lua" */ +#define VERSION 0x50 /* last format change was in 5.0 */ +#define VERSION0 0x50 /* last major change was in 5.0 */ /* a multiple of PI for testing native format */ -/* multiplying by 1E8 gives non-trivial integer values */ -#define TEST_NUMBER 3.14159265358979323846E8 +/* multiplying by 1E7 gives non-trivial integer values */ +#define TEST_NUMBER ((lua_Number)3.14159265358979323846E7) #endif diff --git a/src/lvm.c b/src/lvm.c index 2a00b6a532..eaa5c700b0 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,17 +1,21 @@ /* -** $Id: lvm.c,v 1.146a 2000/10/26 12:47:05 roberto Exp $ +** $Id: lvm.c,v 1.284 2003/04/03 13:35:34 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ -#include +#include #include #include +/* needed only when `lua_number2str' uses `sprintf' */ +#include + +#define lvm_c + #include "lua.h" -#include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -25,243 +29,225 @@ #include "lvm.h" -#ifdef OLD_ANSI -#define strcoll(a,b) strcmp(a,b) -#endif - +/* function to convert a lua_Number to a string */ +#ifndef lua_number2str +#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) +#endif -/* -** Extra stack size to run a function: -** TAG_LINE(1), NAME(1), TM calls(3) (plus some extra...) -*/ -#define EXTRA_STACK 8 +/* limit for table tag-method chains (to avoid loops) */ +#define MAXTAGLOOP 100 -int luaV_tonumber (TObject *obj) { - if (ttype(obj) != LUA_TSTRING) - return 1; - else { - if (!luaO_str2d(svalue(obj), &nvalue(obj))) - return 2; - ttype(obj) = LUA_TNUMBER; - return 0; +const TObject *luaV_tonumber (const TObject *obj, TObject *n) { + lua_Number num; + if (ttisnumber(obj)) return obj; + if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { + setnvalue(n, num); + return n; } + else + return NULL; } -int luaV_tostring (lua_State *L, TObject *obj) { /* LUA_NUMBER */ - if (ttype(obj) != LUA_TNUMBER) - return 1; +int luaV_tostring (lua_State *L, StkId obj) { + if (!ttisnumber(obj)) + return 0; else { char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ - lua_number2str(s, nvalue(obj)); /* convert `s' to number */ - tsvalue(obj) = luaS_new(L, s); - ttype(obj) = LUA_TSTRING; - return 0; + lua_number2str(s, nvalue(obj)); + setsvalue2s(obj, luaS_new(L, s)); + return 1; } } -static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) { - CallInfo *ci = infovalue(base-1); - int *lineinfo = ci->func->f.l->lineinfo; - int pc = (*ci->pc - ci->func->f.l->code) - 1; - int newline; - if (pc == 0) { /* may be first time? */ - ci->line = 1; - ci->refi = 0; - ci->lastpc = pc+1; /* make sure it will call linehook */ +static void traceexec (lua_State *L) { + lu_byte mask = L->hookmask; + if (mask > LUA_MASKLINE) { /* instruction-hook set? */ + if (L->hookcount == 0) { + resethookcount(L); + luaD_callhook(L, LUA_HOOKCOUNT, -1); + return; + } } - newline = luaG_getline(lineinfo, pc, ci->line, &ci->refi); - /* calls linehook when enters a new line or jumps back (loop) */ - if (newline != ci->line || pc <= ci->lastpc) { - ci->line = newline; - L->top = top; - luaD_lineHook(L, base-1, newline, linehook); + if (mask & LUA_MASKLINE) { + CallInfo *ci = L->ci; + Proto *p = ci_func(ci)->l.p; + int newline = getline(p, pcRel(*ci->u.l.pc, p)); + if (!L->hookinit) { + luaG_inithooks(L); + return; + } + lua_assert(ci->state & CI_HASFRAME); + if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */ + ci->u.l.savedpc = *ci->u.l.pc; /* initialize `savedpc' */ + /* calls linehook when enters a new line or jumps back (loop) */ + if (*ci->u.l.pc <= ci->u.l.savedpc || + newline != getline(p, pcRel(ci->u.l.savedpc, p))) { + luaD_callhook(L, LUA_HOOKLINE, newline); + ci = L->ci; /* previous call may reallocate `ci' */ + } + ci->u.l.savedpc = *ci->u.l.pc; } - ci->lastpc = pc; } -static Closure *luaV_closure (lua_State *L, int nelems) { - Closure *c = luaF_newclosure(L, nelems); - L->top -= nelems; - while (nelems--) - c->upvalue[nelems] = *(L->top+nelems); - clvalue(L->top) = c; - ttype(L->top) = LUA_TFUNCTION; - incr_top; - return c; +static void callTMres (lua_State *L, const TObject *f, + const TObject *p1, const TObject *p2) { + setobj2s(L->top, f); /* push function */ + setobj2s(L->top+1, p1); /* 1st argument */ + setobj2s(L->top+2, p2); /* 2nd argument */ + luaD_checkstack(L, 3); /* cannot check before (could invalidate p1, p2) */ + L->top += 3; + luaD_call(L, L->top - 3, 1); + L->top--; /* result will be in L->top */ } -void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems) { - Closure *cl = luaV_closure(L, nelems); - cl->f.c = c; - cl->isC = 1; + +static void callTM (lua_State *L, const TObject *f, + const TObject *p1, const TObject *p2, const TObject *p3) { + setobj2s(L->top, f); /* push function */ + setobj2s(L->top+1, p1); /* 1st argument */ + setobj2s(L->top+2, p2); /* 2nd argument */ + setobj2s(L->top+3, p3); /* 3th argument */ + luaD_checkstack(L, 4); /* cannot check before (could invalidate p1...p3) */ + L->top += 4; + luaD_call(L, L->top - 4, 0); } -void luaV_Lclosure (lua_State *L, Proto *l, int nelems) { - Closure *cl = luaV_closure(L, nelems); - cl->f.l = l; - cl->isC = 0; +static const TObject *luaV_index (lua_State *L, const TObject *t, + TObject *key, int loop) { + const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); + if (tm == NULL) return &luaO_nilobject; /* no TM */ + if (ttisfunction(tm)) { + callTMres(L, tm, t, key); + return L->top; + } + else return luaV_gettable(L, tm, key, loop); +} + +static const TObject *luaV_getnotable (lua_State *L, const TObject *t, + TObject *key, int loop) { + const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (ttisnil(tm)) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + callTMres(L, tm, t, key); + return L->top; + } + else return luaV_gettable(L, tm, key, loop); } /* ** Function to index a table. -** Receives the table at `t' and the key at top. +** Receives the table at `t' and the key at `key'. +** leaves the result at `res'. */ -const TObject *luaV_gettable (lua_State *L, StkId t) { - Closure *tm; - int tg; - if (ttype(t) == LUA_TTABLE && /* `t' is a table? */ - ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */ - luaT_gettm(L, tg, TM_GETTABLE) == NULL)) { /* or no TM? */ - /* do a primitive get */ - const TObject *h = luaH_get(L, hvalue(t), L->top-1); - /* result is no nil or there is no `index' tag method? */ - if (ttype(h) != LUA_TNIL || ((tm=luaT_gettm(L, tg, TM_INDEX)) == NULL)) - return h; /* return result */ - /* else call `index' tag method */ - } - else { /* try a `gettable' tag method */ - tm = luaT_gettmbyObj(L, t, TM_GETTABLE); - } - if (tm != NULL) { /* is there a tag method? */ - luaD_checkstack(L, 2); - *(L->top+1) = *(L->top-1); /* key */ - *L->top = *t; /* table */ - clvalue(L->top-1) = tm; /* tag method */ - ttype(L->top-1) = LUA_TFUNCTION; - L->top += 2; - luaD_call(L, L->top - 3, 1); - return L->top - 1; /* call result */ - } - else { /* no tag method */ - luaG_typeerror(L, t, "index"); - return NULL; /* to avoid warnings */ +const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, + int loop) { + if (loop > MAXTAGLOOP) + luaG_runerror(L, "loop in gettable"); + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + const TObject *v = luaH_get(h, key); /* do a primitive get */ + if (!ttisnil(v)) return v; + else return luaV_index(L, t, key, loop+1); } + else return luaV_getnotable(L, t, key, loop+1); } /* -** Receives table at `t', key at `key' and value at top. +** Receives table at `t', key at `key' and value at `val'. */ -void luaV_settable (lua_State *L, StkId t, StkId key) { - int tg; - if (ttype(t) == LUA_TTABLE && /* `t' is a table? */ - ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */ - luaT_gettm(L, tg, TM_SETTABLE) == NULL)) /* or no TM? */ - *luaH_set(L, hvalue(t), key) = *(L->top-1); /* do a primitive set */ - else { /* try a `settable' tag method */ - Closure *tm = luaT_gettmbyObj(L, t, TM_SETTABLE); - if (tm != NULL) { - luaD_checkstack(L, 3); - *(L->top+2) = *(L->top-1); - *(L->top+1) = *key; - *(L->top) = *t; - clvalue(L->top-1) = tm; - ttype(L->top-1) = LUA_TFUNCTION; - L->top += 3; - luaD_call(L, L->top - 4, 0); /* call `settable' tag method */ +void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { + const TObject *tm; + int loop = 0; + do { + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ + if (!ttisnil(oldval) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ + setobj2t(oldval, val); /* write barrier */ + return; + } + /* else will try the tag method */ } - else /* no tag method... */ + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); - } -} - - -const TObject *luaV_getglobal (lua_State *L, TString *s) { - const TObject *value = luaH_getstr(L->gt, s); - Closure *tm = luaT_gettmbyObj(L, value, TM_GETGLOBAL); - if (tm == NULL) /* is there a tag method? */ - return value; /* default behavior */ - else { /* tag method */ - luaD_checkstack(L, 3); - clvalue(L->top) = tm; - ttype(L->top) = LUA_TFUNCTION; - tsvalue(L->top+1) = s; /* global name */ - ttype(L->top+1) = LUA_TSTRING; - *(L->top+2) = *value; - L->top += 3; - luaD_call(L, L->top - 3, 1); - return L->top - 1; - } + if (ttisfunction(tm)) { + callTM(L, tm, t, key, val); + return; + } + t = tm; /* else repeat with `tm' */ + } while (++loop <= MAXTAGLOOP); + luaG_runerror(L, "loop in settable"); } -void luaV_setglobal (lua_State *L, TString *s) { - const TObject *oldvalue = luaH_getstr(L->gt, s); - Closure *tm = luaT_gettmbyObj(L, oldvalue, TM_SETGLOBAL); - if (tm == NULL) { /* is there a tag method? */ - if (oldvalue != &luaO_nilobject) { - /* cast to remove `const' is OK, because `oldvalue' != luaO_nilobject */ - *(TObject *)oldvalue = *(L->top - 1); - } - else { - TObject key; - ttype(&key) = LUA_TSTRING; - tsvalue(&key) = s; - *luaH_set(L, L->gt, &key) = *(L->top - 1); - } - } - else { - luaD_checkstack(L, 3); - *(L->top+2) = *(L->top-1); /* new value */ - *(L->top+1) = *oldvalue; - ttype(L->top) = LUA_TSTRING; - tsvalue(L->top) = s; - clvalue(L->top-1) = tm; - ttype(L->top-1) = LUA_TFUNCTION; - L->top += 3; - luaD_call(L, L->top - 4, 0); - } +static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, + StkId res, TMS event) { + ptrdiff_t result = savestack(L, res); + const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (!ttisfunction(tm)) return 0; + callTMres(L, tm, p1, p2); + res = restorestack(L, result); /* previous call may change stack */ + setobjs2s(res, L->top); + return 1; } -static int call_binTM (lua_State *L, StkId top, TMS event) { - /* try first operand */ - Closure *tm = luaT_gettmbyObj(L, top-2, event); - L->top = top; - if (tm == NULL) { - tm = luaT_gettmbyObj(L, top-1, event); /* try second operand */ - if (tm == NULL) { - tm = luaT_gettm(L, 0, event); /* try a `global' method */ - if (tm == NULL) - return 0; /* error */ - } - } - lua_pushstring(L, luaT_eventname[event]); - luaD_callTM(L, tm, 3, 1); - return 1; +static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, + TMS event) { + const TObject *tm1 = fasttm(L, mt1, event); + const TObject *tm2; + if (tm1 == NULL) return NULL; /* no metamethod */ + if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ + tm2 = fasttm(L, mt2, event); + if (tm2 == NULL) return NULL; /* no metamethod */ + if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ + return tm1; + return NULL; } -static void call_arith (lua_State *L, StkId top, TMS event) { - if (!call_binTM(L, top, event)) - luaG_binerror(L, top-2, LUA_TNUMBER, "perform arithmetic on"); +static int call_orderTM (lua_State *L, const TObject *p1, const TObject *p2, + TMS event) { + const TObject *tm1 = luaT_gettmbyobj(L, p1, event); + const TObject *tm2; + if (ttisnil(tm1)) return -1; /* no metamethod? */ + tm2 = luaT_gettmbyobj(L, p2, event); + if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ + return -1; + callTMres(L, tm1, p1, p2); + return !l_isfalse(L->top); } -static int luaV_strcomp (const TString *ls, const TString *rs) { - const char *l = ls->str; - size_t ll = ls->len; - const char *r = rs->str; - size_t lr = rs->len; +static int luaV_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = ls->tsv.len; + const char *r = getstr(rs); + size_t lr = rs->tsv.len; for (;;) { int temp = strcoll(l, r); if (temp != 0) return temp; - else { /* strings are equal up to a '\0' */ - size_t len = strlen(l); /* index of first '\0' in both strings */ - if (len == ll) /* l is finished? */ - return (len == lr) ? 0 : -1; /* l is equal or smaller than r */ - else if (len == lr) /* r is finished? */ - return 1; /* l is greater than r (because l is not finished) */ - /* both strings longer than `len'; go on comparing (after the '\0') */ + else { /* strings are equal up to a `\0' */ + size_t len = strlen(l); /* index of first `\0' in both strings */ + if (len == lr) /* r is finished? */ + return (len == ll) ? 0 : 1; + else if (len == ll) /* l is finished? */ + return -1; /* l is smaller than r (because r is not finished) */ + /* both strings longer than `len'; go on comparing (after the `\0') */ len++; l += len; ll -= len; r += len; lr -= len; } @@ -269,442 +255,526 @@ static int luaV_strcomp (const TString *ls, const TString *rs) { } -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top) { - if (ttype(l) == LUA_TNUMBER && ttype(r) == LUA_TNUMBER) - return (nvalue(l) < nvalue(r)); - else if (ttype(l) == LUA_TSTRING && ttype(r) == LUA_TSTRING) - return (luaV_strcomp(tsvalue(l), tsvalue(r)) < 0); - else { /* call TM */ - luaD_checkstack(L, 2); - *top++ = *l; - *top++ = *r; - if (!call_binTM(L, top, TM_LT)) - luaG_ordererror(L, top-2); - L->top--; - return (ttype(L->top) != LUA_TNIL); +int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return nvalue(l) < nvalue(r); + else if (ttisstring(l)) + return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0; + else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) + return res; + return luaG_ordererror(L, l, r); +} + + +static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return nvalue(l) <= nvalue(r); + else if (ttisstring(l)) + return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0; + else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ + return res; + else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ + return !res; + return luaG_ordererror(L, l, r); +} + + +int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { + const TObject *tm; + lua_assert(ttype(t1) == ttype(t2)); + switch (ttype(t1)) { + case LUA_TNIL: return 1; + case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); + case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + tm = get_compTM(L, uvalue(t1)->uv.metatable, uvalue(t2)->uv.metatable, + TM_EQ); + break; /* will try TM */ + } + case LUA_TTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + break; /* will try TM */ + } + default: return gcvalue(t1) == gcvalue(t2); } + if (tm == NULL) return 0; /* no TM? */ + callTMres(L, tm, t1, t2); /* call TM */ + return !l_isfalse(L->top); } -void luaV_strconc (lua_State *L, int total, StkId top) { +void luaV_concat (lua_State *L, int total, int last) { do { + StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ - if (tostring(L, top-2) || tostring(L, top-1)) { - if (!call_binTM(L, top, TM_CONCAT)) - luaG_binerror(L, top-2, LUA_TSTRING, "concat"); - } - else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ + if (!tostring(L, top-2) || !tostring(L, top-1)) { + if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) + luaG_concaterror(L, top-2, top-1); + } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ - lint32 tl = (lint32)tsvalue(top-1)->len + - (lint32)tsvalue(top-2)->len; + lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + + cast(lu_mem, tsvalue(top-2)->tsv.len); char *buffer; int i; - while (n < total && !tostring(L, top-n-1)) { /* collect total length */ - tl += tsvalue(top-n-1)->len; + while (n < total && tostring(L, top-n-1)) { /* collect total length */ + tl += tsvalue(top-n-1)->tsv.len; n++; } - if (tl > MAX_SIZET) lua_error(L, "string size overflow"); - buffer = luaO_openspace(L, tl); + if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); + buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ - size_t l = tsvalue(top-i)->len; - memcpy(buffer+tl, tsvalue(top-i)->str, l); + size_t l = tsvalue(top-i)->tsv.len; + memcpy(buffer+tl, svalue(top-i), l); tl += l; } - tsvalue(top-n) = luaS_newlstr(L, buffer, tl); + setsvalue2s(top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ - top -= n-1; + last -= n-1; } while (total > 1); /* repeat until only 1 result left */ } -static void luaV_pack (lua_State *L, StkId firstelem) { - int i; - Hash *htab = luaH_new(L, 0); - for (i=0; firstelem+itop; i++) - *luaH_setint(L, htab, i+1) = *(firstelem+i); - /* store counter in field `n' */ - luaH_setstrnum(L, htab, luaS_new(L, "n"), i); - L->top = firstelem; /* remove elements from the stack */ - ttype(L->top) = LUA_TTABLE; - hvalue(L->top) = htab; - incr_top; -} - - -static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { - int nvararg = (L->top-base) - nfixargs; - if (nvararg < 0) - luaD_adjusttop(L, base, nfixargs); - luaV_pack(L, base+nfixargs); +static void Arith (lua_State *L, StkId ra, + const TObject *rb, const TObject *rc, TMS op) { + TObject tempb, tempc; + const TObject *b, *c; + if ((b = luaV_tonumber(rb, &tempb)) != NULL && + (c = luaV_tonumber(rc, &tempc)) != NULL) { + switch (op) { + case TM_ADD: setnvalue(ra, nvalue(b) + nvalue(c)); break; + case TM_SUB: setnvalue(ra, nvalue(b) - nvalue(c)); break; + case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; + case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; + case TM_POW: { + const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); + ptrdiff_t res = savestack(L, ra); + if (!ttisfunction(f)) + luaG_runerror(L, "`__pow' (`^' operator) is not a function"); + callTMres(L, f, b, c); + ra = restorestack(L, res); /* previous call may change stack */ + setobjs2s(ra, L->top); + break; + } + default: lua_assert(0); break; + } + } + else if (!call_binTM(L, rb, rc, ra, op)) + luaG_aritherror(L, rb, rc); } -#define dojump(pc, i) { int d = GETARG_S(i); pc += d; } - /* -** Executes the given Lua function. Parameters are between [base,top). -** Returns n such that the the results are between [n,top). +** some macros for common tasks in `luaV_execute' */ -StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { - const Proto *const tf = cl->f.l; - StkId top; /* keep top local, for performance */ - const Instruction *pc = tf->code; - TString **const kstr = tf->kstr; - const 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); - else - luaD_adjusttop(L, base, tf->numparams); - top = L->top; + +#define runtime_check(L, c) { if (!(c)) return 0; } + +#define RA(i) (base+GETARG_A(i)) +/* to be used after possible stack reallocation */ +#define XRA(i) (L->base+GETARG_A(i)) +#define RB(i) (base+GETARG_B(i)) +#define RKB(i) ((GETARG_B(i) < MAXSTACK) ? RB(i) : k+GETARG_B(i)-MAXSTACK) +#define RC(i) (base+GETARG_C(i)) +#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? RC(i) : k+GETARG_C(i)-MAXSTACK) +#define KBx(i) (k+GETARG_Bx(i)) + + +#define dojump(pc, i) ((pc) += (i)) + + +StkId luaV_execute (lua_State *L) { + LClosure *cl; + TObject *k; + const Instruction *pc; + callentry: /* entry point when calling new functions */ + L->ci->u.l.pc = &pc; + if (L->hookmask & LUA_MASKCALL) + luaD_callhook(L, LUA_HOOKCALL, -1); + retentry: /* entry point when returning to old functions */ + lua_assert(L->ci->state == CI_SAVEDPC || + L->ci->state == (CI_SAVEDPC | CI_CALLING)); + L->ci->state = CI_HASFRAME; /* activate frame */ + pc = L->ci->u.l.savedpc; + cl = &clvalue(L->base - 1)->l; + k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; - if (linehook) - traceexec(L, base, top, linehook); - switch (GET_OPCODE(i)) { - case OP_END: { - L->top = top; - return top; + StkId base, ra; + if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && + (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { + traceexec(L); + if (L->ci->state & CI_YIELD) { /* did hook yield? */ + L->ci->u.l.savedpc = pc - 1; + L->ci->state = CI_YIELD | CI_SAVEDPC; + return NULL; } - case OP_RETURN: { - L->top = top; - return base+GETARG_U(i); - } - case OP_CALL: { - int nres = GETARG_B(i); - if (nres == MULT_RET) nres = LUA_MULTRET; - L->top = top; - luaD_call(L, base+GETARG_A(i), nres); - top = L->top; - break; - } - case OP_TAILCALL: { - L->top = top; - luaD_call(L, base+GETARG_A(i), LUA_MULTRET); - return base+GETARG_B(i); - } - case OP_PUSHNIL: { - int n = GETARG_U(i); - LUA_ASSERT(n>0, "invalid argument"); - do { - ttype(top++) = LUA_TNIL; - } while (--n > 0); - break; - } - case OP_POP: { - top -= GETARG_U(i); - break; - } - case OP_PUSHINT: { - ttype(top) = LUA_TNUMBER; - nvalue(top) = (Number)GETARG_S(i); - top++; - break; - } - case OP_PUSHSTRING: { - ttype(top) = LUA_TSTRING; - tsvalue(top) = kstr[GETARG_U(i)]; - top++; + } + /* warning!! several calls may realloc the stack and invalidate `ra' */ + base = L->base; + ra = RA(i); + lua_assert(L->ci->state & CI_HASFRAME); + lua_assert(base == L->ci->base); + lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); + lua_assert(L->top == L->ci->top || + GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || + GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); + switch (GET_OPCODE(i)) { + case OP_MOVE: { + setobjs2s(ra, RB(i)); break; } - case OP_PUSHNUM: { - ttype(top) = LUA_TNUMBER; - nvalue(top) = tf->knum[GETARG_U(i)]; - top++; + case OP_LOADK: { + setobj2s(ra, KBx(i)); break; } - case OP_PUSHNEGNUM: { - ttype(top) = LUA_TNUMBER; - nvalue(top) = -tf->knum[GETARG_U(i)]; - top++; + case OP_LOADBOOL: { + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ break; } - case OP_PUSHUPVALUE: { - *top++ = cl->upvalue[GETARG_U(i)]; + case OP_LOADNIL: { + TObject *rb = RB(i); + do { + setnilvalue(rb--); + } while (rb >= ra); break; } - case OP_GETLOCAL: { - *top++ = *(base+GETARG_U(i)); + case OP_GETUPVAL: { + int b = GETARG_B(i); + setobj2s(ra, cl->upvals[b]->v); break; } case OP_GETGLOBAL: { - L->top = top; - *top = *luaV_getglobal(L, kstr[GETARG_U(i)]); - top++; + TObject *rb = KBx(i); + const TObject *v; + lua_assert(ttisstring(rb) && ttistable(&cl->g)); + v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); + if (!ttisnil(v)) { setobj2s(ra, v); } + else + setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); break; } case OP_GETTABLE: { - L->top = top; - top--; - *(top-1) = *luaV_gettable(L, top-1); + StkId rb = RB(i); + TObject *rc = RKC(i); + if (ttistable(rb)) { + const TObject *v = luaH_get(hvalue(rb), rc); + if (!ttisnil(v)) { setobj2s(ra, v); } + else + setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); + } + else + setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } - case OP_GETDOTTED: { - ttype(top) = LUA_TSTRING; - tsvalue(top) = kstr[GETARG_U(i)]; - L->top = top+1; - *(top-1) = *luaV_gettable(L, top-1); + case OP_SETGLOBAL: { + lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); + luaV_settable(L, &cl->g, KBx(i), ra); break; } - case OP_GETINDEXED: { - *top = *(base+GETARG_U(i)); - L->top = top+1; - *(top-1) = *luaV_gettable(L, top-1); + case OP_SETUPVAL: { + int b = GETARG_B(i); + setobj(cl->upvals[b]->v, ra); /* write barrier */ break; } - case OP_PUSHSELF: { - TObject receiver; - receiver = *(top-1); - ttype(top) = LUA_TSTRING; - tsvalue(top++) = kstr[GETARG_U(i)]; - L->top = top; - *(top-2) = *luaV_gettable(L, top-2); - *(top-1) = receiver; + case OP_SETTABLE: { + luaV_settable(L, ra, RKB(i), RKC(i)); break; } - case OP_CREATETABLE: { - L->top = top; + case OP_NEWTABLE: { + int b = GETARG_B(i); + b = fb2int(b); + sethvalue(ra, luaH_new(L, b, GETARG_C(i))); luaC_checkGC(L); - hvalue(top) = luaH_new(L, GETARG_U(i)); - ttype(top) = LUA_TTABLE; - top++; - break; - } - case OP_SETLOCAL: { - *(base+GETARG_U(i)) = *(--top); - break; - } - case OP_SETGLOBAL: { - L->top = top; - luaV_setglobal(L, kstr[GETARG_U(i)]); - top--; break; } - case OP_SETTABLE: { - StkId t = top-GETARG_A(i); - L->top = top; - luaV_settable(L, t, t+1); - top -= GETARG_B(i); /* pop values */ - break; - } - case OP_SETLIST: { - int aux = GETARG_A(i) * LFIELDS_PER_FLUSH; - int n = GETARG_B(i); - Hash *arr = hvalue(top-n-1); - L->top = top-n; /* final value of `top' (in case of errors) */ - for (; n; n--) - *luaH_setint(L, arr, n+aux) = *(--top); - break; - } - case OP_SETMAP: { - int n = GETARG_U(i); - StkId finaltop = top-2*n; - Hash *arr = hvalue(finaltop-1); - L->top = finaltop; /* final value of `top' (in case of errors) */ - for (; n; n--) { - top-=2; - *luaH_set(L, arr, top) = *(top+1); + case OP_SELF: { + StkId rb = RB(i); + TObject *rc = RKC(i); + runtime_check(L, ttisstring(rc)); + setobjs2s(ra+1, rb); + if (ttistable(rb)) { + const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); + if (!ttisnil(v)) { setobj2s(ra, v); } + else + setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); } - break; - } - case OP_ADD: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top, TM_ADD); else - nvalue(top-2) += nvalue(top-1); - top--; + setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } - case OP_ADDI: { - if (tonumber(top-1)) { - ttype(top) = LUA_TNUMBER; - nvalue(top) = (Number)GETARG_S(i); - call_arith(L, top+1, TM_ADD); + case OP_ADD: { + TObject *rb = RKB(i); + TObject *rc = RKC(i); + if (ttisnumber(rb) && ttisnumber(rc)) { + setnvalue(ra, nvalue(rb) + nvalue(rc)); } else - nvalue(top-1) += (Number)GETARG_S(i); + Arith(L, ra, rb, rc, TM_ADD); break; } case OP_SUB: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top, TM_SUB); + TObject *rb = RKB(i); + TObject *rc = RKC(i); + if (ttisnumber(rb) && ttisnumber(rc)) { + setnvalue(ra, nvalue(rb) - nvalue(rc)); + } else - nvalue(top-2) -= nvalue(top-1); - top--; + Arith(L, ra, rb, rc, TM_SUB); break; } - case OP_MULT: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top, TM_MUL); + case OP_MUL: { + TObject *rb = RKB(i); + TObject *rc = RKC(i); + if (ttisnumber(rb) && ttisnumber(rc)) { + setnvalue(ra, nvalue(rb) * nvalue(rc)); + } else - nvalue(top-2) *= nvalue(top-1); - top--; + Arith(L, ra, rb, rc, TM_MUL); break; } case OP_DIV: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top, TM_DIV); + TObject *rb = RKB(i); + TObject *rc = RKC(i); + if (ttisnumber(rb) && ttisnumber(rc)) { + setnvalue(ra, nvalue(rb) / nvalue(rc)); + } else - nvalue(top-2) /= nvalue(top-1); - top--; + Arith(L, ra, rb, rc, TM_DIV); break; } case OP_POW: { - if (!call_binTM(L, top, TM_POW)) - lua_error(L, "undefined operation"); - top--; - break; - } - case OP_CONCAT: { - int n = GETARG_U(i); - luaV_strconc(L, n, top); - top -= n-1; - L->top = top; - luaC_checkGC(L); + Arith(L, ra, RKB(i), RKC(i), TM_POW); break; } - case OP_MINUS: { - if (tonumber(top-1)) { - ttype(top) = LUA_TNIL; - call_arith(L, top+1, TM_UNM); + case OP_UNM: { + const TObject *rb = RB(i); + TObject temp; + if (tonumber(rb, &temp)) { + setnvalue(ra, -nvalue(rb)); + } + else { + setnilvalue(&temp); + if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) + luaG_aritherror(L, RB(i), &temp); } - else - nvalue(top-1) = -nvalue(top-1); break; } case OP_NOT: { - ttype(top-1) = - (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL; - nvalue(top-1) = 1; - break; - } - case OP_JMPNE: { - top -= 2; - if (!luaO_equalObj(top, top+1)) dojump(pc, i); - break; - } - case OP_JMPEQ: { - top -= 2; - if (luaO_equalObj(top, top+1)) dojump(pc, i); + int res = l_isfalse(RB(i)); /* next assignment may change this value */ + setbvalue(ra, res); break; } - case OP_JMPLT: { - top -= 2; - if (luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i); + case OP_CONCAT: { + int b = GETARG_B(i); + int c = GETARG_C(i); + luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ + base = L->base; + setobjs2s(RA(i), base+b); + luaC_checkGC(L); break; } - case OP_JMPLE: { /* a <= b === !(b b === (b= b === !(atop = ra+b; /* else previous instruction set top */ + nresults = GETARG_C(i) - 1; + firstResult = luaD_precall(L, ra); + if (firstResult) { + if (firstResult > L->top) { /* yield? */ + lua_assert(L->ci->state == (CI_C | CI_YIELD)); + (L->ci - 1)->u.l.savedpc = pc; + (L->ci - 1)->state = CI_SAVEDPC; + return NULL; + } + /* it was a C function (`precall' called it); adjust results */ + luaD_poscall(L, nresults, firstResult); + if (nresults >= 0) L->top = L->ci->top; + } + else { /* it is a Lua function */ + if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ + (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ + (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); + } + else { /* tail call: put new frame in place of previous one */ + int aux; + base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ + ra = RA(i); + if (L->openupval) luaF_close(L, base); + for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ + setobjs2s(base+aux-1, ra+aux); + (L->ci - 1)->top = L->top = base+aux; /* correct top */ + lua_assert(L->ci->state & CI_SAVEDPC); + (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; + (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ + (L->ci - 1)->state = CI_SAVEDPC; + L->ci--; /* remove new frame */ + L->base = L->ci->base; + } + goto callentry; + } break; } - case OP_JMPONF: { - if (ttype(top-1) != LUA_TNIL) top--; - else dojump(pc, i); - break; + case OP_RETURN: { + CallInfo *ci = L->ci - 1; /* previous function frame */ + int b = GETARG_B(i); + if (b != 0) L->top = ra+b-1; + lua_assert(L->ci->state & CI_HASFRAME); + if (L->openupval) luaF_close(L, base); + L->ci->state = CI_SAVEDPC; /* deactivate current function */ + L->ci->u.l.savedpc = pc; + /* previous function was running `here'? */ + if (!(ci->state & CI_CALLING)) { + lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); + return ra; /* no: return */ + } + else { /* yes: continue its execution */ + int nresults; + lua_assert(ci->u.l.pc == &pc && + ttisfunction(ci->base - 1) && + (ci->state & CI_SAVEDPC)); + lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); + nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; + luaD_poscall(L, nresults, ra); + if (nresults >= 0) L->top = L->ci->top; + goto retentry; + } } - case OP_JMP: { - dojump(pc, i); - break; - } - case OP_PUSHNILJMP: { - ttype(top++) = LUA_TNIL; - pc++; - break; - } - case OP_FORPREP: { - if (tonumber(top-1)) - lua_error(L, "`for' step must be a number"); - if (tonumber(top-2)) - lua_error(L, "`for' limit must be a number"); - if (tonumber(top-3)) - lua_error(L, "`for' initial value must be a number"); - if (nvalue(top-1) > 0 ? - nvalue(top-3) > nvalue(top-2) : - nvalue(top-3) < nvalue(top-2)) { /* `empty' loop? */ - top -= 3; /* remove control variables */ - dojump(pc, i); /* jump to loop end */ + case OP_FORLOOP: { + lua_Number step, idx, limit; + const TObject *plimit = ra+1; + const TObject *pstep = ra+2; + if (!ttisnumber(ra)) + luaG_runerror(L, "`for' initial value must be a number"); + if (!tonumber(plimit, ra+1)) + luaG_runerror(L, "`for' limit must be a number"); + if (!tonumber(pstep, ra+2)) + luaG_runerror(L, "`for' step must be a number"); + step = nvalue(pstep); + idx = nvalue(ra) + step; /* increment index */ + limit = nvalue(plimit); + if (step > 0 ? idx <= limit : idx >= limit) { + dojump(pc, GETARG_sBx(i)); /* jump back */ + chgnvalue(ra, idx); /* update index */ } break; } - case OP_FORLOOP: { - LUA_ASSERT(ttype(top-1) == LUA_TNUMBER, "invalid step"); - LUA_ASSERT(ttype(top-2) == LUA_TNUMBER, "invalid limit"); - if (ttype(top-3) != LUA_TNUMBER) - lua_error(L, "`for' index must be a number"); - nvalue(top-3) += nvalue(top-1); /* increment index */ - if (nvalue(top-1) > 0 ? - nvalue(top-3) > nvalue(top-2) : - nvalue(top-3) < nvalue(top-2)) - top -= 3; /* end loop: remove control variables */ + case OP_TFORLOOP: { + int nvar = GETARG_C(i) + 1; + StkId cb = ra + nvar + 2; /* call base */ + setobjs2s(cb, ra); + setobjs2s(cb+1, ra+1); + setobjs2s(cb+2, ra+2); + L->top = cb+3; /* func. + 2 args (state and index) */ + luaD_call(L, cb, nvar); + L->top = L->ci->top; + ra = XRA(i) + 2; /* final position of first result */ + cb = ra + nvar; + do { /* move results to proper positions */ + nvar--; + setobjs2s(ra+nvar, cb+nvar); + } while (nvar > 0); + if (ttisnil(ra)) /* break loop? */ + pc++; /* skip jump (break loop) */ else - dojump(pc, i); /* repeat loop */ + dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ break; } - case OP_LFORPREP: { - Node *node; - if (ttype(top-1) != LUA_TTABLE) - lua_error(L, "`for' table must be a table"); - node = luaH_next(L, hvalue(top-1), &luaO_nilobject); - if (node == NULL) { /* `empty' loop? */ - top--; /* remove table */ - dojump(pc, i); /* jump to loop end */ + case OP_TFORPREP: { /* for compatibility only */ + if (ttistable(ra)) { + setobjs2s(ra+1, ra); + setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } + dojump(pc, GETARG_sBx(i)); + break; + } + case OP_SETLIST: + case OP_SETLISTO: { + int bc; + int n; + Table *h; + runtime_check(L, ttistable(ra)); + h = hvalue(ra); + bc = GETARG_Bx(i); + if (GET_OPCODE(i) == OP_SETLIST) + n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; else { - top += 2; /* index,value */ - *(top-2) = *key(node); - *(top-1) = *val(node); + n = L->top - ra - 1; + L->top = L->ci->top; } + bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ + for (; n > 0; n--) + setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ break; } - case OP_LFORLOOP: { - Node *node; - LUA_ASSERT(ttype(top-3) == LUA_TTABLE, "invalid table"); - node = luaH_next(L, hvalue(top-3), top-2); - if (node == NULL) /* end loop? */ - top -= 3; /* remove table, key, and value */ - else { - *(top-2) = *key(node); - *(top-1) = *val(node); - dojump(pc, i); /* repeat loop */ - } + case OP_CLOSE: { + luaF_close(L, ra); break; } case OP_CLOSURE: { - L->top = top; - luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i)); - top = L->top; + Proto *p; + Closure *ncl; + int nup, j; + p = cl->p->p[GETARG_Bx(i)]; + nup = p->nups; + ncl = luaF_newLclosure(L, nup, &cl->g); + ncl->l.p = p; + for (j=0; jl.upvals[j] = cl->upvals[GETARG_B(*pc)]; + else { + lua_assert(GET_OPCODE(*pc) == OP_MOVE); + ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); + } + } + setclvalue(ra, ncl); luaC_checkGC(L); break; } } } } + diff --git a/src/lvm.h b/src/lvm.h index ace07c82e1..19cce200b6 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 1.27 2000/10/05 12:14:08 roberto Exp $ +** $Id: lvm.h,v 1.47 2002/11/14 16:16:21 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -13,20 +13,23 @@ #include "ltm.h" -#define tonumber(o) ((ttype(o) != LUA_TNUMBER) && (luaV_tonumber(o) != 0)) -#define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0)) +#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) +#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \ + (((o) = luaV_tonumber(o,n)) != NULL)) -int luaV_tonumber (TObject *obj); -int luaV_tostring (lua_State *L, TObject *obj); -const TObject *luaV_gettable (lua_State *L, StkId t); -void luaV_settable (lua_State *L, StkId t, StkId key); -const TObject *luaV_getglobal (lua_State *L, TString *s); -void luaV_setglobal (lua_State *L, TString *s); -StkId luaV_execute (lua_State *L, const Closure *cl, StkId base); -void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems); -void luaV_Lclosure (lua_State *L, Proto *l, int nelems); -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top); -void luaV_strconc (lua_State *L, int total, StkId top); +#define equalobj(L,o1,o2) \ + (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) + + +int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r); +int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2); +const TObject *luaV_tonumber (const TObject *obj, TObject *n); +int luaV_tostring (lua_State *L, StkId obj); +const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, + int loop); +void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val); +StkId luaV_execute (lua_State *L); +void luaV_concat (lua_State *L, int total, int last); #endif diff --git a/src/lzio.c b/src/lzio.c index c958fe4642..3aeca1c588 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,77 +1,62 @@ /* -** $Id: lzio.c,v 1.13 2000/06/12 13:52:05 roberto Exp $ +** $Id: lzio.c,v 1.24 2003/03/20 16:00:56 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ - -#include #include +#define lzio_c + #include "lua.h" +#include "llimits.h" +#include "lmem.h" #include "lzio.h" - -/* ----------------------------------------------------- memory buffers --- */ - -static int zmfilbuf (ZIO* z) { - (void)z; /* to avoid warnings */ - return EOZ; -} - - -ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name) { - if (b==NULL) return NULL; - z->n = size; - z->p = (const unsigned char *)b; - z->filbuf = zmfilbuf; - z->u = NULL; - z->name = name; - return z; +int luaZ_fill (ZIO *z) { + size_t size; + const char *buff = z->reader(NULL, z->data, &size); + if (buff == NULL || size == 0) return EOZ; + z->n = size - 1; + z->p = buff; + return char2int(*(z->p++)); } -/* ------------------------------------------------------------ strings --- */ - -ZIO* zsopen (ZIO* z, const char* s, const char *name) { - if (s==NULL) return NULL; - return zmopen(z, s, strlen(s), name); -} -/* -------------------------------------------------------------- FILEs --- */ - -static int zffilbuf (ZIO* z) { - size_t n; - if (feof((FILE *)z->u)) return EOZ; - n = fread(z->buffer, 1, ZBSIZE, (FILE *)z->u); - if (n==0) return EOZ; - z->n = n-1; - z->p = z->buffer; - return *(z->p++); +int luaZ_lookahead (ZIO *z) { + if (z->n == 0) { + int c = luaZ_fill(z); + if (c == EOZ) return c; + z->n++; + z->p--; + } + return char2int(*z->p); } -ZIO* zFopen (ZIO* z, FILE* f, const char *name) { - if (f==NULL) return NULL; - z->n = 0; - z->p = z->buffer; - z->filbuf = zffilbuf; - z->u = f; +void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { + z->reader = reader; + z->data = data; z->name = name; - return z; + z->n = 0; + z->p = NULL; } /* --------------------------------------------------------------- read --- */ -size_t zread (ZIO *z, void *b, size_t n) { +size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; if (z->n == 0) { - if (z->filbuf(z) == EOZ) + if (luaZ_fill(z) == EOZ) return n; /* return number of missing bytes */ - zungetc(z); /* put result from `filbuf' in the buffer */ + else { + ++z->n; /* filbuf removed first byte; put back it */ + --z->p; + } } m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); @@ -82,3 +67,15 @@ size_t zread (ZIO *z, void *b, size_t n) { } return 0; } + +/* ------------------------------------------------------------------------ */ +char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { + if (n > buff->buffsize) { + if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; + luaM_reallocvector(L, buff->buffer, buff->buffsize, n, char); + buff->buffsize = n; + } + return buff->buffer; +} + + diff --git a/src/lzio.h b/src/lzio.h index 5f4b43de04..5e73615cc0 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.7 2000/10/20 16:36:32 roberto Exp $ +** $Id: lzio.h,v 1.15 2003/03/20 16:00:56 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -8,46 +8,57 @@ #ifndef lzio_h #define lzio_h -#include +#include "lua.h" - -/* For Lua only */ -#define zFopen luaZ_Fopen -#define zsopen luaZ_sopen -#define zmopen luaZ_mopen -#define zread luaZ_read - #define EOZ (-1) /* end of stream */ -typedef struct zio ZIO; +typedef struct Zio ZIO; -ZIO* zFopen (ZIO* z, FILE* f, const char *name); /* open FILEs */ -ZIO* zsopen (ZIO* z, const char* s, const char *name); /* string */ -ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name); /* memory */ -size_t zread (ZIO* z, void* b, size_t n); /* read next n bytes */ +#define char2int(c) cast(int, cast(unsigned char, (c))) + +#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) -#define zgetc(z) (((z)->n--)>0 ? ((int)*(z)->p++): (z)->filbuf(z)) -#define zungetc(z) (++(z)->n,--(z)->p) #define zname(z) ((z)->name) +void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name); +size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ +int luaZ_lookahead (ZIO *z); -/* --------- Private Part ------------------ */ -#ifndef ZBSIZE -#define ZBSIZE 256 /* buffer size */ -#endif +typedef struct Mbuffer { + char *buffer; + size_t buffsize; +} Mbuffer; + + +char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); + +#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) -struct zio { - size_t n; /* bytes still unread */ - const unsigned char* p; /* current position in buffer */ - int (*filbuf)(ZIO* z); - void* u; /* additional data */ +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_buffer(buff) ((buff)->buffer) + +#define luaZ_resizebuffer(L, buff, size) \ + (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ + (buff)->buffsize = size) + +#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Chunkreader reader; + void* data; /* additional data */ const char *name; - unsigned char buffer[ZBSIZE]; /* buffer */ }; +int luaZ_fill (ZIO *z); + #endif diff --git a/test/README b/test/README index 6f410ee4f2..2a6601c5fe 100644 --- a/test/README +++ b/test/README @@ -1,6 +1,27 @@ These are simple tests for Lua. Some of them contain useful code. -They are meant to be run to make sure Lua is ok and also to be read, to see -how Lua programs can look like. +They are meant to be run to make sure Lua is built correctly and also +to be read, to see how Lua programs look. + +Here is a one-line summary of each program: + + bisect.lua bisection method for solving non-linear equations + cf.lua temperature conversion table (celsius to farenheit) + echo.lua echo command line arguments + env.lua environment variables as automatic global variables + factorial.lua factorial without recursion + fib.lua fibonacci function with cache + fibfor.lua fibonacci numbers with coroutines and generators + globals.lua report global variable usage + hello.lua the first program in every language + life.lua Conway's Game of Life + luac.lua bare-bones luac + printf.lua an implementation of printf + readonly.lua make global variables readonly + sieve.lua the sieve of of Eratosthenes programmed with coroutines + sort.lua two implementations of a sort function + table.lua make table, grouping all data for the same item + trace-calls.lua trace calls + trace-globals.lua trace assigments to global variables + undefined.lua catch "undefined" global variables + xd.lua hex dump -In the directory examples/, there is more useful code: a library for PostScript -output and a database for a fake web site. diff --git a/test/bisect.lua b/test/bisect.lua index 9e1d8f707f..f91e69bfba 100644 --- a/test/bisect.lua +++ b/test/bisect.lua @@ -1,25 +1,23 @@ -- bisection method for solving non-linear equations +delta=1e-6 -- tolerance + function bisect(f,a,b,fa,fb) - write(n," a=",a," fa=",fa," b=",b," fb=",fb,"\n") local c=(a+b)/2 - if c==a or c==b then return c end - if abs(a-b) protect(f, err) +-- loadfile +-- loadstring + +-- rawget +-- rawset + +-- getargs = Main.getargs ?? + + +function do_ (f, err) + if not f then print(err); return end + local a,b = pcall(f) + if not a then print(b); return nil + else return b or true + end +end + +function dostring(s) return do_(loadstring(s)) end +-- function dofile(s) return do_(loadfile(s)) end + +------------------------------------------------------------------- +-- Table library +local tab = table +foreach = tab.foreach +foreachi = tab.foreachi +getn = tab.getn +tinsert = tab.insert +tremove = tab.remove +sort = tab.sort + +------------------------------------------------------------------- +-- Debug library +local dbg = debug +getinfo = dbg.getinfo +getlocal = dbg.getlocal +setcallhook = function () error"`setcallhook' is deprecated" end +setlinehook = function () error"`setlinehook' is deprecated" end +setlocal = dbg.setlocal + +------------------------------------------------------------------- +-- math library +local math = math +abs = math.abs +acos = function (x) return math.deg(math.acos(x)) end +asin = function (x) return math.deg(math.asin(x)) end +atan = function (x) return math.deg(math.atan(x)) end +atan2 = function (x,y) return math.deg(math.atan2(x,y)) end +ceil = math.ceil +cos = function (x) return math.cos(math.rad(x)) end +deg = math.deg +exp = math.exp +floor = math.floor +frexp = math.frexp +ldexp = math.ldexp +log = math.log +log10 = math.log10 +max = math.max +min = math.min +mod = math.mod +PI = math.pi +--??? pow = math.pow +rad = math.rad +random = math.random +randomseed = math.randomseed +sin = function (x) return math.sin(math.rad(x)) end +sqrt = math.sqrt +tan = function (x) return math.tan(math.rad(x)) end + +------------------------------------------------------------------- +-- string library +local str = string +strbyte = str.byte +strchar = str.char +strfind = str.find +format = str.format +gsub = str.gsub +strlen = str.len +strlower = str.lower +strrep = str.rep +strsub = str.sub +strupper = str.upper + +------------------------------------------------------------------- +-- os library +clock = os.clock +date = os.date +difftime = os.difftime +execute = os.execute --? +exit = os.exit +getenv = os.getenv +remove = os.remove +rename = os.rename +setlocale = os.setlocale +time = os.time +tmpname = os.tmpname + +------------------------------------------------------------------- +-- compatibility only +getglobal = function (n) return _G[n] end +setglobal = function (n,v) _G[n] = v end + +------------------------------------------------------------------- + +local io, tab = io, table + +-- IO library (files) +_STDIN = io.stdin +_STDERR = io.stderr +_STDOUT = io.stdout +_INPUT = io.stdin +_OUTPUT = io.stdout +seek = io.stdin.seek -- sick ;-) +tmpfile = io.tmpfile +closefile = io.close +openfile = io.open + +function flush (f) + if f then f:flush() + else _OUTPUT:flush() + end +end + +function readfrom (name) + if name == nil then + local f, err, cod = io.close(_INPUT) + _INPUT = io.stdin + return f, err, cod + else + local f, err, cod = io.open(name, "r") + _INPUT = f or _INPUT + return f, err, cod + end +end + +function writeto (name) + if name == nil then + local f, err, cod = io.close(_OUTPUT) + _OUTPUT = io.stdout + return f, err, cod + else + local f, err, cod = io.open(name, "w") + _OUTPUT = f or _OUTPUT + return f, err, cod + end +end + +function appendto (name) + local f, err, cod = io.open(name, "a") + _OUTPUT = f or _OUTPUT + return f, err, cod +end + +function read (...) + local f = _INPUT + if type(arg[1]) == 'userdata' then + f = tab.remove(arg, 1) + end + return f:read(unpack(arg)) +end + +function write (...) + local f = _OUTPUT + if type(arg[1]) == 'userdata' then + f = tab.remove(arg, 1) + end + return f:write(unpack(arg)) +end + diff --git a/test/echo.lua b/test/echo.lua new file mode 100644 index 0000000000..4313439a85 --- /dev/null +++ b/test/echo.lua @@ -0,0 +1,5 @@ +-- echo command line arguments + +for i=0,table.getn(arg) do + print(i,arg[i]) +end diff --git a/test/env.lua b/test/env.lua new file mode 100644 index 0000000000..9e62a57fbf --- /dev/null +++ b/test/env.lua @@ -0,0 +1,7 @@ +-- read environment variables as if they were global variables + +local f=function (t,i) return os.getenv(i) end +setmetatable(getfenv(),{__index=f}) + +-- an example +print(a,USER,PATH) diff --git a/test/examples/ps/hilbert.lua b/test/examples/ps/hilbert.lua deleted file mode 100644 index dbcec96381..0000000000 --- a/test/examples/ps/hilbert.lua +++ /dev/null @@ -1,42 +0,0 @@ --- hilbert.c --- Hilbert curve --- Luiz Henrique de Figueiredo (lhf@csg.uwaterloo.ca) --- 10 Nov 95 - -dofile("ps.lua") - -function p() - PS.lineto(x,y) -end - -function a(n) - if (n==0) then return else n=n-1 end - d(n); y=y+h; p(); a(n); x=x+h; p(); a(n); y=y-h; p(); b(n); -end - -function b(n) - if (n==0) then return else n=n-1 end - c(n); x=x-h; p(); b(n); y=y-h; p(); b(n); x=x+h; p(); a(n); -end - -function c(n) - if (n==0) then return else n=n-1 end - b(n); y=y-h; p(); c(n); x=x-h; p(); c(n); y=y+h; p(); d(n); -end - -function d(n) - if (n==0) then return else n=n-1 end - a(n); x=x+h; p(); d(n); y=y+h; p(); d(n); x=x-h; p(); c(n); -end - -function hilbert(n) - PS.open("hilbert curve") - h=2^(9-n) - x=0 - y=0 - PS.moveto(x,y) - a(n) - PS.close() -end - -hilbert(5) diff --git a/test/examples/ps/ps.lua b/test/examples/ps/ps.lua deleted file mode 100644 index 0d74919412..0000000000 --- a/test/examples/ps/ps.lua +++ /dev/null @@ -1,181 +0,0 @@ --- ps.lua --- lua interface to postscript --- Luiz Henrique de Figueiredo (lhf@csg.uwaterloo.ca) --- 14 May 96 - -PS={} - -function P(x) - write(x.."\n") -end - --------------------------------------------------------------------- control -- - -function PS.open(title) - if title==nil then title="(no title)" end - P("%!PS-Adobe-2.0 EPSF-1.2") - P("%%Title: "..title) - P("%%Creator: ps.lua from Lua 2.4") - P("%%CreationDate: "..date()) - P("%%Pages: (atend)") - P("%%BoundingBox: (atend)") - P("%%EndComments") - P("%%BeginProcSet: ps.lua") - P("/s { stroke } bind def") - P("/f { fill } bind def") - P("/m { moveto } bind def") - P("/l { lineto } bind def") - P("/L { moveto lineto stroke } bind def") - P("/t { show } bind def") - P("/o { 0 360 arc stroke } bind def") - P("/O { 0 360 arc fill } bind def") - P("/p { 3 0 360 arc fil } bind def") - P("/F { findfont exch scalefont setfont } bind def") - P("/LS { 0 setdash } bind def") - P("/LW { setlinewidth } bind def") - P("%%EndProcSet: ps.lua") - P("%%EndProlog") - P("%%BeginSetup") - P("0 setlinewidth") - P("1 setlinejoin") - P("1 setlinecap") - P("10 /Times-Roman F") - P("%%EndSetup\n") - P("%%Page: 1 1") --- cxmin=dv.xmin; cxmax=dv.xmax; cymin=dv.ymin; cymax=dv.ymax - xmin=1000; xmax=-1000; ymin=1000; ymax=-1000 - page=1 -end - -function PS.close() - P("stroke") - P("showpage") - P("%%Trailer") - P("%%Pages: "..page) - P("%%BoundingBox: "..xmin.." "..ymin.." "..xmax.." "..ymax) - P("%%EOF") -end - -function PS.clear() - if (empty) then return end - page=page+1 - P("showpage") - P("%%Page: "..page.." "..page) - empty=1 -end - -function PS.comment(s) - P("% "..s) -end - ---------------------------------------------------------------- direct color -- - -function PS.rgbcolor(r,g,b) - P(r.." "..g.." "..b.." setrgbcolor") -end - -function PS.gray(g) - P(g.." setgray") -end - ----------------------------------------------------------------- named color -- - -function PS.color(c) - P("C"..c) -end - -function PS.defrgbcolor(c,r,g,b) - P("/C"..c.." { "..r.." "..g.." "..b.." setrgbcolor } def") -end - -function PS.defgraycolor(c,g) - P("/C"..c.." { "..g.." setgray } def") -end - ------------------------------------------------------------------------ line -- - -function PS.line(x1,y1,x2,y2) - P(x2.." "..y2.." "..x1.." "..y1.." L") - PS.update(x1,y1) - PS.update(x2,y2) -end - -function PS.moveto(x,y) - P(x.." "..y.." m") - PS.update(x,y) -end - -function PS.lineto(x,y) - P(x.." "..y.." l") - PS.update(x,y) -end - -function PS.linewidth(w) - P(w.." LW") -end - -function PS.linestyle(s) - P("["..s.."] LS") -end - ------------------------------------------------------------------------ text -- - -function PS.font(name,size) - if (size==nil) then size=10 end - P(size.." /"..name.." F") -end - -function PS.text(x,y,s) - P(x.." "..y.."m ("..s..") t") - PS.update(x,y) -end - ---------------------------------------------------------------------- circle -- - -function PS.circle(x,y,r) - P(x.." "..y.." "..r.." o") - PS.update(x-r,y-r) - PS.update(x+r,y+r) -end - -function PS.disk(x,y,r) - P(x.." "..y.." "..r.." O") - PS.update(x-r,y-r) - PS.update(x+r,y+r) -end - -function PS.dot(x,y) - P(x.." "..y.." p") - PS.update(x-r,y-r) - PS.update(x+r,y+r) -end - ------------------------------------------------------------------------- box -- - -function PS.rectangle(xmin,xmax,ymin,ymax) - P(xmin.." "..ymin.." m ".. - xmax.." "..ymin.." l ".. - xmax.." "..ymax.." l ".. - xmin.." "..ymax.." l s") - PS.update(xmin,ymin) - PS.update(xmax,ymax) -end - -function PS.box(xmin,xmax,ymin,ymax) - P(xmin.." "..ymin.." m ".. - xmax.." "..ymin.." l ".. - xmax.." "..ymax.." l ".. - xmin.." "..ymax.." l f") - PS.update(xmin,ymin) - PS.update(xmax,ymax) -end - --------------------------------------------------------- update bounding box -- - -function PS.update(x,y) --- if (x>=cxmin and x<=cxmax and y>=cxmin and y<=cxmax) then - if (xxmax) then xmax=x end - if (yymax) then ymax=y end - empty=0 --- end -end diff --git a/test/examples/www/README b/test/examples/www/README deleted file mode 100644 index b0e1e8bdf7..0000000000 --- a/test/examples/www/README +++ /dev/null @@ -1,10 +0,0 @@ -This directory contains a database for a fake web site. -Standard web page for the persons listed in db.lua are created -automatically from template.html with staff.lua. -(See http://www.cos.ufrj.br for a real web site created in this way.) - -To run, type lua db.lua. - -This example is meant to show the power of gsub and Lua declarative constructs, -which have been combined here into a "mail-merge" application. - diff --git a/test/examples/www/db.lua b/test/examples/www/db.lua deleted file mode 100644 index 53d7802445..0000000000 --- a/test/examples/www/db.lua +++ /dev/null @@ -1,46 +0,0 @@ -dofile("staff.lua") - -global{ - ROOT='http://www.tecgraf.puc-rio.br', - EMAIL="|LOGIN|@tecgraf.puc-rio.br", - WWW="|ROOT|/~|LOGIN|", - webmast='|ROOT|/webmaster.html', - TECGRAF='TeCGraf', - CS='Computer Science Department', - PUCRIO='PUC-Rio', -} - -staff{ -DI="inf.puc-rio.br", - LOGIN="roberto", - NAME="Roberto Ierusalimschy", - TITLE="D.Sc., |PUCRIO|, 1990", - POSITION="Associate Professor, |CS|, |PUCRIO|", - AREAS="Programming Languages, Object Oriented Programming", - EMAIL="|LOGIN|@|DI|", - WWW="http://www.|DI|/~|LOGIN|", -} - -staff{ -PCG="http://www.graphics.cornell.edu", - LOGIN="celes", - NAME="Waldemar Celes", - TITLE="D.Sc., |PUCRIO|, 1995", - POSITION="Postdoctoral Associate at ".. -'Program of Computer Graphics, '.. -'Cornell University', - WWW="|PCG|/~celes/", - AREAS="Image segmentation and 3D reconstruction; " -.."Physical simulation and educational software;" -.."Geometric modeling and topological data structures;" -.."Extension languages and customizable applications" -} - -staff{ - LOGIN="lhf", - NAME="Luiz Henrique de Figueiredo", - TITLE='D.Sc., IMPA, 1992', - POSITION='Associate Researcher at LNCC; Consultant at |TECGRAF|', - AREAS="Geometric modeling; Software tools", - WWW="http://www2.lncc.br/~lhf/", -} diff --git a/test/examples/www/staff.lua b/test/examples/www/staff.lua deleted file mode 100644 index f36df4ad62..0000000000 --- a/test/examples/www/staff.lua +++ /dev/null @@ -1,33 +0,0 @@ -readfrom("template.html") -TEMPLATE=read("*a") -readfrom() - -PAT="|(%a%a*)|" - -GLOBAL={ - DATE=date("%d/%m/%Y %T"), -} - -function get(i) - if LOCAL[i] then return LOCAL[i] - elseif GLOBAL[i] then return GLOBAL[i] - else return "?"..i.."?" end -end - -function global(t) - for i,v in t do - GLOBAL[i]=v - end -end - -function staff(t) - LOCAL=t - if t.AREAS then t.AREAS=gsub(t.AREAS,"[;,] *","\n

  • ") end - local p,n=TEMPLATE - if t.WWW=="" then p=gsub(p,'|NAME|',"|NAME|") end - repeat p,n=gsub(p,PAT,get) until n==0 - write(t.LOGIN,"\n") - writeto(t.LOGIN..".html") - write(p) - writeto() -end diff --git a/test/examples/www/template.html b/test/examples/www/template.html deleted file mode 100644 index c8494b7655..0000000000 --- a/test/examples/www/template.html +++ /dev/null @@ -1,29 +0,0 @@ - - - -Imaginary web site:Staff:|LOGIN| - - - - -

    |NAME|

    -|EMAIL| -

    - -|POSITION|
    -|TITLE|

    - -

    Research areas

    -
      -
    • |AREAS| -
    -

    - -


    -Last update in |DATE| by -websmaster. -

    - - - - diff --git a/test/factorial.lua b/test/factorial.lua index d9cc375cd3..7c4cf0fa45 100644 --- a/test/factorial.lua +++ b/test/factorial.lua @@ -1,12 +1,11 @@ -- function closures are powerful -- traditional fixed-point operator from functional programming - Y = function (g) local a = function (f) return f(f) end return a(function (f) - return %g(function (x) - local c=%f(%f) + return g(function (x) + local c=f(f) return c(x) end) end) @@ -14,24 +13,20 @@ end -- factorial without recursion - F = function (f) return function (n) if n == 0 then return 1 - else return n*%f(n-1) end + else return n*f(n-1) end end end factorial = Y(F) -- factorial is the fixed point of F -- now test it - function test(x) - write(x,"! = ",factorial(x),"\n") + io.write(x,"! = ",factorial(x),"\n") end -test(3) -test(4) -test(5) -test(6) -test(7) +for n=0,16 do + test(n) +end diff --git a/test/fib.lua b/test/fib.lua index d946946a44..97a921b132 100644 --- a/test/fib.lua +++ b/test/fib.lua @@ -1,5 +1,6 @@ --- very inefficient fibonacci function +-- fibonacci function with cache +-- very inefficient fibonacci function function fib(n) N=N+1 if n<2 then @@ -9,31 +10,31 @@ function fib(n) end end --- a much faster cached version - +-- a general-purpose value cache function cache(f) local c={} return function (x) - local y=%c[x] + local y=c[x] if not y then - y=%f(x) - %c[x]=y + y=f(x) + c[x]=y end return y end end -function test(s) +-- run and time it +function test(s,f) N=0 - local c=clock() - local v=fib(n) - local t=clock()-c + local c=os.clock() + local v=f(n) + local t=os.clock()-c print(s,n,v,t,N) end -n=n or 24 -- for other values, do lua -e n=XX fib.lua +n=arg[1] or 24 -- for other values, do lua fib.lua XX n=tonumber(n) print("","n","value","time","evals") -test("plain") +test("plain",fib) fib=cache(fib) -test("cached") +test("cached",fib) diff --git a/test/fibfor.lua b/test/fibfor.lua new file mode 100644 index 0000000000..19bb34b40e --- /dev/null +++ b/test/fibfor.lua @@ -0,0 +1,13 @@ +-- example of for with generator functions + +function generatefib (n) + return coroutine.wrap(function () + local a,b = 1, 1 + while a <= n do + coroutine.yield(a) + a, b = b, a+b + end + end, n) +end + +for i in generatefib(1000) do print(i) end diff --git a/test/globals.lua b/test/globals.lua index baa7504934..d4c20e1565 100644 --- a/test/globals.lua +++ b/test/globals.lua @@ -1,19 +1,13 @@ --- reads the output of luac -d -l -p and reports global variable usage +-- reads luac listings and reports global variable usage -- lines where a global is written to are marked with "*" --- typical usage: luac -p -l file.lua | lua globals.lua | sort - -local P="^.*; " -- pattern to extract comments +-- typical usage: luac -p -l file.lua | lua globals.lua | sort | lua table.lua while 1 do - local s=read() - if s==nil then return end - if strfind(s,"%sGETGLOBAL") then - local g=gsub(s,P,"") - local _,_,l=strfind(s,"(%d+)") - write(g,"\t",l,"\n") - elseif strfind(s,"%sSETGLOBAL") then - local g=gsub(s,P,"") - local _,_,l=strfind(s,"(%d+)") - write(g,"\t",l,"*\n") - end + local s=io.read() + if s==nil then break end + local ok,_,l,op,g=string.find(s,"%[%-?(%d*)%]%s*([GS])ETGLOBAL.-;%s+(.*)$") + if ok then + if op=="S" then op="*" else op="" end + io.write(g,"\t",l,op,"\n") + end end diff --git a/test/hello.lua b/test/hello.lua index ea818b9a92..0925498f21 100644 --- a/test/hello.lua +++ b/test/hello.lua @@ -1,3 +1,3 @@ -- the first program in every language -write("hello world, from Lua!\n") +io.write("Hello world, from ",_VERSION,"!\n") diff --git a/test/life.lua b/test/life.lua index 7c817a044a..911d9fe177 100644 --- a/test/life.lua +++ b/test/life.lua @@ -1,28 +1,25 @@ -- life.lua -- original by Dave Bollinger posted to lua-l -- modified to use ANSI terminal escape sequences +-- modified to use for instead of while -ALIVE="O" -DEAD="-" +local write=io.write + +ALIVE="¥" DEAD="þ" +ALIVE="O" DEAD="-" function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary - local i=10000 - while i>0 do i=i-1 end - -- local i=clock()+1 while(clock()0 do - t[h] = {} - local x=w - while x>0 do - t[h][x]=0 - x=x-1 + local t = {w=w,h=h} + for y=1,h do + t[y] = {} + for x=1,w do + t[y][x]=0 end - h=h-1 end return t end @@ -31,14 +28,10 @@ _CELLS = {} -- give birth to a "shape" within the cell array function _CELLS:spawn(shape,left,top) - local y=0 - while y0) and ALIVE) or DEAD) - x=x+1 end out=out.."\n" - y=y+1 end write(out) end @@ -112,8 +101,9 @@ function LIFE(w,h) thisgen,nextgen = nextgen,thisgen write("\027[H") -- ANSI home cursor thisgen:draw() - write("Generation: "..gen.."\n") + write("Life - generation ",gen,"\n") gen=gen+1 + if gen>2000 then break end --delay() -- no delay end end diff --git a/test/lisp.lua b/test/lisp.lua deleted file mode 100644 index e6bcd08424..0000000000 --- a/test/lisp.lua +++ /dev/null @@ -1,22 +0,0 @@ --- a simple LISP evaluator - -function eval(x) - if type(x)=="table" then - return eval(x[1])(eval(x[2]),eval(x[3])) - else - return x - end -end - -function add(x,y) return x+y end -function sub(x,y) return x-y end -function mul(x,y) return x*y end -function div(x,y) return x/y end -function pow(x,y) return x^y end - --- an example - -function E(x) print(eval(x)) end - -E{add,1,{mul,2,3}} -E{sin,60} diff --git a/test/luac.lua b/test/luac.lua new file mode 100644 index 0000000000..f9aa905299 --- /dev/null +++ b/test/luac.lua @@ -0,0 +1,7 @@ +-- bare-bones luac in Lua +-- usage: lua luac.lua file.lua + +assert(arg[1]~=nil,"usage: lua luac.lua file.lua") +f=assert(io.open("luac.out","w")) +f:write(string.dump(loadfile(arg[1]))) +io.close(f) diff --git a/test/old.lua b/test/old.lua deleted file mode 100644 index ebb4e70b1f..0000000000 --- a/test/old.lua +++ /dev/null @@ -1,42 +0,0 @@ --- implementation of old functions - -function foreach(t,f) - for i,v in t do - local r=f(i,v) - if r then return r end - end -end - -function foreachi(t,f) - for i=1,getn(t) do - local r=f(i,t[i]) - if r then return r end - end -end - -function foreachvar(f) - return foreach(globals(),f) -end - -function nextvar(n) - return next(globals(),n) -end - -function rawgetglobal(n) - return rawget(globals(),n) -end - -function rawsetglobal(n,v) - return rawset(globals(),n,v) -end - -rawsettable=rawset -rawgettable=rawget - -function getglobal(n) - return globals()[n] -end - -function setglobal(n,v) - globals()[n]=v -end diff --git a/test/printf.lua b/test/printf.lua new file mode 100644 index 0000000000..66dfda65d5 --- /dev/null +++ b/test/printf.lua @@ -0,0 +1,7 @@ +-- an implementation of printf + +function printf(...) + io.write(string.format(unpack(arg))) +end + +printf("Hello %s from %s on %s\n",os.getenv"USER" or "there",_VERSION,os.date()) diff --git a/test/qp.lua b/test/qp.lua deleted file mode 100644 index eb6b3205ba..0000000000 --- a/test/qp.lua +++ /dev/null @@ -1,6 +0,0 @@ --- decode quoted-printable text - -T=read"*a" -T=gsub(T,"=\n","") -T=gsub(T,"=(%x%x)",function (x) return strchar(tonumber(x,16)) end) -write(T) diff --git a/test/readonly.lua b/test/readonly.lua new file mode 100644 index 0000000000..85c0b4e013 --- /dev/null +++ b/test/readonly.lua @@ -0,0 +1,12 @@ +-- make global variables readonly + +local f=function (t,i) error("cannot redefine global variable `"..i.."'",2) end +local g={} +local G=getfenv() +setmetatable(g,{__index=G,__newindex=f}) +setfenv(1,g) + +-- an example +rawset(g,"x",3) +x=2 +y=1 -- cannot redefine `y' diff --git a/test/save.lua b/test/save.lua deleted file mode 100644 index 855e4c192b..0000000000 --- a/test/save.lua +++ /dev/null @@ -1,42 +0,0 @@ --- dump global environment - -function savevar (n,v) - if v == nil then return end - if type(v)=="userdata" or type(v)=="function" then return end - -- if type(v)=="userdata" or type(v)=="function" then write("\t-- ") end - write(n,"=") - if type(v) == "string" then write(format("%q",v)) - elseif type(v) == "table" then - if v.__visited__ ~= nil then - write(v.__visited__) - else - write("{}\n") - v.__visited__ = n - for r,f in v do - if r ~= "__visited__" then - if type(r) == 'string' then - savevar(n.."."..r,f) - else - savevar(n.."["..r.."]",f) - end - end - end - end - else write(tostring(v)) end - write("\n") -end - -function save () - write("\n-- global environment\n") - foreach(globals(),savevar) -end - --- an example - -a = 3 -x = {a = 4, b = "name", l={4,5,67}} - -b = {t=5} -x.next = b - -save() diff --git a/test/sieve.lua b/test/sieve.lua new file mode 100644 index 0000000000..0871bb2125 --- /dev/null +++ b/test/sieve.lua @@ -0,0 +1,29 @@ +-- the sieve of of Eratosthenes programmed with coroutines +-- typical usage: lua -e N=1000 sieve.lua | column + +-- generate all the numbers from 2 to n +function gen (n) + return coroutine.wrap(function () + for i=2,n do coroutine.yield(i) end + end) +end + +-- filter the numbers generated by `g', removing multiples of `p' +function filter (p, g) + return coroutine.wrap(function () + while 1 do + local n = g() + if n == nil then return end + if math.mod(n, p) ~= 0 then coroutine.yield(n) end + end + end) +end + +N=N or 1000 -- from command line +x = gen(N) -- generate primes up to N +while 1 do + local n = x() -- pick a number until done + if n == nil then break end + print(n) -- must be a prime number + x = filter(n, x) -- now remove its multiples +end diff --git a/test/sort.lua b/test/sort.lua index 1d50ad4721..0bcb15f837 100644 --- a/test/sort.lua +++ b/test/sort.lua @@ -4,7 +4,7 @@ -- extracted from Programming Pearls, page 110 function qsort(x,l,u,f) if l>> ") ---foreach(t,print) +local level=0 + +function hook(event) + local t=debug.getinfo(3) + io.write(level," >>> ",string.rep(" ",level)) + if t~=nil and t.currentline>=0 then io.write(t.short_src,":",t.currentline," ") end + t=debug.getinfo(2) + if event=="call" then + level=level+1 + else + level=level-1 if level<0 then level=0 end + end if t.what=="main" then - if func=="call" then - write("begin ",t.source) + if event=="call" then + io.write("begin ",t.short_src) else - write("end ",t.source) + io.write("end ",t.short_src) end elseif t.what=="Lua" then - write(func," ",t.name," <",t.linedefined,":",t.source,">") +-- table.foreach(t,print) + io.write(event," ",t.name or "(Lua)"," <",t.linedefined,":",t.short_src,">") else - write(func," ",t.name," [",t.what,"] ") + io.write(event," ",t.name or "(C)"," [",t.what,"] ") end - if t.currentline>=0 then write(":",t.currentline) end - write("\n") + io.write("\n") end -setcallhook(callhook) +debug.sethook(hook,"cr") +level=0 diff --git a/test/trace-globals.lua b/test/trace-globals.lua index 566e1106b7..295e670caa 100644 --- a/test/trace-globals.lua +++ b/test/trace-globals.lua @@ -1,75 +1,38 @@ --- shows how to trace assigments to global variables - --- a tostring that quotes strings. note the use of the original tostring. -local tostring=function(a) - if tag(a)==tag("") then - return format("%q",a) - else - return %tostring(a) +-- trace assigments to global variables + +do + -- a tostring that quotes strings. note the use of the original tostring. + local _tostring=tostring + local tostring=function(a) + if type(a)=="string" then + return string.format("%q",a) + else + return _tostring(a) + end end -end - -local T=newtag() - -local Tlog=function (name,old,new) - local t=getinfo(3,"Sl") - local line=t.currentline - write(t.source) - if line>=0 then write(":",line) end - write(" -- ",name," is now ",%tostring(new)," (was ",%tostring(old),")","\n") -end - -local Tgetnew=function (name) - local t=settag({},%T) - rawset(globals(),name,t) - return nil -end - -local Tsetnew=function (name,old,new) - %Tlog(name,old,new) - local t=settag({value=new},%T) - rawset(globals(),name,t) - return t -end -local Tsetglobal=function (name,old,new) - %Tlog(name,old.value,new) - old.value=new -end - -local Tgetglobal=function (x,value) - return value.value -end - -settagmethod(T,"getglobal",Tgetglobal) -settagmethod(T,"setglobal",Tsetglobal) - --- to trace only selected variables, use the following function --- and comment the next two calls to settagmethod + local log=function (name,old,new) + local t=debug.getinfo(3,"Sl") + local line=t.currentline + io.write(t.short_src) + if line>=0 then io.write(":",line) end + io.write(": ",name," is now ",tostring(new)," (was ",tostring(old),")","\n") + end -function trace(name) - local t=settag({value=rawget(globals(),name)},%T) - rawset(globals(),name,t) + local g={} + local set=function (t,name,value) + log(name,g[name],value) + g[name]=value + end + setmetatable(getfenv(),{__index=g,__newindex=set}) end - -settagmethod(tag(nil),"getglobal",Tgetnew) -settagmethod(tag(nil),"setglobal",Tsetnew) -- an example -trace"a" -print(a) a=1 b=2 -c=3 a=10 b=20 -c=30 -trace"b" -b="lua" -c={} -a=print -c=nil -c=100 - -print(a,b,c,d) +b=nil +b=200 +print(a,b,c) diff --git a/test/undefined.lua b/test/undefined.lua index bbecffe33f..efe5f2459e 100644 --- a/test/undefined.lua +++ b/test/undefined.lua @@ -1,20 +1,9 @@ --- catch "undefined" global variables. see FAQ. +-- catch "undefined" global variables -do - local f=function(name) - local v=rawget(globals(),name) - if v then - return v - else - error("undefined global variable `"..name.."'") - end - end - - settagmethod(tag(nil),"getglobal",f) -end +local f=function (t,i) error("undefined global variable `"..i.."'",2) end +setmetatable(getfenv(),{__index=f}) -- an example - a=1 c=3 -print(a,b,c) -- 'b' is undefined +print(a,b,c) -- `b' is undefined diff --git a/test/webform.lua b/test/webform.lua deleted file mode 100644 index 3e4c3ce46b..0000000000 --- a/test/webform.lua +++ /dev/null @@ -1,8 +0,0 @@ --- convert POST data to Lua table - -T=read"*a" -- for GET, use T=getenv"QUERY_STRING" -T=gsub(T,"=","=[[") -T=gsub(T,"&","]],\n") -T=gsub(T,"+"," ") -T=gsub(T,"%%(%x%x)",function (x) return strchar(tonumber(x,16)) end) -write("form{\n",T,"]]}\n") diff --git a/test/xd.lua b/test/xd.lua new file mode 100644 index 0000000000..32331dc116 --- /dev/null +++ b/test/xd.lua @@ -0,0 +1,14 @@ +-- hex dump +-- usage: lua xd.lua < file + +local offset=0 + +while 1 do + local s=io.read(16) + if s==nil then return end + io.write(string.format("%08X ",offset)) + string.gsub(s,"(.)",function (c) io.write(string.format("%02X ",string.byte(c))) end) + io.write(string.rep(" ",3*(16-string.len(s)))) + io.write(" ",string.gsub(s,"%c","."),"\n") + offset=offset+16 +end From 72286a8eeb927e1a33f24e9d99bb37ec5343ad45 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 25 Nov 2003 12:00:00 +0000 Subject: [PATCH 15/97] Lua 5.0.1 --- DIFFS | 623 +++++++++++++++++++++++++++++++++++++++++++++ UPDATE | 24 ++ doc/manual.html | 231 +++++++++-------- etc/.exrc | 1 - include/lua.h | 4 +- src/ldo.c | 25 +- src/lgc.c | 23 +- src/lgc.h | 4 +- src/lib/lbaselib.c | 4 +- src/lib/liolib.c | 6 +- src/lparser.c | 10 +- src/luac/Makefile | 2 +- src/luac/luac.c | 4 +- src/lvm.c | 10 +- test/luac.lua | 6 +- 15 files changed, 822 insertions(+), 155 deletions(-) create mode 100644 DIFFS create mode 100644 UPDATE delete mode 120000 etc/.exrc diff --git a/DIFFS b/DIFFS new file mode 100644 index 0000000000..006a274829 --- /dev/null +++ b/DIFFS @@ -0,0 +1,623 @@ +diff -r lua-5.0/doc/manual.html lua-5.0.1/doc/manual.html +5c5 +< Lua 5.0 Reference Manual +--- +> Lua: 5.0 reference manual +12,14c12 +< +< [Lua logo] +< +--- +> Lua +22c20 +< © 2003 TeCGraf, PUC-Rio. All rights reserved. +--- +> © 2003 Tecgraf, PUC-Rio. All rights reserved. +32c30 +<

    1 - Introduction

    +--- +>

    1 - Introduction

    +37c35 +< It also offers good suport for object-oriented programming, +--- +> It also offers good support for object-oriented programming, +54c52 +<

    The Lua distribuition includes a stand-alone embedding program, +--- +>

    The Lua distribution includes a stand-alone embedding program, +90c88 +<

    2 - The Language

    +--- +>

    2 - The Language

    +108c106 +<

    2.1 - Lexical Conventions

    +--- +>

    2.1 - Lexical Conventions

    +125,126c123 +< repeat return then true until +< while +--- +> repeat return then true until while +214c211 +<

    2.2 - Values and Types

    +--- +>

    2.2 - Values and Types

    +295c292 +<

    2.2.1 - Coercion

    +--- +>

    2.2.1 - Coercion

    +306c303 +<

    2.3 - Variables

    +--- +>

    2.3 - Variables

    +375c372 +<

    2.4 - Statements

    +--- +>

    2.4 - Statements

    +383c380 +<

    2.4.1 - Chunks

    +--- +>

    2.4.1 - Chunks

    +408c405 +<

    2.4.2 - Blocks

    +--- +>

    2.4.2 - Blocks

    +426c423 +<

    2.4.3 - Assignment

    +--- +>

    2.4.3 - Assignment

    +461c458 +< before it is assigned 4. +--- +> before it is assigned 4. +488c485 +<

    2.4.4 - Control Structures

    +--- +>

    2.4.4 - Control Structures

    +519c516 +< skiping to the next statement after the loop: +--- +> skipping to the next statement after the loop: +539c536 +<

    2.4.5 - For Statement

    +--- +>

    2.4.5 - For Statement

    +626c623 +<

    2.4.6 - Function Calls as Statements

    +--- +>

    2.4.6 - Function Calls as Statements

    +635c632 +<

    2.4.7 - Local Declarations

    +--- +>

    2.4.7 - Local Declarations

    +652c649 +<

    2.5 - Expressions

    +--- +>

    2.5 - Expressions

    +683c680 +<

    2.5.1 - Arithmetic Operators

    +--- +>

    2.5.1 - Arithmetic Operators

    +698c695 +<

    2.5.2 - Relational Operators

    +--- +>

    2.5.2 - Relational Operators

    +734c731 +<

    2.5.3 - Logical Operators

    +--- +>

    2.5.3 - Logical Operators

    +767c764 +<

    2.5.4 - Concatenation

    +--- +>

    2.5.4 - Concatenation

    +774c771 +<

    2.5.5 - Precedence

    +--- +>

    2.5.5 - Precedence

    +787c784 +< As usual, you can use parentheses to change the precedences of an expression. +--- +> You can use parentheses to change the precedences in an expression. +792c789 +<

    2.5.6 - Table Constructors

    +--- +>

    2.5.6 - Table Constructors

    +842c839 +<

    2.5.7 - Function Calls

    +--- +>

    2.5.7 - Function Calls

    +947c944 +< return x, f(x) -- adicional results +--- +> return x, f(x) -- additional results +952c949 +<

    2.5.8 - Function Definitions

    +--- +>

    2.5.8 - Function Definitions

    +1061c1058 +<

    2.6 - Visibility Rules

    +--- +>

    2.6 - Visibility Rules

    +1118c1115 +<

    2.7 - Error Handling

    +--- +>

    2.7 - Error Handling

    +1133c1130 +<

    2.8 - Metatables

    +--- +>

    2.8 - Metatables

    +1315c1312 +< if type(op1) ~= type(op2) then -- diferent types? +--- +> if type(op1) ~= type(op2) then -- different types? +1443c1440 +<

    2.9 - Garbage Collection

    +--- +>

    2.9 - Garbage Collection

    +1474c1471 +<

    2.9.1 - Garbage-Collection Metamethods

    +--- +>

    2.9.1 - Garbage-Collection Metamethods

    +1506c1503 +<

    2.9.2 - Weak Tables

    +--- +>

    2.9.2 - Weak Tables

    +1524c1521 +< If the __mode field is a string containing the character `k´, +--- +> If the __mode field is a string containing the character `k´, +1534c1531 +<

    2.10 - Coroutines

    +--- +>

    2.10 - Coroutines

    +1552c1549 +< passing as argument the thread returned by coroutine.create, +--- +> passing as its first argument the thread returned by coroutine.create, +1633c1630 +<

    3 - The Application Program Interface

    +--- +>

    3 - The Application Program Interface

    +1648c1645 +<

    3.1 - States

    +--- +>

    3.1 - States

    +1684c1681 +<

    3.2 - The Stack and Indices

    +--- +>

    3.2 - The Stack and Indices

    +1694c1691 +< and it is where the C function pushes its results (see 3.16) +--- +> and it is where the C function pushes its results to be returned to the caller (see 3.16) +1739c1736 +< it ensures that at least LUA_MINSTACK positions are available. +--- +> it ensures that at least LUA_MINSTACK stack positions are available. +1763c1760 +<

    3.3 - Stack Manipulation

    +--- +>

    3.3 - Stack Manipulation

    +1816c1813 +<

    3.4 - Querying the Stack

    +--- +>

    3.4 - Querying the Stack

    +1890c1887 +<

    3.5 - Getting Values from the Stack

    +--- +>

    3.5 - Getting Values from the Stack

    +1969c1966 +<

    3.6 - Pushing Values onto the Stack

    +--- +>

    3.6 - Pushing Values onto the Stack

    +1999,2000c1996 +< const char *lua_pushvfstring (lua_State *L, const char *fmt, +< va_list argp); +--- +> const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp); +2028c2024 +< If n is 1, the result is that single string +--- +> If n is 1, the result is that single string +2034c2030 +<

    3.7 - Controlling Garbage Collection

    +--- +>

    3.7 - Controlling Garbage Collection

    +2047c2043 +< int lua_getgccount (lua_State *L); +--- +> int lua_getgccount (lua_State *L); +2067c2063 +<

    3.8 - Userdata

    +--- +>

    3.8 - Userdata

    +2112c2108 +<

    3.9 - Metatables

    +--- +>

    3.9 - Metatables

    +2133c2129 +<

    3.10 - Loading Lua Chunks

    +--- +>

    3.10 - Loading Lua Chunks

    +2160c2156 +<

    lua_load uses an user-supplied reader function to read the chunk. +--- +>

    lua_load uses a user-supplied reader function to read the chunk. +2162c2158 +< it calls the reader, +--- +> lua_load calls the reader, +2182c2178 +<

    3.11 - Manipulating Tables

    +--- +>

    3.11 - Manipulating Tables

    +2263c2259 +<

    3.12 - Manipulating Environments

    +--- +>

    3.12 - Manipulating Environments

    +2295c2291 +<

    3.13 - Using Tables as Arrays

    +--- +>

    3.13 - Using Tables as Arrays

    +2312c2308 +<

    3.14 - Calling Functions

    +--- +>

    3.14 - Calling Functions

    +2367c2363 +<

    3.15 - Protected Calls

    +--- +>

    3.15 - Protected Calls

    +2414c2410 +<

    3.16 - Defining C Functions

    +--- +>

    3.16 - Defining C Functions

    +2482c2478 +<

    3.17 - Defining C Closures

    +--- +>

    3.17 - Defining C Closures

    +2517c2513 +<

    3.18 - Registry

    +--- +>

    3.18 - Registry

    +2535c2531 +<

    3.19 - Error Handling in C

    +--- +>

    3.19 - Error Handling in C

    +2542,2543c2538,2539 +< to set a recover point, +< and any error jumps to the most recent active recover point. +--- +> to set a recover point; +> any error jumps to the most recent active recover point. +2546c2542 +< Lua calls a panic function, +--- +> Lua calls a panic function +2553,2554c2549,2550 +< never returning (e.g. doing a long jump). +< Nevertheless, the corresponding Lua will not be consistent; +--- +> never returning (e.g., by doing a long jump). +> Nevertheless, the corresponding Lua state will not be consistent; +2578c2574 +< Any value returned by func is dicarded. +--- +> Any value returned by func is discarded. +2590c2586 +<

    3.20 - Threads

    +--- +>

    3.20 - Threads

    +2611,2616c2607,2609 +<

    You destroy threads with lua_closethread: +<

    +<        void lua_closethread (lua_State *L, lua_State *thread);
    +< 
    +< You cannot close the sole (or last) thread of a state. +< Instead, you must close the state itself. +--- +>

    There is no explicit function to close or to destroy a thread. +> Threads are subject to garbage collection, +> like any Lua object. +2622c2615 +< int lua_yield (lua_State *L, int nresults); +--- +> int lua_yield (lua_State *L, int nresults); +2632c2625 +< lua_resume returns 0 if there is no errors running the coroutine, +--- +> lua_resume returns 0 if there are no errors running the coroutine, +2660c2653 +<

    4 - The Debug Interface

    +--- +>

    4 - The Debug Interface

    +2669c2662 +<

    4.1 - Stack and Function Information

    +--- +>

    4.1 - Stack and Function Information

    +2681c2674 +< When there is no errors, lua_getstack returns 1; +--- +> When there are no errors, lua_getstack returns 1; +2789c2782 +<

    4.2 - Manipulating Local Variables and Upvalues

    +--- +>

    4.2 - Manipulating Local Variables and Upvalues

    +2866c2859 +<

    4.3 - Hooks

    +--- +>

    4.3 - Hooks

    +2942c2935 +<

    5 - Standard Libraries

    +--- +>

    5 - Standard Libraries

    +2985c2978 +<

    5.1 - Basic Functions

    +--- +>

    5.1 - Basic Functions

    +3018c3011 +< Terminates the last protected function called, +--- +> Terminates the last protected function called +3046c3039 +<

    if the environment has a "__fenv" field, +--- +>

    If the environment has a "__fenv" field, +3151c3144 +< That means that any error inside f is not propagated; +--- +> That means that any error inside f is not propagated; +3155c3148 +< which is true if the call succeeds without errors. +--- +> which is true if the call succeeds without errors. +3330c3323 +<

    5.2 - Coroutine Manipulation

    +--- +>

    5.2 - Coroutine Manipulation

    +3333c3326 +< the basic library, and come inside the table . +--- +> the basic library and come inside the table coroutine. +3388c3381 +<

    5.3 - String Manipulation

    +--- +>

    5.3 - String Manipulation

    +3595c3588 +< a character class is used to represent a set of characters. +--- +> A character class is used to represent a set of characters. +3651c3644 +< a pattern item may be +--- +> A pattern item may be +3688c3681 +< a pattern is a sequence of pattern items. +--- +> A pattern is a sequence of pattern items. +3715c3708 +<

    5.4 - Table Manipulation

    +--- +>

    5.4 - Table Manipulation

    +3824c3817 +<

    5.5 - Mathematical Functions

    +--- +>

    5.5 - Mathematical Functions

    +3879c3872 +<

    5.6 - Input and Output Facilities

    +--- +>

    5.6 - Input and Output Facilities

    +4072c4065 +<

    5.7 - Operating System Facilities

    +--- +>

    5.7 - Operating System Facilities

    +4098c4091 +< wday (weekday, Sunday is 1), +--- +> wday (weekday, Sunday is 1), +4187c4180 +<

    5.8 - The Reflexive Debug Interface

    +--- +>

    5.8 - The Reflexive Debug Interface

    +4323c4316 +<

    6 - Lua Stand-alone

    +--- +>

    6 - Lua Stand-alone

    +4462c4455 +< Vincent Penquerc'h, +--- +> Vincent Penquerc'h. +4583c4576 +<

    exp ::= nil false true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp +--- +>

    exp ::= nil | false | true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp +4612c4605,4609 +< +--- +>


    +> +> Last update: +> Tue Nov 25 16:08:37 BRST 2003 +> +4613a4611,4612 +> +> +diff -r lua-5.0/include/lua.h lua-5.0.1/include/lua.h +2c2 +< ** $Id: lua.h,v 1.175 2003/03/18 12:31:39 roberto Exp $ +--- +> ** $Id: lua.h,v 1.175a 2003/03/18 12:31:39 roberto Exp $ +17c17 +< #define LUA_VERSION "Lua 5.0" +--- +> #define LUA_VERSION "Lua 5.0.1" +diff -r lua-5.0/src/ldo.c lua-5.0.1/src/ldo.c +2c2 +< ** $Id: ldo.c,v 1.217 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: ldo.c,v 1.217a 2003/04/03 13:35:34 roberto Exp $ +325,326c325 +< if (nargs >= L->top - L->base) +< luaG_runerror(L, "cannot resume dead coroutine"); +--- +> lua_assert(nargs < L->top - L->base); +329c328,329 +< else if (ci->state & CI_YIELD) { /* inside a yield? */ +--- +> else { /* inside a yield */ +> lua_assert(ci->state & CI_YIELD); +344,345d343 +< else +< luaG_runerror(L, "cannot resume non-suspended coroutine"); +351a350,358 +> static int resume_error (lua_State *L, const char *msg) { +> L->top = L->ci->base; +> setsvalue2s(L->top, luaS_new(L, msg)); +> incr_top(L); +> lua_unlock(L); +> return LUA_ERRRUN; +> } +> +> +355a363,368 +> if (L->ci == L->base_ci) { +> if (nargs >= L->top - L->base) +> return resume_error(L, "cannot resume dead coroutine"); +> } +> else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ +> return resume_error(L, "cannot resume non-suspended coroutine"); +diff -r lua-5.0/src/lgc.c lua-5.0.1/src/lgc.c +2c2 +< ** $Id: lgc.c,v 1.171 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $ +113c113,114 +< void luaC_separateudata (lua_State *L) { +--- +> size_t luaC_separateudata (lua_State *L) { +> size_t deadmem = 0; +127a129 +> deadmem += sizeudata(gcotou(curr)->uv.len); +136a139 +> return deadmem; +247c250 +< if (!(ci->state & CI_C) && lim < ci->top) +--- +> if (lim < ci->top) +390c393 +< static void checkSizes (lua_State *L) { +--- +> static void checkSizes (lua_State *L, size_t deadmem) { +400c403 +< G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ +--- +> G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ +454c457,458 +< static void mark (lua_State *L) { +--- +> static size_t mark (lua_State *L) { +> size_t deadmem; +467c471 +< luaC_separateudata(L); /* separate userdata to be preserved */ +--- +> deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ +475a480 +> return deadmem; +480c485 +< mark(L); +--- +> size_t deadmem = mark(L); +482c487 +< checkSizes(L); +--- +> checkSizes(L, deadmem); +diff -r lua-5.0/src/lgc.h lua-5.0.1/src/lgc.h +2c2 +< ** $Id: lgc.h,v 1.19 2003/02/28 19:45:15 roberto Exp $ +--- +> ** $Id: lgc.h,v 1.19a 2003/02/28 19:45:15 roberto Exp $ +18c18 +< void luaC_separateudata (lua_State *L); +--- +> size_t luaC_separateudata (lua_State *L); +diff -r lua-5.0/src/lib/lbaselib.c lua-5.0.1/src/lib/lbaselib.c +2c2 +< ** $Id: lbaselib.c,v 1.130 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lbaselib.c,v 1.130a 2003/04/03 13:35:34 roberto Exp $ +327c327 +< char buff[64]; +--- +> char buff[128]; +diff -r lua-5.0/src/lib/liolib.c lua-5.0.1/src/lib/liolib.c +2c2 +< ** $Id: liolib.c,v 2.39 2003/03/19 21:16:12 roberto Exp $ +--- +> ** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $ +161c161 +< if (lua_isnone(L, 1)) { +--- +> if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { +178c178 +< char buff[32]; +--- +> char buff[128]; +diff -r lua-5.0/src/lparser.c lua-5.0.1/src/lparser.c +2c2 +< ** $Id: lparser.c,v 1.208 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lparser.c,v 1.208a 2003/04/03 13:35:34 roberto Exp $ +1143a1144 +> FuncState *fs = ls->fs; +1145c1146,1147 +< init_exp(&v, VLOCAL, ls->fs->freereg++); +--- +> init_exp(&v, VLOCAL, fs->freereg); +> luaK_reserveregs(fs, 1); +1148c1150,1152 +< luaK_storevar(ls->fs, &v, &b); +--- +> luaK_storevar(fs, &v, &b); +> /* debug information will only see the variable after this point! */ +> getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; +diff -r lua-5.0/src/luac/Makefile lua-5.0.1/src/luac/Makefile +16c16 +< $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) +--- +> $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) +diff -r lua-5.0/src/luac/luac.c lua-5.0.1/src/luac/luac.c +2c2 +< ** $Id: luac.c,v 1.44 2003/04/07 20:34:20 lhf Exp $ +--- +> ** $Id: luac.c,v 1.44a 2003/04/07 20:34:20 lhf Exp $ +184a185 +> lua_lock(L); +185a187 +> lua_unlock(L); +diff -r lua-5.0/src/lvm.c lua-5.0.1/src/lvm.c +2c2 +< ** $Id: lvm.c,v 1.284 2003/04/03 13:35:34 roberto Exp $ +--- +> ** $Id: lvm.c,v 1.284a 2003/04/03 13:35:34 roberto Exp $ +69c69 +< if (mask > LUA_MASKLINE) { /* instruction-hook set? */ +--- +> if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ +402d401 +< L->ci->u.l.pc = &pc; +405a405 +> L->ci->u.l.pc = &pc; +676,678c676 +< lua_assert(ci->u.l.pc == &pc && +< ttisfunction(ci->base - 1) && +< (ci->state & CI_SAVEDPC)); +--- +> lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); +diff -r lua-5.0/test/luac.lua lua-5.0.1/test/luac.lua +4,6c4,6 +< assert(arg[1]~=nil,"usage: lua luac.lua file.lua") +< f=assert(io.open("luac.out","w")) +< f:write(string.dump(loadfile(arg[1]))) +--- +> assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") +> f=assert(io.open("luac.out","wb")) +> f:write(string.dump(assert(loadfile(arg[1])))) diff --git a/UPDATE b/UPDATE new file mode 100644 index 0000000000..84be37c2e2 --- /dev/null +++ b/UPDATE @@ -0,0 +1,24 @@ +This is Lua 5.0.1, an update of Lua 5.0 that includes the following changes, +which fix all known bugs in Lua 5.0. + +src/ldo.c + Attempt to resume running coroutine crashed Lua +src/lgc.c + C functions also may have stacks larger than current top + Userdata to be collected still counted into new GC threshold +src/lgc.h + Userdata to be collected still counted into new GC threshold +src/lparser.c + Syntax `local function' did not increment stack size +src/lvm.c + `pc' address was invalidated when a coroutine was suspended + Count hook might be called without being set +src/lib/lbaselib.c + Buffer overflow for unusual %p representation +src/lib/liolib.c + `file.close()' could not be called without arguments + Buffer overflow for unusual %p representation +src/luac/luac.c + Missing lock/unlock + +To use this update, simply open this tarball over the original Lua 5.0 source. diff --git a/doc/manual.html b/doc/manual.html index 17a932f298..2a92d2aaf4 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2,16 +2,14 @@ -Lua 5.0 Reference Manual +Lua: 5.0 reference manual

    - -[Lua logo] - +Lua Lua 5.0 Reference Manual

    @@ -19,7 +17,7 @@

    Copyright -© 2003 TeCGraf, PUC-Rio. All rights reserved. +© 2003 Tecgraf, PUC-Rio. All rights reserved.


    @@ -29,12 +27,12 @@

    -

    1 - Introduction

    +

    1 - Introduction

    Lua is an extension programming language designed to support general procedural programming with data description facilities. -It also offers good suport for object-oriented programming, +It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight configuration language for any program that needs one. @@ -51,7 +49,7 @@

    1 - Introduction

    a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. -

    The Lua distribuition includes a stand-alone embedding program, +

    The Lua distribution includes a stand-alone embedding program, lua, that uses the Lua library to offer a complete Lua interpreter.

    Lua is free software, @@ -87,7 +85,7 @@

    1 - Introduction

    Lua means "moon" in Portuguese and is pronounced LOO-ah.

    -

    2 - The Language

    +

    2 - The Language

    This section describes the lexis, the syntax, and the semantics of Lua. In other words, @@ -105,7 +103,7 @@

    1 - Introduction

    and other terminal symbols are shown in typewriter font, enclosed in single quotes. -

    2.1 - Lexical Conventions

    +

    2.1 - Lexical Conventions

    Identifiers in Lua can be any string of letters, digits, and underscores, @@ -122,8 +120,7 @@

    1 - Introduction

    and break do else elseif end false for function if in local nil not or - repeat return then true until - while + repeat return then true until while
  • Lua is a case-sensitive language: @@ -211,7 +208,7 @@

    1 - Introduction

    This facility allows the use of Lua as a script interpreter in Unix systems (see 6). -

    2.2 - Values and Types

    +

    2.2 - Values and Types

    Lua is a dynamically typed language. That means that @@ -292,7 +289,7 @@

    1 - Introduction

    The library function type returns a string describing the type of a given value (see 5.1). -

    2.2.1 - Coercion

    +

    2.2.1 - Coercion

    Lua provides automatic conversion between string and number values at run time. @@ -303,7 +300,7 @@

    1 - Introduction

    For complete control of how numbers are converted to strings, use the format function from the string library (see 5.3). -

    2.3 - Variables

    +

    2.3 - Variables

    Variables are places that store values. @@ -372,7 +369,7 @@

    1 - Introduction

    (The _env variable is not defined in Lua. We use it here only for explanatory purposes.) -

    2.4 - Statements

    +

    2.4 - Statements

    Lua supports an almost conventional set of statements, similar to those in Pascal or C. @@ -380,7 +377,7 @@

    1 - Introduction

    assignment, control structures, procedure calls, table constructors, and variable declarations. -

    2.4.1 - Chunks

    +

    2.4.1 - Chunks

    The unit of execution of Lua is called a chunk. A chunk is simply a sequence of statements, @@ -405,7 +402,7 @@

    1 - Introduction

    Lua automatically detects the file type and acts accordingly. -

    2.4.2 - Blocks

    +

    2.4.2 - Blocks

    A block is a list of statements; syntactically, a block is equal to a chunk:
    @@ -423,7 +420,7 @@ 

    1 - Introduction

    of another block (see 2.4.4). -

    2.4.3 - Assignment

    +

    2.4.3 - Assignment

    Lua allows multiple assignment. Therefore, the syntax for assignment @@ -458,7 +455,7 @@

    1 - Introduction

    sets a[3] to 20, without affecting a[4] because the i in a[i] is evaluated (to 3) -before it is assigned 4. +before it is assigned 4. Similarly, the line
            x, y = y, x
    @@ -485,7 +482,7 @@ 

    1 - Introduction

    (The _env variable is not defined in Lua. We use it here only for explanatory purposes.) -

    2.4.4 - Control Structures

    +

    2.4.4 - Control Structures

    The control structures if, while, and repeat have the usual meaning and familiar syntax: @@ -516,7 +513,7 @@

    1 - Introduction

    The break statement can be used to terminate the execution of a while, repeat, or for loop, -skiping to the next statement after the loop: +skipping to the next statement after the loop:

     	stat ::= break
    @@ -536,7 +533,7 @@ 

    1 - Introduction

    In practice, those idioms are only used during debugging. -

    2.4.5 - For Statement

    +

    2.4.5 - For Statement

    The for statement has two forms: one numeric and one generic. @@ -623,7 +620,7 @@

    1 - Introduction

    then assign them to other variables before breaking or exiting the loop. -

    2.4.6 - Function Calls as Statements

    +

    2.4.6 - Function Calls as Statements

    To allow possible side-effects, function calls can be executed as statements:
    @@ -632,7 +629,7 @@ 

    1 - Introduction

    In this case, all returned values are thrown away. Function calls are explained in 2.5.7. -

    2.4.7 - Local Declarations

    +

    2.4.7 - Local Declarations

    Local variables may be declared anywhere inside a block. The declaration may include an initial assignment:
    @@ -649,7 +646,7 @@ 

    1 - Introduction

    The visibility rules for local variables are explained in 2.6. -

    2.5 - Expressions

    +

    2.5 - Expressions

    The basic expressions in Lua are the following: @@ -680,7 +677,7 @@

    1 - Introduction

    Expressions can also be built with arithmetic operators, relational operators, and logical operators, all of which are explained below. -

    2.5.1 - Arithmetic Operators

    +

    2.5.1 - Arithmetic Operators

    Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), @@ -695,7 +692,7 @@

    1 - Introduction

    giving the expected meaning to exponentiation (see 5.5). -

    2.5.2 - Relational Operators

    +

    2.5.2 - Relational Operators

    The relational operators in Lua are
            ==    ~=    <     >     <=    >=
    @@ -731,7 +728,7 @@ 

    1 - Introduction

    Otherwise, Lua tries to call the "lt" or the "le" metamethod (see 2.8). -

    2.5.3 - Logical Operators

    +

    2.5.3 - Logical Operators

    The logical operators in Lua are
    @@ -764,14 +761,14 @@ 

    1 - Introduction

    10 and 20 -> 20
    -

    2.5.4 - Concatenation

    +

    2.5.4 - Concatenation

    The string concatenation operator in Lua is denoted by two dots (`..´). If both operands are strings or numbers, then they are converted to strings according to the rules mentioned in 2.2.1. Otherwise, the "concat" metamethod is called (see 2.8). -

    2.5.5 - Precedence

    +

    2.5.5 - Precedence

    Operator precedence in Lua follows the table below, from lower to higher priority:
    @@ -784,12 +781,12 @@ 

    1 - Introduction

    not - (unary) ^
    -As usual, you can use parentheses to change the precedences of an expression. +You can use parentheses to change the precedences in an expression. The concatenation (`..´) and exponentiation (`^´) operators are right associative. All other binary operators are left associative. -

    2.5.6 - Table Constructors

    +

    2.5.6 - Table Constructors

    Table constructors are expressions that create tables. Every time a constructor is evaluated, a new table is created. Constructors can be used to create empty tables, @@ -839,7 +836,7 @@

    1 - Introduction

    The field list may have an optional trailing separator, as a convenience for machine-generated code. -

    2.5.7 - Function Calls

    +

    2.5.7 - Function Calls

    A function call in Lua has the following syntax:
     	functioncall ::= prefixexp args
    @@ -944,12 +941,12 @@ 

    1 - Introduction

       return (f(x))        -- results adjusted to 1
       return 2 * f(x)
    -  return x, f(x)       -- adicional results
    +  return x, f(x)       -- additional results
       f(x); return         -- results discarded
       return x or f(x)     -- results adjusted to 1
     
    -

    2.5.8 - Function Definitions

    +

    2.5.8 - Function Definitions

    The syntax for function definition is

    @@ -1058,7 +1055,7 @@ 

    1 - Introduction

    t.a.b.c.f = function (self, ...) ... end
    -

    2.6 - Visibility Rules

    +

    2.6 - Visibility Rules

    Lua is a lexically scoped language. @@ -1115,7 +1112,7 @@

    1 - Introduction

    Each of these closures uses a different y variable, while all of them share the same x. -

    2.7 - Error Handling

    +

    2.7 - Error Handling

    Because Lua is an extension language, all Lua actions start from C code in the host program @@ -1130,7 +1127,7 @@

    1 - Introduction

    If you need to catch errors in Lua, you can use the pcall function (see 5.1). -

    2.8 - Metatables

    +

    2.8 - Metatables

    Every table and userdata object in Lua may have a metatable. This metatable is an ordinary Lua table @@ -1312,7 +1309,7 @@

    1 - Introduction

    The "eq" event is defined as follows:
      function eq_event (op1, op2)
    -   if type(op1) ~= type(op2) then  -- diferent types?
    +   if type(op1) ~= type(op2) then  -- different types?
          return false   -- different objects
        end
        if op1 == op2 then   -- primitive equal?
    @@ -1440,7 +1437,7 @@ 

    1 - Introduction

    -

    2.9 - Garbage Collection

    +

    2.9 - Garbage Collection

    Lua does automatic memory management. That means that @@ -1471,7 +1468,7 @@

    1 - Introduction

    through the gcinfo and collectgarbage functions (see 5.1). -

    2.9.1 - Garbage-Collection Metamethods

    +

    2.9.1 - Garbage-Collection Metamethods

    Using the C API, you can set garbage-collector metamethods for userdata (see 2.8). @@ -1503,7 +1500,7 @@

    1 - Introduction

    That is, the first finalizer to be called is the one associated with the userdata created last in the program. -

    2.9.2 - Weak Tables

    +

    2.9.2 - Weak Tables

    A weak table is a table whose elements are weak references. @@ -1521,7 +1518,7 @@

    1 - Introduction

    the whole pair is removed from the table. The weakness of a table is controlled by the value of the __mode field of its metatable. -If the __mode field is a string containing the character `k´, +If the __mode field is a string containing the character `k´, the keys in the table are weak. If __mode contains `v´, the values in the table are weak. @@ -1531,7 +1528,7 @@

    1 - Introduction

    Otherwise, the weak behavior of the tables controlled by this metatable is undefined. -

    2.10 - Coroutines

    +

    2.10 - Coroutines

    Lua supports coroutines, also called semi-coroutines @@ -1549,7 +1546,7 @@

    1 - Introduction

    it does not start the coroutine execution.

    When you first call coroutine.resume, -passing as argument the thread returned by coroutine.create, +passing as its first argument the thread returned by coroutine.create, the coroutine starts its execution, at the first line of its main function. Extra arguments passed to coroutine.resume are given as @@ -1630,7 +1627,7 @@

    1 - Introduction

    -

    3 - The Application Program Interface

    +

    3 - The Application Program Interface

    This section describes the C API for Lua, that is, @@ -1645,7 +1642,7 @@

    1 - Introduction

    (except for the first argument, which is always a Lua state), and so do not generate hidden side-effects. -

    3.1 - States

    +

    3.1 - States

    The Lua library is fully reentrant: it has no global variables. @@ -1681,7 +1678,7 @@

    1 - Introduction

    might need to release states as soon as they are not needed, to avoid growing too large. -

    3.2 - The Stack and Indices

    +

    3.2 - The Stack and Indices

    Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value @@ -1691,7 +1688,7 @@

    1 - Introduction

    which is independent of previous stacks and of stacks of C functions that are still active. That stack initially contains any arguments to the C function, -and it is where the C function pushes its results (see 3.16) +and it is where the C function pushes its results to be returned to the caller (see 3.16) to be returned to the caller.

    For convenience, @@ -1736,7 +1733,7 @@

    1 - Introduction

    it is left unchanged.

    Whenever Lua calls C, -it ensures that at least LUA_MINSTACK positions are available. +it ensures that at least LUA_MINSTACK stack positions are available. LUA_MINSTACK is defined in lua.h as 20, so that usually you do not have to worry about stack space unless your code has loops pushing elements onto the stack. @@ -1760,7 +1757,7 @@

    1 - Introduction

    Pseudo-indices are used to access the global environment, the registry, and the upvalues of a C function (see 3.17). -

    3.3 - Stack Manipulation

    +

    3.3 - Stack Manipulation

    The API offers the following functions for basic stack manipulation:
            void lua_settop    (lua_State *L, int index);
    @@ -1813,7 +1810,7 @@ 

    1 - Introduction

    lua_settop(L, 6) --> 30 40 nil nil nil nil*
    -

    3.4 - Querying the Stack

    +

    3.4 - Querying the Stack

    To check the type of a stack element, the following functions are available: @@ -1887,7 +1884,7 @@

    1 - Introduction

    without metamethods. These functions return 0 (false) if any of the indices are non-valid. -

    3.5 - Getting Values from the Stack

    +

    3.5 - Getting Values from the Stack

    To translate a value in the stack to a specific C type, you can use the following conversion functions: @@ -1966,7 +1963,7 @@

    1 - Introduction

    lua_touserdata is explained in 3.8. -

    3.6 - Pushing Values onto the Stack

    +

    3.6 - Pushing Values onto the Stack

    The API has the following functions to push C values onto the stack: @@ -1996,8 +1993,7 @@

    1 - Introduction

    You can also push "formatted" strings:

            const char *lua_pushfstring  (lua_State *L, const char *fmt, ...);
    -       const char *lua_pushvfstring (lua_State *L, const char *fmt,
    -                                                   va_list argp);
    +       const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
     
    These functions push onto the stack a formatted string @@ -2025,13 +2021,13 @@

    1 - Introduction

    concatenates the n values at the top of the stack, pops them, and leaves the result at the top. -If n is 1, the result is that single string +If n is 1, the result is that single string (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is done following the usual semantics of Lua (see 2.5.4). -

    3.7 - Controlling Garbage Collection

    +

    3.7 - Controlling Garbage Collection

    Lua uses two numbers to control its garbage collection: the count and the threshold (see 2.9). @@ -2044,7 +2040,7 @@

    1 - Introduction

    You can access the current values of these two numbers through the following functions:

    -       int  lua_getgccount (lua_State *L);
    +       int  lua_getgccount     (lua_State *L);
            int  lua_getgcthreshold (lua_State *L);
     
    @@ -2064,7 +2060,7 @@

    1 - Introduction

    After the collection, a new threshold is set according to the previous rule. -

    3.8 - Userdata

    +

    3.8 - Userdata

    Userdata represents C values in Lua. Lua supports two types of userdata: @@ -2109,7 +2105,7 @@

    1 - Introduction

    it calls the userdata's gc metamethod, if any, and then it frees the userdata's corresponding memory. -

    3.9 - Metatables

    +

    3.9 - Metatables

    The following functions allow you to manipulate the metatables of an object: @@ -2130,7 +2126,7 @@

    1 - Introduction

    (that is, when the object is neither a userdata nor a table); even then it pops the table from the stack. -

    3.10 - Loading Lua Chunks

    +

    3.10 - Loading Lua Chunks

    You can load a Lua chunk with lua_load:

    @@ -2157,9 +2153,9 @@ 

    1 - Introduction

    lua_load automatically detects whether the chunk is text or binary, and loads it accordingly (see program luac). -

    lua_load uses an user-supplied reader function to read the chunk. +

    lua_load uses a user-supplied reader function to read the chunk. Everytime it needs another piece of the chunk, -it calls the reader, +lua_load calls the reader, passing along its data parameter. The reader must return a pointer to a block of memory with a new piece of the chunk @@ -2179,7 +2175,7 @@

    1 - Introduction

    and for some ready-to-use functions to load chunks from files and strings. -

    3.11 - Manipulating Tables

    +

    3.11 - Manipulating Tables

    Tables are created by calling the function @@ -2260,7 +2256,7 @@

    1 - Introduction

    Recall that lua_tostring changes the value at the given index; this confuses the next call to lua_next. -

    3.12 - Manipulating Environments

    +

    3.12 - Manipulating Environments

    All global variables are kept in ordinary Lua tables, called environments. @@ -2292,7 +2288,7 @@

    1 - Introduction

    If the object at the given index is not a Lua function, lua_setfenv returns 0. -

    3.13 - Using Tables as Arrays

    +

    3.13 - Using Tables as Arrays

    The API has functions that help to use Lua tables as arrays, that is, tables indexed by numbers only: @@ -2309,7 +2305,7 @@

    1 - Introduction

    at stack position index to the value at the top of the stack, removing this value from the stack. -

    3.14 - Calling Functions

    +

    3.14 - Calling Functions

    Functions defined in Lua and C functions registered in Lua @@ -2364,7 +2360,7 @@

    1 - Introduction

    that provide higher level access to Lua. See the source code of the standard libraries for examples.) -

    3.15 - Protected Calls

    +

    3.15 - Protected Calls

    When you call a function with lua_call, any error inside the called function is propagated upwards @@ -2411,7 +2407,7 @@

    1 - Introduction

    error while running the error handler function. -

    3.16 - Defining C Functions

    +

    3.16 - Defining C Functions

    Lua can be extended with functions written in C. These functions must be of type lua_CFunction, @@ -2479,7 +2475,7 @@

    1 - Introduction

    lua_register(L, "average", foo);
    -

    3.17 - Defining C Closures

    +

    3.17 - Defining C Closures

    When a C function is created, it is possible to associate some values with it, @@ -2514,7 +2510,7 @@

    1 - Introduction

    see the standard libraries in the official Lua distribution (src/lib/*.c). -

    3.18 - Registry

    +

    3.18 - Registry

    Lua provides a registry, a pre-defined table that can be used by any C code to @@ -2532,26 +2528,26 @@

    1 - Introduction

    implemented by the auxiliary library, and therefore should not be used by other purposes. -

    3.19 - Error Handling in C

    +

    3.19 - Error Handling in C

    Internally, Lua uses the C longjmp facility to handle errors. When Lua faces any error (such as memory allocation errors, type errors, syntax errors) it raises an error, that is, it does a long jump. A protected environment uses setjmp -to set a recover point, -and any error jumps to the most recent active recover point. +to set a recover point; +any error jumps to the most recent active recover point.

    If an error happens outside any protected environment, -Lua calls a panic function, +Lua calls a panic function and then calls exit(EXIT_FAILURE). You can change the panic function with

            lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
     
    Your new panic function may avoid the application exit by -never returning (e.g. doing a long jump). -Nevertheless, the corresponding Lua will not be consistent; +never returning (e.g., by doing a long jump). +Nevertheless, the corresponding Lua state will not be consistent; the only safe operation with it is to close it.

    Almost any function in the API may raise an error, @@ -2575,7 +2571,7 @@

    1 - Introduction

    (see 3.15), plus the error object on the top of the stack; otherwise, it returns zero, and does not change the stack. -Any value returned by func is dicarded. +Any value returned by func is discarded.

    C code can generate a Lua error calling the function

    @@ -2587,7 +2583,7 @@ 

    1 - Introduction

    This function does a long jump, and therefore never returns. -

    3.20 - Threads

    +

    3.20 - Threads

    Lua offers partial support for multiple threads of execution. If you have a C library that offers multi-threading, @@ -2608,18 +2604,15 @@

    1 - Introduction

    When you create a thread, this table is the same as that of the given state, but you can change each one independently. -

    You destroy threads with lua_closethread: -

    -       void lua_closethread (lua_State *L, lua_State *thread);
    -
    -You cannot close the sole (or last) thread of a state. -Instead, you must close the state itself. +

    There is no explicit function to close or to destroy a thread. +Threads are subject to garbage collection, +like any Lua object.

    To manipulate threads as coroutines, Lua offers the following functions:

            int lua_resume (lua_State *L, int narg);
    -       int lua_yield (lua_State *L, int nresults);
    +       int lua_yield  (lua_State *L, int nresults);
     
    To start a coroutine, you first create a new thread; @@ -2629,7 +2622,7 @@

    1 - Introduction

    This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. -lua_resume returns 0 if there is no errors running the coroutine, +lua_resume returns 0 if there are no errors running the coroutine, or an error code (see 3.15). In case of errors, the stack contains only the error message. @@ -2657,7 +2650,7 @@

    1 - Introduction

    and puhses them into the stack to.

    -

    4 - The Debug Interface

    +

    4 - The Debug Interface

    Lua has no built-in debugging facilities. Instead, it offers a special interface @@ -2666,7 +2659,7 @@

    1 - Introduction

    kinds of debuggers, profilers, and other tools that need "inside information" from the interpreter. -

    4.1 - Stack and Function Information

    +

    4.1 - Stack and Function Information

    The main function to get information about the interpreter runtime stack is

    @@ -2678,7 +2671,7 @@ 

    1 - Introduction

    of the function executing at a given level. Level 0 is the current running function, whereas level n+1 is the function that has called level n. -When there is no errors, lua_getstack returns 1; +When there are no errors, lua_getstack returns 1; when called with a level greater than the stack depth, it returns 0. @@ -2786,7 +2779,7 @@

    1 - Introduction

    -

    4.2 - Manipulating Local Variables and Upvalues

    +

    4.2 - Manipulating Local Variables and Upvalues

    For the manipulation of local variables and upvalues, the debug interface uses indices: @@ -2863,7 +2856,7 @@

    1 - Introduction

    }
    -

    4.3 - Hooks

    +

    4.3 - Hooks

    Lua offers a mechanism of hooks, which are user-defined C functions that are called during the program execution. @@ -2939,7 +2932,7 @@

    1 - Introduction

    that execution occurs without any calls to hooks.

    -

    5 - Standard Libraries

    +

    5 - Standard Libraries

    The standard libraries provide useful functions that are implemented directly through the C API. @@ -2982,7 +2975,7 @@

    1 - Introduction

    -

    5.1 - Basic Functions

    +

    5.1 - Basic Functions

    The basic library provides some core functions to Lua. If you do not include this library in your application, @@ -3015,7 +3008,7 @@

    1 - Introduction

    error (message [, level])

    -Terminates the last protected function called, +Terminates the last protected function called and returns message as the error message. Function error never returns. @@ -3043,7 +3036,7 @@

    1 - Introduction

    getfenv returns the global environment. The default for f is 1. -

    if the environment has a "__fenv" field, +

    If the environment has a "__fenv" field, returns the associated value, instead of the environment.

    getmetatable (object)

    @@ -3148,11 +3141,11 @@

    1 - Introduction

    Calls function f with the given arguments in protected mode. -That means that any error inside f is not propagated; +That means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), -which is true if the call succeeds without errors. +which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message. @@ -3327,10 +3320,10 @@

    1 - Introduction

    In case of any error, xpcall returns false plus the result from err. -

    5.2 - Coroutine Manipulation

    +

    5.2 - Coroutine Manipulation

    The operations related to coroutines comprise a sub-library of -the basic library, and come inside the table . +the basic library and come inside the table coroutine. See 2.10 for a general description of coroutines.

    coroutine.create (f)

    @@ -3385,7 +3378,7 @@

    1 - Introduction

    nor a metamethod, nor an iterator. Any arguments to yield go as extra results to resume. -

    5.3 - String Manipulation

    +

    5.3 - String Manipulation

    This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching. When indexing a string in Lua, the first character is at position 1 @@ -3592,7 +3585,7 @@

    1 - Introduction

    Patterns

    -a character class is used to represent a set of characters. +A character class is used to represent a set of characters. The following combinations are allowed in describing a character class:

    • x (where x is not one of the magic characters @@ -3648,7 +3641,7 @@

      1 - Introduction

      The second form should be preferred for portability.

      -a pattern item may be +A pattern item may be

      • a single character class, @@ -3685,7 +3678,7 @@

        1 - Introduction

      -a pattern is a sequence of pattern items. +A pattern is a sequence of pattern items. A `^´ at the beginning of a pattern anchors the match at the beginning of the subject string. A `$´ at the end of a pattern anchors the match at the @@ -3712,7 +3705,7 @@

      1 - Introduction

      A pattern cannot contain embedded zeros. Use %z instead. -

      5.4 - Table Manipulation

      +

      5.4 - Table Manipulation

      This library provides generic functions for table manipulation. It provides all its functions inside the table table. @@ -3821,7 +3814,7 @@

      1 - Introduction

      Otherwise, it updates an internal state so that subsequent calls to table.getn(table) return n. -

      5.5 - Mathematical Functions

      +

      5.5 - Mathematical Functions

      This library is an interface to most of the functions of the standard C math library. @@ -3876,7 +3869,7 @@

      1 - Introduction

      for the pseudo-random generator: Equal seeds produce equal sequences of numbers. -

      5.6 - Input and Output Facilities

      +

      5.6 - Input and Output Facilities

      The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors, @@ -4069,7 +4062,7 @@

      1 - Introduction

      To write other values, use tostring or string.format before write. -

      5.7 - Operating System Facilities

      +

      5.7 - Operating System Facilities

      This library is implemented through table os. @@ -4095,7 +4088,7 @@

      1 - Introduction

      then date returns a table with the following fields: year (four digits), month (1--12), day (1--31), hour (0--23), min (0--59), sec (0--61), -wday (weekday, Sunday is 1), +wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean). @@ -4184,7 +4177,7 @@

      1 - Introduction

      it is possible for another process to create a file with the same name. -

      5.8 - The Reflexive Debug Interface

      +

      5.8 - The Reflexive Debug Interface

      The debug library provides the functionality of the debug interface to Lua programs. @@ -4320,7 +4313,7 @@

      1 - Introduction

      better error messages.

      -

      6 - Lua Stand-alone

      +

      6 - Lua Stand-alone

      Although Lua has been designed as an extension language, to be embedded in a host C program, @@ -4459,7 +4452,7 @@

      Acknowledgments

      Steve Dekorte, Thatcher Ulrich, Tomás Gorham, -Vincent Penquerc'h, +Vincent Penquerc'h. Thank you!


      @@ -4580,7 +4573,7 @@

      Acknowledgments

      explist1 ::= {exp `,´} exp -

      exp ::= nil false true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp +

      exp ::= nil | false | true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp

      prefixexp ::= var | functioncall | `(´ exp `)´ @@ -4609,5 +4602,11 @@

      Acknowledgments

      - +


      + +Last update: +Tue Nov 25 16:08:37 BRST 2003 + + + diff --git a/etc/.exrc b/etc/.exrc deleted file mode 120000 index d906774993..0000000000 --- a/etc/.exrc +++ /dev/null @@ -1 +0,0 @@ -/home/n/lhf/lib/vi/c \ No newline at end of file diff --git a/include/lua.h b/include/lua.h index 0d827b10c7..c5689379f6 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.175 2003/03/18 12:31:39 roberto Exp $ +** $Id: lua.h,v 1.175a 2003/03/18 12:31:39 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -14,7 +14,7 @@ #include -#define LUA_VERSION "Lua 5.0" +#define LUA_VERSION "Lua 5.0.1" #define LUA_COPYRIGHT "Copyright (C) 1994-2003 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" diff --git a/src/ldo.c b/src/ldo.c index ae4f22fd44..a6d344cd57 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.217 2003/04/03 13:35:34 roberto Exp $ +** $Id: ldo.c,v 1.217a 2003/04/03 13:35:34 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -322,11 +322,11 @@ static void resume (lua_State *L, void *ud) { int nargs = *cast(int *, ud); CallInfo *ci = L->ci; if (ci == L->base_ci) { /* no activation record? */ - if (nargs >= L->top - L->base) - luaG_runerror(L, "cannot resume dead coroutine"); + lua_assert(nargs < L->top - L->base); luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ } - else if (ci->state & CI_YIELD) { /* inside a yield? */ + else { /* inside a yield */ + lua_assert(ci->state & CI_YIELD); if (ci->state & CI_C) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ int nresults; @@ -341,18 +341,31 @@ static void resume (lua_State *L, void *ud) { ci->state &= ~CI_YIELD; } } - else - luaG_runerror(L, "cannot resume non-suspended coroutine"); firstResult = luaV_execute(L); if (firstResult != NULL) /* return? */ luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ } +static int resume_error (lua_State *L, const char *msg) { + L->top = L->ci->base; + setsvalue2s(L->top, luaS_new(L, msg)); + incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; +} + + LUA_API int lua_resume (lua_State *L, int nargs) { int status; lu_byte old_allowhooks; lua_lock(L); + if (L->ci == L->base_ci) { + if (nargs >= L->top - L->base) + return resume_error(L, "cannot resume dead coroutine"); + } + else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ + return resume_error(L, "cannot resume non-suspended coroutine"); old_allowhooks = L->allowhook; lua_assert(L->errfunc == 0 && L->nCcalls == 0); status = luaD_rawrunprotected(L, resume, &nargs); diff --git a/src/lgc.c b/src/lgc.c index 4cc45e39d0..5e036d387a 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.171 2003/04/03 13:35:34 roberto Exp $ +** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -110,7 +110,8 @@ static void marktmu (GCState *st) { /* move `dead' udata that need finalization to list `tmudata' */ -void luaC_separateudata (lua_State *L) { +size_t luaC_separateudata (lua_State *L) { + size_t deadmem = 0; GCObject **p = &G(L)->rootudata; GCObject *curr; GCObject *collected = NULL; /* to collect udata with gc event */ @@ -125,6 +126,7 @@ void luaC_separateudata (lua_State *L) { p = &curr->gch.next; } else { /* must call its gc method */ + deadmem += sizeudata(gcotou(curr)->uv.len); *p = curr->gch.next; curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ *lastcollected = curr; @@ -134,6 +136,7 @@ void luaC_separateudata (lua_State *L) { /* insert collected udata with gc event into `tmudata' list */ *lastcollected = G(L)->tmudata; G(L)->tmudata = collected; + return deadmem; } @@ -244,7 +247,7 @@ static void traversestack (GCState *st, lua_State *L1) { for (ci = L1->base_ci; ci <= L1->ci; ci++) { lua_assert(ci->top <= L1->stack_last); lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC)); - if (!(ci->state & CI_C) && lim < ci->top) + if (lim < ci->top) lim = ci->top; } for (o = L1->stack; o < L1->top; o++) @@ -387,7 +390,7 @@ static void sweepstrings (lua_State *L, int all) { } -static void checkSizes (lua_State *L) { +static void checkSizes (lua_State *L, size_t deadmem) { /* check size of string hash */ if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && G(L)->strt.size > MINSTRTABSIZE*2) @@ -397,7 +400,7 @@ static void checkSizes (lua_State *L) { size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2; luaZ_resizebuffer(L, &G(L)->buff, newsize); } - G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ + G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ } @@ -451,7 +454,8 @@ static void markroot (GCState *st, lua_State *L) { } -static void mark (lua_State *L) { +static size_t mark (lua_State *L) { + size_t deadmem; GCState st; GCObject *wkv; st.g = G(L); @@ -464,7 +468,7 @@ static void mark (lua_State *L) { wkv = st.wkv; /* keys must be cleared after preserving udata */ st.wkv = NULL; st.wv = NULL; - luaC_separateudata(L); /* separate userdata to be preserved */ + deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ marktmu(&st); /* mark `preserved' userdata */ propagatemarks(&st); /* remark, to propagate `preserveness' */ cleartablekeys(wkv); @@ -473,13 +477,14 @@ static void mark (lua_State *L) { cleartablevalues(st.wv); cleartablekeys(st.wkv); cleartablevalues(st.wkv); + return deadmem; } void luaC_collectgarbage (lua_State *L) { - mark(L); + size_t deadmem = mark(L); luaC_sweep(L, 0); - checkSizes(L); + checkSizes(L, deadmem); luaC_callGCTM(L); } diff --git a/src/lgc.h b/src/lgc.h index 6ab6c91749..3f4d7486e9 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 1.19 2003/02/28 19:45:15 roberto Exp $ +** $Id: lgc.h,v 1.19a 2003/02/28 19:45:15 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -15,7 +15,7 @@ if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); } -void luaC_separateudata (lua_State *L); +size_t luaC_separateudata (lua_State *L); void luaC_callGCTM (lua_State *L); void luaC_sweep (lua_State *L, int all); void luaC_collectgarbage (lua_State *L); diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index 7381cf3357..45bc7cfe57 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.130 2003/04/03 13:35:34 roberto Exp $ +** $Id: lbaselib.c,v 1.130a 2003/04/03 13:35:34 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -324,7 +324,7 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { - char buff[64]; + char buff[128]; luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 14bd7d9909..96b38831d2 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.39 2003/03/19 21:16:12 roberto Exp $ +** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -158,7 +158,7 @@ static int aux_close (lua_State *L) { static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) { + if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { lua_pushstring(L, IO_OUTPUT); lua_rawget(L, lua_upvalueindex(1)); } @@ -175,7 +175,7 @@ static int io_gc (lua_State *L) { static int io_tostring (lua_State *L) { - char buff[32]; + char buff[128]; FILE **f = topfile(L, 1); if (*f == NULL) strcpy(buff, "closed"); diff --git a/src/lparser.c b/src/lparser.c index c1323ecd2a..99bd3020e7 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.208 2003/04/03 13:35:34 roberto Exp $ +** $Id: lparser.c,v 1.208a 2003/04/03 13:35:34 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -1141,11 +1141,15 @@ static void ifstat (LexState *ls, int line) { static void localfunc (LexState *ls) { expdesc v, b; + FuncState *fs = ls->fs; new_localvar(ls, str_checkname(ls), 0); - init_exp(&v, VLOCAL, ls->fs->freereg++); + init_exp(&v, VLOCAL, fs->freereg); + luaK_reserveregs(fs, 1); adjustlocalvars(ls, 1); body(ls, &b, 0, ls->linenumber); - luaK_storevar(ls->fs, &v, &b); + luaK_storevar(fs, &v, &b); + /* debug information will only see the variable after this point! */ + getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; } diff --git a/src/luac/Makefile b/src/luac/Makefile index 7a620826f3..9e772b412d 100644 --- a/src/luac/Makefile +++ b/src/luac/Makefile @@ -13,7 +13,7 @@ T= $(BIN)/luac all: $T $T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) + $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) # print.c needs opcode names from lopcodes.c lopcodes.o: ../lopcodes.c ../lopcodes.h diff --git a/src/luac/luac.c b/src/luac/luac.c index 9ea23342da..1aff0bd93f 100644 --- a/src/luac/luac.c +++ b/src/luac/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.44 2003/04/07 20:34:20 lhf Exp $ +** $Id: luac.c,v 1.44a 2003/04/07 20:34:20 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -182,7 +182,9 @@ int main(int argc, char* argv[]) FILE* D=fopen(output,"wb"); if (D==NULL) cannot(output,"open","out"); if (stripping) strip(L,f); + lua_lock(L); luaU_dump(L,f,writer,D); + lua_unlock(L); if (ferror(D)) cannot(output,"write","out"); fclose(D); } diff --git a/src/lvm.c b/src/lvm.c index eaa5c700b0..18005d03e8 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.284 2003/04/03 13:35:34 roberto Exp $ +** $Id: lvm.c,v 1.284a 2003/04/03 13:35:34 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -66,7 +66,7 @@ int luaV_tostring (lua_State *L, StkId obj) { static void traceexec (lua_State *L) { lu_byte mask = L->hookmask; - if (mask > LUA_MASKLINE) { /* instruction-hook set? */ + if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); @@ -399,10 +399,10 @@ StkId luaV_execute (lua_State *L) { TObject *k; const Instruction *pc; callentry: /* entry point when calling new functions */ - L->ci->u.l.pc = &pc; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ + L->ci->u.l.pc = &pc; lua_assert(L->ci->state == CI_SAVEDPC || L->ci->state == (CI_SAVEDPC | CI_CALLING)); L->ci->state = CI_HASFRAME; /* activate frame */ @@ -673,9 +673,7 @@ StkId luaV_execute (lua_State *L) { } else { /* yes: continue its execution */ int nresults; - lua_assert(ci->u.l.pc == &pc && - ttisfunction(ci->base - 1) && - (ci->state & CI_SAVEDPC)); + lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); diff --git a/test/luac.lua b/test/luac.lua index f9aa905299..b009ae9da5 100644 --- a/test/luac.lua +++ b/test/luac.lua @@ -1,7 +1,7 @@ -- bare-bones luac in Lua -- usage: lua luac.lua file.lua -assert(arg[1]~=nil,"usage: lua luac.lua file.lua") -f=assert(io.open("luac.out","w")) -f:write(string.dump(loadfile(arg[1]))) +assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") +f=assert(io.open("luac.out","wb")) +f:write(string.dump(assert(loadfile(arg[1])))) io.close(f) From e7731a8fb8a317aa5c444ef073bfad82fa5baa54 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Wed, 17 Mar 2004 12:00:00 +0000 Subject: [PATCH 16/97] Lua 5.0.2 --- COPYRIGHT | 2 +- DIFFS | 523 ++++++--------------------------------------- MANIFEST | 259 +++++++++++----------- Makefile | 3 + UPDATE | 7 +- doc/contents.html | 123 +++++++++++ doc/readme.html | 4 +- include/lua.h | 8 +- src/lib/lbaselib.c | 5 +- src/lvm.c | 7 +- test/compat.lua | 192 ----------------- test/table.lua | 2 +- 12 files changed, 337 insertions(+), 798 deletions(-) create mode 100644 doc/contents.html delete mode 100644 test/compat.lua diff --git a/COPYRIGHT b/COPYRIGHT index fd3cdf9b3e..16321abf6b 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 2003 Tecgraf, PUC-Rio. +Copyright (C) 2003-2004 Tecgraf, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/DIFFS b/DIFFS index 006a274829..f7d5ba27eb 100644 --- a/DIFFS +++ b/DIFFS @@ -1,456 +1,38 @@ -diff -r lua-5.0/doc/manual.html lua-5.0.1/doc/manual.html -5c5 -< Lua 5.0 Reference Manual ---- -> Lua: 5.0 reference manual -12,14c12 -< -< [Lua logo] -< ---- -> Lua -22c20 -< © 2003 TeCGraf, PUC-Rio. All rights reserved. ---- -> © 2003 Tecgraf, PUC-Rio. All rights reserved. -32c30 -<

      1 - Introduction

      ---- ->

      1 - Introduction

      -37c35 -< It also offers good suport for object-oriented programming, ---- -> It also offers good support for object-oriented programming, -54c52 -<

      The Lua distribuition includes a stand-alone embedding program, ---- ->

      The Lua distribution includes a stand-alone embedding program, -90c88 -<

      2 - The Language

      ---- ->

      2 - The Language

      -108c106 -<

      2.1 - Lexical Conventions

      ---- ->

      2.1 - Lexical Conventions

      -125,126c123 -< repeat return then true until -< while ---- -> repeat return then true until while -214c211 -<

      2.2 - Values and Types

      ---- ->

      2.2 - Values and Types

      -295c292 -<

      2.2.1 - Coercion

      ---- ->

      2.2.1 - Coercion

      -306c303 -<

      2.3 - Variables

      ---- ->

      2.3 - Variables

      -375c372 -<

      2.4 - Statements

      ---- ->

      2.4 - Statements

      -383c380 -<

      2.4.1 - Chunks

      ---- ->

      2.4.1 - Chunks

      -408c405 -<

      2.4.2 - Blocks

      ---- ->

      2.4.2 - Blocks

      -426c423 -<

      2.4.3 - Assignment

      ---- ->

      2.4.3 - Assignment

      -461c458 -< before it is assigned 4. ---- -> before it is assigned 4. -488c485 -<

      2.4.4 - Control Structures

      ---- ->

      2.4.4 - Control Structures

      -519c516 -< skiping to the next statement after the loop: ---- -> skipping to the next statement after the loop: -539c536 -<

      2.4.5 - For Statement

      ---- ->

      2.4.5 - For Statement

      -626c623 -<

      2.4.6 - Function Calls as Statements

      ---- ->

      2.4.6 - Function Calls as Statements

      -635c632 -<

      2.4.7 - Local Declarations

      ---- ->

      2.4.7 - Local Declarations

      -652c649 -<

      2.5 - Expressions

      ---- ->

      2.5 - Expressions

      -683c680 -<

      2.5.1 - Arithmetic Operators

      ---- ->

      2.5.1 - Arithmetic Operators

      -698c695 -<

      2.5.2 - Relational Operators

      ---- ->

      2.5.2 - Relational Operators

      -734c731 -<

      2.5.3 - Logical Operators

      ---- ->

      2.5.3 - Logical Operators

      -767c764 -<

      2.5.4 - Concatenation

      ---- ->

      2.5.4 - Concatenation

      -774c771 -<

      2.5.5 - Precedence

      ---- ->

      2.5.5 - Precedence

      -787c784 -< As usual, you can use parentheses to change the precedences of an expression. ---- -> You can use parentheses to change the precedences in an expression. -792c789 -<

      2.5.6 - Table Constructors

      ---- ->

      2.5.6 - Table Constructors

      -842c839 -<

      2.5.7 - Function Calls

      ---- ->

      2.5.7 - Function Calls

      -947c944 -< return x, f(x) -- adicional results ---- -> return x, f(x) -- additional results -952c949 -<

      2.5.8 - Function Definitions

      ---- ->

      2.5.8 - Function Definitions

      -1061c1058 -<

      2.6 - Visibility Rules

      ---- ->

      2.6 - Visibility Rules

      -1118c1115 -<

      2.7 - Error Handling

      ---- ->

      2.7 - Error Handling

      -1133c1130 -<

      2.8 - Metatables

      ---- ->

      2.8 - Metatables

      -1315c1312 -< if type(op1) ~= type(op2) then -- diferent types? ---- -> if type(op1) ~= type(op2) then -- different types? -1443c1440 -<

      2.9 - Garbage Collection

      ---- ->

      2.9 - Garbage Collection

      -1474c1471 -<

      2.9.1 - Garbage-Collection Metamethods

      ---- ->

      2.9.1 - Garbage-Collection Metamethods

      -1506c1503 -<

      2.9.2 - Weak Tables

      ---- ->

      2.9.2 - Weak Tables

      -1524c1521 -< If the __mode field is a string containing the character `k´, ---- -> If the __mode field is a string containing the character `k´, -1534c1531 -<

      2.10 - Coroutines

      ---- ->

      2.10 - Coroutines

      -1552c1549 -< passing as argument the thread returned by coroutine.create, ---- -> passing as its first argument the thread returned by coroutine.create, -1633c1630 -<

      3 - The Application Program Interface

      ---- ->

      3 - The Application Program Interface

      -1648c1645 -<

      3.1 - States

      ---- ->

      3.1 - States

      -1684c1681 -<

      3.2 - The Stack and Indices

      ---- ->

      3.2 - The Stack and Indices

      -1694c1691 -< and it is where the C function pushes its results (see 3.16) ---- -> and it is where the C function pushes its results to be returned to the caller (see 3.16) -1739c1736 -< it ensures that at least LUA_MINSTACK positions are available. +diff -r lua-5.0/COPYRIGHT lua-5.0.2/COPYRIGHT +12c12 +< Copyright (C) 2003 Tecgraf, PUC-Rio. +--- +> Copyright (C) 2003-2004 Tecgraf, PUC-Rio. +diff -r lua-5.0/Makefile lua-5.0.2/Makefile +98a99,101 +> newer: +> @find . -newer MANIFEST -type f +> +diff -r lua-5.0/doc/readme.html lua-5.0.2/doc/readme.html +16c16 +<
    • Reference manual --- -> it ensures that at least LUA_MINSTACK stack positions are available. -1763c1760 -<

      3.3 - Stack Manipulation

      +>
    • Reference manual +31c31 +< Tue Apr 1 14:35:18 EST 2003 --- ->

      3.3 - Stack Manipulation

      -1816c1813 -<

      3.4 - Querying the Stack

      ---- ->

      3.4 - Querying the Stack

      -1890c1887 -<

      3.5 - Getting Values from the Stack

      ---- ->

      3.5 - Getting Values from the Stack

      -1969c1966 -<

      3.6 - Pushing Values onto the Stack

      ---- ->

      3.6 - Pushing Values onto the Stack

      -1999,2000c1996 -< const char *lua_pushvfstring (lua_State *L, const char *fmt, -< va_list argp); ---- -> const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp); -2028c2024 -< If n is 1, the result is that single string ---- -> If n is 1, the result is that single string -2034c2030 -<

      3.7 - Controlling Garbage Collection

      ---- ->

      3.7 - Controlling Garbage Collection

      -2047c2043 -< int lua_getgccount (lua_State *L); ---- -> int lua_getgccount (lua_State *L); -2067c2063 -<

      3.8 - Userdata

      ---- ->

      3.8 - Userdata

      -2112c2108 -<

      3.9 - Metatables

      ---- ->

      3.9 - Metatables

      -2133c2129 -<

      3.10 - Loading Lua Chunks

      ---- ->

      3.10 - Loading Lua Chunks

      -2160c2156 -<

      lua_load uses an user-supplied reader function to read the chunk. ---- ->

      lua_load uses a user-supplied reader function to read the chunk. -2162c2158 -< it calls the reader, ---- -> lua_load calls the reader, -2182c2178 -<

      3.11 - Manipulating Tables

      ---- ->

      3.11 - Manipulating Tables

      -2263c2259 -<

      3.12 - Manipulating Environments

      ---- ->

      3.12 - Manipulating Environments

      -2295c2291 -<

      3.13 - Using Tables as Arrays

      ---- ->

      3.13 - Using Tables as Arrays

      -2312c2308 -<

      3.14 - Calling Functions

      ---- ->

      3.14 - Calling Functions

      -2367c2363 -<

      3.15 - Protected Calls

      ---- ->

      3.15 - Protected Calls

      -2414c2410 -<

      3.16 - Defining C Functions

      ---- ->

      3.16 - Defining C Functions

      -2482c2478 -<

      3.17 - Defining C Closures

      ---- ->

      3.17 - Defining C Closures

      -2517c2513 -<

      3.18 - Registry

      ---- ->

      3.18 - Registry

      -2535c2531 -<

      3.19 - Error Handling in C

      ---- ->

      3.19 - Error Handling in C

      -2542,2543c2538,2539 -< to set a recover point, -< and any error jumps to the most recent active recover point. ---- -> to set a recover point; -> any error jumps to the most recent active recover point. -2546c2542 -< Lua calls a panic function, ---- -> Lua calls a panic function -2553,2554c2549,2550 -< never returning (e.g. doing a long jump). -< Nevertheless, the corresponding Lua will not be consistent; ---- -> never returning (e.g., by doing a long jump). -> Nevertheless, the corresponding Lua state will not be consistent; -2578c2574 -< Any value returned by func is dicarded. ---- -> Any value returned by func is discarded. -2590c2586 -<

      3.20 - Threads

      ---- ->

      3.20 - Threads

      -2611,2616c2607,2609 -<

      You destroy threads with lua_closethread: -<

      -<        void lua_closethread (lua_State *L, lua_State *thread);
      -< 
      -< You cannot close the sole (or last) thread of a state. -< Instead, you must close the state itself. ---- ->

      There is no explicit function to close or to destroy a thread. -> Threads are subject to garbage collection, -> like any Lua object. -2622c2615 -< int lua_yield (lua_State *L, int nresults); ---- -> int lua_yield (lua_State *L, int nresults); -2632c2625 -< lua_resume returns 0 if there is no errors running the coroutine, ---- -> lua_resume returns 0 if there are no errors running the coroutine, -2660c2653 -<

      4 - The Debug Interface

      ---- ->

      4 - The Debug Interface

      -2669c2662 -<

      4.1 - Stack and Function Information

      ---- ->

      4.1 - Stack and Function Information

      -2681c2674 -< When there is no errors, lua_getstack returns 1; ---- -> When there are no errors, lua_getstack returns 1; -2789c2782 -<

      4.2 - Manipulating Local Variables and Upvalues

      ---- ->

      4.2 - Manipulating Local Variables and Upvalues

      -2866c2859 -<

      4.3 - Hooks

      ---- ->

      4.3 - Hooks

      -2942c2935 -<

      5 - Standard Libraries

      ---- ->

      5 - Standard Libraries

      -2985c2978 -<

      5.1 - Basic Functions

      ---- ->

      5.1 - Basic Functions

      -3018c3011 -< Terminates the last protected function called, ---- -> Terminates the last protected function called -3046c3039 -<

      if the environment has a "__fenv" field, ---- ->

      If the environment has a "__fenv" field, -3151c3144 -< That means that any error inside f is not propagated; ---- -> That means that any error inside f is not propagated; -3155c3148 -< which is true if the call succeeds without errors. ---- -> which is true if the call succeeds without errors. -3330c3323 -<

      5.2 - Coroutine Manipulation

      ---- ->

      5.2 - Coroutine Manipulation

      -3333c3326 -< the basic library, and come inside the table . ---- -> the basic library and come inside the table coroutine. -3388c3381 -<

      5.3 - String Manipulation

      ---- ->

      5.3 - String Manipulation

      -3595c3588 -< a character class is used to represent a set of characters. ---- -> A character class is used to represent a set of characters. -3651c3644 -< a pattern item may be ---- -> A pattern item may be -3688c3681 -< a pattern is a sequence of pattern items. ---- -> A pattern is a sequence of pattern items. -3715c3708 -<

      5.4 - Table Manipulation

      ---- ->

      5.4 - Table Manipulation

      -3824c3817 -<

      5.5 - Mathematical Functions

      ---- ->

      5.5 - Mathematical Functions

      -3879c3872 -<

      5.6 - Input and Output Facilities

      ---- ->

      5.6 - Input and Output Facilities

      -4072c4065 -<

      5.7 - Operating System Facilities

      ---- ->

      5.7 - Operating System Facilities

      -4098c4091 -< wday (weekday, Sunday is 1), ---- -> wday (weekday, Sunday is 1), -4187c4180 -<

      5.8 - The Reflexive Debug Interface

      ---- ->

      5.8 - The Reflexive Debug Interface

      -4323c4316 -<

      6 - Lua Stand-alone

      ---- ->

      6 - Lua Stand-alone

      -4462c4455 -< Vincent Penquerc'h, ---- -> Vincent Penquerc'h. -4583c4576 -<

      exp ::= nil false true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp ---- ->

      exp ::= nil | false | true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp -4612c4605,4609 -< ---- ->


      -> -> Last update: -> Tue Nov 25 16:08:37 BRST 2003 -> -4613a4611,4612 -> -> -diff -r lua-5.0/include/lua.h lua-5.0.1/include/lua.h +> Thu Mar 11 23:08:56 BRT 2004 +diff -r lua-5.0/include/lua.h lua-5.0.2/include/lua.h 2c2 < ** $Id: lua.h,v 1.175 2003/03/18 12:31:39 roberto Exp $ --- -> ** $Id: lua.h,v 1.175a 2003/03/18 12:31:39 roberto Exp $ -17c17 +> ** $Id: lua.h,v 1.175b 2003/03/18 12:31:39 roberto Exp $ +17,18c17,18 < #define LUA_VERSION "Lua 5.0" +< #define LUA_COPYRIGHT "Copyright (C) 1994-2003 Tecgraf, PUC-Rio" +--- +> #define LUA_VERSION "Lua 5.0.2" +> #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" +368c368 +< * Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved. --- -> #define LUA_VERSION "Lua 5.0.1" -diff -r lua-5.0/src/ldo.c lua-5.0.1/src/ldo.c +> * Copyright (C) 1994-2004 Tecgraf, PUC-Rio. All rights reserved. +diff -r lua-5.0/src/ldo.c lua-5.0.2/src/ldo.c 2c2 < ** $Id: ldo.c,v 1.217 2003/04/03 13:35:34 roberto Exp $ --- @@ -485,7 +67,7 @@ diff -r lua-5.0/src/ldo.c lua-5.0.1/src/ldo.c > } > else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ > return resume_error(L, "cannot resume non-suspended coroutine"); -diff -r lua-5.0/src/lgc.c lua-5.0.1/src/lgc.c +diff -r lua-5.0/src/lgc.c lua-5.0.2/src/lgc.c 2c2 < ** $Id: lgc.c,v 1.171 2003/04/03 13:35:34 roberto Exp $ --- @@ -530,7 +112,7 @@ diff -r lua-5.0/src/lgc.c lua-5.0.1/src/lgc.c < checkSizes(L); --- > checkSizes(L, deadmem); -diff -r lua-5.0/src/lgc.h lua-5.0.1/src/lgc.h +diff -r lua-5.0/src/lgc.h lua-5.0.2/src/lgc.h 2c2 < ** $Id: lgc.h,v 1.19 2003/02/28 19:45:15 roberto Exp $ --- @@ -539,16 +121,22 @@ diff -r lua-5.0/src/lgc.h lua-5.0.1/src/lgc.h < void luaC_separateudata (lua_State *L); --- > size_t luaC_separateudata (lua_State *L); -diff -r lua-5.0/src/lib/lbaselib.c lua-5.0.1/src/lib/lbaselib.c +diff -r lua-5.0/src/lib/lbaselib.c lua-5.0.2/src/lib/lbaselib.c 2c2 < ** $Id: lbaselib.c,v 1.130 2003/04/03 13:35:34 roberto Exp $ --- -> ** $Id: lbaselib.c,v 1.130a 2003/04/03 13:35:34 roberto Exp $ -327c327 +> ** $Id: lbaselib.c,v 1.130b 2003/04/03 13:35:34 roberto Exp $ +276a277 +> int n = lua_gettop(L); +280c281 +< return lua_gettop(L) - 1; +--- +> return lua_gettop(L) - n; +327c328 < char buff[64]; --- > char buff[128]; -diff -r lua-5.0/src/lib/liolib.c lua-5.0.1/src/lib/liolib.c +diff -r lua-5.0/src/lib/liolib.c lua-5.0.2/src/lib/liolib.c 2c2 < ** $Id: liolib.c,v 2.39 2003/03/19 21:16:12 roberto Exp $ --- @@ -561,7 +149,7 @@ diff -r lua-5.0/src/lib/liolib.c lua-5.0.1/src/lib/liolib.c < char buff[32]; --- > char buff[128]; -diff -r lua-5.0/src/lparser.c lua-5.0.1/src/lparser.c +diff -r lua-5.0/src/lparser.c lua-5.0.2/src/lparser.c 2c2 < ** $Id: lparser.c,v 1.208 2003/04/03 13:35:34 roberto Exp $ --- @@ -579,12 +167,12 @@ diff -r lua-5.0/src/lparser.c lua-5.0.1/src/lparser.c > luaK_storevar(fs, &v, &b); > /* debug information will only see the variable after this point! */ > getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; -diff -r lua-5.0/src/luac/Makefile lua-5.0.1/src/luac/Makefile +diff -r lua-5.0/src/luac/Makefile lua-5.0.2/src/luac/Makefile 16c16 < $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) --- > $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) -diff -r lua-5.0/src/luac/luac.c lua-5.0.1/src/luac/luac.c +diff -r lua-5.0/src/luac/luac.c lua-5.0.2/src/luac/luac.c 2c2 < ** $Id: luac.c,v 1.44 2003/04/07 20:34:20 lhf Exp $ --- @@ -593,26 +181,34 @@ diff -r lua-5.0/src/luac/luac.c lua-5.0.1/src/luac/luac.c > lua_lock(L); 185a187 > lua_unlock(L); -diff -r lua-5.0/src/lvm.c lua-5.0.1/src/lvm.c +diff -r lua-5.0/src/lvm.c lua-5.0.2/src/lvm.c 2c2 < ** $Id: lvm.c,v 1.284 2003/04/03 13:35:34 roberto Exp $ --- -> ** $Id: lvm.c,v 1.284a 2003/04/03 13:35:34 roberto Exp $ +> ** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ 69c69 < if (mask > LUA_MASKLINE) { /* instruction-hook set? */ --- > if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ -402d401 +402,403c402,403 < L->ci->u.l.pc = &pc; -405a405 +< if (L->hookmask & LUA_MASKCALL) +--- +> if (L->hookmask & LUA_MASKCALL) { +> L->ci->u.l.pc = &pc; +404a405 +> } +405a407 > L->ci->u.l.pc = &pc; -676,678c676 +676,678c678 < lua_assert(ci->u.l.pc == &pc && < ttisfunction(ci->base - 1) && < (ci->state & CI_SAVEDPC)); --- > lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); -diff -r lua-5.0/test/luac.lua lua-5.0.1/test/luac.lua +779a780 +> +diff -r lua-5.0/test/luac.lua lua-5.0.2/test/luac.lua 4,6c4,6 < assert(arg[1]~=nil,"usage: lua luac.lua file.lua") < f=assert(io.open("luac.out","w")) @@ -621,3 +217,8 @@ diff -r lua-5.0/test/luac.lua lua-5.0.1/test/luac.lua > assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") > f=assert(io.open("luac.out","wb")) > f:write(string.dump(assert(loadfile(arg[1])))) +diff -r lua-5.0/test/table.lua lua-5.0.2/test/table.lua +8c8 +< local _,_,a,b=string.find(l,'"?(%w+)"?%s*(.*)$') +--- +> local _,_,a,b=string.find(l,'"?([_%w]+)"?%s*(.*)$') diff --git a/MANIFEST b/MANIFEST index e26c9de27b..0c7b8dce0b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,130 +1,131 @@ -MANIFEST contents of Lua 5.0 distribution on Fri Apr 11 11:01:08 BRT 2003 -lua-5.0 -lua-5.0/COPYRIGHT -lua-5.0/HISTORY -lua-5.0/INSTALL -lua-5.0/MANIFEST -lua-5.0/Makefile -lua-5.0/README -lua-5.0/bin -lua-5.0/build -lua-5.0/config -lua-5.0/configure -lua-5.0/doc -lua-5.0/doc/logo.gif -lua-5.0/doc/lua.1 -lua-5.0/doc/lua.html -lua-5.0/doc/luac.1 -lua-5.0/doc/luac.html -lua-5.0/doc/manual.html -lua-5.0/doc/readme.html -lua-5.0/etc -lua-5.0/etc/.exrc -lua-5.0/etc/Makefile -lua-5.0/etc/README -lua-5.0/etc/bin2c.c -lua-5.0/etc/compat.lua -lua-5.0/etc/doall.lua -lua-5.0/etc/lua.ico -lua-5.0/etc/lua.magic -lua-5.0/etc/lua.xpm -lua-5.0/etc/luser_number.h -lua-5.0/etc/luser_tests.h -lua-5.0/etc/min.c -lua-5.0/etc/noparser.c -lua-5.0/etc/saconfig.c -lua-5.0/etc/trace.c -lua-5.0/include -lua-5.0/include/Makefile -lua-5.0/include/lauxlib.h -lua-5.0/include/lua.h -lua-5.0/include/lualib.h -lua-5.0/lib -lua-5.0/src -lua-5.0/src/Makefile -lua-5.0/src/README -lua-5.0/src/lapi.c -lua-5.0/src/lapi.h -lua-5.0/src/lcode.c -lua-5.0/src/lcode.h -lua-5.0/src/ldebug.c -lua-5.0/src/ldebug.h -lua-5.0/src/ldo.c -lua-5.0/src/ldo.h -lua-5.0/src/ldump.c -lua-5.0/src/lfunc.c -lua-5.0/src/lfunc.h -lua-5.0/src/lgc.c -lua-5.0/src/lgc.h -lua-5.0/src/lib -lua-5.0/src/lib/Makefile -lua-5.0/src/lib/README -lua-5.0/src/lib/lauxlib.c -lua-5.0/src/lib/lbaselib.c -lua-5.0/src/lib/ldblib.c -lua-5.0/src/lib/liolib.c -lua-5.0/src/lib/lmathlib.c -lua-5.0/src/lib/loadlib.c -lua-5.0/src/lib/lstrlib.c -lua-5.0/src/lib/ltablib.c -lua-5.0/src/llex.c -lua-5.0/src/llex.h -lua-5.0/src/llimits.h -lua-5.0/src/lmem.c -lua-5.0/src/lmem.h -lua-5.0/src/lobject.c -lua-5.0/src/lobject.h -lua-5.0/src/lopcodes.c -lua-5.0/src/lopcodes.h -lua-5.0/src/lparser.c -lua-5.0/src/lparser.h -lua-5.0/src/lstate.c -lua-5.0/src/lstate.h -lua-5.0/src/lstring.c -lua-5.0/src/lstring.h -lua-5.0/src/ltable.c -lua-5.0/src/ltable.h -lua-5.0/src/ltests.c -lua-5.0/src/ltm.c -lua-5.0/src/ltm.h -lua-5.0/src/lua -lua-5.0/src/lua/Makefile -lua-5.0/src/lua/README -lua-5.0/src/lua/lua.c -lua-5.0/src/luac -lua-5.0/src/luac/Makefile -lua-5.0/src/luac/README -lua-5.0/src/luac/luac.c -lua-5.0/src/luac/print.c -lua-5.0/src/lundump.c -lua-5.0/src/lundump.h -lua-5.0/src/lvm.c -lua-5.0/src/lvm.h -lua-5.0/src/lzio.c -lua-5.0/src/lzio.h -lua-5.0/test -lua-5.0/test/README -lua-5.0/test/bisect.lua -lua-5.0/test/cf.lua -lua-5.0/test/compat.lua -lua-5.0/test/echo.lua -lua-5.0/test/env.lua -lua-5.0/test/factorial.lua -lua-5.0/test/fib.lua -lua-5.0/test/fibfor.lua -lua-5.0/test/globals.lua -lua-5.0/test/hello.lua -lua-5.0/test/life.lua -lua-5.0/test/lua -lua-5.0/test/luac -lua-5.0/test/luac.lua -lua-5.0/test/printf.lua -lua-5.0/test/readonly.lua -lua-5.0/test/sieve.lua -lua-5.0/test/sort.lua -lua-5.0/test/table.lua -lua-5.0/test/trace-calls.lua -lua-5.0/test/trace-globals.lua -lua-5.0/test/undefined.lua -lua-5.0/test/xd.lua +MANIFEST contents of Lua 5.0.2 distribution on Wed Mar 17 17:59:01 BRT 2004 +lua-5.0.2 +lua-5.0.2/COPYRIGHT +lua-5.0.2/DIFFS +lua-5.0.2/HISTORY +lua-5.0.2/INSTALL +lua-5.0.2/MANIFEST +lua-5.0.2/Makefile +lua-5.0.2/README +lua-5.0.2/UPDATE +lua-5.0.2/bin +lua-5.0.2/build +lua-5.0.2/config +lua-5.0.2/configure +lua-5.0.2/doc +lua-5.0.2/doc/contents.html +lua-5.0.2/doc/logo.gif +lua-5.0.2/doc/lua.1 +lua-5.0.2/doc/lua.html +lua-5.0.2/doc/luac.1 +lua-5.0.2/doc/luac.html +lua-5.0.2/doc/manual.html +lua-5.0.2/doc/readme.html +lua-5.0.2/etc +lua-5.0.2/etc/Makefile +lua-5.0.2/etc/README +lua-5.0.2/etc/bin2c.c +lua-5.0.2/etc/compat.lua +lua-5.0.2/etc/doall.lua +lua-5.0.2/etc/lua.ico +lua-5.0.2/etc/lua.magic +lua-5.0.2/etc/lua.xpm +lua-5.0.2/etc/luser_number.h +lua-5.0.2/etc/luser_tests.h +lua-5.0.2/etc/min.c +lua-5.0.2/etc/noparser.c +lua-5.0.2/etc/saconfig.c +lua-5.0.2/etc/trace.c +lua-5.0.2/include +lua-5.0.2/include/Makefile +lua-5.0.2/include/lauxlib.h +lua-5.0.2/include/lua.h +lua-5.0.2/include/lualib.h +lua-5.0.2/lib +lua-5.0.2/src +lua-5.0.2/src/Makefile +lua-5.0.2/src/README +lua-5.0.2/src/lapi.c +lua-5.0.2/src/lapi.h +lua-5.0.2/src/lcode.c +lua-5.0.2/src/lcode.h +lua-5.0.2/src/ldebug.c +lua-5.0.2/src/ldebug.h +lua-5.0.2/src/ldo.c +lua-5.0.2/src/ldo.h +lua-5.0.2/src/ldump.c +lua-5.0.2/src/lfunc.c +lua-5.0.2/src/lfunc.h +lua-5.0.2/src/lgc.c +lua-5.0.2/src/lgc.h +lua-5.0.2/src/lib +lua-5.0.2/src/lib/Makefile +lua-5.0.2/src/lib/README +lua-5.0.2/src/lib/lauxlib.c +lua-5.0.2/src/lib/lbaselib.c +lua-5.0.2/src/lib/ldblib.c +lua-5.0.2/src/lib/liolib.c +lua-5.0.2/src/lib/lmathlib.c +lua-5.0.2/src/lib/loadlib.c +lua-5.0.2/src/lib/lstrlib.c +lua-5.0.2/src/lib/ltablib.c +lua-5.0.2/src/llex.c +lua-5.0.2/src/llex.h +lua-5.0.2/src/llimits.h +lua-5.0.2/src/lmem.c +lua-5.0.2/src/lmem.h +lua-5.0.2/src/lobject.c +lua-5.0.2/src/lobject.h +lua-5.0.2/src/lopcodes.c +lua-5.0.2/src/lopcodes.h +lua-5.0.2/src/lparser.c +lua-5.0.2/src/lparser.h +lua-5.0.2/src/lstate.c +lua-5.0.2/src/lstate.h +lua-5.0.2/src/lstring.c +lua-5.0.2/src/lstring.h +lua-5.0.2/src/ltable.c +lua-5.0.2/src/ltable.h +lua-5.0.2/src/ltests.c +lua-5.0.2/src/ltm.c +lua-5.0.2/src/ltm.h +lua-5.0.2/src/lua +lua-5.0.2/src/lua/Makefile +lua-5.0.2/src/lua/README +lua-5.0.2/src/lua/lua.c +lua-5.0.2/src/luac +lua-5.0.2/src/luac/Makefile +lua-5.0.2/src/luac/README +lua-5.0.2/src/luac/luac.c +lua-5.0.2/src/luac/print.c +lua-5.0.2/src/lundump.c +lua-5.0.2/src/lundump.h +lua-5.0.2/src/lvm.c +lua-5.0.2/src/lvm.h +lua-5.0.2/src/lzio.c +lua-5.0.2/src/lzio.h +lua-5.0.2/test +lua-5.0.2/test/README +lua-5.0.2/test/bisect.lua +lua-5.0.2/test/cf.lua +lua-5.0.2/test/echo.lua +lua-5.0.2/test/env.lua +lua-5.0.2/test/factorial.lua +lua-5.0.2/test/fib.lua +lua-5.0.2/test/fibfor.lua +lua-5.0.2/test/globals.lua +lua-5.0.2/test/hello.lua +lua-5.0.2/test/life.lua +lua-5.0.2/test/lua +lua-5.0.2/test/luac +lua-5.0.2/test/luac.lua +lua-5.0.2/test/printf.lua +lua-5.0.2/test/readonly.lua +lua-5.0.2/test/sieve.lua +lua-5.0.2/test/sort.lua +lua-5.0.2/test/table.lua +lua-5.0.2/test/trace-calls.lua +lua-5.0.2/test/trace-globals.lua +lua-5.0.2/test/undefined.lua +lua-5.0.2/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index 007b72d0a9..9ab901d4da 100644 --- a/Makefile +++ b/Makefile @@ -96,4 +96,7 @@ lecho: @make echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' @echo "-- EOF" +newer: + @find . -newer MANIFEST -type f + # (end of Makefile) diff --git a/UPDATE b/UPDATE index 84be37c2e2..f0921887dd 100644 --- a/UPDATE +++ b/UPDATE @@ -1,5 +1,5 @@ -This is Lua 5.0.1, an update of Lua 5.0 that includes the following changes, -which fix all known bugs in Lua 5.0. +This is Lua 5.0.2, an update of Lua 5.0 that includes the following changes, +which fix all known bugs in Lua 5.0. For the exact differences, see DIFFS. src/ldo.c Attempt to resume running coroutine crashed Lua @@ -15,10 +15,9 @@ src/lvm.c Count hook might be called without being set src/lib/lbaselib.c Buffer overflow for unusual %p representation + Wrong number of returns from chunks loaded from stdin src/lib/liolib.c `file.close()' could not be called without arguments Buffer overflow for unusual %p representation src/luac/luac.c Missing lock/unlock - -To use this update, simply open this tarball over the original Lua 5.0 source. diff --git a/doc/contents.html b/doc/contents.html new file mode 100644 index 0000000000..06bd6fb4c7 --- /dev/null +++ b/doc/contents.html @@ -0,0 +1,123 @@ + + +Lua: 5.0 reference manual - contents + + + + +
      +

      +Lua +Reference manual for Lua 5.0 +

      + +Lua 5.0 Reference Manual +[ +top +| +ps +| +pdf +] +

      + + +Copyright +© 2003 Tecgraf, PUC-Rio. All rights reserved. +


      + + + +
      + +Last update: +Wed May 7 18:34:34 EST 2003 + + + + diff --git a/doc/readme.html b/doc/readme.html index c50459d15c..baa7cc8a07 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -13,7 +13,7 @@

      • Official web site -
      • Reference manual +
      • Reference manual
      • lua man page
      • luac man page
      • lua/README @@ -28,7 +28,7 @@


        Last update: -Tue Apr 1 14:35:18 EST 2003 +Thu Mar 11 23:08:56 BRT 2004 diff --git a/include/lua.h b/include/lua.h index c5689379f6..88b0191e9a 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.175a 2003/03/18 12:31:39 roberto Exp $ +** $Id: lua.h,v 1.175b 2003/03/18 12:31:39 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -14,8 +14,8 @@ #include -#define LUA_VERSION "Lua 5.0.1" -#define LUA_COPYRIGHT "Copyright (C) 1994-2003 Tecgraf, PUC-Rio" +#define LUA_VERSION "Lua 5.0.2" +#define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -365,7 +365,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2004 Tecgraf, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index 45bc7cfe57..b6a4baedc2 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.130a 2003/04/03 13:35:34 roberto Exp $ +** $Id: lbaselib.c,v 1.130b 2003/04/03 13:35:34 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -274,10 +274,11 @@ static int luaB_loadfile (lua_State *L) { static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); + int n = lua_gettop(L); int status = luaL_loadfile(L, fname); if (status != 0) lua_error(L); lua_call(L, 0, LUA_MULTRET); - return lua_gettop(L) - 1; + return lua_gettop(L) - n; } diff --git a/src/lvm.c b/src/lvm.c index 18005d03e8..94e2802d86 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.284a 2003/04/03 13:35:34 roberto Exp $ +** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -399,8 +399,10 @@ StkId luaV_execute (lua_State *L) { TObject *k; const Instruction *pc; callentry: /* entry point when calling new functions */ - if (L->hookmask & LUA_MASKCALL) + if (L->hookmask & LUA_MASKCALL) { + L->ci->u.l.pc = &pc; luaD_callhook(L, LUA_HOOKCALL, -1); + } retentry: /* entry point when returning to old functions */ L->ci->u.l.pc = &pc; lua_assert(L->ci->state == CI_SAVEDPC || @@ -776,3 +778,4 @@ StkId luaV_execute (lua_State *L) { } } + diff --git a/test/compat.lua b/test/compat.lua deleted file mode 100644 index 2a7f3731e0..0000000000 --- a/test/compat.lua +++ /dev/null @@ -1,192 +0,0 @@ -------------------------------------------------------------------- --- Real globals --- _ALERT --- _ERRORMESSAGE --- _VERSION --- _G --- assert --- error --- metatable --- next --- print --- require --- tonumber --- tostring --- type --- unpack - -------------------------------------------------------------------- --- collectgarbage --- gcinfo - --- globals - --- call -> protect(f, err) --- loadfile --- loadstring - --- rawget --- rawset - --- getargs = Main.getargs ?? - - -function do_ (f, err) - if not f then print(err); return end - local a,b = pcall(f) - if not a then print(b); return nil - else return b or true - end -end - -function dostring(s) return do_(loadstring(s)) end --- function dofile(s) return do_(loadfile(s)) end - -------------------------------------------------------------------- --- Table library -local tab = table -foreach = tab.foreach -foreachi = tab.foreachi -getn = tab.getn -tinsert = tab.insert -tremove = tab.remove -sort = tab.sort - -------------------------------------------------------------------- --- Debug library -local dbg = debug -getinfo = dbg.getinfo -getlocal = dbg.getlocal -setcallhook = function () error"`setcallhook' is deprecated" end -setlinehook = function () error"`setlinehook' is deprecated" end -setlocal = dbg.setlocal - -------------------------------------------------------------------- --- math library -local math = math -abs = math.abs -acos = function (x) return math.deg(math.acos(x)) end -asin = function (x) return math.deg(math.asin(x)) end -atan = function (x) return math.deg(math.atan(x)) end -atan2 = function (x,y) return math.deg(math.atan2(x,y)) end -ceil = math.ceil -cos = function (x) return math.cos(math.rad(x)) end -deg = math.deg -exp = math.exp -floor = math.floor -frexp = math.frexp -ldexp = math.ldexp -log = math.log -log10 = math.log10 -max = math.max -min = math.min -mod = math.mod -PI = math.pi ---??? pow = math.pow -rad = math.rad -random = math.random -randomseed = math.randomseed -sin = function (x) return math.sin(math.rad(x)) end -sqrt = math.sqrt -tan = function (x) return math.tan(math.rad(x)) end - -------------------------------------------------------------------- --- string library -local str = string -strbyte = str.byte -strchar = str.char -strfind = str.find -format = str.format -gsub = str.gsub -strlen = str.len -strlower = str.lower -strrep = str.rep -strsub = str.sub -strupper = str.upper - -------------------------------------------------------------------- --- os library -clock = os.clock -date = os.date -difftime = os.difftime -execute = os.execute --? -exit = os.exit -getenv = os.getenv -remove = os.remove -rename = os.rename -setlocale = os.setlocale -time = os.time -tmpname = os.tmpname - -------------------------------------------------------------------- --- compatibility only -getglobal = function (n) return _G[n] end -setglobal = function (n,v) _G[n] = v end - -------------------------------------------------------------------- - -local io, tab = io, table - --- IO library (files) -_STDIN = io.stdin -_STDERR = io.stderr -_STDOUT = io.stdout -_INPUT = io.stdin -_OUTPUT = io.stdout -seek = io.stdin.seek -- sick ;-) -tmpfile = io.tmpfile -closefile = io.close -openfile = io.open - -function flush (f) - if f then f:flush() - else _OUTPUT:flush() - end -end - -function readfrom (name) - if name == nil then - local f, err, cod = io.close(_INPUT) - _INPUT = io.stdin - return f, err, cod - else - local f, err, cod = io.open(name, "r") - _INPUT = f or _INPUT - return f, err, cod - end -end - -function writeto (name) - if name == nil then - local f, err, cod = io.close(_OUTPUT) - _OUTPUT = io.stdout - return f, err, cod - else - local f, err, cod = io.open(name, "w") - _OUTPUT = f or _OUTPUT - return f, err, cod - end -end - -function appendto (name) - local f, err, cod = io.open(name, "a") - _OUTPUT = f or _OUTPUT - return f, err, cod -end - -function read (...) - local f = _INPUT - if type(arg[1]) == 'userdata' then - f = tab.remove(arg, 1) - end - return f:read(unpack(arg)) -end - -function write (...) - local f = _OUTPUT - if type(arg[1]) == 'userdata' then - f = tab.remove(arg, 1) - end - return f:write(unpack(arg)) -end - diff --git a/test/table.lua b/test/table.lua index bc2cd60cef..235089c04b 100644 --- a/test/table.lua +++ b/test/table.lua @@ -5,7 +5,7 @@ local A while 1 do local l=io.read() if l==nil then break end - local _,_,a,b=string.find(l,'"?(%w+)"?%s*(.*)$') + local _,_,a,b=string.find(l,'"?([_%w]+)"?%s*(.*)$') if a~=A then A=a io.write("\n",a,":") end io.write(" ",b) end From ced7bbbe7a257ce6de94069d5dbf6672aeafd4d9 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Wed, 24 Mar 2004 12:00:00 +0000 Subject: [PATCH 17/97] Lua 5.1-work0 --- DIFFS | 224 -- INSTALL | 9 +- MANIFEST | 131 -- Makefile | 14 +- RCS | 1 + UPDATE | 23 - config | 21 +- doc/contents.html | 123 -- doc/logo.gif | Bin 4232 -> 0 bytes doc/lua.1 | 167 -- doc/lua.html | 175 -- doc/luac.1 | 136 -- doc/luac.html | 144 -- doc/manual.html | 4612 ------------------------------------------ doc/readme.html | 35 - etc/Makefile | 11 +- etc/RCS | 1 + etc/README | 38 +- etc/bin2c.c | 67 - etc/compat.lua | 192 -- etc/doall.lua | 6 - etc/lua.magic | 12 - etc/lua.xpm | 44 - etc/luser_number.h | 34 - etc/luser_tests.h | 68 - etc/min.c | 47 +- etc/noparser.c | 16 +- etc/saconfig.c | 4 +- etc/trace.c | 55 - include/RCS | 1 + include/lauxlib.h | 33 +- include/lua.h | 62 +- src/Makefile | 2 - src/RCS | 1 + src/lapi.c | 430 ++-- src/lapi.h | 4 +- src/lcode.c | 52 +- src/ldebug.c | 113 +- src/ldebug.h | 9 +- src/ldo.c | 141 +- src/ldo.h | 8 +- src/ldump.c | 22 +- src/lfunc.c | 66 +- src/lfunc.h | 12 +- src/lgc.c | 669 +++--- src/lgc.h | 81 +- src/lib/RCS | 1 + src/lib/lauxlib.c | 125 +- src/lib/lbaselib.c | 139 +- src/lib/ldblib.c | 150 +- src/lib/liolib.c | 130 +- src/lib/lmathlib.c | 14 +- src/lib/loadlib.c | 26 +- src/lib/lstrlib.c | 54 +- src/lib/ltablib.c | 6 +- src/llex.c | 449 ++-- src/llex.h | 6 +- src/llimits.h | 65 +- src/lmem.c | 82 +- src/lobject.c | 48 +- src/lobject.h | 122 +- src/lopcodes.c | 87 +- src/lopcodes.h | 45 +- src/lparser.c | 254 ++- src/lparser.h | 16 +- src/lstate.c | 171 +- src/lstate.h | 64 +- src/lstring.c | 37 +- src/lstring.h | 6 +- src/ltable.c | 109 +- src/ltable.h | 15 +- src/ltm.c | 22 +- src/ltm.h | 10 +- src/lua/RCS | 1 + src/lua/README | 2 +- src/lua/lua.c | 13 +- src/luac/Makefile | 8 +- src/luac/RCS | 1 + src/luac/README | 2 +- src/luac/luac.c | 77 +- src/luac/print.c | 39 +- src/lundump.c | 89 +- src/lundump.h | 11 +- src/lvm.c | 488 +++-- src/lvm.h | 15 +- src/lzio.c | 16 +- src/lzio.h | 18 +- test/fibfor.lua | 2 +- test/trace-calls.lua | 2 +- 89 files changed, 2687 insertions(+), 8466 deletions(-) delete mode 100644 DIFFS delete mode 100644 MANIFEST create mode 120000 RCS delete mode 100644 UPDATE delete mode 100644 doc/contents.html delete mode 100644 doc/logo.gif delete mode 100644 doc/lua.1 delete mode 100644 doc/lua.html delete mode 100644 doc/luac.1 delete mode 100644 doc/luac.html delete mode 100644 doc/manual.html delete mode 100644 doc/readme.html create mode 120000 etc/RCS delete mode 100644 etc/bin2c.c delete mode 100644 etc/compat.lua delete mode 100644 etc/doall.lua delete mode 100644 etc/lua.magic delete mode 100644 etc/lua.xpm delete mode 100644 etc/luser_number.h delete mode 100644 etc/luser_tests.h delete mode 100644 etc/trace.c create mode 120000 include/RCS create mode 120000 src/RCS create mode 120000 src/lib/RCS create mode 120000 src/lua/RCS create mode 120000 src/luac/RCS diff --git a/DIFFS b/DIFFS deleted file mode 100644 index f7d5ba27eb..0000000000 --- a/DIFFS +++ /dev/null @@ -1,224 +0,0 @@ -diff -r lua-5.0/COPYRIGHT lua-5.0.2/COPYRIGHT -12c12 -< Copyright (C) 2003 Tecgraf, PUC-Rio. ---- -> Copyright (C) 2003-2004 Tecgraf, PUC-Rio. -diff -r lua-5.0/Makefile lua-5.0.2/Makefile -98a99,101 -> newer: -> @find . -newer MANIFEST -type f -> -diff -r lua-5.0/doc/readme.html lua-5.0.2/doc/readme.html -16c16 -<
      • Reference manual ---- ->
      • Reference manual -31c31 -< Tue Apr 1 14:35:18 EST 2003 ---- -> Thu Mar 11 23:08:56 BRT 2004 -diff -r lua-5.0/include/lua.h lua-5.0.2/include/lua.h -2c2 -< ** $Id: lua.h,v 1.175 2003/03/18 12:31:39 roberto Exp $ ---- -> ** $Id: lua.h,v 1.175b 2003/03/18 12:31:39 roberto Exp $ -17,18c17,18 -< #define LUA_VERSION "Lua 5.0" -< #define LUA_COPYRIGHT "Copyright (C) 1994-2003 Tecgraf, PUC-Rio" ---- -> #define LUA_VERSION "Lua 5.0.2" -> #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" -368c368 -< * Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved. ---- -> * Copyright (C) 1994-2004 Tecgraf, PUC-Rio. All rights reserved. -diff -r lua-5.0/src/ldo.c lua-5.0.2/src/ldo.c -2c2 -< ** $Id: ldo.c,v 1.217 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: ldo.c,v 1.217a 2003/04/03 13:35:34 roberto Exp $ -325,326c325 -< if (nargs >= L->top - L->base) -< luaG_runerror(L, "cannot resume dead coroutine"); ---- -> lua_assert(nargs < L->top - L->base); -329c328,329 -< else if (ci->state & CI_YIELD) { /* inside a yield? */ ---- -> else { /* inside a yield */ -> lua_assert(ci->state & CI_YIELD); -344,345d343 -< else -< luaG_runerror(L, "cannot resume non-suspended coroutine"); -351a350,358 -> static int resume_error (lua_State *L, const char *msg) { -> L->top = L->ci->base; -> setsvalue2s(L->top, luaS_new(L, msg)); -> incr_top(L); -> lua_unlock(L); -> return LUA_ERRRUN; -> } -> -> -355a363,368 -> if (L->ci == L->base_ci) { -> if (nargs >= L->top - L->base) -> return resume_error(L, "cannot resume dead coroutine"); -> } -> else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ -> return resume_error(L, "cannot resume non-suspended coroutine"); -diff -r lua-5.0/src/lgc.c lua-5.0.2/src/lgc.c -2c2 -< ** $Id: lgc.c,v 1.171 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $ -113c113,114 -< void luaC_separateudata (lua_State *L) { ---- -> size_t luaC_separateudata (lua_State *L) { -> size_t deadmem = 0; -127a129 -> deadmem += sizeudata(gcotou(curr)->uv.len); -136a139 -> return deadmem; -247c250 -< if (!(ci->state & CI_C) && lim < ci->top) ---- -> if (lim < ci->top) -390c393 -< static void checkSizes (lua_State *L) { ---- -> static void checkSizes (lua_State *L, size_t deadmem) { -400c403 -< G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ ---- -> G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ -454c457,458 -< static void mark (lua_State *L) { ---- -> static size_t mark (lua_State *L) { -> size_t deadmem; -467c471 -< luaC_separateudata(L); /* separate userdata to be preserved */ ---- -> deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ -475a480 -> return deadmem; -480c485 -< mark(L); ---- -> size_t deadmem = mark(L); -482c487 -< checkSizes(L); ---- -> checkSizes(L, deadmem); -diff -r lua-5.0/src/lgc.h lua-5.0.2/src/lgc.h -2c2 -< ** $Id: lgc.h,v 1.19 2003/02/28 19:45:15 roberto Exp $ ---- -> ** $Id: lgc.h,v 1.19a 2003/02/28 19:45:15 roberto Exp $ -18c18 -< void luaC_separateudata (lua_State *L); ---- -> size_t luaC_separateudata (lua_State *L); -diff -r lua-5.0/src/lib/lbaselib.c lua-5.0.2/src/lib/lbaselib.c -2c2 -< ** $Id: lbaselib.c,v 1.130 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lbaselib.c,v 1.130b 2003/04/03 13:35:34 roberto Exp $ -276a277 -> int n = lua_gettop(L); -280c281 -< return lua_gettop(L) - 1; ---- -> return lua_gettop(L) - n; -327c328 -< char buff[64]; ---- -> char buff[128]; -diff -r lua-5.0/src/lib/liolib.c lua-5.0.2/src/lib/liolib.c -2c2 -< ** $Id: liolib.c,v 2.39 2003/03/19 21:16:12 roberto Exp $ ---- -> ** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $ -161c161 -< if (lua_isnone(L, 1)) { ---- -> if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { -178c178 -< char buff[32]; ---- -> char buff[128]; -diff -r lua-5.0/src/lparser.c lua-5.0.2/src/lparser.c -2c2 -< ** $Id: lparser.c,v 1.208 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lparser.c,v 1.208a 2003/04/03 13:35:34 roberto Exp $ -1143a1144 -> FuncState *fs = ls->fs; -1145c1146,1147 -< init_exp(&v, VLOCAL, ls->fs->freereg++); ---- -> init_exp(&v, VLOCAL, fs->freereg); -> luaK_reserveregs(fs, 1); -1148c1150,1152 -< luaK_storevar(ls->fs, &v, &b); ---- -> luaK_storevar(fs, &v, &b); -> /* debug information will only see the variable after this point! */ -> getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; -diff -r lua-5.0/src/luac/Makefile lua-5.0.2/src/luac/Makefile -16c16 -< $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) ---- -> $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) -diff -r lua-5.0/src/luac/luac.c lua-5.0.2/src/luac/luac.c -2c2 -< ** $Id: luac.c,v 1.44 2003/04/07 20:34:20 lhf Exp $ ---- -> ** $Id: luac.c,v 1.44a 2003/04/07 20:34:20 lhf Exp $ -184a185 -> lua_lock(L); -185a187 -> lua_unlock(L); -diff -r lua-5.0/src/lvm.c lua-5.0.2/src/lvm.c -2c2 -< ** $Id: lvm.c,v 1.284 2003/04/03 13:35:34 roberto Exp $ ---- -> ** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ -69c69 -< if (mask > LUA_MASKLINE) { /* instruction-hook set? */ ---- -> if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ -402,403c402,403 -< L->ci->u.l.pc = &pc; -< if (L->hookmask & LUA_MASKCALL) ---- -> if (L->hookmask & LUA_MASKCALL) { -> L->ci->u.l.pc = &pc; -404a405 -> } -405a407 -> L->ci->u.l.pc = &pc; -676,678c678 -< lua_assert(ci->u.l.pc == &pc && -< ttisfunction(ci->base - 1) && -< (ci->state & CI_SAVEDPC)); ---- -> lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); -779a780 -> -diff -r lua-5.0/test/luac.lua lua-5.0.2/test/luac.lua -4,6c4,6 -< assert(arg[1]~=nil,"usage: lua luac.lua file.lua") -< f=assert(io.open("luac.out","w")) -< f:write(string.dump(loadfile(arg[1]))) ---- -> assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") -> f=assert(io.open("luac.out","wb")) -> f:write(string.dump(assert(loadfile(arg[1])))) -diff -r lua-5.0/test/table.lua lua-5.0.2/test/table.lua -8c8 -< local _,_,a,b=string.find(l,'"?(%w+)"?%s*(.*)$') ---- -> local _,_,a,b=string.find(l,'"?([_%w]+)"?%s*(.*)$') diff --git a/INSTALL b/INSTALL index 748c6861d0..6828f23cbd 100644 --- a/INSTALL +++ b/INSTALL @@ -49,12 +49,15 @@ This is Lua 5.0. You may need to include ./lib in the LD_LIBRARY_PATH environment variable to link programs that use the shared libraries if you don't put them in the official places with "make install". (You may need to use the full path.) + Note also that by default these official places live under /usr/local but + /usr/local/lib may not be a place that is checked for shared libraries. + In Linux, the places checked are in /etc/ld.so.conf. Try also "man ld.so". Building shared libraries in other systems is similar but details differ; you may need to fix a few details in the top-level Makefile. * Installation on Windows and other systems - ----------------------------------------------------- + ----------------------------------------- The instructions for building Lua on other systems machine depend on the particular compiler you are using. The simplest way is to create a folder with all .c and .h files, and then create projects for the core library, @@ -62,14 +65,14 @@ This is Lua 5.0. core lib: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c - ltable.c ltests.c ltm.c lundump.c lvm.c lzio.c + ltable.c ltm.c lundump.c lvm.c lzio.c standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c ltablib.c lstrlib.c loadlib.c interpreter: core lib, standard lib, lua.c - compiler: core lib, standard lib, luac.c print.c + compiler: core lib, lauxlib.c luac.c print.c and also lopcodes.c (with LUA_OPNAMES defined) from core. Of course, to use Lua as a library, you'll have to know how to create diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index 0c7b8dce0b..0000000000 --- a/MANIFEST +++ /dev/null @@ -1,131 +0,0 @@ -MANIFEST contents of Lua 5.0.2 distribution on Wed Mar 17 17:59:01 BRT 2004 -lua-5.0.2 -lua-5.0.2/COPYRIGHT -lua-5.0.2/DIFFS -lua-5.0.2/HISTORY -lua-5.0.2/INSTALL -lua-5.0.2/MANIFEST -lua-5.0.2/Makefile -lua-5.0.2/README -lua-5.0.2/UPDATE -lua-5.0.2/bin -lua-5.0.2/build -lua-5.0.2/config -lua-5.0.2/configure -lua-5.0.2/doc -lua-5.0.2/doc/contents.html -lua-5.0.2/doc/logo.gif -lua-5.0.2/doc/lua.1 -lua-5.0.2/doc/lua.html -lua-5.0.2/doc/luac.1 -lua-5.0.2/doc/luac.html -lua-5.0.2/doc/manual.html -lua-5.0.2/doc/readme.html -lua-5.0.2/etc -lua-5.0.2/etc/Makefile -lua-5.0.2/etc/README -lua-5.0.2/etc/bin2c.c -lua-5.0.2/etc/compat.lua -lua-5.0.2/etc/doall.lua -lua-5.0.2/etc/lua.ico -lua-5.0.2/etc/lua.magic -lua-5.0.2/etc/lua.xpm -lua-5.0.2/etc/luser_number.h -lua-5.0.2/etc/luser_tests.h -lua-5.0.2/etc/min.c -lua-5.0.2/etc/noparser.c -lua-5.0.2/etc/saconfig.c -lua-5.0.2/etc/trace.c -lua-5.0.2/include -lua-5.0.2/include/Makefile -lua-5.0.2/include/lauxlib.h -lua-5.0.2/include/lua.h -lua-5.0.2/include/lualib.h -lua-5.0.2/lib -lua-5.0.2/src -lua-5.0.2/src/Makefile -lua-5.0.2/src/README -lua-5.0.2/src/lapi.c -lua-5.0.2/src/lapi.h -lua-5.0.2/src/lcode.c -lua-5.0.2/src/lcode.h -lua-5.0.2/src/ldebug.c -lua-5.0.2/src/ldebug.h -lua-5.0.2/src/ldo.c -lua-5.0.2/src/ldo.h -lua-5.0.2/src/ldump.c -lua-5.0.2/src/lfunc.c -lua-5.0.2/src/lfunc.h -lua-5.0.2/src/lgc.c -lua-5.0.2/src/lgc.h -lua-5.0.2/src/lib -lua-5.0.2/src/lib/Makefile -lua-5.0.2/src/lib/README -lua-5.0.2/src/lib/lauxlib.c -lua-5.0.2/src/lib/lbaselib.c -lua-5.0.2/src/lib/ldblib.c -lua-5.0.2/src/lib/liolib.c -lua-5.0.2/src/lib/lmathlib.c -lua-5.0.2/src/lib/loadlib.c -lua-5.0.2/src/lib/lstrlib.c -lua-5.0.2/src/lib/ltablib.c -lua-5.0.2/src/llex.c -lua-5.0.2/src/llex.h -lua-5.0.2/src/llimits.h -lua-5.0.2/src/lmem.c -lua-5.0.2/src/lmem.h -lua-5.0.2/src/lobject.c -lua-5.0.2/src/lobject.h -lua-5.0.2/src/lopcodes.c -lua-5.0.2/src/lopcodes.h -lua-5.0.2/src/lparser.c -lua-5.0.2/src/lparser.h -lua-5.0.2/src/lstate.c -lua-5.0.2/src/lstate.h -lua-5.0.2/src/lstring.c -lua-5.0.2/src/lstring.h -lua-5.0.2/src/ltable.c -lua-5.0.2/src/ltable.h -lua-5.0.2/src/ltests.c -lua-5.0.2/src/ltm.c -lua-5.0.2/src/ltm.h -lua-5.0.2/src/lua -lua-5.0.2/src/lua/Makefile -lua-5.0.2/src/lua/README -lua-5.0.2/src/lua/lua.c -lua-5.0.2/src/luac -lua-5.0.2/src/luac/Makefile -lua-5.0.2/src/luac/README -lua-5.0.2/src/luac/luac.c -lua-5.0.2/src/luac/print.c -lua-5.0.2/src/lundump.c -lua-5.0.2/src/lundump.h -lua-5.0.2/src/lvm.c -lua-5.0.2/src/lvm.h -lua-5.0.2/src/lzio.c -lua-5.0.2/src/lzio.h -lua-5.0.2/test -lua-5.0.2/test/README -lua-5.0.2/test/bisect.lua -lua-5.0.2/test/cf.lua -lua-5.0.2/test/echo.lua -lua-5.0.2/test/env.lua -lua-5.0.2/test/factorial.lua -lua-5.0.2/test/fib.lua -lua-5.0.2/test/fibfor.lua -lua-5.0.2/test/globals.lua -lua-5.0.2/test/hello.lua -lua-5.0.2/test/life.lua -lua-5.0.2/test/lua -lua-5.0.2/test/luac -lua-5.0.2/test/luac.lua -lua-5.0.2/test/printf.lua -lua-5.0.2/test/readonly.lua -lua-5.0.2/test/sieve.lua -lua-5.0.2/test/sort.lua -lua-5.0.2/test/table.lua -lua-5.0.2/test/trace-calls.lua -lua-5.0.2/test/trace-globals.lua -lua-5.0.2/test/undefined.lua -lua-5.0.2/test/xd.lua -END OF MANIFEST diff --git a/Makefile b/Makefile index 9ab901d4da..1939243574 100644 --- a/Makefile +++ b/Makefile @@ -7,15 +7,17 @@ LUA= . include $(LUA)/config # primary targets ("co" and "klean" are used for making the distribution) -all clean co klean: dirs +all clean co klean: cd include; $(MAKE) $@ cd src; $(MAKE) $@ cd src/lib; $(MAKE) $@ cd src/luac; $(MAKE) $@ cd src/lua; $(MAKE) $@ +clean klean: soclean + # in case they were not created during unpacking -dirs: bin lib +all: bin lib bin lib: mkdir -p $@ @@ -44,7 +46,7 @@ so: # binaries using shared libraries sobin: - rm -f bin/* + rm -f bin/lua* cd src/lua; $(MAKE) cd src/luac; $(MAKE) @@ -55,7 +57,7 @@ soinstall: # clean shared libraries soclean: - rm -f lib/*.so* bin/* + rm -f lib/*.so* bin/lua* # echo config parameters echo: @@ -96,7 +98,7 @@ lecho: @make echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' @echo "-- EOF" +# (end of Makefile) + newer: @find . -newer MANIFEST -type f - -# (end of Makefile) diff --git a/RCS b/RCS new file mode 120000 index 0000000000..1ae3893605 --- /dev/null +++ b/RCS @@ -0,0 +1 @@ +../RCS \ No newline at end of file diff --git a/UPDATE b/UPDATE deleted file mode 100644 index f0921887dd..0000000000 --- a/UPDATE +++ /dev/null @@ -1,23 +0,0 @@ -This is Lua 5.0.2, an update of Lua 5.0 that includes the following changes, -which fix all known bugs in Lua 5.0. For the exact differences, see DIFFS. - -src/ldo.c - Attempt to resume running coroutine crashed Lua -src/lgc.c - C functions also may have stacks larger than current top - Userdata to be collected still counted into new GC threshold -src/lgc.h - Userdata to be collected still counted into new GC threshold -src/lparser.c - Syntax `local function' did not increment stack size -src/lvm.c - `pc' address was invalidated when a coroutine was suspended - Count hook might be called without being set -src/lib/lbaselib.c - Buffer overflow for unusual %p representation - Wrong number of returns from chunks loaded from stdin -src/lib/liolib.c - `file.close()' could not be called without arguments - Buffer overflow for unusual %p representation -src/luac/luac.c - Missing lock/unlock diff --git a/config b/config index 34c77ea372..2700e6d93f 100644 --- a/config +++ b/config @@ -13,17 +13,17 @@ USERCONF= # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= -# --------------------------------------------------------------- Lua libraries +# ------------------------------------------------------------- dynamic loading # Support for dynamically loading C libraries for Lua is a very important # feature, which we strongly recommend be enabled. By default, this support is # enabled on Windows systems (see below) but disabled on other systems because # it relies on system-dependent code that is not part of ANSI C. For more -# information on dynamic loading, read the comments in src/lib/liolib.c . +# information on dynamic loading, read the comments in src/lib/loadlib.c . # # To enable support for dynamic loading on Unix systems that support the dlfcn # interface (e.g., Linux, Solaris, IRIX, BSD, AIX, HPUX, and probably others), -# uncomment the next two lines. +# uncomment the next two lines. Also read the next paragraph. # #LOADLIB= -DUSE_DLOPEN=1 #DLLIB= -ldl @@ -40,6 +40,8 @@ USERCONF= # #LOADLIB= -DUSE_DLL=0 +# --------------------------------------------------------------- Lua libraries + # The Lua IO library (src/lib/liolib.c) has support for pipes using popen and # pclose. This support is enabled by default on POSIX systems. # If your system is not POSIX but has popen and pclose, define USE_POPEN=1. @@ -48,7 +50,7 @@ USERCONF= #POPEN= -DUSE_POPEN=1 #POPEN= -DUSE_POPEN=0 # -# The form below will probably work in (some) Windows systems. +# The form below will probably work on (some) Windows systems. # #POPEN= -DUSE_POPEN=1 -Dpopen=_popen -Dpclose=_pclose @@ -97,11 +99,10 @@ EXTRA_LIBS= -lm # If you want to customize the stand-alone Lua interpreter, uncomment and # edit the following two lines; also edit etc/saconfig.c to suit your needs. # -DUSE_READLINE adds line editing and history to the interpreter. You need -# to add -lreadline (and perhaps also -lhistory and -lcurses or -lncurses) -# to EXTRA_LIBS. +# to add -lreadline (and perhaps also -lhistory and -ltermcap) to EXTRA_LIBS. # #USERCONF=-DLUA_USERCONFIG='"$(LUA)/etc/saconfig.c"' -DUSE_READLINE -#EXTRA_LIBS= -lm -ldl -lreadline # -lhistory -lcurses -lncurses +#EXTRA_LIBS= -lm $(DLLIB) -lreadline # -lhistory -ltermcap -lcurses -lncurses # ------------------------------------------------------------------ C compiler @@ -127,7 +128,7 @@ MYCFLAGS= -O2 # ------------------------------------------------------------------ librarian -# This should work in all Unix systems. +# This should work on all Unix systems. # AR= ar rcu @@ -140,7 +141,7 @@ RANLIB= ranlib # ------------------------------------------------------------------ stripper -# This should work in all Unix systems, but you may want to add options. +# This should work on all Unix systems, but you may want to add options. # STRIP= strip @@ -164,7 +165,7 @@ INSTALL_DATA= cp # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= -V=5.0 +V= 5.0 BIN= $(LUA)/bin INC= $(LUA)/include diff --git a/doc/contents.html b/doc/contents.html deleted file mode 100644 index 06bd6fb4c7..0000000000 --- a/doc/contents.html +++ /dev/null @@ -1,123 +0,0 @@ - - -Lua: 5.0 reference manual - contents - - - - -
        -

        -Lua -Reference manual for Lua 5.0 -

        - -Lua 5.0 Reference Manual -[ -top -| -ps -| -pdf -] -

        - - -Copyright -© 2003 Tecgraf, PUC-Rio. All rights reserved. -


        - - - -
        - -Last update: -Wed May 7 18:34:34 EST 2003 - - - - diff --git a/doc/logo.gif b/doc/logo.gif deleted file mode 100644 index 2f5e4ac2e742fbb7675e739879211553758aea9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4232 zcmeH``9G8i;K!fm@ywWE@XWZzZ5SF?A>^uN#>^O6HI%DVL*tw8h1>$H%uPC0$QQ=txe!o}PX)Ev+jn>*nFZ-TC=<^76WcLZL(=DJm)| zEiIKwrInSHXU?3duCC_u@5try#>U2`rlw1mF15F}U%!66tE;QKyIUmcDJ<+QF77*W zFJd#&)VAl)kJ6K zi<>tmZ{3>g>+2gB7#JQNe(>OdLh;A=`1q42PbMZNCMPF*dXxhLZw3aYhlZwyhu@Bj z%#4n{d-Q1b$&i4QMce4L#8^!oMdw{PDnm4D66&3*dxX=-YIX6DQL_g`jbzkd4k zZDCoLf=%jL&vIeE zO=XcZ9fxt`f}-DQ^%H*PHMUs(JN%UWkI|Y8h9#6~I$Cw@{RqzO4&P-x;jHCPJ6Ks2 zoU%foi)nXd_sdkiuJa@@5J4RrreKfWSnz5>eMa5yTP=)16uu)TIdx~Fhho))6jZl) z($*i>QrIX4u}u3>m{WSn_ehkUGQ& zs})aUlTH1Cj1g3ZE3=MPXsSniEwJ{e6C3N#HjD=B4`8rWIsz!a7ecYpec?WuH+y?Wsm18^$cS4WmHhH3_=r zh*ILlm*X1dB^E5($KVl&zT524%l}vpHg%;Y+LezV_&TAJCmH`idhuj-n$4FZ)UE|jXLayXa-&O3Q z?Iyo!x*$5hD_HfFnDfGYj-RD|eIb7I?%>Y_kf%}Nbd`BXb4l1(Pc+}zoUR|9%_!7f zum2T;wbx&pohtI+&@~wm3nH9xLbOYkg*`phY~TK5iC#3tZNXo9s`cahx+8j2)rh5C zQgZh6D7Ekgib|hpdhxYf{r!PTJc z!vsYG@{hA}l5kL)g)0N_)(nC<*L0qdUi*3fD5<0sn58>zklX@6Tyv3*X^}m=Cqc40 zQ6GfjG@kd1mFIm`qaubWunm_?P>WUZ`9|f_z%gGHi{n|uu(N8!L=aw5(qAcDj$-QK zu;D#j6e42OXTQD>)i zlvM$LX`$n9EEjxM$_QDF&a z7cme_rat}aXmiN&7`6Q98}dh4Z@8L_uAb#nK&GQiZOOUnA9kAEVb-csuN1AWL=sXt z{z9GCN%%l0N9QvJM;tl1nf?rrhT{*sE%4WqR?{0~aIrfCcCPxf4eh_*jjQ=`$p53Y z@_|Rsx2i}|3dNFetMQQ5y8agTK-E0D&7;@3-LUxfvZ7 z7~!p@&mFe^oca2^F|CBt+4Ly?^ViUVSAhAH>JH1GN{^TQb3QnM*x0ZiZgDyNI@_c3 z@{}(WH4*e3T~}n_^0}da4ElIxAf9B!IaL7z9X0Icvj@cIkE*~W--17&WN`Ea5)Gn> z#gpfRb#44;jVTOS{FuaZgd(-ZD848=fQzgST2MxR>wSLc1P=2HDvByz$B$IsNCC6L zCM?nK*OHj6JA9gz4|b<~2%RqelN^1Y)jIqnRs!mDKV^BQTfo@hOtz7*Ug}Ee^cbsj zNNlumRgAmt`1$b5MO;&X#5-EP<}AaY;52ihIpem&MTea$?3!DrwbYa?V`NjEfWF3z zUq5JY8Ch;L{kx&J<1K&Fe_Vn;8gk{%c;n?nA2(%(f%DCRHko3uT~VI7RE^JWEqaCq z)i|%nfj(*4|V*XhY3W%M# z*yn6SN4eUOHFxAD7B&9E_PO`G5bqgs^@J{9bk>&;PlUAiqo`j3rjQDgD!}mqLUtb` zCB}ZD@m@s#pf7bV4jreOC*JVfHZ|hyHkX!rauVdd_I9FL45d{gWH!DNYu;i(|8wVx z!)eLY6YXxZ2{Coae0xuTnxo1ACb5wtED?VJAz&@114$Ao6uG9YSy*!K;m5_mj=0^j zw%?b%AOs}ql@$TGC-!^^*_#RT5+y_kTzQG9?LPPZNAtt6cJ%d2$q(I)ws21*?xF%p zN+NeGnWRQ<5w70Rc(bl|S0Xr&5@WrmdurS|IgPB|EyuZO#=tf!35)G!HJ`E1jh^lH zTBu~rL#DhQO*XAWtBt}JHH$lc>3%r0yD|maW_(W=B_J+y164F>O4dO|@&@N3Z3p=B zmVl{|^Z&#atHY|9n&la)SBo}=3AFIF=_~LDJk6MTlA73CXtX+4bnn+c!}N}IPa5pp zwyqbqIkN|I3j_3vD6$zlu{Ps(N-J|*qzEt<$5Soh;s^AuKv_ z-Tz+O1_~6*9CJh4r}`}mbUtjbf#fX58RIIkP6&@*y9kI|5fK*_eZ%jv3U$5*x<>D_ za2M(TV8?XY+9xy>0En#Te<6X4$0&dbyd(go$~eq4u(u)EA2msyF<5ssLZ zDP|I}=~Bi_q)whWv=Ri~L1TYaNrR;5cMB@s78HF1{w&r(6GJ;_2@bD?#1p&P4n_?n0#9Vx~$qjMX=Lk?*!@aKo8m&$iPO7S{g3sFUwr`*<53(68xx7?z`2xf# zGSicy_zI(PJ|%qc2VxT+6bOE--a{k&aq7$<<= zFt)C<@|TPs`+eycPGoGL1Wn9|Ed&a2JyAmjnkm3DQBECX&`bt~odH9cUPq4M{#$-q?G3!)qO-it*&YHw+j-O* zYy78V*`4Q=kQ@^Yz*b6Tal4(Me7BGeS^;phWAW8+L^5A(=D)t?k!rLIwVAKtq=f7h z&^n&VX1-T$ScvN~639QLZ^d@niMaS{C-Q)8oHHBhwD*r~-1Ze#Q)GFOFptW32a-uF z;M@ux%i%a25NwIgXt*=GHX$3~aZfwovGL!}sf?j9TsVo^cn(%&a<--0mIXYqGe>c PWz_J}_#7St0k8iB@FZjZ diff --git a/doc/lua.1 b/doc/lua.1 deleted file mode 100644 index c9bba7d700..0000000000 --- a/doc/lua.1 +++ /dev/null @@ -1,167 +0,0 @@ -.\" lua.man,v 1.8 2003/04/02 00:05:20 lhf Exp -.TH LUA 1 "2003/04/02 00:05:20" -.SH NAME -lua \- Lua interpreter -.SH SYNOPSIS -.B lua -[ -.I options -] -[ -.I script -[ -.I args -] -] -.SH DESCRIPTION -.B lua -is the stand-alone Lua interpreter. -It loads and executes Lua programs, -either in textual source form or -in precompiled binary form. -(Precompiled binaries are output by -.BR luac , -the Lua compiler.) -.B lua -can be used as a batch interpreter and also interactively. -.LP -The given -.I options -(see below) -are executed and then -the Lua program in file -.I script -is loaded and executed. -The given -.I args -are available to -.I script -as strings in a global table named -.BR arg . -If these arguments contain spaces or other characters special to the shell, -then they should be quoted -(but note that the quotes will be removed by the shell). -The arguments in -.B arg -start at 0, -which contains the string -.RI ` script '. -The index of the last argument is stored in -.BR "arg.n" . -The arguments given in the command line before -.IR script , -including the name of the interpreter, -are available in negative indices in -.BR arg . -.LP -At the very start, -before even handling the command line, -.B lua -executes the contents of the environment variable -.BR LUA_INIT , -if it is defined. -If the value of -.B LUA_INIT -is of the form -.RI `@ filename ', -then -.I filename -is executed. -Otherwise, the string is assumed to be a Lua statement and is executed. -.LP -Options start with -.B \- -and are described below. -You can use -.B "\--" -to signal the end of options. -.LP -If no arguments are given, -then -.B "\-v \-i" -is assumed when the standard input is a terminal; -otherwise, -.B "\-" -is assumed. -.LP -In interactive mode, -.B lua -prompts the user, -reads lines from the standard input, -and executes them as they are read. -If a line does not contain a complete statement, -then a secondary prompt is displayed and -lines are read until a complete statement is formed or -a syntax error is found. -So, one way to interrupt the reading of an incomplete statement is -to force a syntax error: -adding a -.B `;' -in the middle of a statement is a sure way of forcing a syntax error -(except inside multiline strings and comments; these must be closed explicitly). -If a line starts with -.BR `=' , -then -.B lua -displays the values of all the expressions in the remainder of the -line. The expressions must be separated by commas. -The primary prompt is the value of the global variable -.BR _PROMPT , -if this value is a string; -otherwise, the default prompt is used. -Similarly, the secondary prompt is the value of the global variable -.BR _PROMPT2 . -So, -to change the prompts, -set the corresponding variable to a string of your choice. -You can do that after calling the interpreter -or on the command line with -.BR "_PROMPT" "=\'lua: \'" , -for example. -(Note the need for quotes, because the string contains a space.) -The default prompts are ``> '' and ``>> ''. -.SH OPTIONS -.TP -.B \- -load and execute the standard input as a file, -that is, -not interactively, -even when the standard input is a terminal. -.TP -.BI \-e " stat" -execute statement -.IR stat . -You need to quote -.I stat -if it contains spaces, quotes, -or other characters special to the shell. -.TP -.B \-i -enter interactive mode after -.I script -is executed. -.TP -.BI \-l " file" -call -.BI require( file ) -before executing -.IR script. -Typically used to load libraries -(hence the letter -.IR l ). -.TP -.B \-v -show version information. -.SH "SEE ALSO" -.BR luac (1) -.br -http://www.lua.org/ -.SH DIAGNOSTICS -Error messages should be self explanatory. -.SH AUTHORS -R. Ierusalimschy, -L. H. de Figueiredo, -and -W. Celes -(lua@tecgraf.puc-rio.br) -.\" EOF diff --git a/doc/lua.html b/doc/lua.html deleted file mode 100644 index 073d4b525a..0000000000 --- a/doc/lua.html +++ /dev/null @@ -1,175 +0,0 @@ - - - -LUA man page - - - - -

        NAME

        -lua - Lua interpreter -

        SYNOPSIS

        -lua -[ -options -] -[ -script -[ -args -] -] -

        DESCRIPTION

        -lua -is the stand-alone Lua interpreter. -It loads and executes Lua programs, -either in textual source form or -in precompiled binary form. -(Precompiled binaries are output by -luac, -the Lua compiler.) -lua -can be used as a batch interpreter and also interactively. -

        -The given -options -(see below) -are executed and then -the Lua program in file -script -is loaded and executed. -The given -args -are available to -script -as strings in a global table named -arg. -If these arguments contain spaces or other characters special to the shell, -then they should be quoted -(but note that the quotes will be removed by the shell). -The arguments in -arg -start at 0, -which contains the string -`script'. -The index of the last argument is stored in -"arg.n". -The arguments given in the command line before -script, -including the name of the interpreter, -are available in negative indices in -arg. -

        -At the very start, -before even handling the command line, -lua -executes the contents of the environment variable -LUA_INIT, -if it is defined. -If the value of -LUA_INIT -is of the form -`@filename', -then -filename -is executed. -Otherwise, the string is assumed to be a Lua statement and is executed. -

        -Options start with -- -and are described below. -You can use -"--" -to signal the end of options. -

        -If no arguments are given, -then -"-v -i" -is assumed when the standard input is a terminal; -otherwise, -"-" -is assumed. -

        -In interactive mode, -lua -prompts the user, -reads lines from the standard input, -and executes them as they are read. -If a line does not contain a complete statement, -then a secondary prompt is displayed and -lines are read until a complete statement is formed or -a syntax error is found. -So, one way to interrupt the reading of an incomplete statement is -to force a syntax error: -adding a -`;' -in the middle of a statement is a sure way of forcing a syntax error -(except inside multiline strings and comments; these must be closed explicitly). -If a line starts with -`=', -then -lua -displays the values of all the expressions in the remainder of the -line. The expressions must be separated by commas. -The primary prompt is the value of the global variable -_PROMPT, -if this value is a string; -otherwise, the default prompt is used. -Similarly, the secondary prompt is the value of the global variable -_PROMPT2. -So, -to change the prompts, -set the corresponding variable to a string of your choice. -You can do that after calling the interpreter -or on the command line with -"_PROMPT" "=\'lua: \'", -for example. -(Note the need for quotes, because the string contains a space.) -The default prompts are ``> '' and ``>> ''. -

        OPTIONS

        -

        -- -load and execute the standard input as a file, -that is, -not interactively, -even when the standard input is a terminal. -

        --e "stat" -execute statement -stat. -You need to quote -stat -if it contains spaces, quotes, -or other characters special to the shell. -

        --i -enter interactive mode after -script -is executed. -

        --l "file" -call -require( file) -before executing -script. -Typically used to load libraries -(hence the letter -l). -

        --v -show version information. -

        SEE ALSO

        -luac(1) -
        -http://www.lua.org/ -

        DIAGNOSTICS

        -Error messages should be self explanatory. -

        AUTHORS

        -R. Ierusalimschy, -L. H. de Figueiredo, -and -W. Celes -(lua AT tecgraf.puc-rio.br) - - - diff --git a/doc/luac.1 b/doc/luac.1 deleted file mode 100644 index c6523060f8..0000000000 --- a/doc/luac.1 +++ /dev/null @@ -1,136 +0,0 @@ -.\" luac.man,v 1.25 2002/12/13 11:45:12 lhf Exp -.TH LUAC 1 "2002/12/13 11:45:12" -.SH NAME -luac \- Lua compiler -.SH SYNOPSIS -.B luac -[ -.I options -] [ -.I filenames -] -.SH DESCRIPTION -.B luac -is the Lua compiler. -It translates programs written in the Lua programming language -into binary files that can be latter loaded and executed. -.LP -The main advantages of precompiling chunks are: -faster loading, -protecting source code from user changes, -and -off-line syntax checking. -.LP -Pre-compiling does not imply faster execution -because in Lua chunks are always compiled into bytecodes before being executed. -.B luac -simply allows those bytecodes to be saved in a file for later execution. -.LP -.B luac -produces a single output file containing the bytecodes -for all source files given. -By default, -the output file is named -.BR luac.out , -but you can change this with the -.B \-o -option. -.LP -The binary files created by -.B luac -are portable to all architectures with the same word size. -This means that -binary files created on a 32-bit platform (such as Intel) -can be read without change in another 32-bit platform (such as Sparc), -even if the byte order (``endianness'') is different. -On the other hand, -binary files created on a 16-bit platform cannot be read in a 32-bit platform, -nor vice-versa. -.LP -In the command line, -you can mix -text files containing Lua source and -binary files containing precompiled chunks. -This is useful to combine several precompiled chunks, -even from different (but compatible) platforms, -into a single precompiled chunk. -.LP -You can use -.B "\-" -to indicate the standard input as a source file -and -.B "\--" -to signal the end of options -(that is, -all remaining arguments will be treated as files even if they start with -.BR "\-" ). -.LP -The internal format of the binary files produced by -.B luac -is likely to change when a new version of Lua is released. -So, -save the source files of all Lua programs that you precompile. -.LP -.SH OPTIONS -Options must be separate. -.TP -.B \-l -produce a listing of the compiled bytecode for Lua's virtual machine. -Listing bytecodes is useful to learn about Lua's virtual machine. -If no files are given, then -.B luac -loads -.B luac.out -and lists its contents. -.TP -.BI \-o " file" -output to -.IR file , -instead of the default -.BR luac.out . -The output file may be a source file because -all files are loaded before the output file is written. -Be careful not to overwrite precious files. -.TP -.B \-p -load files but do not generate any output file. -Used mainly for syntax checking and for testing precompiled chunks: -corrupted files will probably generate errors when loaded. -Lua always performs a thorough integrity test on precompiled chunks. -Bytecode that passes this test is completely safe, -in the sense that it will not break the interpreter. -However, -there is no guarantee that such code does anything sensible. -(None can be given, because the halting problem is unsolvable.) -If no files are given, then -.B luac -loads -.B luac.out -and tests its contents. -No messages are displayed if the file passes the integrity test. -.TP -.B \-s -strip debug information before writing the output file. -This saves some space in very large chunks, -but if errors occur when running these chunks, -then the error messages may not contain the full information they usually do -(line numbers and names of locals are lost). -.TP -.B \-v -show version information. -.SH FILES -.TP 15 -.B luac.out -default output file -.SH "SEE ALSO" -.BR lua (1) -.br -http://www.lua.org/ -.SH DIAGNOSTICS -Error messages should be self explanatory. -.SH AUTHORS -L. H. de Figueiredo, -R. Ierusalimschy and -W. Celes -(lua@tecgraf.puc-rio.br) -.\" EOF diff --git a/doc/luac.html b/doc/luac.html deleted file mode 100644 index 3a71622e0b..0000000000 --- a/doc/luac.html +++ /dev/null @@ -1,144 +0,0 @@ - - - -LUAC man page - - - - -

        NAME

        -luac - Lua compiler -

        SYNOPSIS

        -luac -[ -options -] [ -filenames -] -

        DESCRIPTION

        -luac -is the Lua compiler. -It translates programs written in the Lua programming language -into binary files that can be latter loaded and executed. -

        -The main advantages of precompiling chunks are: -faster loading, -protecting source code from user changes, -and -off-line syntax checking. -

        -Pre-compiling does not imply faster execution -because in Lua chunks are always compiled into bytecodes before being executed. -luac -simply allows those bytecodes to be saved in a file for later execution. -

        -luac -produces a single output file containing the bytecodes -for all source files given. -By default, -the output file is named -luac.out, -but you can change this with the --o -option. -

        -The binary files created by -luac -are portable to all architectures with the same word size. -This means that -binary files created on a 32-bit platform (such as Intel) -can be read without change in another 32-bit platform (such as Sparc), -even if the byte order (``endianness'') is different. -On the other hand, -binary files created on a 16-bit platform cannot be read in a 32-bit platform, -nor vice-versa. -

        -In the command line, -you can mix -text files containing Lua source and -binary files containing precompiled chunks. -This is useful to combine several precompiled chunks, -even from different (but compatible) platforms, -into a single precompiled chunk. -

        -You can use -"-" -to indicate the standard input as a source file -and -"--" -to signal the end of options -(that is, -all remaining arguments will be treated as files even if they start with -"-"). -

        -The internal format of the binary files produced by -luac -is likely to change when a new version of Lua is released. -So, -save the source files of all Lua programs that you precompile. -

        -

        OPTIONS

        -Options must be separate. -

        --l -produce a listing of the compiled bytecode for Lua's virtual machine. -Listing bytecodes is useful to learn about Lua's virtual machine. -If no files are given, then -luac -loads -luac.out -and lists its contents. -

        --o "file" -output to -file, -instead of the default -luac.out. -The output file may be a source file because -all files are loaded before the output file is written. -Be careful not to overwrite precious files. -

        --p -load files but do not generate any output file. -Used mainly for syntax checking and for testing precompiled chunks: -corrupted files will probably generate errors when loaded. -Lua always performs a thorough integrity test on precompiled chunks. -Bytecode that passes this test is completely safe, -in the sense that it will not break the interpreter. -However, -there is no guarantee that such code does anything sensible. -(None can be given, because the halting problem is unsolvable.) -If no files are given, then -luac -loads -luac.out -and tests its contents. -No messages are displayed if the file passes the integrity test. -

        --s -strip debug information before writing the output file. -This saves some space in very large chunks, -but if errors occur when running these chunks, -then the error messages may not contain the full information they usually do -(line numbers and names of locals are lost). -

        --v -show version information. -

        FILES

        -

        -luac.out -default output file -

        SEE ALSO

        -lua(1) -
        -http://www.lua.org/ -

        DIAGNOSTICS

        -Error messages should be self explanatory. -

        AUTHORS

        -L. H. de Figueiredo, -R. Ierusalimschy and -W. Celes -(lua AT tecgraf.puc-rio.br) - - - diff --git a/doc/manual.html b/doc/manual.html deleted file mode 100644 index 2a92d2aaf4..0000000000 --- a/doc/manual.html +++ /dev/null @@ -1,4612 +0,0 @@ - - - - -Lua: 5.0 reference manual - - - - -
        -

        -Lua -Lua 5.0 Reference Manual -

        - -by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes -

        - -Copyright -© 2003 Tecgraf, PUC-Rio. All rights reserved. - -


        - -

        -

        - - - - -

        1 - Introduction

        - -

        Lua is an extension programming language designed to support -general procedural programming with data description -facilities. -It also offers good support for object-oriented programming, -functional programming, and data-driven programming. -Lua is intended to be used as a powerful, light-weight -configuration language for any program that needs one. -Lua is implemented as a library, written in clean C -(that is, in the common subset of ANSI C and C++). - -

        Being an extension language, Lua has no notion of a "main" program: -it only works embedded in a host client, -called the embedding program or simply the host. -This host program can invoke functions to execute a piece of Lua code, -can write and read Lua variables, -and can register C functions to be called by Lua code. -Through the use of C functions, Lua can be augmented to cope with -a wide range of different domains, -thus creating customized programming languages sharing a syntactical framework. - -

        The Lua distribution includes a stand-alone embedding program, -lua, that uses the Lua library to offer a complete Lua interpreter. - -

        Lua is free software, -and is provided as usual with no guarantees, -as stated in its copyright notice. -The implementation described in this manual is available -at Lua's official web site, www.lua.org. - -

        Like any other reference manual, -this document is dry in places. -For a discussion of the decisions behind the design of Lua, -see the papers below, -which are available at Lua's web site. -

          -
        • -R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. -Lua---an extensible extension language. -Software: Practice & Experience 26 #6 (1996) 635-652. -
        • -L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. -The design and implementation of a language for extending applications. -Proceedings of XXI Brazilian Seminar on Software and Hardware (1994) 273-283. -
        • -L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. -Lua: an extensible embedded language. -Dr. Dobb's Journal 21 #12 (Dec 1996) 26-33. -
        • -R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. -The evolution of an extension language: a history of Lua, -Proceedings of V Brazilian Symposium on Programming Languages (2001) B-14-B-28. -
        - -

        Lua means "moon" in Portuguese and is pronounced LOO-ah. - -

        -

        2 - The Language

        - -

        This section describes the lexis, the syntax, and the semantics of Lua. -In other words, -this section describes -which tokens are valid, -how they can be combined, -and what their combinations mean. - -

        The language constructs will be explained using the usual extended BNF, -in which -{a} means 0 or more a's, and -[a] means an optional a. -Non-terminals are shown in italics, -keywords are shown in bold, -and other terminal symbols are shown in typewriter font, -enclosed in single quotes. - -

        2.1 - Lexical Conventions

        - -

        Identifiers in Lua can be any string of letters, -digits, and underscores, -not beginning with a digit. -This coincides with the definition of identifiers in most languages. -(The definition of letter depends on the current locale: -any character considered alphabetic by the current locale -can be used in an identifier.) - -

        The following keywords are reserved -and cannot be used as identifiers: - -

        -       and       break     do        else      elseif
        -       end       false     for       function  if
        -       in        local     nil       not       or
        -       repeat    return    then      true      until     while
        -
        - -

        Lua is a case-sensitive language: -and is a reserved word, but And and AND -are two different, valid identifiers. -As a convention, identifiers starting with an underscore followed by -uppercase letters (such as _VERSION) -are reserved for internal variables used by Lua. - -

        The following strings denote other tokens: -

        -       +     -     *     /     ^     =
        -       ~=    <=    >=    <     >     ==
        -       (     )     {     }     [     ]
        -       ;     :     ,     .     ..    ...
        -
        - -

        Literal strings -can be delimited by matching single or double quotes, -and can contain the following C-like escape sequences: -

          -
        • \a --- bell -
        • \b --- backspace -
        • \f --- form feed -
        • \n --- newline -
        • \r --- carriage return -
        • \t --- horizontal tab -
        • \v --- vertical tab -
        • \\ --- backslash -
        • \" --- quotation mark -
        • \' --- apostrophe -
        • \[ --- left square bracket -
        • \] --- right square bracket -
        -Moreover, a `\newline´ -(that is, a backslash followed by a real newline) -results in a newline in the string. -A character in a string may also be specified by its numerical value -using the escape sequence `\ddd´, -where ddd is a sequence of up to three decimal digits. -Strings in Lua may contain any 8-bit value, including embedded zeros, -which can be specified as `\0´. - -

        Literal strings can also be delimited by matching double square brackets -[[ · · · ]]. -Literals in this bracketed form may run for several lines, -may contain nested [[ · · · ]] pairs, -and do not interpret any escape sequences. -For convenience, -when the opening `[[´ is immediately followed by a newline, -the newline is not included in the string. -As an example, in a system using ASCII -(in which `a´ is coded as 97, -newline is coded as 10, and `1´ is coded as 49), -the four literals below denote the same string: -

        -      (1)   "alo\n123\""
        -      (2)   '\97lo\10\04923"'
        -      (3)   [[alo
        -            123"]]
        -      (4)   [[
        -            alo
        -            123"]]
        -
        - -

        Numerical constants may be written with an optional decimal part -and an optional decimal exponent. -Examples of valid numerical constants are -

        -       3     3.0     3.1416  314.16e-2   0.31416E1
        -
        - -

        Comments start anywhere outside a string with a -double hyphen (--). -If the text immediately after -- is different from [[, -the comment is a short comment, -which runs until the end of the line. -Otherwise, it is a long comment, -which runs until the corresponding ]]. -Long comments may run for several lines -and may contain nested [[ · · · ]] pairs. - -

        For convenience, -the first line of a chunk is skipped if it starts with #. -This facility allows the use of Lua as a script interpreter -in Unix systems (see 6). - -

        2.2 - Values and Types

        - -

        Lua is a dynamically typed language. -That means that -variables do not have types; only values do. -There are no type definitions in the language. -All values carry their own type. - -

        There are eight basic types in Lua: -nil, boolean, number, -string, function, userdata, thread, and table. -Nil is the type of the value nil, -whose main property is to be different from any other value; -usually it represents the absence of a useful value. -Boolean is the type of the values false and true. -In Lua, both nil and false make a condition false; -any other value makes it true. -Number represents real (double-precision floating-point) numbers. -(It is easy to build Lua interpreters that use other -internal representations for numbers, -such as single-precision float or long integers.) -String represents arrays of characters. - -Lua is 8-bit clean: -Strings may contain any 8-bit character, -including embedded zeros ('\0') (see 2.1). - -

        Functions are first-class values in Lua. -That means that functions can be stored in variables, -passed as arguments to other functions, and returned as results. -Lua can call (and manipulate) functions written in Lua and -functions written in C -(see 2.5.7). - -

        The type userdata is provided to allow arbitrary C data to -be stored in Lua variables. -This type corresponds to a block of raw memory -and has no pre-defined operations in Lua, -except assignment and identity test. -However, by using metatables, -the programmer can define operations for userdata values -(see 2.8). -Userdata values cannot be created or modified in Lua, -only through the C API. -This guarantees the integrity of data owned by the host program. - -

        The type thread represents independent threads of execution -and it is used to implement coroutines. - -

        The type table implements associative arrays, -that is, arrays that can be indexed not only with numbers, -but with any value (except nil). -Moreover, -tables can be heterogeneous, -that is, they can contain values of all types (except nil). -Tables are the sole data structuring mechanism in Lua; -they may be used to represent ordinary arrays, -symbol tables, sets, records, graphs, trees, etc. -To represent records, Lua uses the field name as an index. -The language supports this representation by -providing a.name as syntactic sugar for a["name"]. -There are several convenient ways to create tables in Lua -(see 2.5.6). - -

        Like indices, -the value of a table field can be of any type (except nil). -In particular, -because functions are first class values, -table fields may contain functions. -Thus tables may also carry methods (see 2.5.8). - -

        Tables, functions, and userdata values are objects: -variables do not actually contain these values, -only references to them. -Assignment, parameter passing, and function returns -always manipulate references to such values; -these operations do not imply any kind of copy. - -

        The library function type returns a string describing the type -of a given value (see 5.1). - -

        2.2.1 - Coercion

        - -

        Lua provides automatic conversion between -string and number values at run time. -Any arithmetic operation applied to a string tries to convert -that string to a number, following the usual rules. -Conversely, whenever a number is used where a string is expected, -the number is converted to a string, in a reasonable format. -For complete control of how numbers are converted to strings, -use the format function from the string library (see 5.3). - -

        2.3 - Variables

        - -

        Variables are places that store values. - -There are three kinds of variables in Lua: -global variables, local variables, and table fields. - -

        A single name can denote a global variable or a local variable -(or a formal parameter of a function, -which is a particular form of local variable): -

        -	var ::= Name
        -
        -Variables are assumed to be global unless explicitly declared local -(see 2.4.7). -Local variables are lexically scoped: -Local variables can be freely accessed by functions -defined inside their scope (see 2.6). - -

        Before the first assignment to a variable, its value is nil. - -

        Square brackets are used to index a table: -

        -	var ::= prefixexp `[´ exp `]´
        -
        -The first expression (prefixexp)should result in a table value; -the second expression (exp) -identifies a specific entry inside that table. -The expression denoting the table to be indexed has a restricted syntax; -see 2.5 for details. - -

        The syntax var.NAME is just syntactic sugar for -var["NAME"]: -

        -	var ::= prefixexp `.´ Name
        -
        - -

        The meaning of accesses to global variables -and table fields can be changed via metatables. -An access to an indexed variable t[i] is equivalent to -a call gettable_event(t,i). -(See 2.8 for a complete description of the -gettable_event function. -This function is not defined or callable in Lua. -We use it here only for explanatory purposes.) - -

        All global variables live as fields in ordinary Lua tables, -called environment tables or simply environments. -Functions written in C and exported to Lua (C functions) -all share a common global environment. -Each function written in Lua (a Lua function) -has its own reference to an environment, -so that all global variables in that function -will refer to that environment table. -When a function is created, -it inherits the environment from the function that created it. -To change or get the environment table of a Lua function, -you call setfenv or getfenv (see 5.1). - -

        An access to a global variable x -is equivalent to _env.x, -which in turn is equivalent to -

        -       gettable_event(_env, "x")
        -
        -where _env is the environment of the running function. -(The _env variable is not defined in Lua. -We use it here only for explanatory purposes.) - -

        2.4 - Statements

        - -

        Lua supports an almost conventional set of statements, -similar to those in Pascal or C. -This set includes -assignment, control structures, procedure calls, -table constructors, and variable declarations. - -

        2.4.1 - Chunks

        - -

        The unit of execution of Lua is called a chunk. -A chunk is simply a sequence of statements, -which are executed sequentially. -Each statement can be optionally followed by a semicolon: -

        -	chunk ::= {stat [`;´]}
        -
        - -

        Lua handles a chunk as the body of an anonymous function (see 2.5.8). -As such, chunks can define local variables and return values. - -

        A chunk may be stored in a file or in a string inside the host program. -When a chunk is executed, first it is pre-compiled into opcodes for -a virtual machine, -and then the compiled code is executed -by an interpreter for the virtual machine. - -

        Chunks may also be pre-compiled into binary form; -see program luac for details. -Programs in source and compiled forms are interchangeable; -Lua automatically detects the file type and acts accordingly. - - -

        2.4.2 - Blocks

        -A block is a list of statements; -syntactically, a block is equal to a chunk: -
        -	block ::= chunk
        -
        - -

        A block may be explicitly delimited to produce a single statement: -

        -	stat ::= do block end
        -
        -Explicit blocks are useful -to control the scope of variable declarations. -Explicit blocks are also sometimes used to -add a return or break statement in the middle -of another block (see 2.4.4). - - -

        2.4.3 - Assignment

        - -

        Lua allows multiple assignment. -Therefore, the syntax for assignment -defines a list of variables on the left side -and a list of expressions on the right side. -The elements in both lists are separated by commas: -

        -	stat ::= varlist1 `=´ explist1
        -	varlist1 ::= var {`,´ var}
        -	explist1 ::= exp {`,´ exp}
        -
        -Expressions are discussed in 2.5. - -

        Before the assignment, -the list of values is adjusted to the length of -the list of variables. -If there are more values than needed, -the excess values are thrown away. -If there are fewer values than needed, -the list is extended with as many nil's as needed. -If the list of expressions ends with a function call, -then all values returned by that function call enter in the list of values, -before the adjustment -(except when the call is enclosed in parentheses; see 2.5). - -

        The assignment statement first evaluates all its expressions -and only then are the assignments performed. -Thus the code -

        -       i = 3
        -       i, a[i] = i+1, 20
        -
        -sets a[3] to 20, without affecting a[4] -because the i in a[i] is evaluated (to 3) -before it is assigned 4. -Similarly, the line -
        -       x, y = y, x
        -
        -exchanges the values of x and y. - -

        The meaning of assignments to global variables -and table fields can be changed via metatables. -An assignment to an indexed variable t[i] = val is equivalent to -settable_event(t,i,val). -(See 2.8 for a complete description of the -settable_event function. -This function is not defined or callable in Lua. -We use it here only for explanatory purposes.) - -

        An assignment to a global variable x = val -is equivalent to the assignment -_env.x = val, -which in turn is equivalent to -

        -       settable_event(_env, "x", val)
        -
        -where _env is the environment of the running function. -(The _env variable is not defined in Lua. -We use it here only for explanatory purposes.) - -

        2.4.4 - Control Structures

        -The control structures -if, while, and repeat have the usual meaning and -familiar syntax: - - - -
        -	stat ::= while exp do block end
        -	stat ::= repeat block until exp
        -	stat ::= if exp then block {elseif exp then block} [else block] end
        -
        -Lua also has a for statement, in two flavors (see 2.4.5). - -

        The condition expression exp of a -control structure may return any value. -Both false and nil are considered false. -All values different from nil and false are considered true -(in particular, the number 0 and the empty string are also true). - -

        The return statement is used to return values -from a function or from a chunk. - -Functions and chunks may return more than one value, -so the syntax for the return statement is -

        -	stat ::= return [explist1]
        -
        - -

        The break statement can be used to terminate the execution of a -while, repeat, or for loop, -skipping to the next statement after the loop: - -

        -	stat ::= break
        -
        -A break ends the innermost enclosing loop. - -

        For syntactic reasons, return and break -statements can only be written as the last statement of a block. -If it is really necessary to return or break in the -middle of a block, -then an explicit inner block can be used, -as in the idioms -`do return end´ and -`do break end´, -because now return and break are the last statements in -their (inner) blocks. -In practice, -those idioms are only used during debugging. - -

        2.4.5 - For Statement

        - -

        The for statement has two forms: -one numeric and one generic. - - -

        The numeric for loop repeats a block of code while a -control variable runs through an arithmetic progression. -It has the following syntax: -

        -	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end
        -
        -The block is repeated for name starting at the value of -the first exp, until it passes the second exp by steps of the -third exp. -More precisely, a for statement like -
        -       for var = e1, e2, e3 do block end
        -
        -is equivalent to the code: -
        -       do
        -         local var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
        -         if not (var and _limit and _step) then error() end
        -         while (_step>0 and var<=_limit) or (_step<=0 and var>=_limit) do
        -           block
        -           var = var + _step
        -         end
        -       end
        -
        -Note the following: -
          -
        • All three control expressions are evaluated only once, -before the loop starts. -They must all result in numbers. -
        • _limit and _step are invisible variables. -The names are here for explanatory purposes only. -
        • The behavior is undefined if you assign to var inside -the block. -
        • If the third expression (the step) is absent, then a step of 1 is used. -
        • You can use break to exit a for loop. -
        • The loop variable var is local to the statement; -you cannot use its value after the for ends or is broken. -If you need the value of the loop variable var, -then assign it to another variable before breaking or exiting the loop. -
        - -

        The generic for statement works over functions, -called iterators. -For each iteration, it calls its iterator function to produce a new value, -stopping when the new value is nil. -The generic for loop has the following syntax: -

        -	stat ::= for Name {`,´ Name} in explist1 do block end
        -
        -A for statement like -
        -       for var_1, ..., var_n in explist do block end
        -
        -is equivalent to the code: -
        -       do
        -         local _f, _s, var_1 = explist
        -         local var_2, ... , var_n
        -         while true do
        -           var_1, ..., var_n = _f(_s, var_1)
        -           if var_1 == nil then break end
        -           block
        -         end
        -       end
        -
        -Note the following: -
          -
        • explist is evaluated only once. -Its results are an iterator function, -a state, and an initial value for the first iterator variable. -
        • _f and _s are invisible variables. -The names are here for explanatory purposes only. -
        • The behavior is undefined if you assign to -var_1 inside the block. -
        • You can use break to exit a for loop. -
        • The loop variables var_i are local to the statement; -you cannot use their values after the for ends. -If you need these values, -then assign them to other variables before breaking or exiting the loop. -
        - -

        2.4.6 - Function Calls as Statements

        -To allow possible side-effects, -function calls can be executed as statements: -
        -	stat ::= functioncall
        -
        -In this case, all returned values are thrown away. -Function calls are explained in 2.5.7. - -

        2.4.7 - Local Declarations

        -Local variables may be declared anywhere inside a block. -The declaration may include an initial assignment: -
        -	stat ::= local namelist [`=´ explist1]
        -	namelist ::= Name {`,´ Name}
        -
        -If present, an initial assignment has the same semantics -of a multiple assignment (see 2.4.3). -Otherwise, all variables are initialized with nil. - -

        A chunk is also a block (see 2.4.1), -so local variables can be declared in a chunk outside any explicit block. -Such local variables die when the chunk ends. - -

        The visibility rules for local variables are explained in 2.6. - -

        2.5 - Expressions

        - -

        -The basic expressions in Lua are the following: -

        -	exp ::= prefixexp
        -	exp ::= nil | false | true
        -	exp ::= Number
        -	exp ::= Literal
        -	exp ::= function
        -	exp ::= tableconstructor
        -	prefixexp ::= var | functioncall | `(´ exp `)´
        -
        - -

        Numbers and literal strings are explained in 2.1; -variables are explained in 2.3; -function definitions are explained in 2.5.8; -function calls are explained in 2.5.7; -table constructors are explained in 2.5.6. - - -

        An expression enclosed in parentheses always results in only one value. -Thus, -(f(x,y,z)) is always a single value, -even if f returns several values. -(The value of (f(x,y,z)) is the first value returned by f -or nil if f does not return any values.) - -

        Expressions can also be built with arithmetic operators, relational operators, -and logical operators, all of which are explained below. - -

        2.5.1 - Arithmetic Operators

        -Lua supports the usual arithmetic operators: -the binary + (addition), -- (subtraction), * (multiplication), -/ (division), and ^ (exponentiation); -and unary - (negation). -If the operands are numbers, or strings that can be converted to -numbers (see 2.2.1), -then all operations except exponentiation have the usual meaning. -Exponentiation calls a global function __pow; -otherwise, an appropriate metamethod is called (see 2.8). -The standard mathematical library defines function __pow, -giving the expected meaning to exponentiation -(see 5.5). - -

        2.5.2 - Relational Operators

        -The relational operators in Lua are -
        -       ==    ~=    <     >     <=    >=
        -
        -These operators always result in false or true. - -

        Equality (==) first compares the type of its operands. -If the types are different, then the result is false. -Otherwise, the values of the operands are compared. -Numbers and strings are compared in the usual way. -Objects (tables, userdata, threads, and functions) -are compared by reference: -Two objects are considered equal only if they are the same object. -Every time you create a new object (a table, userdata, or function), -this new object is different from any previously existing object. - -

        You can change the way that Lua compares tables and userdata -using the "eq" metamethod (see 2.8). - -

        The conversion rules of 2.2.1 -do not apply to equality comparisons. -Thus, "0"==0 evaluates to false, -and t[0] and t["0"] denote different -entries in a table. - - -

        The operator ~= is exactly the negation of equality (==). - -

        The order operators work as follows. -If both arguments are numbers, then they are compared as such. -Otherwise, if both arguments are strings, -then their values are compared according to the current locale. -Otherwise, Lua tries to call the "lt" or the "le" -metamethod (see 2.8). - -

        2.5.3 - Logical Operators

        -The logical operators in Lua are - -
        -       and   or    not
        -
        -Like the control structures (see 2.4.4), -all logical operators consider both false and nil as false -and anything else as true. - - -

        The operator not always return false or true. - -

        The conjunction operator and returns its first argument -if this value is false or nil; -otherwise, and returns its second argument. -The disjunction operator or returns its first argument -if this value is different from nil and false; -otherwise, or returns its second argument. -Both and and or use short-cut evaluation, -that is, -the second operand is evaluated only if necessary. -For example, -

        -       10 or error()       -> 10
        -       nil or "a"          -> "a"
        -       nil and 10          -> nil
        -       false and error()   -> false
        -       false and nil       -> false
        -       false or nil        -> nil
        -       10 and 20           -> 20
        -
        - -

        2.5.4 - Concatenation

        -The string concatenation operator in Lua is -denoted by two dots (`..´). -If both operands are strings or numbers, then they are converted to -strings according to the rules mentioned in 2.2.1. -Otherwise, the "concat" metamethod is called (see 2.8). - -

        2.5.5 - Precedence

        -Operator precedence in Lua follows the table below, -from lower to higher priority: -
        -       or
        -       and
        -       <     >     <=    >=    ~=    ==
        -       ..
        -       +     -
        -       *     /
        -       not   - (unary)
        -       ^
        -
        -You can use parentheses to change the precedences in an expression. -The concatenation (`..´) and exponentiation (`^´) -operators are right associative. -All other binary operators are left associative. - -

        2.5.6 - Table Constructors

        -Table constructors are expressions that create tables. -Every time a constructor is evaluated, a new table is created. -Constructors can be used to create empty tables, -or to create a table and initialize some of its fields. -The general syntax for constructors is -
        -	tableconstructor ::= `{´ [fieldlist] `}´
        -	fieldlist ::= field {fieldsep field} [fieldsep]
        -	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
        -	fieldsep ::= `,´ | `;´
        -
        - -

        Each field of the form [exp1] = exp2 adds to the new table an entry -with key exp1 and value exp2. -A field of the form name = exp is equivalent to -["name"] = exp. -Finally, fields of the form exp are equivalent to -[i] = exp, where i are consecutive numerical integers, -starting with 1. -Fields in the other formats do not affect this counting. -For example, -

        -       a = {[f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45}
        -
        -is equivalent to -
        -       do
        -         local temp = {}
        -         temp[f(1)] = g
        -         temp[1] = "x"         -- 1st exp
        -         temp[2] = "y"         -- 2nd exp
        -         temp.x = 1            -- temp["x"] = 1
        -         temp[3] = f(x)        -- 3rd exp
        -         temp[30] = 23
        -         temp[4] = 45          -- 4th exp
        -         a = temp
        -       end
        -
        - -

        If the last field in the list has the form exp -and the expression is a function call, -then all values returned by the call enter the list consecutively -(see 2.5.7). -To avoid this, -enclose the function call in parentheses (see 2.5). - -

        The field list may have an optional trailing separator, -as a convenience for machine-generated code. - -

        2.5.7 - Function Calls

        -A function call in Lua has the following syntax: -
        -	functioncall ::= prefixexp args
        -
        -In a function call, -first prefixexp and args are evaluated. -If the value of prefixexp has type function, -then that function is called -with the given arguments. -Otherwise, its "call" metamethod is called, -having as first parameter the value of prefixexp, -followed by the original call arguments -(see 2.8). - -

        The form -

        -	functioncall ::= prefixexp `:´ Name args
        -
        -can be used to call "methods". -A call v:name(...) -is syntactic sugar for v.name(v,...), -except that v is evaluated only once. - -

        Arguments have the following syntax: -

        -	args ::= `(´ [explist1] `)´
        -	args ::= tableconstructor
        -	args ::= Literal
        -
        -All argument expressions are evaluated before the call. -A call of the form f{...} is syntactic sugar for -f({...}), that is, -the argument list is a single new table. -A call of the form f'...' -(or f"..." or f[[...]]) is syntactic sugar for -f('...'), that is, -the argument list is a single literal string. - -

        Because a function can return any number of results -(see 2.4.4), -the number of results must be adjusted before they are used. -If the function is called as a statement (see 2.4.6), -then its return list is adjusted to zero elements, -thus discarding all returned values. -If the function is called inside another expression -or in the middle of a list of expressions, -then its return list is adjusted to one element, -thus discarding all returned values except the first one. -If the function is called as the last element of a list of expressions, -then no adjustment is made -(unless the call is enclosed in parentheses). - -

        Here are some examples: -

        -       f()                -- adjusted to 0 results
        -       g(f(), x)          -- f() is adjusted to 1 result
        -       g(x, f())          -- g gets x plus all values returned by f()
        -       a,b,c = f(), x     -- f() is adjusted to 1 result (and c gets nil)
        -       a,b,c = x, f()     -- f() is adjusted to 2 results
        -       a,b,c = f()        -- f() is adjusted to 3 results
        -       return f()         -- returns all values returned by f()
        -       return x,y,f()     -- returns x, y, and all values returned by f()
        -       {f()}              -- creates a list with all values returned by f()
        -       {f(), nil}         -- f() is adjusted to 1 result
        -
        - -

        If you enclose a function call in parentheses, -then it is adjusted to return exactly one value: -

        -       return x,y,(f())   -- returns x, y, and the first value from f()
        -       {(f())}            -- creates a table with exactly one element
        -
        - -

        As an exception to the free-format syntax of Lua, -you cannot put a line break before the `(´ in a function call. -That restriction avoids some ambiguities in the language. -If you write -

        -       a = f
        -       (g).x(a)
        -
        -Lua would read that as a = f(g).x(a). -So, if you want two statements, you must add a semi-colon between them. -If you actually want to call f, -you must remove the line break before (g). - -

        A call of the form return functioncall is called -a tail call. -Lua implements proper tail calls -(or proper tail recursion): -In a tail call, -the called function reuses the stack entry of the calling function. -Therefore, there is no limit on the number of nested tail calls that -a program can execute. -However, a tail call erases any debug information about the -calling function. -Note that a tail call only happens with a particular syntax, -where the return has one single function call as argument; -this syntax makes the calling function returns exactly -the returns of the called function. -So, all the following examples are not tails calls: -

        -  return (f(x))        -- results adjusted to 1
        -  return 2 * f(x)
        -  return x, f(x)       -- additional results
        -  f(x); return         -- results discarded
        -  return x or f(x)     -- results adjusted to 1
        -
        - -

        2.5.8 - Function Definitions

        - -

        The syntax for function definition is -

        -	function ::= function funcbody
        -	funcbody ::= `(´ [parlist1] `)´ block end
        -
        - -

        The following syntactic sugar simplifies function definitions: -

        -	stat ::= function funcname funcbody
        -	stat ::= local function Name funcbody
        -	funcname ::= Name {`.´ Name} [`:´ Name]
        -
        -The statement -
        -       function f () ... end
        -
        -translates to -
        -       f = function () ... end
        -
        -The statement -
        -       function t.a.b.c.f () ... end
        -
        -translates to -
        -       t.a.b.c.f = function () ... end
        -
        -The statement -
        -       local function f () ... end
        -
        -translates to -
        -       local f; f = function () ... end
        -
        - -

        A function definition is an executable expression, -whose value has type function. -When Lua pre-compiles a chunk, -all its function bodies are pre-compiled too. -Then, whenever Lua executes the function definition, -the function is instantiated (or closed). -This function instance (or closure) -is the final value of the expression. -Different instances of the same function -may refer to different external local variables -and may have different environment tables. - -

        Parameters act as local variables that are -initialized with the argument values: -

        -	parlist1 ::= namelist [`,´ `...´]
        -	parlist1 ::= `...´
        -
        -When a function is called, -the list of arguments is adjusted to -the length of the list of parameters, -unless the function is a variadic or vararg function, -which is -indicated by three dots (`...´) at the end of its parameter list. -A vararg function does not adjust its argument list; -instead, it collects all extra arguments into an implicit parameter, -called arg. -The value of arg is a table, -with a field n that holds the number of extra arguments -and with the extra arguments at positions 1, 2, ..., n. - -

        As an example, consider the following definitions: -

        -       function f(a, b) end
        -       function g(a, b, ...) end
        -       function r() return 1,2,3 end
        -
        -Then, we have the following mapping from arguments to parameters: -
        -       CALL            PARAMETERS
        -
        -       f(3)             a=3, b=nil
        -       f(3, 4)          a=3, b=4
        -       f(3, 4, 5)       a=3, b=4
        -       f(r(), 10)       a=1, b=10
        -       f(r())           a=1, b=2
        -
        -       g(3)             a=3, b=nil, arg={n=0}
        -       g(3, 4)          a=3, b=4,   arg={n=0}
        -       g(3, 4, 5, 8)    a=3, b=4,   arg={5, 8; n=2}
        -       g(5, r())        a=5, b=1,   arg={2, 3; n=2}
        -
        - -

        Results are returned using the return statement (see 2.4.4). -If control reaches the end of a function -without encountering a return statement, -then the function returns with no results. - -

        The colon syntax -is used for defining methods, -that is, functions that have an implicit extra parameter self. -Thus, the statement -

        -       function t.a.b.c:f (...) ... end
        -
        -is syntactic sugar for -
        -       t.a.b.c.f = function (self, ...) ... end
        -
        - -

        2.6 - Visibility Rules

        - - -

        Lua is a lexically scoped language. -The scope of variables begins at the first statement after -their declaration and lasts until the end of the innermost block that -includes the declaration. -For instance: -

        -  x = 10                -- global variable
        -  do                    -- new block
        -    local x = x         -- new `x', with value 10
        -    print(x)            --> 10
        -    x = x+1
        -    do                  -- another block
        -      local x = x+1     -- another `x'
        -      print(x)          --> 12
        -    end
        -    print(x)            --> 11
        -  end
        -  print(x)              --> 10  (the global one)
        -
        -Notice that, in a declaration like local x = x, -the new x being declared is not in scope yet, -and so the second x refers to the outside variable. - -

        Because of the lexical scoping rules, -local variables can be freely accessed by functions -defined inside their scope. -For instance: -

        -  local counter = 0
        -  function inc (x)
        -    counter = counter + x
        -    return counter
        -  end
        -
        -A local variable used by an inner function is called -an upvalue, or external local variable, -inside the inner function. - -

        Notice that each execution of a local statement -defines new local variables. -Consider the following example: -

        -  a = {}
        -  local x = 20
        -  for i=1,10 do
        -    local y = 0
        -    a[i] = function () y=y+1; return x+y end
        -  end
        -
        -The loop creates ten closures -(that is, ten instances of the anonymous function). -Each of these closures uses a different y variable, -while all of them share the same x. - -

        2.7 - Error Handling

        - -

        Because Lua is an extension language, -all Lua actions start from C code in the host program -calling a function from the Lua library (see 3.15). -Whenever an error occurs during Lua compilation or execution, -control returns to C, -which can take appropriate measures -(such as print an error message). - -

        Lua code can explicitly generate an error by calling the -error function (see 5.1). -If you need to catch errors in Lua, -you can use the pcall function (see 5.1). - -

        2.8 - Metatables

        - -

        Every table and userdata object in Lua may have a metatable. -This metatable is an ordinary Lua table -that defines the behavior of the original table and userdata -under certain special operations. -You can change several aspects of the behavior -of an object by setting specific fields in its metatable. -For instance, when an object is the operand of an addition, -Lua checks for a function in the field "__add" in its metatable. -If it finds one, -Lua calls that function to perform the addition. - -

        We call the keys in a metatable events -and the values metamethods. -In the previous example, the event is "add" -and the metamethod is the function that performs the addition. - -

        You can query and change the metatable of an object -through the set/getmetatable -functions (see 5.1). - -

        A metatable may control how an object behaves in arithmetic operations, -order comparisons, concatenation, and indexing. -A metatable can also define a function to be called when a userdata -is garbage collected. -For each of those operations Lua associates a specific key -called an event. -When Lua performs one of those operations over a table or a userdata, -it checks whether that object has a metatable with the corresponding event. -If so, the value associated with that key (the metamethod) -controls how Lua will perform the operation. - -

        Metatables control the operations listed next. -Each operation is identified by its corresponding name. -The key for each operation is a string with its name prefixed by -two underscores; -for instance, the key for operation "add" is the -string "__add". -The semantics of these operations is better explained by a Lua function -describing how the interpreter executes that operation. - -

        The code shown here in Lua is only illustrative; -the real behavior is hard coded in the interpreter -and it is much more efficient than this simulation. -All functions used in these descriptions -(rawget, tonumber, etc.) -are described in 5.1. -In particular, to retrieve the metamethod of a given object, -we use the expression -

        -  metatable(obj)[event]
        -
        -This should be read as -
        -  rawget(metatable(obj) or {}, event)
        -
        -That is, the access to a metamethod does not invoke other metamethods, -and the access to objects with no metatables does not fail -(it simply results in nil). - -

          - -

        • "add": -the + operation. - -

          The function getbinhandler below defines how Lua chooses a handler -for a binary operation. -First, Lua tries the first operand. -If its type does not define a handler for the operation, -then Lua tries the second operand. -

          - function getbinhandler (op1, op2, event)
          -   return metatable(op1)[event] or metatable(op2)[event]
          - end
          -
          -Using that function, -the behavior of the op1 + op2 is -
          - function add_event (op1, op2)
          -   local o1, o2 = tonumber(op1), tonumber(op2)
          -   if o1 and o2 then  -- both operands are numeric?
          -     return o1 + o2   -- `+' here is the primitive `add'
          -   else  -- at least one of the operands is not numeric
          -     local h = getbinhandler(op1, op2, "__add")
          -     if h then
          -       -- call the handler with both operands
          -       return h(op1, op2)
          -     else  -- no handler available: default behavior
          -       error("...")
          -     end
          -   end
          - end
          -
          - -

        • "sub": -the - operation. -Behavior similar to the "add" operation. - -

        • "mul": -the * operation. -Behavior similar to the "add" operation. - -

        • "div": -the / operation. -Behavior similar to the "add" operation. - -

        • "pow": -the ^ (exponentiation) operation. -
          - function pow_event (op1, op2)
          -   local o1, o2 = tonumber(op1), tonumber(op2)
          -   if o1 and o2 then  -- both operands are numeric?
          -     return __pow(o1, o2)   -- call global `__pow'
          -   else  -- at least one of the operands is not numeric
          -     local h = getbinhandler(op1, op2, "__pow")
          -     if h then
          -       -- call the handler with both operands
          -       return h(op1, op2)
          -     else  -- no handler available: default behavior
          -       error("...")
          -     end
          -   end
          -  end
          -
          - -

        • "unm": -the unary - operation. -
          - function unm_event (op)
          -   local o = tonumber(op)
          -   if o then  -- operand is numeric?
          -     return -o  -- `-' here is the primitive `unm'
          -   else  -- the operand is not numeric.
          -     -- Try to get a handler from the operand
          -     local h = metatable(op).__unm
          -     if h then
          -       -- call the handler with the operand and nil
          -       return h(op, nil)
          -     else  -- no handler available: default behavior
          -       error("...")
          -     end
          -   end
          - end
          -
          - -

        • "concat": -the .. (concatenation) operation. -
          - function concat_event (op1, op2)
          -   if (type(op1) == "string" or type(op1) == "number") and
          -      (type(op2) == "string" or type(op2) == "number") then
          -     return op1 .. op2  -- primitive string concatenation
          -   else
          -     local h = getbinhandler(op1, op2, "__concat")
          -     if h then
          -       return h(op1, op2)
          -     else
          -       error("...")
          -     end
          -   end
          - end
          -
          - -

        • "eq": -the == operation. -The function getcomphandler defines how Lua chooses a metamethod -for comparison operators. -A metamethod only is selected when both objects -being compared have the same type -and the same metamethod for the selected operation. -
          - function getcomphandler (op1, op2, event)
          -   if type(op1) ~= type(op2) then return nil end
          -   local mm1 = metatable(op1)[event]
          -   local mm2 = metatable(op2)[event]
          -   if mm1 == mm2 then return mm1 else return nil end
          - end
          -
          -The "eq" event is defined as follows: -
          - function eq_event (op1, op2)
          -   if type(op1) ~= type(op2) then  -- different types?
          -     return false   -- different objects
          -   end
          -   if op1 == op2 then   -- primitive equal?
          -     return true   -- objects are equal
          -   end
          -   -- try metamethod
          -   local h = getcomphandler(op1, op2, "__eq")
          -   if h then
          -     return h(op1, op2)
          -   else
          -     return false
          -   end
          - end
          -
          -a ~= b is equivalent to not (a == b). - -

        • "lt": -the < operation. -
          - function lt_event (op1, op2)
          -   if type(op1) == "number" and type(op2) == "number" then
          -     return op1 < op2   -- numeric comparison
          -   elseif type(op1) == "string" and type(op2) == "string" then
          -     return op1 < op2   -- lexicographic comparison
          -   else
          -     local h = getcomphandler(op1, op2, "__lt")
          -     if h then
          -       return h(op1, op2)
          -     else
          -       error("...");
          -     end
          -   end
          - end
          -
          -a > b is equivalent to b < a. - -

        • "le": -the <= operation. -
          - function le_event (op1, op2)
          -   if type(op1) == "number" and type(op2) == "number" then
          -     return op1 <= op2   -- numeric comparison
          -   elseif type(op1) == "string" and type(op2) == "string" then
          -     return op1 <= op2   -- lexicographic comparison
          -   else
          -     local h = getcomphandler(op1, op2, "__le")
          -     if h then
          -       return h(op1, op2)
          -     else
          -       h = getcomphandler(op1, op2, "__lt")
          -       if h then
          -         return not h(op2, op1)
          -       else
          -         error("...");
          -       end
          -     end
          -   end
          - end
          -
          -a >= b is equivalent to b <= a. -Note that, in the absence of a "le" metamethod, -Lua tries the "lt", assuming that a <= b is -equivalent to not (b < a). - -

        • "index": -The indexing access table[key]. -
          - function gettable_event (table, key)
          -   local h
          -   if type(table) == "table" then
          -     local v = rawget(table, key)
          -     if v ~= nil then return v end
          -     h = metatable(table).__index
          -     if h == nil then return nil end
          -   else
          -     h = metatable(table).__index
          -     if h == nil then
          -       error("...");
          -     end
          -   end
          -   if type(h) == "function" then
          -     return h(table, key)      -- call the handler
          -   else return h[key]          -- or repeat operation on it
          - end
          -
          - -

        • "newindex": -The indexing assignment table[key] = value. -
          - function settable_event (table, key, value)
          -   local h
          -   if type(table) == "table" then
          -     local v = rawget(table, key)
          -     if v ~= nil then rawset(table, key, value); return end
          -     h = metatable(table).__newindex
          -     if h == nil then rawset(table, key, value); return end
          -   else
          -     h = metatable(table).__newindex
          -     if h == nil then
          -       error("...");
          -     end
          -   end
          -   if type(h) == "function" then
          -     return h(table, key,value)    -- call the handler
          -   else h[key] = value             -- or repeat operation on it
          - end
          -
          - -

        • "call": -called when Lua calls a value. -
          - function function_event (func, ...)
          -   if type(func) == "function" then
          -     return func(unpack(arg))   -- primitive call
          -   else
          -     local h = metatable(func).__call
          -     if h then
          -       return h(func, unpack(arg))
          -     else
          -       error("...")
          -     end
          -   end
          - end
          -
          - -

        - -

        2.9 - Garbage Collection

        - -

        Lua does automatic memory management. -That means that -you do not have to worry about allocating memory for new objects -and freeing it when the objects are no longer needed. -Lua manages memory automatically by running -a garbage collector from time to time -to collect all dead objects -(that is, those objects that are no longer accessible from Lua). -All objects in Lua are subject to automatic management: -tables, userdata, functions, threads, and strings. - -

        Lua uses two numbers to control its garbage-collection cycles. -One number counts how many bytes of dynamic memory Lua is using; -the other is a threshold. -When the number of bytes crosses the threshold, -Lua runs the garbage collector, -which reclaims the memory of all dead objects. -The byte counter is adjusted, -and then the threshold is reset to twice the new value of the byte counter. - -

        Through the C API, you can query those numbers -and change the threshold (see 3.7). -Setting the threshold to zero actually forces an immediate -garbage-collection cycle, -while setting it to a huge number effectively stops the garbage collector. -Using Lua code you have a more limited control over garbage-collection cycles, -through the gcinfo and collectgarbage functions -(see 5.1). - -

        2.9.1 - Garbage-Collection Metamethods

        - -

        Using the C API, -you can set garbage-collector metamethods for userdata (see 2.8). -These metamethods are also called finalizers. -Finalizers allow you to coordinate Lua's garbage collection -with external resource management -(such as closing files, network or database connections, -or freeing your own memory). - -

        Free userdata with a field __gc in their metatables are not -collected immediately by the garbage collector. -Instead, Lua puts them in a list. -After the collection, -Lua does the equivalent of the following function -for each userdata in that list: -

        - function gc_event (udata)
        -   local h = metatable(udata).__gc
        -   if h then
        -     h(udata)
        -   end
        - end
        -
        - -

        At the end of each garbage-collection cycle, -the finalizers for userdata are called in reverse -order of their creation, -among those collected in that cycle. -That is, the first finalizer to be called is the one associated -with the userdata created last in the program. - -

        2.9.2 - Weak Tables

        - -

        A weak table is a table whose elements are -weak references. -A weak reference is ignored by the garbage collector. -In other words, -if the only references to an object are weak references, -then the garbage collector will collect that object. - -

        A weak table can have weak keys, weak values, or both. -A table with weak keys allows the collection of its keys, -but prevents the collection of its values. -A table with both weak keys and weak values allows the collection of -both keys and values. -In any case, if either the key or the value is collected, -the whole pair is removed from the table. -The weakness of a table is controlled by the value of the -__mode field of its metatable. -If the __mode field is a string containing the character `k´, -the keys in the table are weak. -If __mode contains `v´, -the values in the table are weak. - -

        After you use a table as a metatable, -you should not change the value of its field __mode. -Otherwise, the weak behavior of the tables controlled by this -metatable is undefined. - -

        2.10 - Coroutines

        - -

        Lua supports coroutines, -also called semi-coroutines -or collaborative multithreading. -A coroutine in Lua represents an independent thread of execution. -Unlike threads in multithread systems, however, -a coroutine only suspends its execution by explicitly calling -a yield function. - -

        You create a coroutine with a call to coroutine.create. -Its sole argument is a function -that is the main function of the coroutine. -The create function only creates a new coroutine and -returns a handle to it (an object of type thread); -it does not start the coroutine execution. - -

        When you first call coroutine.resume, -passing as its first argument the thread returned by coroutine.create, -the coroutine starts its execution, -at the first line of its main function. -Extra arguments passed to coroutine.resume are given as -parameters for the coroutine main function. -After the coroutine starts running, -it runs until it terminates or yields. - -

        A coroutine can terminate its execution in two ways: -Normally, when its main function returns -(explicitly or implicitly, after the last instruction); -and abnormally, if there is an unprotected error. -In the first case, coroutine.resume returns true, -plus any values returned by the coroutine main function. -In case of errors, coroutine.resume returns false -plus an error message. - -

        A coroutine yields by calling coroutine.yield. -When a coroutine yields, -the corresponding coroutine.resume returns immediately, -even if the yield happens inside nested function calls -(that is, not in the main function, -but in a function directly or indirectly called by the main function). -In the case of a yield, coroutine.resume also returns true, -plus any values passed to coroutine.yield. -The next time you resume the same coroutine, -it continues its execution from the point where it yielded, -with the call to coroutine.yield returning any extra -arguments passed to coroutine.resume. - -

        The coroutine.wrap function creates a coroutine -like coroutine.create, -but instead of returning the coroutine itself, -it returns a function that, when called, resumes the coroutine. -Any arguments passed to that function -go as extra arguments to resume. -The function returns all the values returned by resume, -except the first one (the boolean error code). -Unlike coroutine.resume, -this function does not catch errors; -any error is propagated to the caller. - -

        As an example, -consider the next code: -

        -function foo1 (a)
        -  print("foo", a)
        -  return coroutine.yield(2*a)
        -end
        -
        -co = coroutine.create(function (a,b)
        -      print("co-body", a, b)
        -      local r = foo1(a+1)
        -      print("co-body", r)
        -      local r, s = coroutine.yield(a+b, a-b)
        -      print("co-body", r, s)
        -      return b, "end"
        -end)
        -       
        -a, b = coroutine.resume(co, 1, 10)
        -print("main", a, b)
        -a, b, c = coroutine.resume(co, "r")
        -print("main", a, b, c)
        -a, b, c = coroutine.resume(co, "x", "y")
        -print("main", a, b, c)
        -a, b = coroutine.resume(co, "x", "y")
        -print("main", a, b)
        -
        -When you run it, it produces the following output: -
        -co-body 1       10
        -foo     2
        -main    true    4
        -co-body r
        -main    true    11      -9
        -co-body x       y
        -main    true    10      end
        -main    false   cannot resume dead coroutine
        -
        - -

        -

        3 - The Application Program Interface

        - - -

        This section describes the C API for Lua, that is, -the set of C functions available to the host program to communicate -with Lua. -All API functions and related types and constants -are declared in the header file lua.h. - -

        Even when we use the term "function", -any facility in the API may be provided as a macro instead. -All such macros use each of its arguments exactly once -(except for the first argument, which is always a Lua state), -and so do not generate hidden side-effects. - -

        3.1 - States

        - -

        The Lua library is fully reentrant: -it has no global variables. - -The whole state of the Lua interpreter -(global variables, stack, etc.) -is stored in a dynamically allocated structure of type lua_State. - -A pointer to this state must be passed as the first argument to -every function in the library, except to lua_open, -which creates a Lua state from scratch. - -

        Before calling any API function, -you must create a state by calling lua_open: -

        -       lua_State *lua_open (void);
        -
        - - -

        To release a state created with lua_open, call lua_close: -

        -       void lua_close (lua_State *L);
        -
        - -This function destroys all objects in the given Lua state -(calling the corresponding garbage-collection metamethods, if any) -and frees all dynamic memory used by that state. -On several platforms, you may not need to call this function, -because all resources are naturally released when the host program ends. -On the other hand, -long-running programs, -such as a daemon or a web server, -might need to release states as soon as they are not needed, -to avoid growing too large. - -

        3.2 - The Stack and Indices

        - -

        Lua uses a virtual stack to pass values to and from C. -Each element in this stack represents a Lua value -(nil, number, string, etc.). - -

        Whenever Lua calls C, the called function gets a new stack, -which is independent of previous stacks and of stacks of -C functions that are still active. -That stack initially contains any arguments to the C function, -and it is where the C function pushes its results to be returned to the caller (see 3.16) -to be returned to the caller. - -

        For convenience, -most query operations in the API do not follow a strict stack discipline. -Instead, they can refer to any element in the stack by using an index: -A positive index represents an absolute stack position -(starting at 1); -a negative index represents an offset from the top of the stack. -More specifically, if the stack has n elements, -then index 1 represents the first element -(that is, the element that was pushed onto the stack first) -and -index n represents the last element; -index -1 also represents the last element -(that is, the element at the top) -and index -n represents the first element. -We say that an index is valid -if it lies between 1 and the stack top -(that is, if 1 <= abs(index) <= top). - - -

        At any time, you can get the index of the top element by calling -lua_gettop: -

        -       int lua_gettop (lua_State *L);
        -
        -Because indices start at 1, -the result of lua_gettop is equal to the number of elements in the stack -(and so 0 means an empty stack). - -

        When you interact with Lua API, -you are responsible for controlling stack overflow. -The function -

        -       int lua_checkstack (lua_State *L, int extra);
        -
        - -grows the stack size to top + extra elements; -it returns false if it cannot grow the stack to that size. -This function never shrinks the stack; -if the stack is already larger than the new size, -it is left unchanged. - -

        Whenever Lua calls C, -it ensures that at least LUA_MINSTACK stack positions are available. -LUA_MINSTACK is defined in lua.h as 20, -so that usually you do not have to worry about stack space -unless your code has loops pushing elements onto the stack. - -

        Most query functions accept as indices any value inside the -available stack space, that is, indices up to the maximum stack size -you have set through lua_checkstack. -Such indices are called acceptable indices. -More formally, we define an acceptable index -as follows: -

        -     (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
        -
        -Note that 0 is never an acceptable index. - -

        Unless otherwise noted, -any function that accepts valid indices can also be called with -pseudo-indices, -which represent some Lua values that are accessible to the C code -but are not in the stack. -Pseudo-indices are used to access the global environment, -the registry, and the upvalues of a C function (see 3.17). - -

        3.3 - Stack Manipulation

        -The API offers the following functions for basic stack manipulation: -
        -       void lua_settop    (lua_State *L, int index);
        -       void lua_pushvalue (lua_State *L, int index);
        -       void lua_remove    (lua_State *L, int index);
        -       void lua_insert    (lua_State *L, int index);
        -       void lua_replace   (lua_State *L, int index);
        -
        - - - -

        lua_settop accepts any acceptable index, -or 0, -and sets the stack top to that index. -If the new top is larger than the old one, -then the new elements are filled with nil. -If index is 0, then all stack elements are removed. -A useful macro defined in the lua.h is -

        -       #define lua_pop(L,n)   lua_settop(L, -(n)-1)
        -
        - -which pops n elements from the stack. - -

        lua_pushvalue pushes onto the stack a copy of the element -at the given index. -lua_remove removes the element at the given position, -shifting down the elements above that position to fill the gap. -lua_insert moves the top element into the given position, -shifting up the elements above that position to open space. -lua_replace moves the top element into the given position, -without shifting any element (therefore replacing the value at -the given position). -All these functions accept only valid indices. -(You cannot call lua_remove or lua_insert with -pseudo-indices, as they do not represent a stack position.) - -

        As an example, if the stack starts as 10 20 30 40 50* -(from bottom to top; the `*´ marks the top), -then -

        -       lua_pushvalue(L, 3)    --> 10 20 30 40 50 30*
        -       lua_pushvalue(L, -1)   --> 10 20 30 40 50 30 30*
        -       lua_remove(L, -3)      --> 10 20 30 40 30 30*
        -       lua_remove(L,  6)      --> 10 20 30 40 30*
        -       lua_insert(L,  1)      --> 30 10 20 30 40*
        -       lua_insert(L, -1)      --> 30 10 20 30 40*  (no effect)
        -       lua_replace(L, 2)      --> 30 40 20 30*
        -       lua_settop(L, -3)      --> 30 40*
        -       lua_settop(L,  6)      --> 30 40 nil nil nil nil*
        -
        - -

        3.4 - Querying the Stack

        - -

        To check the type of a stack element, -the following functions are available: -

        -       int lua_type            (lua_State *L, int index);
        -       int lua_isnil           (lua_State *L, int index);
        -       int lua_isboolean       (lua_State *L, int index);
        -       int lua_isnumber        (lua_State *L, int index);
        -       int lua_isstring        (lua_State *L, int index);
        -       int lua_istable         (lua_State *L, int index);
        -       int lua_isfunction      (lua_State *L, int index);
        -       int lua_iscfunction     (lua_State *L, int index);
        -       int lua_isuserdata      (lua_State *L, int index);
        -       int lua_islightuserdata (lua_State *L, int index);
        -
        - - - - - -These functions can be called with any acceptable index. - -

        lua_type returns the type of a value in the stack, -or LUA_TNONE for a non-valid index -(that is, if that stack position is "empty"). -The types returned by lua_type are coded by the following constants -defined in lua.h: -LUA_TNIL, -LUA_TNUMBER, -LUA_TBOOLEAN, -LUA_TSTRING, -LUA_TTABLE, -LUA_TFUNCTION, -LUA_TUSERDATA, -LUA_TTHREAD, -LUA_TLIGHTUSERDATA. -The following function translates these constants to strings: -

        -       const char *lua_typename  (lua_State *L, int type);
        -
        - - -

        The lua_is* functions return 1 if the object is compatible -with the given type, and 0 otherwise. -lua_isboolean is an exception to this rule: -It succeeds only for boolean values -(otherwise it would be useless, -as any value has a boolean value). -They always return 0 for a non-valid index. -lua_isnumber accepts numbers and numerical strings; -lua_isstring accepts strings and numbers (see 2.2.1); -lua_isfunction accepts both Lua functions and C functions; -and lua_isuserdata accepts both full and light userdata. -To distinguish between Lua functions and C functions, -you can use lua_iscfunction. -To distinguish between full and light userdata, -you can use lua_islightuserdata. -To distinguish between numbers and numerical strings, -you can use lua_type. - -

        The API also contains functions to compare two values in the stack: -

        -       int lua_equal    (lua_State *L, int index1, int index2);
        -       int lua_rawequal (lua_State *L, int index1, int index2);
        -       int lua_lessthan (lua_State *L, int index1, int index2);
        -
        - -lua_equal and lua_lessthan -are equivalent to their counterparts in Lua (see 2.5.2). -lua_rawequal compares the values for primitive equality, -without metamethods. -These functions return 0 (false) if any of the indices are non-valid. - -

        3.5 - Getting Values from the Stack

        - -

        To translate a value in the stack to a specific C type, -you can use the following conversion functions: -

        -       int            lua_toboolean   (lua_State *L, int index);
        -       lua_Number     lua_tonumber    (lua_State *L, int index);
        -       const char    *lua_tostring    (lua_State *L, int index);
        -       size_t         lua_strlen      (lua_State *L, int index);
        -       lua_CFunction  lua_tocfunction (lua_State *L, int index);
        -       void          *lua_touserdata  (lua_State *L, int index);
        -       lua_State     *lua_tothread    (lua_State *L, int index);
        -       void          *lua_topointer   (lua_State *L, int index);
        -
        - - - -These functions can be called with any acceptable index. -When called with a non-valid index, -they act as if the given value had an incorrect type. - -

        lua_toboolean converts the Lua value at the given index -to a C "boolean" value (0 or 1). -Like all tests in Lua, lua_toboolean returns 1 for any Lua value -different from false and nil; -otherwise it returns 0. -It also returns 0 when called with a non-valid index. -(If you want to accept only real boolean values, -use lua_isboolean to test the type of the value.) - -

        lua_tonumber converts the Lua value at the given index -to a number (by default, lua_Number is double). - -The Lua value must be a number or a string convertible to number -(see 2.2.1); otherwise, lua_tonumber returns 0. - -

        lua_tostring converts the Lua value at the given index to a string -(const char*). -The Lua value must be a string or a number; -otherwise, the function returns NULL. -If the value is a number, -then lua_tostring also -changes the actual value in the stack to a string. -(This change confuses lua_next -when lua_tostring is applied to keys.) -lua_tostring returns a fully aligned pointer -to a string inside the Lua state. -This string always has a zero ('\0') -after its last character (as in C), -but may contain other zeros in its body. -If you do not know whether a string may contain zeros, -you can use lua_strlen to get its actual length. -Because Lua has garbage collection, -there is no guarantee that the pointer returned by lua_tostring -will be valid after the corresponding value is removed from the stack. -If you need the string after the current function returns, -then you should duplicate it or put it into the registry (see 3.18). - -

        lua_tocfunction converts a value in the stack to a C function. -This value must be a C function; -otherwise, lua_tocfunction returns NULL. -The type lua_CFunction is explained in 3.16. - -

        lua_tothread converts a value in the stack to a Lua thread -(represented as lua_State *). -This value must be a thread; -otherwise, lua_tothread returns NULL. - -

        lua_topointer converts a value in the stack to a generic -C pointer (void *). -The value may be a userdata, a table, a thread, or a function; -otherwise, lua_topointer returns NULL. -Lua ensures that different objects of the -same type return different pointers. -There is no direct way to convert the pointer back to its original value. -Typically this function is used for debug information. - -

        lua_touserdata is explained in 3.8. - -

        3.6 - Pushing Values onto the Stack

        - -

        The API has the following functions to -push C values onto the stack: -

        -       void lua_pushboolean       (lua_State *L, int b);
        -       void lua_pushnumber        (lua_State *L, lua_Number n);
        -       void lua_pushlstring       (lua_State *L, const char *s, size_t len);
        -       void lua_pushstring        (lua_State *L, const char *s);
        -       void lua_pushnil           (lua_State *L);
        -       void lua_pushcfunction     (lua_State *L, lua_CFunction f);
        -       void lua_pushlightuserdata (lua_State *L, void *p);
        -
        - -

        - - -These functions receive a C value, -convert it to a corresponding Lua value, -and push the result onto the stack. -In particular, lua_pushlstring and lua_pushstring -make an internal copy of the given string. -lua_pushstring can only be used to push proper C strings -(that is, strings that end with a zero and do not contain embedded zeros); -otherwise, you should use the more general lua_pushlstring, -which accepts an explicit size. - -

        You can also push "formatted" strings: -

        -       const char *lua_pushfstring  (lua_State *L, const char *fmt, ...);
        -       const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
        -
        - -These functions push onto the stack a formatted string -and return a pointer to that string. -They are similar to sprintf and vsprintf, -but with some important differences: -
          -
        • You do not have to allocate the space for the result: -The result is a Lua string and Lua takes care of memory allocation -(and deallocation, through garbage collection). -
        • The conversion specifiers are quite restricted. -There are no flags, widths, or precisions. -The conversion specifiers can be simply -`%%´ (inserts a `%´ in the string), -`%s´ (inserts a zero-terminated string, with no size restrictions), -`%f´ (inserts a lua_Number), -`%d´ (inserts an int), and -`%c´ (inserts an int as a character). -
        - -

        The function -

        -       void lua_concat (lua_State *L, int n);
        -
        - -concatenates the n values at the top of the stack, -pops them, and leaves the result at the top. -If n is 1, the result is that single string -(that is, the function does nothing); -if n is 0, the result is the empty string. -Concatenation is done following the usual semantics of Lua -(see 2.5.4). - -

        3.7 - Controlling Garbage Collection

        - -

        Lua uses two numbers to control its garbage collection: -the count and the threshold (see 2.9). -The first counts the amount of memory in use by Lua; -when the count reaches the threshold, -Lua runs its garbage collector. -After the collection, the count is updated -and the threshold is set to twice the count value. - -

        You can access the current values of these two numbers through the -following functions: -

        -       int  lua_getgccount     (lua_State *L);
        -       int  lua_getgcthreshold (lua_State *L);
        -
        - -Both return their respective values in Kbytes. -You can change the threshold value with -
        -       void  lua_setgcthreshold (lua_State *L, int newthreshold);
        -
        - -Again, the newthreshold value is given in Kbytes. -When you call this function, -Lua sets the new threshold and checks it against the byte counter. -If the new threshold is less than the byte counter, -then Lua immediately runs the garbage collector. -In particular -lua_setgcthreshold(L,0) forces a garbage collection. -After the collection, -a new threshold is set according to the previous rule. - -

        3.8 - Userdata

        - -

        Userdata represents C values in Lua. -Lua supports two types of userdata: -full userdata and light userdata. - -

        A full userdata represents a block of memory. -It is an object (like a table): -You must create it, it can have its own metatable, -and you can detect when it is being collected. -A full userdata is only equal to itself (under raw equality). - -

        A light userdata represents a pointer. -It is a value (like a number): -You do not create it, it has no metatables, -it is not collected (as it was never created). -A light userdata is equal to "any" -light userdata with the same C address. - -

        In Lua code, there is no way to test whether a userdata is full or light; -both have type userdata. -In C code, lua_type returns LUA_TUSERDATA for full userdata, -and LUA_TLIGHTUSERDATA for light userdata. - -

        You can create a new full userdata with the following function: -

        -       void *lua_newuserdata (lua_State *L, size_t size);
        -
        - -This function allocates a new block of memory with the given size, -pushes on the stack a new userdata with the block address, -and returns this address. - -

        To push a light userdata into the stack you use -lua_pushlightuserdata (see 3.6). - -

        lua_touserdata (see 3.5) retrieves the value of a userdata. -When applied on a full userdata, it returns the address of its block; -when applied on a light userdata, it returns its pointer; -when applied on a non-userdata value, it returns NULL. - -

        When Lua collects a full userdata, -it calls the userdata's gc metamethod, if any, -and then it frees the userdata's corresponding memory. - -

        3.9 - Metatables

        - -

        The following functions allow you to manipulate the metatables -of an object: -

        -       int lua_getmetatable (lua_State *L, int index);
        -       int lua_setmetatable (lua_State *L, int index);
        -
        - -lua_getmetatable pushes on the stack the metatable of a given object. -If the index is not valid, -or if the object does not have a metatable, -lua_getmetatable returns 0 and pushes nothing on the stack. - -

        lua_setmetatable pops a table from the stack and -sets it as the new metatable for the given object. -lua_setmetatable returns 0 when it cannot -set the metatable of the given object -(that is, when the object is neither a userdata nor a table); -even then it pops the table from the stack. - -

        3.10 - Loading Lua Chunks

        - -

        You can load a Lua chunk with lua_load: -

        -       typedef const char * (*lua_Chunkreader)
        -                                (lua_State *L, void *data, size_t *size);
        -
        -       int lua_load (lua_State *L, lua_Chunkreader reader, void *data,
        -                                   const char *chunkname);
        -
        - -The return values of lua_load are: -
          -
        • 0 --- no errors; -
        • LUA_ERRSYNTAX --- -syntax error during pre-compilation. -
        • LUA_ERRMEM --- -memory allocation error. -
        -If there are no errors, -lua_load pushes the compiled chunk as a Lua -function on top of the stack. -Otherwise, it pushes an error message. - -

        lua_load automatically detects whether the chunk is text or binary, -and loads it accordingly (see program luac). - -

        lua_load uses a user-supplied reader function to read the chunk. -Everytime it needs another piece of the chunk, -lua_load calls the reader, -passing along its data parameter. -The reader must return a pointer to a block of memory -with a new piece of the chunk -and set size to the block size. -To signal the end of the chunk, the reader returns NULL. -The reader function may return pieces of any size greater than zero. - -

        In the current implementation, -the reader function cannot call any Lua function; -to ensure that, it always receives NULL as the Lua state. - -

        The chunkname is used for error messages -and debug information (see 4). - -

        See the auxiliary library (lauxlib.c) -for examples of how to use lua_load -and for some ready-to-use functions to load chunks -from files and strings. - -

        3.11 - Manipulating Tables

        - -

        Tables are created by calling -the function -

        -       void lua_newtable (lua_State *L);
        -
        - -This function creates a new, empty table and pushes it onto the stack. - -

        To read a value from a table that resides somewhere in the stack, -call -

        -       void lua_gettable (lua_State *L, int index);
        -
        - -where index points to the table. -lua_gettable pops a key from the stack -and returns (on the stack) the contents of the table at that key. -The table is left where it was in the stack. -As in Lua, this function may trigger a metamethod -for the "index" event (see 2.8). -To get the real value of any table key, -without invoking any metamethod, -use the raw version: -
        -       void lua_rawget (lua_State *L, int index);
        -
        - - -

        To store a value into a table that resides somewhere in the stack, -you push the key and then the value onto the stack, -and call -

        -       void lua_settable (lua_State *L, int index);
        -
        - -where index points to the table. -lua_settable pops from the stack both the key and the value. -The table is left where it was in the stack. -As in Lua, this operation may trigger a metamethod -for the "settable" or "newindex" events. -To set the real value of any table index, -without invoking any metamethod, -use the raw version: -
        -       void lua_rawset (lua_State *L, int index);
        -
        - - -

        You can traverse a table with the function -

        -       int lua_next (lua_State *L, int index);
        -
        - -where index points to the table to be traversed. -The function pops a key from the stack, -and pushes a key-value pair from the table -(the "next" pair after the given key). -If there are no more elements, then lua_next returns 0 -(and pushes nothing). -Use a nil key to signal the start of a traversal. - -

        A typical traversal looks like this: -

        -       /* table is in the stack at index `t' */
        -       lua_pushnil(L);  /* first key */
        -       while (lua_next(L, t) != 0) {
        -         /* `key' is at index -2 and `value' at index -1 */
        -         printf("%s - %s\n",
        -           lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
        -         lua_pop(L, 1);  /* removes `value'; keeps `key' for next iteration */
        -       }
        -
        - -

        While traversing a table, -do not call lua_tostring directly on a key, -unless you know that the key is actually a string. -Recall that lua_tostring changes the value at the given index; -this confuses the next call to lua_next. - -

        3.12 - Manipulating Environments

        - -

        All global variables are kept in ordinary Lua tables, -called environments. -The initial environment is called the global environment. -This table is always at pseudo-index LUA_GLOBALSINDEX. - -

        To access and change the value of global variables, -you can use regular table operations over an environment table. -For instance, to access the value of a global variable, do -

        -       lua_pushstring(L, varname);
        -       lua_gettable(L, LUA_GLOBALSINDEX);
        -
        - -

        You can change the global environment of a Lua thread using lua_replace. - -

        The following functions get and set the environment of Lua functions: -

        -       void lua_getfenv (lua_State *L, int index);
        -       int  lua_setfenv (lua_State *L, int index);
        -
        - -lua_getfenv pushes on the stack the environment table of -the function at index index in the stack. -If the function is a C function, -lua_getfenv pushes the global environment. -lua_setfenv pops a table from the stack and sets it as -the new environment for the function at index index in the stack. -If the object at the given index is not a Lua function, -lua_setfenv returns 0. - -

        3.13 - Using Tables as Arrays

        -The API has functions that help to use Lua tables as arrays, -that is, -tables indexed by numbers only: -
        -       void lua_rawgeti (lua_State *L, int index, int n);
        -       void lua_rawseti (lua_State *L, int index, int n);
        -
        - - - -

        lua_rawgeti pushes the value of the n-th element of the table -at stack position index. -lua_rawseti sets the value of the n-th element of the table -at stack position index to the value at the top of the stack, -removing this value from the stack. - -

        3.14 - Calling Functions

        - -

        Functions defined in Lua -and C functions registered in Lua -can be called from the host program. -This is done using the following protocol: -First, the function to be called is pushed onto the stack; -then, the arguments to the function are pushed -in direct order, that is, the first argument is pushed first. -Finally, the function is called using -

        -       void lua_call (lua_State *L, int nargs, int nresults);
        -
        - -nargs is the number of arguments that you pushed onto the stack. -All arguments and the function value are popped from the stack, -and the function results are pushed. -The number of results are adjusted to nresults, -unless nresults is LUA_MULTRET. -In that case, all results from the function are pushed. -Lua takes care that the returned values fit into the stack space. -The function results are pushed onto the stack in direct order -(the first result is pushed first), -so that after the call the last result is on the top. - -

        The following example shows how the host program may do the -equivalent to this Lua code: -

        -       a = f("how", t.x, 14)
        -
        -Here it is in C: -
        -    lua_pushstring(L, "t");
        -    lua_gettable(L, LUA_GLOBALSINDEX);          /* global `t' (for later use) */
        -    lua_pushstring(L, "a");                                       /* var name */
        -    lua_pushstring(L, "f");                                  /* function name */
        -    lua_gettable(L, LUA_GLOBALSINDEX);               /* function to be called */
        -    lua_pushstring(L, "how");                                 /* 1st argument */
        -    lua_pushstring(L, "x");                            /* push the string "x" */
        -    lua_gettable(L, -5);                      /* push result of t.x (2nd arg) */
        -    lua_pushnumber(L, 14);                                    /* 3rd argument */
        -    lua_call(L, 3, 1);         /* call function with 3 arguments and 1 result */
        -    lua_settable(L, LUA_GLOBALSINDEX);             /* set global variable `a' */
        -    lua_pop(L, 1);                               /* remove `t' from the stack */
        -
        -Note that the code above is "balanced": -at its end, the stack is back to its original configuration. -This is considered good programming practice. - -

        (We did this example using only the raw functions provided by Lua's API, -to show all the details. -Usually programmers define and use several macros and auxiliary functions -that provide higher level access to Lua. -See the source code of the standard libraries for examples.) - -

        3.15 - Protected Calls

        - -

        When you call a function with lua_call, -any error inside the called function is propagated upwards -(with a longjmp). -If you need to handle errors, -then you should use lua_pcall: -

        -       int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
        -
        -Both nargs and nresults have the same meaning as -in lua_call. -If there are no errors during the call, -lua_pcall behaves exactly like lua_call. -However, if there is any error, -lua_pcall catches it, -pushes a single value at the stack (the error message), -and returns an error code. -Like lua_call, -lua_pcall always removes the function -and its arguments from the stack. - -

        If errfunc is 0, -then the error message returned is exactly the original error message. -Otherwise, errfunc gives the stack index for an -error handler function. -(In the current implementation, that index cannot be a pseudo-index.) -In case of runtime errors, -that function will be called with the error message -and its return value will be the message returned by lua_pcall. - -

        Typically, the error handler function is used to add more debug -information to the error message, such as a stack traceback. -Such information cannot be gathered after the return of lua_pcall, -since by then the stack has unwound. - -

        The lua_pcall function returns 0 in case of success -or one of the following error codes -(defined in lua.h): -

          -
        • LUA_ERRRUN --- a runtime error. -
        • LUA_ERRMEM --- memory allocation error. -For such errors, Lua does not call the error handler function. -
        • LUA_ERRERR --- -error while running the error handler function. -
        - -

        3.16 - Defining C Functions

        - -

        Lua can be extended with functions written in C. -These functions must be of type lua_CFunction, -which is defined as -

        -       typedef int (*lua_CFunction) (lua_State *L);
        -
        - -A C function receives a Lua state and returns an integer, -the number of values it wants to return to Lua. - -

        In order to communicate properly with Lua, -a C function must follow the following protocol, -which defines the way parameters and results are passed: -A C function receives its arguments from Lua in its stack -in direct order (the first argument is pushed first). -So, when the function starts, -its first argument (if any) is at index 1. -To return values to Lua, a C function just pushes them onto the stack, -in direct order (the first result is pushed first), -and returns the number of results. -Any other value in the stack below the results will be properly -discharged by Lua. -Like a Lua function, a C function called by Lua can also return -many results. - -

        As an example, the following function receives a variable number -of numerical arguments and returns their average and sum: -

        -       static int foo (lua_State *L) {
        -         int n = lua_gettop(L);    /* number of arguments */
        -         lua_Number sum = 0;
        -         int i;
        -         for (i = 1; i <= n; i++) {
        -           if (!lua_isnumber(L, i)) {
        -             lua_pushstring(L, "incorrect argument to function `average'");
        -             lua_error(L);
        -           }
        -           sum += lua_tonumber(L, i);
        -         }
        -         lua_pushnumber(L, sum/n);        /* first result */
        -         lua_pushnumber(L, sum);         /* second result */
        -         return 2;                   /* number of results */
        -       }
        -
        - -

        To register a C function to Lua, -there is the following convenience macro: -

        -       #define lua_register(L,n,f) \
        -               (lua_pushstring(L, n), \
        -                lua_pushcfunction(L, f), \
        -                lua_settable(L, LUA_GLOBALSINDEX))
        -     /* lua_State *L;    */
        -     /* const char *n;   */
        -     /* lua_CFunction f; */
        -
        - -which receives the name the function will have in Lua -and a pointer to the function. -Thus, -the C function foo above may be registered in Lua as -average by calling -
        -       lua_register(L, "average", foo);
        -
        - -

        3.17 - Defining C Closures

        - -

        When a C function is created, -it is possible to associate some values with it, -thus creating a C closure; -these values are then accessible to the function whenever it is called. -To associate values with a C function, -first these values should be pushed onto the stack -(when there are multiple values, the first value is pushed first). -Then the function -

        -       void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
        -
        - -is used to push the C function onto the stack, -with the argument n telling how many values should be -associated with the function -(lua_pushcclosure also pops these values from the stack); -in fact, the macro lua_pushcfunction is defined as -lua_pushcclosure with n set to 0. - -

        Then, whenever the C function is called, -those values are located at specific pseudo-indices. -Those pseudo-indices are produced by a macro lua_upvalueindex. -The first value associated with a function is at position -lua_upvalueindex(1), and so on. -Any access to lua_upvalueindex(n), -where n is greater than the number of upvalues of the -current function, -produces an acceptable (but invalid) index. - -

        For examples of C functions and closures, -see the standard libraries in the official Lua distribution -(src/lib/*.c). - -

        3.18 - Registry

        - -

        Lua provides a registry, -a pre-defined table that can be used by any C code to -store whatever Lua value it needs to store, -specially if the C code needs to keep that Lua value -outside the life span of a C function. -This table is always located at pseudo-index -LUA_REGISTRYINDEX. -Any C library can store data into this table, -as long as it chooses keys different from other libraries. -Typically, you should use as key a string containing your library name -or a light userdata with the address of a C object in your code. - -

        The integer keys in the registry are used by the reference mechanism, -implemented by the auxiliary library, -and therefore should not be used by other purposes. - -

        3.19 - Error Handling in C

        - -

        Internally, Lua uses the C longjmp facility to handle errors. -When Lua faces any error -(such as memory allocation errors, type errors, syntax errors) -it raises an error, that is, it does a long jump. -A protected environment uses setjmp -to set a recover point; -any error jumps to the most recent active recover point. - -

        If an error happens outside any protected environment, -Lua calls a panic function -and then calls exit(EXIT_FAILURE). -You can change the panic function with -

        -       lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
        -
        -Your new panic function may avoid the application exit by -never returning (e.g., by doing a long jump). -Nevertheless, the corresponding Lua state will not be consistent; -the only safe operation with it is to close it. - -

        Almost any function in the API may raise an error, -for instance due to a memory allocation error. -The following functions run in protected mode -(that is, they create a protected environment to run), -so they never raise an error: -lua_open, lua_close, lua_load, -and lua_pcall. - -

        There is yet another function that runs a given C function in protected mode: -

        -       int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
        -
        - -lua_cpcall calls func in protected mode. -func starts with only one element in its stack, -a light userdata containing ud. -In case of errors, -lua_cpcall returns the same error codes as lua_pcall -(see 3.15), -plus the error object on the top of the stack; -otherwise, it returns zero, and does not change the stack. -Any value returned by func is discarded. - -

        C code can generate a Lua error calling the function -

        -       void lua_error (lua_State *L);
        -
        - -The error message (which actually can be any type of object) -must be on the stack top. -This function does a long jump, -and therefore never returns. - -

        3.20 - Threads

        - -

        Lua offers partial support for multiple threads of execution. -If you have a C library that offers multi-threading, -then Lua can cooperate with it to implement the equivalent facility in Lua. -Also, Lua implements its own coroutine system on top of threads. -The following function creates a new thread in Lua: -

        -       lua_State *lua_newthread (lua_State *L);
        -
        - -This function pushes the thread on the stack and returns a pointer to -a lua_State that represents this new thread. -The new state returned by this function shares with the original state -all global objects (such as tables), -but has an independent run-time stack. - -

        Each thread has an independent global environment table. -When you create a thread, this table is the same as that of the given state, -but you can change each one independently. - -

        There is no explicit function to close or to destroy a thread. -Threads are subject to garbage collection, -like any Lua object. - -

        To manipulate threads as coroutines, -Lua offers the following functions: -

        -       int lua_resume (lua_State *L, int narg);
        -       int lua_yield  (lua_State *L, int nresults);
        -
        - -To start a coroutine, you first create a new thread; -then you push on its stack the body function plus any eventual arguments; -then you call lua_resume, -with narg being the number of arguments. -This call returns when the coroutine suspends or finishes its execution. -When it returns, the stack contains all values passed to lua_yield, -or all values returned by the body function. -lua_resume returns 0 if there are no errors running the coroutine, -or an error code (see 3.15). -In case of errors, -the stack contains only the error message. -To restart a coroutine, you put on its stack only the values to -be passed as results from yield, -and then call lua_resume. - -

        The lua_yield function can only be called as the -return expression of a C function, as follows: -

        -       return lua_yield (L, nresults);
        -
        -When a C function calls lua_yield in that way, -the running coroutine suspends its execution, -and the call to lua_resume that started this coroutine returns. -The parameter nresults is the number of values from the stack -that are passed as results to lua_resume. - -

        To exchange values between different threads, -you may use lua_xmove: -

        -       void lua_xmove (lua_State *from, lua_State *to, int n);
        -
        -It pops n values from the stack from, -and puhses them into the stack to. - -

        -

        4 - The Debug Interface

        - -

        Lua has no built-in debugging facilities. -Instead, it offers a special interface -by means of functions and hooks. -This interface allows the construction of different -kinds of debuggers, profilers, and other tools -that need "inside information" from the interpreter. - -

        4.1 - Stack and Function Information

        - -

        The main function to get information about the interpreter runtime stack is -

        -       int lua_getstack (lua_State *L, int level, lua_Debug *ar);
        -
        - -This function fills parts of a lua_Debug structure with -an identification of the activation record -of the function executing at a given level. -Level 0 is the current running function, -whereas level n+1 is the function that has called level n. -When there are no errors, lua_getstack returns 1; -when called with a level greater than the stack depth, -it returns 0. - -

        The structure lua_Debug is used to carry different pieces of -information about an active function: -

        -      typedef struct lua_Debug {
        -        int event;
        -        const char *name;      /* (n) */
        -        const char *namewhat;  /* (n) `global', `local', `field', `method' */
        -        const char *what;      /* (S) `Lua' function, `C' function, Lua `main' */
        -        const char *source;    /* (S) */
        -        int currentline;       /* (l) */
        -        int nups;              /* (u) number of upvalues */
        -        int linedefined;       /* (S) */
        -        char short_src[LUA_IDSIZE]; /* (S) */
        -
        -        /* private part */
        -        ...
        -      } lua_Debug;
        -
        - -lua_getstack fills only the private part -of this structure, for later use. -To fill the other fields of lua_Debug with useful information, -call -
        -       int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
        -
        - -This function returns 0 on error -(for instance, an invalid option in what). -Each character in the string what -selects some fields of the structure ar to be filled, -as indicated by the letter in parentheses in the definition of lua_Debug -above: -`S´ fills in the fields source, linedefined, -and what; -`l´ fills in the field currentline, etc. -Moreover, `f´ pushes onto the stack the function that is -running at the given level. - -

        To get information about a function that is not active -(that is, not in the stack), -you push it onto the stack -and start the what string with the character `>´. -For instance, to know in which line a function f was defined, -you can write -

        -       lua_Debug ar;
        -       lua_pushstring(L, "f");
        -       lua_gettable(L, LUA_GLOBALSINDEX);  /* get global `f' */
        -       lua_getinfo(L, ">S", &ar);
        -       printf("%d\n", ar.linedefined);
        -
        -The fields of lua_Debug have the following meaning: -
          - -

        • source -If the function was defined in a string, -then source is that string. -If the function was defined in a file, -then source starts with a `@´ followed by the file name. - -

        • short_src -A "printable" version of source, to be used in error messages. - -

        • linedefined -the line number where the definition of the function starts. - -

        • what the string "Lua" if this is a Lua function, -"C" if this is a C function, -"main" if this is the main part of a chunk, -and "tail" if this was a function that did a tail call. -In the latter case, -Lua has no other information about this function. - -

        • currentline -the current line where the given function is executing. -When no line information is available, -currentline is set to -1. - -

        • name -a reasonable name for the given function. -Because functions in Lua are first class values, -they do not have a fixed name: -Some functions may be the value of multiple global variables, -while others may be stored only in a table field. -The lua_getinfo function checks how the function was -called or whether it is the value of a global variable to -find a suitable name. -If it cannot find a name, -then name is set to NULL. - -

        • namewhat -Explains the name field. -The value of namewhat can be -"global", "local", "method", -"field", or "" (the empty string), -according to how the function was called. -(Lua uses the empty string when no other option seems to apply.) - -

        • nups -The number of upvalues of the function. - -

        - -

        4.2 - Manipulating Local Variables and Upvalues

        - -

        For the manipulation of local variables and upvalues, -the debug interface uses indices: -The first parameter or local variable has index 1, and so on, -until the last active local variable. -Upvalues have no particular order, -as they are active through the whole function. - -

        The following functions allow the manipulation of the -local variables of a given activation record: -

        -       const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
        -       const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
        -
        - -The parameter ar must be a valid activation record that was -filled by a previous call to lua_getstack or -given as argument to a hook (see 4.3). -lua_getlocal gets the index n of a local variable, -pushes the variable's value onto the stack, -and returns its name. -lua_setlocal assigns the value at the top of the stack -to the variable and returns its name. -Both functions return NULL -when the index is greater than -the number of active local variables. - -

        The following functions allow the manipulation of the -upvalues of a given function -(unlike local variables, -the upvalues of a function are accessible even when the -function is not active): -

        -       const char *lua_getupvalue (lua_State *L, int funcindex, int n);
        -       const char *lua_setupvalue (lua_State *L, int funcindex, int n);
        -
        - -These functions operate both on Lua functions and on C functions. -(For Lua functions, -upvalues are the external local variables that the function uses, -and that consequently are included in its closure.) -funcindex points to a function in the stack. -lua_getpuvalue gets the index n of an upvalue, -pushes the upvalue's value onto the stack, -and returns its name. -lua_setupvalue assigns the value at the top of the stack -to the upvalue and returns its name. -Both functions return NULL -when the index is greater than the number of upvalues. -For C functions, these functions use the empty string "" -as a name for all upvalues. - -

        As an example, the following function lists the names of all -local variables and upvalues for a function at a given level of the stack: -

        -       int listvars (lua_State *L, int level) {
        -         lua_Debug ar;
        -         int i;
        -         const char *name;
        -         if (lua_getstack(L, level, &ar) == 0)
        -           return 0;  /* failure: no such level in the stack */
        -         i = 1;
        -         while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
        -           printf("local %d %s\n", i-1, name);
        -           lua_pop(L, 1);  /* remove variable value */
        -         }
        -         lua_getinfo(L, "f", &ar);  /* retrieves function */
        -         i = 1;
        -         while ((name = lua_getpuvalue(L, -1, i++)) != NULL) {
        -           printf("upvalue %d %s\n", i-1, name);
        -           lua_pop(L, 1);  /* remove upvalue value */
        -         }
        -         return 1;
        -       }
        -
        - -

        4.3 - Hooks

        - -

        Lua offers a mechanism of hooks, which are -user-defined C functions that are called during the program execution. -A hook may be called in four different events: -a call event, when Lua calls a function; -a return event, when Lua returns from a function; -a line event, when Lua starts executing a new line of code; -and a count event, which happens every "count" instructions. -Lua identifies these events with the following constants: -LUA_HOOKCALL, -LUA_HOOKRET (or LUA_HOOKTAILRET, see below), -LUA_HOOKLINE, -and LUA_HOOKCOUNT. - -

        A hook has type lua_Hook, defined as follows: -

        -       typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
        -
        - -You can set the hook with the following function: -
        -       int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
        -
        - -func is the hook. -mask specifies on which events the hook will be called: -It is formed by a disjunction of the constants -LUA_MASKCALL, -LUA_MASKRET, -LUA_MASKLINE, -and LUA_MASKCOUNT. -The count argument is only meaningful when the mask -includes LUA_MASKCOUNT. -For each event, the hook is called as explained below: -
          -
        • The call hook is called when the interpreter calls a function. -The hook is called just after Lua enters the new function. -
        • The return hook is called when the interpreter returns from a function. -The hook is called just before Lua leaves the function. -
        • The line hook is called when the interpreter is about to -start the execution of a new line of code, -or when it jumps back in the code (even to the same line). -(This event only happens while Lua is executing a Lua function.) -
        • The count hook is called after the interpreter executes every -count instructions. -(This event only happens while Lua is executing a Lua function.) -
        - -

        A hook is disabled by setting mask to zero. - -

        You can get the current hook, the current mask, -and the current count with the next functions: -

        -       lua_Hook lua_gethook      (lua_State *L);
        -       int      lua_gethookmask  (lua_State *L);
        -       int      lua_gethookcount (lua_State *L);
        -
        - - -

        Whenever a hook is called, its ar argument has its field -event set to the specific event that triggered the hook. -Moreover, for line events, the field currentline is also set. -To get the value of any other field in ar, -the hook must call lua_getinfo. -For return events, event may be LUA_HOOKRET, -the normal value, or LUA_HOOKTAILRET. -In the latter case, Lua is simulating a return from -a function that did a tail call; -in this case, it is useless to call lua_getinfo. - -

        While Lua is running a hook, it disables other calls to hooks. -Therefore, if a hook calls back Lua to execute a function or a chunk, -that execution occurs without any calls to hooks. - -

        -

        5 - Standard Libraries

        - -

        The standard libraries provide useful functions -that are implemented directly through the C API. -Some of these functions provide essential services to the language -(e.g., type and getmetatable); -others provide access to "outside" services (e.g., I/O); -and others could be implemented in Lua itself, -but are quite useful or have critical performance to -deserve an implementation in C (e.g., sort). - -

        All libraries are implemented through the official C API -and are provided as separate C modules. -Currently, Lua has the following standard libraries: -

          -
        • basic library; -
        • string manipulation; -
        • table manipulation; -
        • mathematical functions (sin, log, etc.); -
        • input and output; -
        • operating system facilities; -
        • debug facilities. -
        -Except for the basic library, -each library provides all its functions as fields of a global table -or as methods of its objects. - -

        To have access to these libraries, -the C host program must first call the functions -luaopen_base (for the basic library), -luaopen_string (for the string library), -luaopen_table (for the table library), -luaopen_math (for the mathematical library), -luaopen_io (for the I/O and the Operating System libraries), -and luaopen_debug (for the debug library). -These functions are declared in lualib.h. - - - - - - - -

        5.1 - Basic Functions

        - -

        The basic library provides some core functions to Lua. -If you do not include this library in your application, -you should check carefully whether you need to provide some alternative -implementation for some of its facilities. - -

        assert (v [, message])

        -Issues an error when -the value of its argument v is nil or false; -otherwise, returns this value. -message is an error message; -when absent, it defaults to "assertion failed!" - -

        collectgarbage ([limit])

        - -

        Sets the garbage-collection threshold to the given limit -(in Kbytes) and checks it against the byte counter. -If the new threshold is smaller than the byte counter, -then Lua immediately runs the garbage collector (see 2.9). -If limit is absent, it defaults to zero -(thus forcing a garbage-collection cycle). - -

        dofile (filename)

        -Opens the named file and executes its contents as a Lua chunk. -When called without arguments, -dofile executes the contents of the standard input (stdin). -Returns any value returned by the chunk. -In case of errors, dofile propagates the error -to its caller (that is, it does not run in protected mode). - -

        error (message [, level])

        - -Terminates the last protected function called -and returns message as the error message. -Function error never returns. - -

        The level argument specifies where the error -message points the error. -With level 1 (the default), the error position is where the -error function was called. -Level 2 points the error to where the function -that called error was called; and so on. - -

        _G

        -A global variable (not a function) that -holds the global environment (that is, _G._G = _G). -Lua itself does not use this variable; -changing its value does not affect any environment. -(Use setfenv to change environments.) - -

        getfenv (f)

        -Returns the current environment in use by the function. -f can be a Lua function or a number, -which specifies the function at that stack level: -Level 1 is the function calling getfenv. -If the given function is not a Lua function, -or if f is 0, -getfenv returns the global environment. -The default for f is 1. - -

        If the environment has a "__fenv" field, -returns the associated value, instead of the environment. - -

        getmetatable (object)

        - - -

        If the object does not have a metatable, returns nil. -Otherwise, -if the object's metatable has a "__metatable" field, -returns the associated value. -Otherwise, returns the metatable of the given object. - -

        gcinfo ()

        - -

        Returns two results: -the number of Kbytes of dynamic memory that Lua is using -and the current garbage collector threshold (also in Kbytes). - -

        ipairs (t)

        - -

        Returns an iterator function, the table t, and 0, -so that the construction -

        -       for i,v in ipairs(t) do ... end
        -
        -will iterate over the pairs (1,t[1]), (2,t[2]), ..., -up to the first integer key with a nil value in the table. - -

        loadfile (filename)

        - -

        Loads a file as a Lua chunk (without running it). -If there are no errors, -returns the compiled chunk as a function; -otherwise, returns nil plus the error message. -The environment of the returned function is the global environment. - -

        loadlib (libname, funcname)

        - -

        Links the program with the dynamic C library libname. -Inside this library, looks for a function funcname -and returns this function as a C function. - -

        libname must be the complete file name of the C library, -including any eventual path and extension. - -

        This function is not supported by ANSI C. -As such, it is only available on some platforms -(Windows, Linux, Solaris, BSD, plus other Unix systems that -support the dlfcn standard). - -

        loadstring (string [, chunkname])

        -Loads a string as a Lua chunk (without running it). -If there are no errors, -returns the compiled chunk as a function; -otherwise, returns nil plus the error message. -The environment of the returned function is the global environment. - -

        The optional parameter chunkname -is the name to be used in error messages and debug information. - -

        To load and run a given string, use the idiom -

        -      assert(loadstring(s))()
        -
        - -

        next (table [, index])

        -Allows a program to traverse all fields of a table. -Its first argument is a table and its second argument -is an index in this table. -next returns the next index of the table and the -value associated with the index. -When called with nil as its second argument, -next returns the first index -of the table and its associated value. -When called with the last index, -or with nil in an empty table, -next returns nil. -If the second argument is absent, then it is interpreted as nil. - -

        Lua has no declaration of fields; -There is no difference between a -field not present in a table or a field with value nil. -Therefore, next only considers fields with non-nil values. -The order in which the indices are enumerated is not specified, -even for numeric indices. -(To traverse a table in numeric order, -use a numerical for or the ipairs function.) - -

        The behavior of next is undefined if, -during the traversal, -you assign any value to a non-existent field in the table. - -

        pairs (t)

        - -

        Returns the next function and the table t (plus a nil), -so that the construction -

        -       for k,v in pairs(t) do ... end
        -
        -will iterate over all key-value pairs of table t. - -

        pcall (f, arg1, arg2, ...)

        - -

        Calls function f with -the given arguments in protected mode. -That means that any error inside f is not propagated; -instead, pcall catches the error -and returns a status code. -Its first result is the status code (a boolean), -which is true if the call succeeds without errors. -In such case, pcall also returns all results from the call, -after this first result. -In case of any error, pcall returns false plus the error message. - -

        print (e1, e2, ...)

        -Receives any number of arguments, -and prints their values in stdout, -using the tostring function to convert them to strings. -This function is not intended for formatted output, -but only as a quick way to show a value, -typically for debugging. -For formatted output, use format (see 5.3). - -

        rawequal (v1, v2)

        -Checks whether v1 is equal to v2, -without invoking any metamethod. -Returns a boolean. - -

        rawget (table, index)

        -Gets the real value of table[index], -without invoking any metamethod. -table must be a table; -index is any value different from nil. - -

        rawset (table, index, value)

        -Sets the real value of table[index] to value, -without invoking any metamethod. -table must be a table, -index is any value different from nil, -and value is any Lua value. - -

        require (packagename)

        - -

        Loads the given package. -The function starts by looking into the table _LOADED -to determine whether packagename is already loaded. -If it is, then require returns the value that the package -returned when it was first loaded. -Otherwise, it searches a path looking for a file to load. - -

        If the global variable LUA_PATH is a string, -this string is the path. -Otherwise, require tries the environment variable LUA_PATH. -As a last resort, it uses the predefined path "?;?.lua". - -

        The path is a sequence of templates separated by semicolons. -For each template, require will change each interrogation -mark in the template to packagename, -and then will try to load the resulting file name. -So, for instance, if the path is -

        -  "./?.lua;./?.lc;/usr/local/?/?.lua;/lasttry"
        -
        -a require "mod" will try to load the files -./mod.lua, -./mod.lc, -/usr/local/mod/mod.lua, -and /lasttry, in that order. - -

        The function stops the search as soon as it can load a file, -and then it runs the file. -After that, it associates, in table _LOADED, -the package name with the value that the package returned, -and returns that value. -If the package returns nil (or no value), -require converts this value to true. -If the package returns false, -require also returns false. -However, as the mark in table _LOADED is false, -any new attempt to reload the file -will happen as if the package was not loaded -(that is, the package will be loaded again). - -

        If there is any error loading or running the file, -or if it cannot find any file in the path, -then require signals an error. - -

        While running a file, -require defines the global variable _REQUIREDNAME -with the package name. -The package being loaded always runs within the global environment. - -

        setfenv (f, table)

        - -

        Sets the current environment to be used by the given function. -f can be a Lua function or a number, -which specifies the function at that stack level: -Level 1 is the function calling setfenv. - -

        As a special case, when f is 0 setfenv changes -the global environment of the running thread. - -

        If the original environment has a "__fenv" field, -setfenv raises an error. - -

        setmetatable (table, metatable)

        - -

        Sets the metatable for the given table. -(You cannot change the metatable of a userdata from Lua.) -If metatable is nil, removes the metatable of the given table. -If the original metatable has a "__metatable" field, -raises an error. - -

        tonumber (e [, base])

        -Tries to convert its argument to a number. -If the argument is already a number or a string convertible -to a number, then tonumber returns that number; -otherwise, it returns nil. - -

        An optional argument specifies the base to interpret the numeral. -The base may be any integer between 2 and 36, inclusive. -In bases above 10, the letter `A´ (in either upper or lower case) -represents 10, `B´ represents 11, and so forth, -with `Z´ representing 35. -In base 10 (the default), the number may have a decimal part, -as well as an optional exponent part (see 2.2.1). -In other bases, only unsigned integers are accepted. - -

        tostring (e)

        -Receives an argument of any type and -converts it to a string in a reasonable format. -For complete control of how numbers are converted, -use format (see 5.3). - -

        If the metatable of e has a "__tostring" field, -tostring calls the corresponding value -with e as argument, -and uses the result of the call as its result. - -

        type (v)

        -Returns the type of its only argument, coded as a string. -The possible results of this function are -"nil" (a string, not the value nil), -"number", -"string", -"boolean, -"table", -"function", -"thread", -and "userdata". - -

        unpack (list)

        -Returns all elements from the given list. -This function is equivalent to -
        -  return list[1], list[2], ..., list[n]
        -
        -except that the above code can be written only for a fixed n. -The number n is the size of the list, -as defined for the table.getn function. - -

        _VERSION

        -A global variable (not a function) that -holds a string containing the current interpreter version. -The current content of this string is "Lua 5.0". - -

        xpcall (f, err)

        - -

        This function is similar to pcall, -except that you can set a new error handler. - -

        xpcall calls function f in protected mode, -using err as the error handler. -Any error inside f is not propagated; -instead, xpcall catches the error, -calls the err function with the original error object, -and returns a status code. -Its first result is the status code (a boolean), -which is true if the call succeeds without errors. -In such case, xpcall also returns all results from the call, -after this first result. -In case of any error, -xpcall returns false plus the result from err. - -

        5.2 - Coroutine Manipulation

        - -

        The operations related to coroutines comprise a sub-library of -the basic library and come inside the table coroutine. -See 2.10 for a general description of coroutines. - -

        coroutine.create (f)

        - -

        Creates a new coroutine, with body f. -f must be a Lua function. -Returns this new coroutine, -an object with type "thread". - -

        coroutine.resume (co, val1, ...)

        - -

        Starts or continues the execution of coroutine co. -The first time you resume a coroutine, -it starts running its body. -The arguments val1, ... go as the arguments to the body function. -If the coroutine has yielded, -resume restarts it; -the arguments val1, ... go as the results from the yield. - -

        If the coroutine runs without any errors, -resume returns true plus any values passed to yield -(if the coroutine yields) or any values returned by the body function -(if the coroutine terminates). -If there is any error, -resume returns false plus the error message. - -

        coroutine.status (co)

        - -

        Returns the status of coroutine co, as a string: -"running", -if the coroutine is running (that is, it called status); -"suspended", if the coroutine is suspended in a call to yield, -or if it has not started running yet; -and "dead" if the coroutine has finished its body function, -or if it has stopped with an error. - -

        coroutine.wrap (f)

        - -

        Creates a new coroutine, with body f. -f must be a Lua function. -Returns a function that resumes the coroutine each time it is called. -Any arguments passed to the function behave as the -extra arguments to resume. -Returns the same values returned by resume, -except the first boolean. -In case of error, propagates the error. - -

        coroutine.yield (val1, ...)

        - -

        Suspends the execution of the calling coroutine. -The coroutine cannot be running neither a C function, -nor a metamethod, nor an iterator. -Any arguments to yield go as extra results to resume. - -

        5.3 - String Manipulation

        -This library provides generic functions for string manipulation, -such as finding and extracting substrings, and pattern matching. -When indexing a string in Lua, the first character is at position 1 -(not at 0, as in C). -Indices are allowed to be negative and are interpreted as indexing backwards, -from the end of the string. -Thus, the last character is at position -1, and so on. - -

        The string library provides all its functions inside the table -string. - -

        string.byte (s [, i])

        -Returns the internal numerical code of the i-th character of s, -or nil if the index is out of range. -If i is absent, then it is assumed to be 1. -i may be negative. - -

        Note that numerical codes are not necessarily portable across platforms. - -

        string.char (i1, i2, ...)

        -Receives 0 or more integers. -Returns a string with length equal to the number of arguments, -in which each character has the internal numerical code equal -to its correspondent argument. - -

        Note that numerical codes are not necessarily portable across platforms. - -

        string.dump (function)

        - -

        Returns a binary representation of the given function, -so that a later loadstring on that string returns -a copy of the function. -function must be a Lua function without upvalues. - -

        string.find (s, pattern [, init [, plain]])

        -Looks for the first match of -pattern in the string s. -If it finds one, then find returns the indices of s -where this occurrence starts and ends; -otherwise, it returns nil. -If the pattern specifies captures (see string.gsub below), -the captured strings are returned as extra results. -A third, optional numerical argument init specifies -where to start the search; -its default value is 1 and may be negative. -A value of true as a fourth, optional argument plain -turns off the pattern matching facilities, -so the function does a plain "find substring" operation, -with no characters in pattern being considered "magic". -Note that if plain is given, then init must be given too. - -

        string.len (s)

        -Receives a string and returns its length. -The empty string "" has length 0. -Embedded zeros are counted, -so "a\000b\000c" has length 5. - -

        string.lower (s)

        -Receives a string and returns a copy of that string with all -uppercase letters changed to lowercase. -All other characters are left unchanged. -The definition of what is an uppercase letter depends on the current locale. - -

        string.rep (s, n)

        -Returns a string that is the concatenation of n copies of -the string s. - -

        string.sub (s, i [, j])

        -Returns the substring of s that -starts at i and continues until j; -i and j may be negative. -If j is absent, then it is assumed to be equal to -1 -(which is the same as the string length). -In particular, -the call string.sub(s,1,j) returns a prefix of s -with length j, -and string.sub(s, -i) returns a suffix of s -with length i. - -

        string.upper (s)

        -Receives a string and returns a copy of that string with all -lowercase letters changed to uppercase. -All other characters are left unchanged. -The definition of what is a lowercase letter depends on the current locale. - -

        string.format (formatstring, e1, e2, ...)

        - -Returns a formatted version of its variable number of arguments -following the description given in its first argument (which must be a string). -The format string follows the same rules as the printf family of -standard C functions. -The only differences are that the options/modifiers -*, l, L, n, p, -and h are not supported, -and there is an extra option, q. -The q option formats a string in a form suitable to be safely read -back by the Lua interpreter: -The string is written between double quotes, -and all double quotes, newlines, and backslashes in the string -are correctly escaped when written. -For instance, the call -
        -       string.format('%q', 'a string with "quotes" and \n new line')
        -
        -will produce the string: -
        -"a string with \"quotes\" and \
        - new line"
        -
        - -

        The options c, d, E, e, f, -g, G, i, o, u, X, and x all -expect a number as argument, -whereas q and s expect a string. -The * modifier can be simulated by building -the appropriate format string. -For example, "%*g" can be simulated with -"%"..width.."g". - -

        String values to be formatted with -%s cannot contain embedded zeros. - -

        string.gfind (s, pat)

        - -

        Returns an iterator function that, -each time it is called, -returns the next captures from pattern pat over string s. - -

        If pat specifies no captures, -then the whole match is produced in each call. - -

        As an example, the following loop -

        -  s = "hello world from Lua"
        -  for w in string.gfind(s, "%a+") do
        -    print(w)
        -  end
        -
        -will iterate over all the words from string s, -printing one per line. -The next example collects all pairs key=value from the -given string into a table: -
        -  t = {}
        -  s = "from=world, to=Lua"
        -  for k, v in string.gfind(s, "(%w+)=(%w+)") do
        -    t[k] = v
        -  end
        -
        - -

        string.gsub (s, pat, repl [, n])

        - -Returns a copy of s -in which all occurrences of the pattern pat have been -replaced by a replacement string specified by repl. -gsub also returns, as a second value, -the total number of substitutions made. - -

        If repl is a string, then its value is used for replacement. -Any sequence in repl of the form %n, -with n between 1 and 9, -stands for the value of the n-th captured substring (see below). - -

        If repl is a function, then this function is called every time a -match occurs, with all captured substrings passed as arguments, -in order; -if the pattern specifies no captures, -then the whole match is passed as a sole argument. -If the value returned by this function is a string, -then it is used as the replacement string; -otherwise, the replacement string is the empty string. - -

        The optional last parameter n limits -the maximum number of substitutions to occur. -For instance, when n is 1 only the first occurrence of -pat is replaced. - -

        Here are some examples: -

        -   x = string.gsub("hello world", "(%w+)", "%1 %1")
        -   --> x="hello hello world world"
        -
        -   x = string.gsub("hello world", "(%w+)", "%1 %1", 1)
        -   --> x="hello hello world"
        -
        -   x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
        -   --> x="world hello Lua from"
        -
        -   x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
        -   --> x="home = /home/roberto, user = roberto"
        -
        -   x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
        -         return loadstring(s)()
        -       end)
        -   --> x="4+5 = 9"
        -
        -   local t = {name="lua", version="5.0"}
        -   x = string.gsub("$name_$version.tar.gz", "%$(%w+)", function (v)
        -         return t[v]
        -       end)
        -   --> x="lua_5.0.tar.gz"
        -
        - -

        Patterns

        - -

        -A character class is used to represent a set of characters. -The following combinations are allowed in describing a character class: -

          -
        • x (where x is not one of the magic characters -^$()%.[]*+-?) ---- represents the character x itself. -
        • . --- (a dot) represents all characters. -
        • %a --- represents all letters. -
        • %c --- represents all control characters. -
        • %d --- represents all digits. -
        • %l --- represents all lowercase letters. -
        • %p --- represents all punctuation characters. -
        • %s --- represents all space characters. -
        • %u --- represents all uppercase letters. -
        • %w --- represents all alphanumeric characters. -
        • %x --- represents all hexadecimal digits. -
        • %z --- represents the character with representation 0. -
        • %x (where x is any non-alphanumeric character) --- -represents the character x. -This is the standard way to escape the magic characters. -Any punctuation character (even the non magic) -can be preceded by a `%´ -when used to represent itself in a pattern. - -

        • [set] --- -represents the class which is the union of all -characters in set. -A range of characters may be specified by -separating the end characters of the range with a `-´. -All classes %x described above may also be used as -components in set. -All other characters in set represent themselves. -For example, [%w_] (or [_%w]) -represents all alphanumeric characters plus the underscore, -[0-7] represents the octal digits, -and [0-7%l%-] represents the octal digits plus -the lowercase letters plus the `-´ character. - -

          The interaction between ranges and classes is not defined. -Therefore, patterns like [%a-z] or [a-%%] -have no meaning. - -

        • [^set] --- -represents the complement of set, -where set is interpreted as above. -
        -For all classes represented by single letters (%a, %c, etc.), -the corresponding uppercase letter represents the complement of the class. -For instance, %S represents all non-space characters. - -

        The definitions of letter, space, and other character groups -depend on the current locale. -In particular, the class [a-z] may not be equivalent to %l. -The second form should be preferred for portability. - -

        -A pattern item may be -

          -
        • -a single character class, -which matches any single character in the class; -
        • -a single character class followed by `*´, -which matches 0 or more repetitions of characters in the class. -These repetition items will always match the longest possible sequence; -
        • -a single character class followed by `+´, -which matches 1 or more repetitions of characters in the class. -These repetition items will always match the longest possible sequence; -
        • -a single character class followed by `-´, -which also matches 0 or more repetitions of characters in the class. -Unlike `*´, -these repetition items will always match the shortest possible sequence; -
        • -a single character class followed by `?´, -which matches 0 or 1 occurrence of a character in the class; -
        • -%n, for n between 1 and 9; -such item matches a substring equal to the n-th captured string -(see below); -
        • -%bxy, where x and y are two distinct characters; -such item matches strings that start with x, end with y, -and where the x and y are balanced. -This means that, if one reads the string from left to right, -counting +1 for an x and -1 for a y, -the ending y is the first y where the count reaches 0. -For instance, the item %b() matches expressions with -balanced parentheses. -
        - -

        -A pattern is a sequence of pattern items. -A `^´ at the beginning of a pattern anchors the match at the -beginning of the subject string. -A `$´ at the end of a pattern anchors the match at the -end of the subject string. -At other positions, -`^´ and `$´ have no special meaning and represent themselves. - -

        -A pattern may contain sub-patterns enclosed in parentheses; -they describe captures. -When a match succeeds, the substrings of the subject string -that match captures are stored (captured) for future use. -Captures are numbered according to their left parentheses. -For instance, in the pattern "(a*(.)%w(%s*))", -the part of the string matching "a*(.)%w(%s*)" is -stored as the first capture (and therefore has number 1); -the character matching . is captured with number 2, -and the part matching %s* has number 3. - -

        As a special case, the empty capture () captures -the current string position (a number). -For instance, if we apply the pattern "()aa()" on the -string "flaaap", there will be two captures: 3 and 5. - -

        A pattern cannot contain embedded zeros. Use %z instead. - -

        5.4 - Table Manipulation

        -This library provides generic functions for table manipulation. -It provides all its functions inside the table table. - -

        Most functions in the table library assume that the table -represents an array or a list. -For those functions, an important concept is the size of the array. -There are three ways to specify that size: -

          -
        • the field "n" --- -When the table has a field "n" with a numerical value, -that value is assumed as its size. -
        • setn --- -You can call the table.setn function to explicitly set -the size of a table. -
        • implicit size --- -Otherwise, the size of the object is one less the first integer index -with a nil value. -
        -For more details, see the descriptions of the table.getn and -table.setn functions. - -

        table.concat (table [, sep [, i [, j]]])

        - -Returns table[i]..sep..table[i+1] ... sep..table[j]. -The default value for sep is the empty string, -the default for i is 1, -and the default for j is the size of the table. -If i is greater than j, returns the empty string. - -

        table.foreach (table, f)

        -Executes the given f over all elements of table. -For each element, f is called with the index and -respective value as arguments. -If f returns a non-nil value, -then the loop is broken, and this value is returned -as the final value of foreach. - -

        See the next function for extra information about table traversals. - -

        table.foreachi (table, f)

        -Executes the given f over the -numerical indices of table. -For each index, f is called with the index and -respective value as arguments. -Indices are visited in sequential order, -from 1 to n, -where n is the size of the table (see 5.4). -If f returns a non-nil value, -then the loop is broken and this value is returned -as the result of foreachi. - -

        table.getn (table)

        -Returns the size of a table, when seen as a list. -If the table has an n field with a numeric value, -this value is the size of the table. -Otherwise, if there was a previous call -to table.setn over this table, -the respective value is returned. -Otherwise, the size is one less the first integer index with -a nil value. - -

        table.sort (table [, comp])

        -Sorts table elements in a given order, in-place, -from table[1] to table[n], -where n is the size of the table (see 5.4). -If comp is given, -then it must be a function that receives two table elements, -and returns true -when the first is less than the second -(so that not comp(a[i+1],a[i]) will be true after the sort). -If comp is not given, -then the standard Lua operator < is used instead. - -

        The sort algorithm is not stable, -that is, elements considered equal by the given order -may have their relative positions changed by the sort. - -

        table.insert (table, [pos,] value)

        - -

        Inserts element value at position pos in table, -shifting up other elements to open space, if necessary. -The default value for pos is n+1, -where n is the size of the table (see 5.4), -so that a call table.insert(t,x) inserts x at the end -of table t. -This function also updates the size of the table by -calling table.setn(table, n+1). - -

        table.remove (table [, pos])

        - -

        Removes from table the element at position pos, -shifting down other elements to close the space, if necessary. -Returns the value of the removed element. -The default value for pos is n, -where n is the size of the table (see 5.4), -so that a call table.remove(t) removes the last element -of table t. -This function also updates the size of the table by -calling table.setn(table, n-1). - -

        table.setn (table, n)

        - -

        Updates the size of a table. -If the table has a field "n" with a numerical value, -that value is changed to the given n. -Otherwise, it updates an internal state -so that subsequent calls to table.getn(table) return n. - -

        5.5 - Mathematical Functions

        - -

        This library is an interface to most of the functions of the -standard C math library. -(Some have slightly different names.) -It provides all its functions inside the table math. -In addition, -it registers the global __pow -for the binary exponentiation operator ^, -so that x^y returns xy. -The library provides the following functions: - - - - - - - - - -

        -       math.abs     math.acos    math.asin    math.atan    math.atan2
        -       math.ceil    math.cos     math.deg     math.exp     math.floor
        -       math.log     math.log10   math.max     math.min     math.mod
        -       math.pow     math.rad     math.sin     math.sqrt    math.tan
        -       math.frexp   math.ldexp   math.random  math.randomseed
        -
        -plus a variable math.pi. -Most of them -are only interfaces to the corresponding functions in the C library. -All trigonometric functions work in radians -(previous versions of Lua used degrees). -The functions math.deg and math.rad convert -between radians and degrees. - -

        The function math.max returns the maximum -value of its numeric arguments. -Similarly, math.min computes the minimum. -Both can be used with 1, 2, or more arguments. - -

        The functions math.random and math.randomseed -are interfaces to the simple random generator functions -rand and srand that are provided by ANSI C. -(No guarantees can be given for their statistical properties.) -When called without arguments, -math.random returns a pseudo-random real number -in the range [0,1). -When called with a number n, -math.random returns a pseudo-random integer in the range [1,n]. -When called with two arguments, l and u, -math.random returns a pseudo-random integer in the range [l,u]. -The math.randomseed function sets a "seed" -for the pseudo-random generator: -Equal seeds produce equal sequences of numbers. - -

        5.6 - Input and Output Facilities

        - -

        The I/O library provides two different styles for file manipulation. -The first one uses implicit file descriptors, -that is, there are operations to set a default input file and a -default output file, -and all input/output operations are over those default files. -The second style uses explicit file descriptors. - -

        When using implicit file descriptors, -all operations are supplied by table io. -When using explicit file descriptors, -the operation io.open returns a file descriptor -and then all operations are supplied as methods by the file descriptor. - -

        The table io also provides -three predefined file descriptors with their usual meanings from C: -io.stdin, io.stdout, and io.stderr. - -

        A file handle is a userdata containing the file stream (FILE*), -with a distinctive metatable created by the I/O library. - -

        Unless otherwise stated, -all I/O functions return nil on failure -(plus an error message as a second result) -and some value different from nil on success. - -

        io.close ([file])

        - -

        Equivalent to file:close(). -Without a file, closes the default output file. - -

        io.flush ()

        - -

        Equivalent to file:flush over the default output file. - -

        io.input ([file])

        - -

        When called with a file name, it opens the named file (in text mode), -and sets its handle as the default input file. -When called with a file handle, -it simply sets that file handle as the default input file. -When called without parameters, -it returns the current default input file. - -

        In case of errors this function raises the error, -instead of returning an error code. - -

        io.lines ([filename])

        - -

        Opens the given file name in read mode -and returns an iterator function that, -each time it is called, -returns a new line from the file. -Therefore, the construction -

        -       for line in io.lines(filename) do ... end
        -
        -will iterate over all lines of the file. -When the iterator function detects the end of file, -it returns nil (to finish the loop) and automatically closes the file. - -

        The call io.lines() (without a file name) is equivalent -to io.input():lines(), that is, it iterates over the -lines of the default input file. - -

        io.open (filename [, mode])

        - -

        This function opens a file, -in the mode specified in the string mode. -It returns a new file handle, -or, in case of errors, nil plus an error message. - -

        The mode string can be any of the following: -

          -
        • "r" read mode (the default); -
        • "w" write mode; -
        • "a" append mode; -
        • "r+" update mode, all previous data is preserved; -
        • "w+" update mode, all previous data is erased; -
        • "a+" append update mode, previous data is preserved, - writing is only allowed at the end of file. -
        -The mode string may also have a b at the end, -which is needed in some systems to open the file in binary mode. -This string is exactly what is used in the standard C function fopen. - -

        io.output ([file])

        - -

        Similar to io.input, but operates over the default output file. - -

        io.read (format1, ...)

        - -

        Equivalent to io.input():read. - -

        io.tmpfile ()

        - -

        Returns a handle for a temporary file. -This file is open in update mode -and it is automatically removed when the program ends. - -

        io.type (obj)

        - -

        Checks whether obj is a valid file handle. -Returns the string "file" if obj is an open file handle, -"closed file" if obj is a closed file handle, -and nil if obj is not a file handle. - -

        io.write (value1, ...)

        - -

        Equivalent to io.output():write. - -

        file:close ()

        - -

        Closes file. - -

        file:flush ()

        - -

        Saves any written data to file. - -

        file:lines ()

        - -

        Returns an iterator function that, -each time it is called, -returns a new line from the file. -Therefore, the construction -

        -       for line in file:lines() do ... end
        -
        -will iterate over all lines of the file. -(Unlike io.lines, this function does not close the file -when the loop ends.) - -

        file:read (format1, ...)

        - -

        Reads the file file, -according to the given formats, which specify what to read. -For each format, -the function returns a string (or a number) with the characters read, -or nil if it cannot read data with the specified format. -When called without formats, -it uses a default format that reads the entire next line -(see below). - -

        The available formats are -

          -
        • "*n" reads a number; -this is the only format that returns a number instead of a string. -
        • "*a" reads the whole file, starting at the current position. -On end of file, it returns the empty string. -
        • "*l" reads the next line (skipping the end of line), -returning nil on end of file. -This is the default format. -
        • number reads a string with up to that number of characters, -returning nil on end of file. -If number is zero, -it reads nothing and returns an empty string, -or nil on end of file. -
        - -

        file:seek ([whence] [, offset])

        - -

        Sets and gets the file position, -measured from the beginning of the file, -to the position given by offset plus a base -specified by the string whence, as follows: -

          -
        • "set" base is position 0 (beginning of the file); -
        • "cur" base is current position; -
        • "end" base is end of file; -
        -In case of success, function seek returns the final file position, -measured in bytes from the beginning of the file. -If this function fails, it returns nil, -plus a string describing the error. - -

        The default value for whence is "cur", -and for offset is 0. -Therefore, the call file:seek() returns the current -file position, without changing it; -the call file:seek("set") sets the position to the -beginning of the file (and returns 0); -and the call file:seek("end") sets the position to the -end of the file, and returns its size. - -

        file:write (value1, ...)

        - -

        Writes the value of each of its arguments to -the filehandle file. -The arguments must be strings or numbers. -To write other values, -use tostring or string.format before write. - -

        5.7 - Operating System Facilities

        - -

        This library is implemented through table os. - -

        os.clock ()

        - -

        Returns an approximation of the amount of CPU time -used by the program, in seconds. - -

        os.date ([format [, time]])

        - -

        Returns a string or a table containing date and time, -formatted according to the given string format. - -

        If the time argument is present, -this is the time to be formatted -(see the os.time function for a description of this value). -Otherwise, date formats the current time. - -

        If format starts with `!´, -then the date is formatted in Coordinated Universal Time. -After that optional character, -if format is *t, -then date returns a table with the following fields: -year (four digits), month (1--12), day (1--31), -hour (0--23), min (0--59), sec (0--61), -wday (weekday, Sunday is 1), -yday (day of the year), -and isdst (daylight saving flag, a boolean). - -

        If format is not *t, -then date returns the date as a string, -formatted according with the same rules as the C function strftime. - -

        When called without arguments, -date returns a reasonable date and time representation that depends on -the host system and on the current locale -(that is, os.date() is equivalent to os.date("%c")). - -

        os.difftime (t2, t1)

        - -

        Returns the number of seconds from time t1 to time t2. -In Posix, Windows, and some other systems, -this value is exactly t2-t1. - -

        os.execute (command)

        - -

        This function is equivalent to the C function system. -It passes command to be executed by an operating system shell. -It returns a status code, which is system-dependent. - -

        os.exit ([code])

        - -

        Calls the C function exit, -with an optional code, -to terminate the host program. -The default value for code is the success code. - -

        os.getenv (varname)

        - -

        Returns the value of the process environment variable varname, -or nil if the variable is not defined. - -

        os.remove (filename)

        - -

        Deletes the file with the given name. -If this function fails, it returns nil, -plus a string describing the error. - -

        os.rename (oldname, newname)

        - -

        Renames file named oldname to newname. -If this function fails, it returns nil, -plus a string describing the error. - -

        os.setlocale (locale [, category])

        - -

        Sets the current locale of the program. -locale is a string specifying a locale; -category is an optional string describing which category to change: -"all", "collate", "ctype", -"monetary", "numeric", or "time"; -the default category is "all". -The function returns the name of the new locale, -or nil if the request cannot be honored. - -

        os.time ([table])

        - -

        Returns the current time when called without arguments, -or a time representing the date and time specified by the given table. -This table must have fields year, month, and day, -and may have fields hour, min, sec, and isdst -(for a description of these fields, see the os.date function). - -

        The returned value is a number, whose meaning depends on your system. -In Posix, Windows, and some other systems, this number counts the number -of seconds since some given start time (the "epoch"). -In other systems, the meaning is not specified, -and the number returned by time can be used only as an argument to -date and difftime. - -

        os.tmpname ()

        - -

        Returns a string with a file name that can -be used for a temporary file. -The file must be explicitly opened before its use -and removed when no longer needed. - -

        This function is equivalent to the tmpnam C function, -and many people (and even some compilers!) advise against its use, -because between the time you call this function -and the time you open the file, -it is possible for another process -to create a file with the same name. - -

        5.8 - The Reflexive Debug Interface

        - -

        The debug library provides -the functionality of the debug interface to Lua programs. -You should exert care when using this library. -The functions provided here should be used exclusively for debugging -and similar tasks, such as profiling. -Please resist the temptation to use them as a -usual programming tool: -They can be very slow. -Moreover, setlocal and getlocal -violate the privacy of local variables -and therefore can compromise some otherwise secure code. - -

        All functions in this library are provided -inside a debug table. - -

        debug.debug ()

        - -

        Enters an interactive mode with the user, -running each string that the user enters. -Using simple commands and other debug facilities, -the user can inspect global and local variables, -change their values, evaluate expressions, and so on. -A line containing only the word cont finishes this function, -so that the caller continues its execution. - -

        Note that commands for debug.debug are not lexically nested -with any function, so they have no direct access to local variables. - -

        debug.gethook ()

        - -

        Returns the current hook settings, as three values: -the current hook function, the current hook mask, -and the current hook count (as set by the debug.sethook function). - -

        debug.getinfo (function [, what])

        - -

        This function returns a table with information about a function. -You can give the function directly, -or you can give a number as the value of function, -which means the function running at level function of the call stack: -Level 0 is the current function (getinfo itself); -level 1 is the function that called getinfo; -and so on. -If function is a number larger than the number of active functions, -then getinfo returns nil. - -

        The returned table contains all the fields returned by lua_getinfo, -with the string what describing which fields to fill in. -The default for what is to get all information available. -If present, -the option `f´ -adds a field named func with the function itself. - -

        For instance, the expression debug.getinfo(1,"n").name returns -the name of the current function, if a reasonable name can be found, -and debug.getinfo(print) returns a table with all available information -about the print function. - -

        debug.getlocal (level, local)

        - -

        This function returns the name and the value of the local variable -with index local of the function at level level of the stack. -(The first parameter or local variable has index 1, and so on, -until the last active local variable.) -The function returns nil if there is no local -variable with the given index, -and raises an error when called with a level out of range. -(You can call debug.getinfo to check whether the level is valid.) - -

        debug.getupvalue (func, up)

        - -

        This function returns the name and the value of the upvalue -with index up of the function func. -The function returns nil if there is no upvalue with the given index. - -

        debug.setlocal (level, local, value)

        - -

        This function assigns the value value to the local variable -with index local of the function at level level of the stack. -The function returns nil if there is no local -variable with the given index, -and raises an error when called with a level out of range. -(You can call getinfo to check whether the level is valid.) - -

        debug.setupvalue (func, up, value)

        - -

        This function assigns the value value to the upvalue -with index up of the function func. -The function returns nil if there is no upvalue -with the given index. - -

        debug.sethook (hook, mask [, count])

        - - -

        Sets the given function as a hook. -The string mask and the number count describe -when the hook will be called. -The string mask may have the following characters, -with the given meaning: -

          -
        • "c" The hook is called every time Lua calls a function; -
        • "r" The hook is called every time Lua returns from a function; -
        • "l" The hook is called every time Lua enters a new line of code. -
        -With a count different from zero, -the hook is called after every count instructions. - -

        When called without arguments, -the debug.sethook function turns off the hook. - -

        When the hook is called, its first parameter is always a string -describing the event that triggered its call: -"call", "return" (or "tail return"), -"line", and "count". -Moreover, for line events, -it also gets as its second parameter the new line number. -Inside a hook, -you can call getinfo with level 2 to get more information about -the running function -(level 0 is the getinfo function, -and level 1 is the hook function), -unless the event is "tail return". -In this case, Lua is only simulating the return, -and a call to getinfo will return invalid data. - -

        debug.traceback ([message])

        - -

        Returns a string with a traceback of the call stack. -An optional message string is appended -at the beginning of the traceback. -This function is typically used with xpcall to produce -better error messages. - -

        -

        6 - Lua Stand-alone

        - -

        Although Lua has been designed as an extension language, -to be embedded in a host C program, -it is also frequently used as a stand-alone language. -An interpreter for Lua as a stand-alone language, -called simply lua, -is provided with the standard distribution. -The stand-alone interpreter includes -all standard libraries plus the reflexive debug interface. -Its usage is: -

        -      lua [options] [script [args]]
        -
        -The options are: -
          -
        • - executes stdin as a file; -
        • -e stat executes string stat; -
        • -l file "requires" file; -
        • -i enters interactive mode after running script; -
        • -v prints version information; -
        • -- stop handling options. -
        -After handling its options, lua runs the given script, -passing to it the given args. -When called without arguments, -lua behaves as lua -v -i when stdin is a terminal, -and as lua - otherwise. - -

        Before running any argument, -the interpreter checks for an environment variable LUA_INIT. -If its format is @filename, -then lua executes the file. -Otherwise, lua executes the string itself. - -

        All options are handled in order, except -i. -For instance, an invocation like -

        -       $ lua -e'a=1' -e 'print(a)' script.lua
        -
        -will first set a to 1, then print a, -and finally run the file script.lua. -(Here, $ is the shell prompt. Your prompt may be different.) - -

        Before starting to run the script, -lua collects all arguments in the command line -in a global table called arg. -The script name is stored in index 0, -the first argument after the script name goes to index 1, -and so on. -The field n gets the number of arguments after the script name. -Any arguments before the script name -(that is, the interpreter name plus the options) -go to negative indices. -For instance, in the call -

        -       $ lua -la.lua b.lua t1 t2
        -
        -the interpreter first runs the file a.lua, -then creates a table -
        -       arg = { [-2] = "lua", [-1] = "-la.lua", [0] = "b.lua",
        -               [1] = "t1", [2] = "t2"; n = 2 }
        -
        -and finally runs the file b.lua. - -

        In interactive mode, -if you write an incomplete statement, -the interpreter waits for its completion. - -

        If the global variable _PROMPT is defined as a string, -then its value is used as the prompt. -Therefore, the prompt can be changed directly on the command line: -

        -       $ lua -e"_PROMPT='myprompt> '" -i
        -
        -(the outer pair of quotes is for the shell, -the inner is for Lua), -or in any Lua programs by assigning to _PROMPT. -Note the use of -i to enter interactive mode; otherwise, -the program would end just after the assignment to _PROMPT. - -

        In Unix systems, Lua scripts can be made into executable programs -by using chmod +x and the #! form, -as in -

        -#!/usr/local/bin/lua
        -
        -(Of course, -the location of the Lua interpreter may be different in your machine. -If lua is in your PATH, -then -
        -#!/usr/bin/env lua
        -
        -is a more portable solution.) - -

        -

        Acknowledgments

        - -

        The Lua team is grateful to Tecgraf for its continued support to Lua. -We thank everyone at Tecgraf, -specially the head of the group, Marcelo Gattass. -At the risk of omitting several names, -we also thank the following individuals for supporting, -contributing to, and spreading the word about Lua: -Alan Watson. -André Clinio, -André Costa, -Antonio Scuri, -Asko Kauppi, -Bret Mogilefsky, -Cameron Laird, -Carlos Cassino, -Carlos Henrique Levy, -Claudio Terra, -David Jeske, -Ed Ferguson, -Edgar Toernig, -Erik Hougaard, -Jim Mathies, -John Belmonte, -John Passaniti, -John Roll, -Jon Erickson, -Jon Kleiser, -Mark Ian Barlow, -Nick Trout, -Noemi Rodriguez, -Norman Ramsey, -Philippe Lhoste, -Renata Ratton, -Renato Borges, -Renato Cerqueira, -Reuben Thomas, -Stephan Herrmann, -Steve Dekorte, -Thatcher Ulrich, -Tomás Gorham, -Vincent Penquerc'h. -Thank you! - -


        - -

        Incompatibilities with Previous Versions

        - - -

        Lua 5.0 is a major release. -There are several incompatibilities with its previous version, Lua 4.0. - -

        Incompatibilities with version 4.0

        - -

        Changes in the Language

        -
          - -

        • -The whole tag-method scheme was replaced by metatables. - -

        • -Function calls written between parentheses result in exactly one value. - -

        • -A function call as the last expression in a list constructor -(like {a,b,f()}) has all its return values inserted in the list. - -

        • -The precedence of or is smaller than the precedence of and. - -

        • -in, false, and true are reserved words. - -

        • -The old construction for k,v in t, where t is a table, -is deprecated (although it is still supported). -Use for k,v in pairs(t) instead. - -

        • -When a literal string of the form [[...]] starts with a newline, -this newline is ignored. - -

          - -

        • Upvalues in the form %var are obsolete; -use external local variables instead. - -

        - -

        Changes in the Libraries

        -
          - -

        • -Most library functions now are defined inside tables. -There is a compatibility script (compat.lua) that -redefine most of them as global names. - -

        • -In the math library, angles are expressed in radians. -With the compatibility script (compat.lua), -functions still work in degrees. - -

        • -The call function is deprecated. -Use f(unpack(tab)) instead of call(f, tab) -for unprotected calls, -or the new pcall function for protected calls. - -

        • -dofile do not handle errors, but simply propagates them. - -

        • -dostring is deprecated. Use loadstring instead. - -

        • -The read option *w is obsolete. - -

        • -The format option %n$ is obsolete. - -

        - -

        Changes in the API

        -
          - -

        • -lua_open does not have a stack size as its argument -(stacks are dynamic). - -

        • -lua_pushuserdata is deprecated. -Use lua_newuserdata or lua_pushlightuserdata instead. - -

        - -

        - -

        The Complete Syntax of Lua

        - - -

        - -

        -
        -

        chunk ::= {stat [`;´]} - -

        block ::= chunk - -

        stat ::= varlist1 `=´ explist1 | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | return [explist1] | break | for Name `=´ exp `,´ exp [`,´ exp] do block end | for Name {`,´ Name} in explist1 do block end | function funcname funcbody | local function Name funcbody | local namelist [init] - -

        funcname ::= Name {`.´ Name} [`:´ Name] - -

        varlist1 ::= var {`,´ var} - -

        var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name - -

        namelist ::= Name {`,´ Name} - -

        init ::= `=´ explist1 - -

        explist1 ::= {exp `,´} exp - -

        exp ::= nil | false | true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp - -

        prefixexp ::= var | functioncall | `(´ exp `)´ - -

        functioncall ::= prefixexp args | prefixexp `:´ Name args - -

        args ::= `(´ [explist1] `)´ | tableconstructor | Literal - -

        function ::= function funcbody - -

        funcbody ::= `(´ [parlist1] `)´ block end - -

        parlist1 ::= Name {`,´ Name} [`,´ `...´] | `...´ - -

        tableconstructor ::= `{´ [fieldlist] `}´ - fieldlist ::= field {fieldsep field} [fieldsep] - field ::= `[´ exp `]´ `=´ exp | name `=´ exp | exp - fieldsep ::= `,´ | `;´ - -

        binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `..´ | `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | and | or - -

        unop ::= `-´ | not - -

        - -

        - -

        - -


        - -Last update: -Tue Nov 25 16:08:37 BRST 2003 - - - - diff --git a/doc/readme.html b/doc/readme.html deleted file mode 100644 index baa7cc8a07..0000000000 --- a/doc/readme.html +++ /dev/null @@ -1,35 +0,0 @@ - - -Lua documentation - - - - -
        -

        -Lua -Documentation -

        - - - -
        - -Last update: -Thu Mar 11 23:08:56 BRT 2004 - - - - diff --git a/etc/Makefile b/etc/Makefile index 1286c6403a..0fc318cdaa 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -5,7 +5,7 @@ LUA= .. include $(LUA)/config LIBLUA=$(LIB)/liblua.a -ALL= bin2c min trace noparser luab +ALL= bin2c min noparser luab all: @echo 'choose a target:' $(ALL) @@ -16,14 +16,11 @@ bin2c: bin2c.c min: min.c $(LIBLUA) $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -trace: trace.c $(LIBLUA) - $(CC) -g $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib $(EXTRA_LIBS) - noparser: noparser.c $(CC) $(CFLAGS) -I$(LUA)/src -o $@.o -c $@.c luab: noparser $(LIBLUA) - cc -o $@ noparser.o $(LUA)/src/lua/lua.o -L$(LIB) -llua -llualib $(EXTRA_LIBS) + $(CC) -o $@ noparser.o $(LUA)/src/lua/lua.o -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(BIN)/luac $(LUA)/test/hello.lua $@ luac.out -$@ -e'a=1' @@ -36,7 +33,3 @@ $(LIBLUA): clean: rm -f $(ALL) a.out core *.o luac.out - -luser_tests.h: RCS/ltests.h,v - co -q -M ltests.h - mv -f ltests.h $@ diff --git a/etc/RCS b/etc/RCS new file mode 120000 index 0000000000..1ae3893605 --- /dev/null +++ b/etc/RCS @@ -0,0 +1 @@ +../RCS \ No newline at end of file diff --git a/etc/README b/etc/README index c838a7fe19..6a383ef80d 100644 --- a/etc/README +++ b/etc/README @@ -1,42 +1,10 @@ This directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. -bin2c.c - This program converts files to byte arrays that are automatically run - with lua_dobuffer. This allows C programs to include all necessary Lua - code, even in precompiled form. Even if the code is included in source - form, bin2c is useful because it avoids the hassle of having to quote - special characters in C strings. - Example of usage: Run bin2c file1 file2 ... > init.h. Then, in your - C program, just do #include "init.h" anywhere in the *body* of a - function. This will be equivalent to calling - lua_dofile(L,"file1"); lua_dofile(L,"file2"); ... - Note that the Lua state is called "L". If you use a different name, - say "mystate", just #define L mystate before you #include "init.h". - -compat.lua - A compatibility module for Lua 4.0 functions. - -doall.lua - Emulate the command line behaviour of Lua 4.0 - lua.ico - A Lua icon for Windows. + A Lua icon for Windows (and web sites, as favicon.ico). Drawn by hand by Markus Gritsch . -lua.magic - Data for teaching file(1) about Lua precompiled chunks. - -lua.xpm - The same icon as lua.ico, but in XPM format. - It was converted with ImageMagick by Andy Tai . - -luser_number.h - Number type configuration for Lua core. - -luser_tests.h - Self-test configuration for Lua core. - min.c A minimal Lua interpreter. Good for learning and for starting your own. @@ -48,7 +16,3 @@ noparser.c saconfig.c Configuration for Lua interpreter. - -trace.c - A simple execution tracer. - An example of how to use the debug hooks in C. diff --git a/etc/bin2c.c b/etc/bin2c.c deleted file mode 100644 index 0993b16d83..0000000000 --- a/etc/bin2c.c +++ /dev/null @@ -1,67 +0,0 @@ -/* -* bin2c.c -* convert files to byte arrays for automatic loading with lua_dobuffer -* Luiz Henrique de Figueiredo (lhf@tecgraf.puc-rio.br) -* 02 Apr 2003 20:44:31 -*/ - -#include -#include -#include - -static void dump(FILE* f, int n) -{ - printf("static const unsigned char B%d[]={\n",n); - for (n=1;;n++) - { - int c=getc(f); - if (c==EOF) break; - printf("%3u,",c); - if (n==20) { putchar('\n'); n=0; } - } - printf("\n};\n\n"); -} - -static void fdump(const char* fn, int n) -{ - FILE* f= fopen(fn,"rb"); /* must open in binary mode */ - if (f==NULL) - { - fprintf(stderr,"bin2c: cannot open "); - perror(fn); - exit(1); - } - else - { - printf("/* %s */\n",fn); - dump(f,n); - fclose(f); - } -} - -static void emit(const char* fn, int n) -{ - printf(" lua_dobuffer(L,(const char*)B%d,sizeof(B%d),\"%s\");\n",n,n,fn); -} - -int main(int argc, char* argv[]) -{ - printf("/* code automatically generated by bin2c -- DO NOT EDIT */\n"); - printf("{\n"); - if (argc<2) - { - dump(stdin,0); - emit("=stdin",0); - } - else - { - int i; - printf("/* #include'ing this file in a C program is equivalent to calling\n"); - for (i=1; i protect(f, err) --- loadfile --- loadstring - --- rawget --- rawset - --- getargs = Main.getargs ?? - - -function do_ (f, err) - if not f then print(err); return end - local a,b = pcall(f) - if not a then print(b); return nil - else return b or true - end -end - -function dostring(s) return do_(loadstring(s)) end --- function dofile(s) return do_(loadfile(s)) end - -------------------------------------------------------------------- --- Table library -local tab = table -foreach = tab.foreach -foreachi = tab.foreachi -getn = tab.getn -tinsert = tab.insert -tremove = tab.remove -sort = tab.sort - -------------------------------------------------------------------- --- Debug library -local dbg = debug -getinfo = dbg.getinfo -getlocal = dbg.getlocal -setcallhook = function () error"`setcallhook' is deprecated" end -setlinehook = function () error"`setlinehook' is deprecated" end -setlocal = dbg.setlocal - -------------------------------------------------------------------- --- math library -local math = math -abs = math.abs -acos = function (x) return math.deg(math.acos(x)) end -asin = function (x) return math.deg(math.asin(x)) end -atan = function (x) return math.deg(math.atan(x)) end -atan2 = function (x,y) return math.deg(math.atan2(x,y)) end -ceil = math.ceil -cos = function (x) return math.cos(math.rad(x)) end -deg = math.deg -exp = math.exp -floor = math.floor -frexp = math.frexp -ldexp = math.ldexp -log = math.log -log10 = math.log10 -max = math.max -min = math.min -mod = math.mod -PI = math.pi ---??? pow = math.pow -rad = math.rad -random = math.random -randomseed = math.randomseed -sin = function (x) return math.sin(math.rad(x)) end -sqrt = math.sqrt -tan = function (x) return math.tan(math.rad(x)) end - -------------------------------------------------------------------- --- string library -local str = string -strbyte = str.byte -strchar = str.char -strfind = str.find -format = str.format -gsub = str.gsub -strlen = str.len -strlower = str.lower -strrep = str.rep -strsub = str.sub -strupper = str.upper - -------------------------------------------------------------------- --- os library -clock = os.clock -date = os.date -difftime = os.difftime -execute = os.execute --? -exit = os.exit -getenv = os.getenv -remove = os.remove -rename = os.rename -setlocale = os.setlocale -time = os.time -tmpname = os.tmpname - -------------------------------------------------------------------- --- compatibility only -getglobal = function (n) return _G[n] end -setglobal = function (n,v) _G[n] = v end - -------------------------------------------------------------------- - -local io, tab = io, table - --- IO library (files) -_STDIN = io.stdin -_STDERR = io.stderr -_STDOUT = io.stdout -_INPUT = io.stdin -_OUTPUT = io.stdout -seek = io.stdin.seek -- sick ;-) -tmpfile = io.tmpfile -closefile = io.close -openfile = io.open - -function flush (f) - if f then f:flush() - else _OUTPUT:flush() - end -end - -function readfrom (name) - if name == nil then - local f, err, cod = io.close(_INPUT) - _INPUT = io.stdin - return f, err, cod - else - local f, err, cod = io.open(name, "r") - _INPUT = f or _INPUT - return f, err, cod - end -end - -function writeto (name) - if name == nil then - local f, err, cod = io.close(_OUTPUT) - _OUTPUT = io.stdout - return f, err, cod - else - local f, err, cod = io.open(name, "w") - _OUTPUT = f or _OUTPUT - return f, err, cod - end -end - -function appendto (name) - local f, err, cod = io.open(name, "a") - _OUTPUT = f or _OUTPUT - return f, err, cod -end - -function read (...) - local f = _INPUT - if type(arg[1]) == 'userdata' then - f = tab.remove(arg, 1) - end - return f:read(unpack(arg)) -end - -function write (...) - local f = _OUTPUT - if type(arg[1]) == 'userdata' then - f = tab.remove(arg, 1) - end - return f:write(unpack(arg)) -end - diff --git a/etc/doall.lua b/etc/doall.lua deleted file mode 100644 index fb0fad702f..0000000000 --- a/etc/doall.lua +++ /dev/null @@ -1,6 +0,0 @@ --- emulate the command line behaviour of Lua 4.0 --- usage: lua doall.lua f1.lua f2.lua f3.lua ... - -for i=1,table.getn(arg) do - dofile(arg[i]) -end diff --git a/etc/lua.magic b/etc/lua.magic deleted file mode 100644 index c7ae595573..0000000000 --- a/etc/lua.magic +++ /dev/null @@ -1,12 +0,0 @@ - -# Lua precompiled files. Versions 2.3 and 4.1 were never officially released. -0 string \33Lua precompiled chunk for Lua ->4 byte 0x23 2.3* ->4 byte 0x24 2.4 ->4 byte 0x25 2.5 ->4 byte 0x30 3.0 ->4 byte 0x31 3.1 ->4 byte 0x32 3.2 ->4 byte 0x40 4.0 ->4 byte 0x41 4.1* ->4 byte 0x50 5.0 diff --git a/etc/lua.xpm b/etc/lua.xpm deleted file mode 100644 index d3dcd379af..0000000000 --- a/etc/lua.xpm +++ /dev/null @@ -1,44 +0,0 @@ -/* XPM */ -static char *magick[] = { -/* columns rows colors chars-per-pixel */ -"32 32 6 1", -" c Gray0", -". c #000000008080", -"X c #808080808080", -"o c #c0c0c0c0c0c0", -"O c Gray100", -"+ c None", -/* pixels */ -"++++++++++++++++++++++++++ooo+++", -"++++++++++++++++++++++++oX...Xo+", -"++++++++++++++++++++++++X.....X+", -"+++++++++++++++++++++++o.......o", -"+++++++++XX......XX++++o.......o", -"+++++++X............X++o.......o", -"+++++o................o+X.....X+", -"++++X..................XoX...Xo+", -"+++X..............XXX...X+ooo+++", -"++o.............XoOOOoX..o++++++", -"++..............oOOOOOo...++++++", -"+X.............XOOOOOOOX..X+++++", -"+..............XOOOOOOOX...+++++", -"X..............XOOOOOOOX...X++++", -"X...............oOOOOOo....X++++", -"................XoOOOoX.....++++", -"....XO............XXX.......++++", -"....XO......................++++", -"....XO.....OX..OX.XOOOo.....++++", -"....XO.....OX..OX.OoXXOX....++++", -"....XO.....OX..OX....XOX....++++", -"X...XO.....OX..OX..OOoOX...X++++", -"X...XO.....OX..OX.OX..OX...X++++", -"+...XOXXXX.OoXoOX.OXXXOX...+++++", -"+X..XOOOOO.XOOXOX.XOOOXo..X+++++", -"++........................++++++", -"++o......................o++++++", -"+++X....................X+++++++", -"++++X..................X++++++++", -"+++++o................o+++++++++", -"+++++++X............X+++++++++++", -"+++++++++XX......XX+++++++++++++" -}; diff --git a/etc/luser_number.h b/etc/luser_number.h deleted file mode 100644 index 8cc2678e50..0000000000 --- a/etc/luser_number.h +++ /dev/null @@ -1,34 +0,0 @@ -/* luser_number.h -- number type configuration for Lua core -* -* #define LUA_USER_H to this file and #define one of USE_* below -*/ - -#ifdef USE_DOUBLE -#define LUA_NUMBER double -#define LUA_NUMBER_SCAN "%lf" -#define LUA_NUMBER_FMT "%.14g" -#endif - -#ifdef USE_FLOAT -#define LUA_NUMBER float -#define LUA_NUMBER_SCAN "%f" -#define LUA_NUMBER_FMT "%.5g" -#endif - -#ifdef USE_LONG -#define LUA_NUMBER long -#define LUA_NUMBER_SCAN "%ld" -#define LUA_NUMBER_FMT "%ld" -#define lua_str2number(s,p) strtol((s), (p), 10) -#endif - -#ifdef USE_INT -#define LUA_NUMBER int -#define LUA_NUMBER_SCAN "%d" -#define LUA_NUMBER_FMT "%d" -#define lua_str2number(s,p) ((int) strtol((s), (p), 10)) -#endif - -#ifdef USE_FASTROUND -#define lua_number2int(i,d) __asm__("fldl %1\nfistpl %0":"=m"(i):"m"(d)) -#endif diff --git a/etc/luser_tests.h b/etc/luser_tests.h deleted file mode 100644 index 1ee6e3fd81..0000000000 --- a/etc/luser_tests.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -** $Id: ltests.h,v 1.20 2002/12/04 17:29:05 roberto Exp $ -** Internal Header for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - -#ifndef ltests_h -#define ltests_h - - -#include - - -#define LUA_DEBUG - -#define LUA_OPNAMES - -#undef NDEBUG -#include -#define lua_assert(c) assert(c) -#define check_exp(c,e) (lua_assert(c), (e)) -#define api_check(L, o) lua_assert(o) - - -/* to avoid warnings, and to make sure value is really unused */ -#define UNUSED(x) (x=0, (void)(x)) - - -/* memory allocator control variables */ -extern unsigned long memdebug_numblocks; -extern unsigned long memdebug_total; -extern unsigned long memdebug_maxmem; -extern unsigned long memdebug_memlimit; - - -#define l_realloc(b, os, s) debug_realloc(b, os, s) -#define l_free(b, os) debug_realloc(b, os, 0) - -void *debug_realloc (void *block, size_t oldsize, size_t size); - - - -/* test for lock/unlock */ -extern int islocked; -#define LUA_USERSTATE int * -#define getlock(l) (*(cast(LUA_USERSTATE *, l) - 1)) -#define lua_userstateopen(l) if (l != NULL) getlock(l) = &islocked; -#define lua_lock(l) lua_assert((*getlock(l))++ == 0) -#define lua_unlock(l) lua_assert(--(*getlock(l)) == 0) - - -int luaB_opentests (lua_State *L); - -#define LUA_EXTRALIBS { "tests", luaB_opentests }, - - -/* real main will be defined at `ltests.c' */ -int l_main (int argc, char *argv[]); -#define main l_main - - - -/* change some sizes to give some bugs a chance */ - -#define LUAL_BUFFERSIZE 27 -#define MINSTRTABSIZE 2 - -#endif diff --git a/etc/min.c b/etc/min.c index 45731c9d5a..bc1c682141 100644 --- a/etc/min.c +++ b/etc/min.c @@ -1,46 +1,37 @@ /* * min.c -- a minimal Lua interpreter -* loads stdin only with minimal error handling. -* no interaction, and no standard library, only a "print" function. +* only dynamic loading is enabled -- all libraries must be dynamically loaded +* no interaction, only batch execution */ #include #include "lua.h" +#include "lualib.h" +#include "lauxlib.h" -static int print(lua_State *L) +static int run(lua_State *L) { - int n=lua_gettop(L); - int i; - for (i=1; i<=n; i++) + char **argv=lua_touserdata(L,1); + lua_register(L,"error",lua_error); + luaopen_loadlib(L); + while (*++argv) { - if (i>1) printf("\t"); - if (lua_isstring(L,i)) - printf("%s",lua_tostring(L,i)); - else if (lua_isnil(L,i)) - printf("%s","nil"); - else if (lua_isboolean(L,i)) - printf("%s",lua_toboolean(L,i) ? "true" : "false"); - else - printf("%s:%p",lua_typename(L,lua_type(L,i)),lua_topointer(L,i)); + if (luaL_loadfile(L,*argv)) lua_error(L); else lua_call(L,0,0); } - printf("\n"); return 0; } -static const char *getF(lua_State *L, void *ud, size_t *size) -{ - FILE *f=(FILE *)ud; - static char buff[512]; - if (feof(f)) return NULL; - *size=fread(buff,1,sizeof(buff),f); - return (*size>0) ? buff : NULL; -} +#define report(s) fprintf(stderr,"%s\n",s) -int main(void) +int main(int argc, char *argv[]) { lua_State *L=lua_open(); - lua_register(L,"print",print); - if (lua_load(L,getF,stdin,"=stdin") || lua_pcall(L,0,0,0)) - fprintf(stderr,"%s\n",lua_tostring(L,-1)); + if (L==NULL) + { + report("not enough memory for state"); + return 1; + } + if (lua_cpcall(L,run,argv)) report(lua_tostring(L,-1)); + lua_close(L); return 0; } diff --git a/etc/noparser.c b/etc/noparser.c index 00c2b12625..9d52f7c0c6 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -17,10 +17,24 @@ void luaX_init (lua_State *L) { UNUSED(L); } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { UNUSED(z); UNUSED(buff); lua_pushstring(L,"parser not loaded"); lua_error(L); return NULL; } + +/* +* If you also want to avoid the dump module, ldump.o, enable the code below. +*/ +#ifdef NODUMP +#include "lundump.h" + +int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip) +{ + return 0; + lua_pushstring(L,"dumper not loaded"); + lua_error(L); +} +#endif diff --git a/etc/saconfig.c b/etc/saconfig.c index bf3c64b701..6c07cce102 100644 --- a/etc/saconfig.c +++ b/etc/saconfig.c @@ -1,10 +1,10 @@ -/* sa-config.c -- configuration for stand-alone Lua interpreter +/* saconfig.c -- configuration for stand-alone Lua interpreter * * #define LUA_USERCONFIG to this file * * Here are the features that can be customized using #define: * -*** Line edit and history: +*** Line editing and history: * #define USE_READLINE to use the GNU readline library. * * To use another library for this, use the code below as a start. diff --git a/etc/trace.c b/etc/trace.c deleted file mode 100644 index c29f1c9d17..0000000000 --- a/etc/trace.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -* trace.c -- a simple execution tracer for Lua -*/ - -#include -#include -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" - -static FILE* LOG; /* log file */ -static int I=0; /* indentation level */ - -static void hook(lua_State *L, lua_Debug *ar) -{ - const char* s=""; - switch (ar->event) - { - case LUA_HOOKTAILRET: ar->event=LUA_HOOKRET; - case LUA_HOOKRET: s="return"; break; - case LUA_HOOKCALL: s="call"; break; - case LUA_HOOKLINE: s="line"; break; - default: break; - } - fprintf(LOG,"[%d]\t%*s%s\t-- %d\n",I,I,"",s,ar->currentline); - if (ar->event==LUA_HOOKCALL) ++I; else if (ar->event==LUA_HOOKRET) --I; -} - -static void start_trace(lua_State *L, FILE* logfile) -{ - lua_sethook(L,hook,LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 0); - LOG=logfile; -} - -static void stop_trace(lua_State *L) -{ - lua_sethook(L,NULL,0,0); - fclose(LOG); -} - -int main(void) -{ - int rc; - lua_State *L=lua_open(); - lua_baselibopen(L); - lua_tablibopen(L); - lua_iolibopen(L); - lua_strlibopen(L); - lua_mathlibopen(L); - lua_dblibopen(L); - start_trace(L,stderr); - rc=lua_dofile(L,NULL); - stop_trace(L); - return rc; -} diff --git a/include/RCS b/include/RCS new file mode 120000 index 0000000000..1ae3893605 --- /dev/null +++ b/include/RCS @@ -0,0 +1 @@ +../RCS \ No newline at end of file diff --git a/include/lauxlib.h b/include/lauxlib.h index 450e16c720..58f250052d 100644 --- a/include/lauxlib.h +++ b/include/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.60 2003/04/03 13:35:34 roberto Exp $ +** $Id: lauxlib.h,v 1.63 2004/03/13 13:32:09 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -39,6 +39,10 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int numArg, LUALIB_API lua_Number luaL_checknumber (lua_State *L, int numArg); LUALIB_API lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number def); +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int numArg); +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int nArg, + lua_Integer def); + LUALIB_API void luaL_checkstack (lua_State *L, int sz, const char *msg); LUALIB_API void luaL_checktype (lua_State *L, int narg, int t); LUALIB_API void luaL_checkany (lua_State *L, int narg); @@ -62,6 +66,8 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename); LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name); +LUALIB_API lua_State *(luaL_newstate) (void); + /* @@ -70,14 +76,14 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, ** =============================================================== */ -#define luaL_argcheck(L, cond,numarg,extramsg) if (!(cond)) \ - luaL_argerror(L, numarg,extramsg) +#define luaL_argcheck(L, cond,numarg,extramsg) \ + ((void)((cond) || luaL_argerror(L, numarg,extramsg))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) -#define luaL_checkint(L,n) ((int)luaL_checknumber(L, n)) -#define luaL_checklong(L,n) ((long)luaL_checknumber(L, n)) -#define luaL_optint(L,n,d) ((int)luaL_optnumber(L, n,(lua_Number)(d))) -#define luaL_optlong(L,n,d) ((long)luaL_optnumber(L, n,(lua_Number)(d))) +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, n)) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, n,d)) +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, n)) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, n,d)) /* @@ -127,19 +133,6 @@ LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t sz, const char *n); -#define luaL_check_lstr luaL_checklstring -#define luaL_opt_lstr luaL_optlstring -#define luaL_check_number luaL_checknumber -#define luaL_opt_number luaL_optnumber -#define luaL_arg_check luaL_argcheck -#define luaL_check_string luaL_checkstring -#define luaL_opt_string luaL_optstring -#define luaL_check_int luaL_checkint -#define luaL_check_long luaL_checklong -#define luaL_opt_int luaL_optint -#define luaL_opt_long luaL_optlong - - #endif diff --git a/include/lua.h b/include/lua.h index 88b0191e9a..bcb37a0608 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.175b 2003/03/18 12:31:39 roberto Exp $ +** $Id: lua.h,v 1.187 2004/03/09 17:34:35 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -14,11 +14,13 @@ #include -#define LUA_VERSION "Lua 5.0.2" +#define LUA_VERSION "Lua 5.1 (work)" #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" +/* mark for precompiled code (`Lua') */ +#define LUA_SIGNATURE "\033Lua" /* option for multiple returns in `lua_pcall' and `lua_call' */ #define LUA_MULTRET (-1) @@ -54,6 +56,12 @@ typedef int (*lua_Chunkwriter) (lua_State *L, const void* p, size_t sz, void* ud); +/* +** prototype for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + /* ** basic types */ @@ -90,6 +98,14 @@ typedef LUA_NUMBER lua_Number; #endif +/* type for integer functions */ +#ifndef LUA_INTEGER +typedef long lua_Integer; +#else +typedef LUA_INTEGER lua_Integer; +#endif + + /* mark for all API functions */ #ifndef LUA_API #define LUA_API extern @@ -99,7 +115,7 @@ typedef LUA_NUMBER lua_Number; /* ** state manipulation */ -LUA_API lua_State *lua_open (void); +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud); LUA_API void lua_close (lua_State *L); LUA_API lua_State *lua_newthread (lua_State *L); @@ -136,6 +152,7 @@ LUA_API int lua_rawequal (lua_State *L, int idx1, int idx2); LUA_API int lua_lessthan (lua_State *L, int idx1, int idx2); LUA_API lua_Number lua_tonumber (lua_State *L, int idx); +LUA_API lua_Integer lua_tointeger (lua_State *L, int idx); LUA_API int lua_toboolean (lua_State *L, int idx); LUA_API const char *lua_tostring (lua_State *L, int idx); LUA_API size_t lua_strlen (lua_State *L, int idx); @@ -150,6 +167,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx); */ LUA_API void lua_pushnil (lua_State *L); LUA_API void lua_pushnumber (lua_State *L, lua_Number n); +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n); LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t l); LUA_API void lua_pushstring (lua_State *L, const char *s); LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, @@ -164,9 +182,10 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p); ** get functions (Lua -> stack) */ LUA_API void lua_gettable (lua_State *L, int idx); +LUA_API void lua_getfield (lua_State *L, int idx, const char *k); LUA_API void lua_rawget (lua_State *L, int idx); LUA_API void lua_rawgeti (lua_State *L, int idx, int n); -LUA_API void lua_newtable (lua_State *L); +LUA_API void lua_createtable (lua_State *L, int narr, int nrec); LUA_API void *lua_newuserdata (lua_State *L, size_t sz); LUA_API int lua_getmetatable (lua_State *L, int objindex); LUA_API void lua_getfenv (lua_State *L, int idx); @@ -176,6 +195,7 @@ LUA_API void lua_getfenv (lua_State *L, int idx); ** set functions (stack -> Lua) */ LUA_API void lua_settable (lua_State *L, int idx); +LUA_API void lua_setfield (lua_State *L, int idx, const char *k); LUA_API void lua_rawset (lua_State *L, int idx); LUA_API void lua_rawseti (lua_State *L, int idx, int n); LUA_API int lua_setmetatable (lua_State *L, int objindex); @@ -201,11 +221,16 @@ LUA_API int lua_yield (lua_State *L, int nresults); LUA_API int lua_resume (lua_State *L, int narg); /* -** garbage-collection functions +** garbage-collection function and options */ -LUA_API int lua_getgcthreshold (lua_State *L); -LUA_API int lua_getgccount (lua_State *L); -LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold); + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 + +LUA_API int lua_gc (lua_State *L, int what, int data); + /* ** miscellaneous functions @@ -219,6 +244,8 @@ LUA_API int lua_next (lua_State *L, int idx); LUA_API void lua_concat (lua_State *L, int n); +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud); + /* @@ -234,10 +261,9 @@ LUA_API void lua_concat (lua_State *L, int n); #define lua_pop(L,n) lua_settop(L, -(n)-1) -#define lua_register(L,n,f) \ - (lua_pushstring(L, n), \ - lua_pushcfunction(L, f), \ - lua_settable(L, LUA_GLOBALSINDEX)) +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L,f), lua_setglobal(L,n)) #define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) @@ -246,27 +272,27 @@ LUA_API void lua_concat (lua_State *L, int n); #define lua_islightuserdata(L,n) (lua_type(L,n) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L,n) == LUA_TNIL) #define lua_isboolean(L,n) (lua_type(L,n) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L,n) == LUA_TTHREAD) #define lua_isnone(L,n) (lua_type(L,n) == LUA_TNONE) #define lua_isnoneornil(L, n) (lua_type(L,n) <= 0) #define lua_pushliteral(L, s) \ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) +#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, s) +#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s) + /* ** compatibility macros and functions */ - -LUA_API int lua_pushupvalues (lua_State *L); +#define lua_open() luaL_newstate() #define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) -#define lua_setglobal(L,s) \ - (lua_pushstring(L, s), lua_insert(L, -2), lua_settable(L, LUA_GLOBALSINDEX)) -#define lua_getglobal(L,s) \ - (lua_pushstring(L, s), lua_gettable(L, LUA_GLOBALSINDEX)) +#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) /* compatibility with ref system */ diff --git a/src/Makefile b/src/Makefile index bf64c03f08..7812b9188f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,6 @@ OBJS= \ lstate.o \ lstring.o \ ltable.o \ - ltests.o \ ltm.o \ lundump.o \ lvm.o \ @@ -42,7 +41,6 @@ SRCS= \ lstate.c \ lstring.c \ ltable.c \ - ltests.c \ ltm.c \ lundump.c \ lvm.c \ diff --git a/src/RCS b/src/RCS new file mode 120000 index 0000000000..1ae3893605 --- /dev/null +++ b/src/RCS @@ -0,0 +1 @@ +../RCS \ No newline at end of file diff --git a/src/lapi.c b/src/lapi.c index d5dd9ca465..1b086a0b8d 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,11 +1,12 @@ /* -** $Id: lapi.c,v 1.235 2003/04/07 14:36:08 roberto Exp $ +** $Id: lapi.c,v 2.5 2004/03/23 17:07:34 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include +#include #include #define lapi_c @@ -27,6 +28,12 @@ #include "lvm.h" +/* function to convert a lua_Number to lua_Integer (with any rounding method) */ +#ifndef lua_number2integer +#define lua_number2integer(i,n) ((i)=(lua_Integer)(n)) +#endif + + const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" "$Authors: " LUA_AUTHORS " $\n" @@ -35,63 +42,44 @@ const char lua_ident[] = #ifndef api_check -#define api_check(L, o) /*{ assert(o); }*/ +#define api_check(L, o) lua_assert(o) #endif #define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} +#define api_checkvalidindex(L, i) api_check(L, (i) != &luaO_nilobject) +#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} -static TObject *negindex (lua_State *L, int idx) { - if (idx > LUA_REGISTRYINDEX) { +static TValue *luaA_index (lua_State *L, int idx) { + if (idx > 0) { + TValue *o = L->base + (idx - 1); + api_check(L, idx <= L->stack_last - L->base); + if (o >= L->top) return cast(TValue *, &luaO_nilobject); + else return o; + } + else if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); - return L->top+idx; + return L->top + idx; } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_GLOBALSINDEX: return gt(L); default: { - TObject *func = (L->base - 1); + Closure *func = curr_func(L); idx = LUA_GLOBALSINDEX - idx; - lua_assert(iscfunction(func)); - return (idx <= clvalue(func)->c.nupvalues) - ? &clvalue(func)->c.upvalue[idx-1] - : NULL; + return (idx <= func->c.nupvalues) + ? &func->c.upvalue[idx-1] + : cast(TValue *, &luaO_nilobject); } } } -static TObject *luaA_index (lua_State *L, int idx) { - if (idx > 0) { - api_check(L, idx <= L->top - L->base); - return L->base + idx - 1; - } - else { - TObject *o = negindex(L, idx); - api_check(L, o != NULL); - return o; - } -} - - -static TObject *luaA_indexAcceptable (lua_State *L, int idx) { - if (idx > 0) { - TObject *o = L->base+(idx-1); - api_check(L, idx <= L->stack_last - L->base); - if (o >= L->top) return NULL; - else return o; - } - else - return negindex(L, idx); -} - - -void luaA_pushobject (lua_State *L, const TObject *o) { - setobj2s(L->top, o); +void luaA_pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); incr_top(L); } @@ -114,11 +102,12 @@ LUA_API int lua_checkstack (lua_State *L, int size) { LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { int i; + if (from == to) return; lua_lock(to); api_checknelems(from, n); from->top -= n; for (i = 0; i < n; i++) { - setobj2s(to->top, from->top + i); + setobj2s(to, to->top, from->top + i); api_incr_top(to); } lua_unlock(to); @@ -140,7 +129,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { lua_lock(L); luaC_checkGC(L); L1 = luaE_newthread(L); - setthvalue(L->top, L1); + setthvalue(L, L->top, L1); api_incr_top(L); lua_unlock(L); lua_userstateopen(L1); @@ -179,7 +168,8 @@ LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); p = luaA_index(L, idx); - while (++p < L->top) setobjs2s(p-1, p); + api_checkvalidindex(L, p); + while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); } @@ -190,16 +180,22 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId q; lua_lock(L); p = luaA_index(L, idx); - for (q = L->top; q>p; q--) setobjs2s(q, q-1); - setobjs2s(p, L->top); + api_checkvalidindex(L, p); + for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + setobjs2s(L, p, L->top); lua_unlock(L); } LUA_API void lua_replace (lua_State *L, int idx) { + StkId o; lua_lock(L); api_checknelems(L, 1); - setobj(luaA_index(L, idx), L->top - 1); /* write barrier */ + o = luaA_index(L, idx); + api_checkvalidindex(L, o); + setobj(L, o, L->top - 1); + if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), L->top - 1); L->top--; lua_unlock(L); } @@ -207,7 +203,7 @@ LUA_API void lua_replace (lua_State *L, int idx) { LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); - setobj2s(L->top, luaA_index(L, idx)); + setobj2s(L, L->top, luaA_index(L, idx)); api_incr_top(L); lua_unlock(L); } @@ -220,8 +216,8 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? LUA_TNONE : ttype(o); + StkId o = luaA_index(L, idx); + return (o == &luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -232,15 +228,15 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? 0 : iscfunction(o); + StkId o = luaA_index(L, idx); + return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && tonumber(o, &n)); + TValue n; + const TValue *o = luaA_index(L, idx); + return tonumber(o, &n); } @@ -251,16 +247,16 @@ LUA_API int lua_isstring (lua_State *L, int idx) { LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && (ttisuserdata(o) || ttislightuserdata(o))); + const TValue *o = luaA_index(L, idx); + return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = luaA_indexAcceptable(L, index1); - StkId o2 = luaA_indexAcceptable(L, index2); - return (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : luaO_rawequalObj(o1, o2); + StkId o1 = luaA_index(L, index1); + StkId o2 = luaA_index(L, index2); + return (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + : luaO_rawequalObj(o1, o2); } @@ -268,10 +264,10 @@ LUA_API int lua_equal (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : equalobj(L, o1, o2); + o1 = luaA_index(L, index1); + o2 = luaA_index(L, index2); + i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + : equalobj(L, o1, o2); lua_unlock(L); return i; } @@ -281,10 +277,10 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out-of-range */ - : luaV_lessthan(L, o1, o2); + o1 = luaA_index(L, index1); + o2 = luaA_index(L, index2); + i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); lua_unlock(L); return i; } @@ -292,26 +288,37 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - if (o != NULL && tonumber(o, &n)) + TValue n; + const TValue *o = luaA_index(L, idx); + if (tonumber(o, &n)) return nvalue(o); else return 0; } +LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { + TValue n; + const TValue *o = luaA_index(L, idx); + if (tonumber(o, &n)) { + lua_Integer res; + lua_number2integer(res, nvalue(o)); + return res; + } + else + return 0; +} + + LUA_API int lua_toboolean (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL) && !l_isfalse(o); + const TValue *o = luaA_index(L, idx); + return !l_isfalse(o); } LUA_API const char *lua_tostring (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return NULL; - else if (ttisstring(o)) + StkId o = luaA_index(L, idx); + if (ttisstring(o)) return svalue(o); else { const char *s; @@ -325,15 +332,13 @@ LUA_API const char *lua_tostring (lua_State *L, int idx) { LUA_API size_t lua_strlen (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return 0; - else if (ttisstring(o)) - return tsvalue(o)->tsv.len; + StkId o = luaA_index(L, idx); + if (ttisstring(o)) + return tsvalue(o)->len; else { size_t l; lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) ? tsvalue(o)->tsv.len : 0); + l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); lua_unlock(L); return l; } @@ -341,16 +346,15 @@ LUA_API size_t lua_strlen (lua_State *L, int idx) { LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->c.f; + StkId o = luaA_index(L, idx); + return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; + StkId o = luaA_index(L, idx); switch (ttype(o)) { - case LUA_TUSERDATA: return (uvalue(o) + 1); + case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } @@ -358,24 +362,21 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) { LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o); + StkId o = luaA_index(L, idx); + return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; - else { - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(o); - case LUA_TFUNCTION: return clvalue(o); - case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); - default: return NULL; - } + StkId o = luaA_index(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TFUNCTION: return clvalue(o); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return NULL; } } @@ -402,10 +403,18 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { } +LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { + lua_lock(L); + setnvalue(L->top, cast(lua_Number, n)); + api_incr_top(L); + lua_unlock(L); +} + + LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { lua_lock(L); luaC_checkGC(L); - setsvalue2s(L->top, luaS_newlstr(L, s, len)); + setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); api_incr_top(L); lua_unlock(L); } @@ -452,8 +461,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { cl->c.f = fn; L->top -= n; while (n--) - setobj2n(&cl->c.upvalue[n], L->top+n); - setclvalue(L->top, cl); + setobj2n(L, &cl->c.upvalue[n], L->top+n); + setclvalue(L, L->top, cl); + lua_assert(iswhite(obj2gco(cl))); api_incr_top(L); lua_unlock(L); } @@ -485,7 +495,21 @@ LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = luaA_index(L, idx); - setobj2s(L->top - 1, luaV_gettable(L, t, L->top - 1, 0)); + api_checkvalidindex(L, t); + luaV_gettable(L, t, L->top - 1, L->top - 1); + lua_unlock(L); +} + + +LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + t = luaA_index(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_gettable(L, t, &key, L->top); + api_incr_top(L); lua_unlock(L); } @@ -495,7 +519,7 @@ LUA_API void lua_rawget (lua_State *L, int idx) { lua_lock(L); t = luaA_index(L, idx); api_check(L, ttistable(t)); - setobj2s(L->top - 1, luaH_get(hvalue(t), L->top - 1)); + setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } @@ -505,41 +529,39 @@ LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { lua_lock(L); o = luaA_index(L, idx); api_check(L, ttistable(o)); - setobj2s(L->top, luaH_getnum(hvalue(o), n)); + setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); lua_unlock(L); } -LUA_API void lua_newtable (lua_State *L) { +LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { lua_lock(L); luaC_checkGC(L); - sethvalue(L->top, luaH_new(L, 0, 0)); + sethvalue(L, L->top, luaH_new(L, narray, luaO_log2(nrec) + 1)); api_incr_top(L); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { - const TObject *obj; + const TValue *obj; Table *mt = NULL; int res; lua_lock(L); - obj = luaA_indexAcceptable(L, objindex); - if (obj != NULL) { - switch (ttype(obj)) { - case LUA_TTABLE: - mt = hvalue(obj)->metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj)->uv.metatable; - break; - } + obj = luaA_index(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj)->metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj)->metatable; + break; } - if (mt == NULL || mt == hvalue(defaultmeta(L))) + if (mt == NULL) res = 0; else { - sethvalue(L->top, mt); + sethvalue(L, L->top, mt); api_incr_top(L); res = 1; } @@ -552,7 +574,8 @@ LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); o = luaA_index(L, idx); - setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); + api_checkvalidindex(L, o); + setobj2s(L, L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); api_incr_top(L); lua_unlock(L); } @@ -568,19 +591,35 @@ LUA_API void lua_settable (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 2); t = luaA_index(L, idx); + api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); } +LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + StkId t; + TValue key; + lua_lock(L); + api_checknelems(L, 1); + t = luaA_index(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, &key, luaS_new(L, k)); + luaV_settable(L, t, &key, L->top - 1); + L->top--; /* pop value */ + lua_unlock(L); +} + + LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = luaA_index(L, idx); api_check(L, ttistable(t)); - setobj2t(luaH_set(L, hvalue(t), L->top-2), L->top-1); /* write barrier */ + setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); + luaC_barrier(L, hvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } @@ -592,27 +631,38 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { api_checknelems(L, 1); o = luaA_index(L, idx); api_check(L, ttistable(o)); - setobj2t(luaH_setnum(L, hvalue(o), n), L->top-1); /* write barrier */ + setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + luaC_barrier(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TObject *obj, *mt; + TValue *obj; + Table *mt; int res = 1; lua_lock(L); api_checknelems(L, 1); obj = luaA_index(L, objindex); - mt = (!ttisnil(L->top - 1)) ? L->top - 1 : defaultmeta(L); - api_check(L, ttistable(mt)); + api_checkvalidindex(L, obj); + if (ttisnil(L->top - 1)) + mt = NULL; + else { + api_check(L, ttistable(L->top - 1)); + mt = hvalue(L->top - 1); + } switch (ttype(obj)) { case LUA_TTABLE: { - hvalue(obj)->metatable = hvalue(mt); /* write barrier */ + hvalue(obj)->metatable = mt; + if (mt) + luaC_objbarrier(L, hvalue(obj), mt); break; } case LUA_TUSERDATA: { - uvalue(obj)->uv.metatable = hvalue(mt); /* write barrier */ + uvalue(obj)->metatable = mt; + if (mt) + luaC_objbarrier(L, rawuvalue(obj), mt); break; } default: { @@ -632,6 +682,7 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 1); o = luaA_index(L, idx); + api_checkvalidindex(L, o); L->top--; api_check(L, ttistable(L->top)); if (isLfunction(o)) { @@ -679,7 +730,13 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { int status; ptrdiff_t func; lua_lock(L); - func = (errfunc == 0) ? 0 : savestack(L, luaA_index(L, errfunc)); + if (errfunc == 0) + func = 0; + else { + StkId o = luaA_index(L, errfunc); + api_checkvalidindex(L, o); + func = savestack(L, o); + } c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); @@ -702,7 +759,7 @@ static void f_Ccall (lua_State *L, void *ud) { Closure *cl; cl = luaF_newCclosure(L, 0); cl->c.f = c->func; - setclvalue(L->top, cl); /* push function */ + setclvalue(L, L->top, cl); /* push function */ incr_top(L); setpvalue(L->top, c->ud); /* push only argument */ incr_top(L); @@ -726,12 +783,10 @@ LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, const char *chunkname) { ZIO z; int status; - int c; lua_lock(L); if (!chunkname) chunkname = "?"; - luaZ_init(&z, reader, data, chunkname); - c = luaZ_lookahead(&z); - status = luaD_protectedparser(L, &z, (c == LUA_SIGNATURE[0])); + luaZ_init(L, &z, reader, data); + status = luaD_protectedparser(L, &z, chunkname); lua_unlock(L); return status; } @@ -739,14 +794,12 @@ LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { int status; - TObject *o; + TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; - if (isLfunction(o) && clvalue(o)->l.nupvalues == 0) { - luaU_dump(L, clvalue(o)->l.p, writer, data); - status = 1; - } + if (isLfunction(o)) + status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); else status = 0; lua_unlock(L); @@ -755,39 +808,34 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { /* -** Garbage-collection functions +** Garbage-collection function */ -/* GC values are expressed in Kbytes: #bytes/2^10 */ -#define GCscalel(x) ((x)>>10) -#define GCscale(x) (cast(int, GCscalel(x))) -#define GCunscale(x) (cast(lu_mem, x)<<10) - -LUA_API int lua_getgcthreshold (lua_State *L) { - int threshold; - lua_lock(L); - threshold = GCscale(G(L)->GCthreshold); - lua_unlock(L); - return threshold; +LUA_API int lua_gc (lua_State *L, int what, int data) { + global_State *g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->GCthreshold = MAXLMEM; + return 0; + } + case LUA_GCRESTART: { + g->GCthreshold = g->nblocks; + return 0; + } + case LUA_GCCOLLECT: { + lua_lock(L); + luaC_fullgc(L); + lua_unlock(L); + return 0; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + return cast(int, g->nblocks >> 10); + } + default: return -1; /* invalid option */ + } } -LUA_API int lua_getgccount (lua_State *L) { - int count; - lua_lock(L); - count = GCscale(G(L)->nblocks); - lua_unlock(L); - return count; -} - -LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { - lua_lock(L); - if (cast(lu_mem, newthreshold) > GCscalel(MAX_LUMEM)) - G(L)->GCthreshold = MAX_LUMEM; - else - G(L)->GCthreshold = GCunscale(newthreshold); - luaC_checkGC(L); - lua_unlock(L); -} /* @@ -835,7 +883,7 @@ LUA_API void lua_concat (lua_State *L, int n) { L->top -= (n-1); } else if (n == 0) { /* push empty string */ - setsvalue2s(L->top, luaS_newlstr(L, NULL, 0)); + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); api_incr_top(L); } /* else n == 1; nothing to do */ @@ -843,39 +891,28 @@ LUA_API void lua_concat (lua_State *L, int n) { } +LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + *ud = G(L)->ud; + return G(L)->realloc; +} + + LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); u = luaS_newudata(L, size); - setuvalue(L->top, u); + setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); return u + 1; } -LUA_API int lua_pushupvalues (lua_State *L) { - Closure *func; - int n, i; - lua_lock(L); - api_check(L, iscfunction(L->base - 1)); - func = clvalue(L->base - 1); - n = func->c.nupvalues; - luaD_checkstack(L, n + LUA_MINSTACK); - for (i=0; itop, &func->c.upvalue[i]); - L->top++; - } - lua_unlock(L); - return n; -} -static const char *aux_upvalue (lua_State *L, int funcindex, int n, - TObject **val) { +static const char *aux_upvalue (lua_State *L, StkId fi, int n, TValue **val) { Closure *f; - StkId fi = luaA_index(L, funcindex); if (!ttisfunction(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { @@ -894,11 +931,11 @@ static const char *aux_upvalue (lua_State *L, int funcindex, int n, LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; - TObject *val; + TValue *val; lua_lock(L); - name = aux_upvalue(L, funcindex, n, &val); + name = aux_upvalue(L, luaA_index(L, funcindex), n, &val); if (name) { - setobj2s(L->top, val); + setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); @@ -908,13 +945,16 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; - TObject *val; + TValue *val; + StkId fi; lua_lock(L); + fi = luaA_index(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(L, funcindex, n, &val); + name = aux_upvalue(L, fi, n, &val); if (name) { L->top--; - setobj(val, L->top); /* write barrier */ + setobj(L, val, L->top); + luaC_barrier(L, clvalue(fi), L->top); } lua_unlock(L); return name; diff --git a/src/lapi.h b/src/lapi.h index d12612f304..0ff8beb641 100644 --- a/src/lapi.h +++ b/src/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 1.21 2002/03/04 21:29:41 roberto Exp $ +** $Id: lapi.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -11,6 +11,6 @@ #include "lobject.h" -void luaA_pushobject (lua_State *L, const TObject *o); +void luaA_pushobject (lua_State *L, const TValue *o); #endif diff --git a/src/lcode.c b/src/lcode.c index d626ecd60e..de6939bb48 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 1.117 2003/04/03 13:35:34 roberto Exp $ +** $Id: lcode.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "lcode.h" #include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" @@ -88,7 +89,7 @@ static int luaK_getjump (FuncState *fs, int pc) { static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT)) + if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) return pi-1; else return pi; @@ -206,41 +207,46 @@ static void freeexp (FuncState *fs, expdesc *e) { } -static int addk (FuncState *fs, TObject *k, TObject *v) { - const TObject *idx = luaH_get(fs->h, k); +static int addk (FuncState *fs, TValue *k, TValue *v) { + lua_State *L = fs->L; + TValue *idx = luaH_set(L, fs->h, k); + Proto *f = fs->f; + int oldsize = f->sizek; if (ttisnumber(idx)) { lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v)); return cast(int, nvalue(idx)); } else { /* constant not found; create a new entry */ - Proto *f = fs->f; - luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject, + setnvalue(idx, cast(lua_Number, fs->nk)); + luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, MAXARG_Bx, "constant table overflow"); - setobj2n(&f->k[fs->nk], v); - setnvalue(luaH_set(fs->L, fs->h, k), cast(lua_Number, fs->nk)); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[fs->nk], v); + luaC_barrier(L, f, v); return fs->nk++; } } int luaK_stringK (FuncState *fs, TString *s) { - TObject o; - setsvalue(&o, s); + TValue o; + setsvalue(fs->L, &o, s); return addk(fs, &o, &o); } int luaK_numberK (FuncState *fs, lua_Number r) { - TObject o; + TValue o; setnvalue(&o, r); return addk(fs, &o, &o); } static int nil_constant (FuncState *fs) { - TObject k, v; + TValue k, v; setnilvalue(&v); - sethvalue(&k, fs->h); /* cannot use nil as key; instead use table itself */ + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs->L, &k, fs->h); return addk(fs, &k, &v); } @@ -416,25 +422,25 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { } -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { - freeexp(fs, exp); - luaK_exp2reg(fs, exp, var->info); + freeexp(fs, ex); + luaK_exp2reg(fs, ex, var->info); return; } case VUPVAL: { - int e = luaK_exp2anyreg(fs, exp); + int e = luaK_exp2anyreg(fs, ex); luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0); break; } case VGLOBAL: { - int e = luaK_exp2anyreg(fs, exp); + int e = luaK_exp2anyreg(fs, ex); luaK_codeABx(fs, OP_SETGLOBAL, e, var->info); break; } case VINDEXED: { - int e = luaK_exp2RK(fs, exp); + int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e); break; } @@ -443,7 +449,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { break; } } - freeexp(fs, exp); + freeexp(fs, ex); } @@ -462,8 +468,7 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { static void invertjump (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->info); - lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) && - GET_OPCODE(*pc) != OP_TEST); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } @@ -703,12 +708,15 @@ int luaK_code (FuncState *fs, Instruction i, int line) { int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); } int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); } diff --git a/src/ldebug.c b/src/ldebug.c index 8e511e3bd9..42080ccde6 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,13 +1,15 @@ /* -** $Id: ldebug.c,v 1.150 2003/03/19 21:24:04 roberto Exp $ +** $Id: ldebug.c,v 2.3 2004/03/23 13:10:16 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ -#include +#include +#include #include + #define ldebug_c #include "lua.h" @@ -30,14 +32,8 @@ static const char *getfuncname (CallInfo *ci, const char **name); -#define isLua(ci) (!((ci)->state & CI_C)) - - static int currentpc (CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ - if (ci->state & CI_HASFRAME) /* function has a frame? */ - ci->u.l.savedpc = *ci->u.l.pc; /* use `pc' from there */ - /* function's pc is saved */ return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); } @@ -51,14 +47,6 @@ static int currentline (CallInfo *ci) { } -void luaG_inithooks (lua_State *L) { - CallInfo *ci; - for (ci = L->ci; ci != L->base_ci; ci--) /* update all `savedpc's */ - currentpc(ci); - L->hookinit = 1; -} - - /* ** this function can be called asynchronous (e.g. during a signal) */ @@ -71,7 +59,6 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { L->basehookcount = count; resethookcount(L); L->hookmask = cast(lu_byte, mask); - L->hookinit = 0; return 1; } @@ -97,7 +84,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { lua_lock(L); for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { level--; - if (!(ci->state & CI_C)) /* Lua function? */ + if (f_isLua(ci)) /* Lua function? */ level -= ci->u.l.tailcalls; /* skip lost tail calls */ } if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ @@ -151,7 +138,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { if (!name || name[0] == '(') /* `(' starts private locals */ name = NULL; else - setobjs2s(ci->base+(n-1), L->top); + setobjs2s(L, ci->base+(n-1), L->top); } lua_unlock(L); return name; @@ -174,18 +161,6 @@ static void funcinfo (lua_Debug *ar, StkId func) { } -static const char *travglobals (lua_State *L, const TObject *o) { - Table *g = hvalue(gt(L)); - int i = sizenode(g); - while (i--) { - Node *n = gnode(g, i); - if (luaO_rawequalObj(o, gval(n)) && ttisstring(gkey(n))) - return getstr(tsvalue(gkey(n))); - } - return NULL; -} - - static void info_tailcall (lua_State *L, lua_Debug *ar) { ar->name = ar->namewhat = ""; ar->what = "tail"; @@ -217,15 +192,13 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, case 'n': { ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; if (ar->namewhat == NULL) { - /* try to find a global name */ - if ((ar->name = travglobals(L, f)) != NULL) - ar->namewhat = "global"; - else ar->namewhat = ""; /* not found */ + ar->namewhat = ""; /* not found */ + ar->name = NULL; } break; } case 'f': { - setobj2s(L->top, f); + setobj2s(L, L->top, f); break; } default: status = 0; /* invalid option */ @@ -296,8 +269,16 @@ static int checkopenop (const Proto *pt, int pc) { } -static int checkRK (const Proto *pt, int r) { - return (r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); +static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { + switch (mode) { + case OpArgN: check(r == 0); break; + case OpArgU: break; + case OpArgR: checkreg(pt, r); break; + case OpArgK: + check(r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); + break; + } + return 1; } @@ -312,34 +293,34 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { int a = GETARG_A(i); int b = 0; int c = 0; + check(op < NUM_OPCODES); checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); - if (testOpMode(op, OpModeBreg)) { - checkreg(pt, b); - } - else if (testOpMode(op, OpModeBrk)) - check(checkRK(pt, b)); - if (testOpMode(op, OpModeCrk)) - check(checkRK(pt, c)); + check(checkArgMode(pt, b, getBMode(op))); + check(checkArgMode(pt, c, getCMode(op))); break; } case iABx: { b = GETARG_Bx(i); - if (testOpMode(op, OpModeK)) check(b < pt->sizek); + if (getBMode(op) == OpArgK) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); + if (getBMode(op) == OpArgR) { + int dest = pc+1+b; + check(0 <= dest && dest < pt->sizecode); + } break; } } - if (testOpMode(op, OpModesetA)) { + if (testAMode(op)) { if (a == reg) last = pc; /* change register `a' */ } - if (testOpMode(op, OpModeT)) { + if (testTMode(op)) { check(pc+2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); } @@ -369,20 +350,21 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_CONCAT: { - /* `c' is a register, and at least two operands */ - check(c < MAXSTACK && b < c); + check(b < c); /* at least two operands */ break; } - case OP_TFORLOOP: - checkreg(pt, a+c+5); + case OP_TFORLOOP: { + checkreg(pt, a+5); /* space for control variables */ if (reg >= a) last = pc; /* affect all registers above base */ - /* go through */ + break; + } + case OP_TFORPREP: case OP_FORLOOP: - checkreg(pt, a+2); + case OP_FORPREP: + checkreg(pt, a+3); /* go through */ case OP_JMP: { int dest = pc+1+b; - check(0 <= dest && dest < pt->sizecode); /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ @@ -436,7 +418,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { int luaG_checkcode (const Proto *pt) { - return luaG_symbexec(pt, pt->sizecode, NO_REG); + return (luaG_symbexec(pt, pt->sizecode, NO_REG) != 0); } @@ -478,6 +460,11 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { *name = kname(p, k); return "field"; } + case OP_GETUPVAL: { + int u = GETARG_B(i); /* upvalue index */ + *name = getstr(p->upvalues[u]); + return "upvalue"; + } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); @@ -504,7 +491,7 @@ static const char *getfuncname (CallInfo *ci, const char **name) { /* only ANSI way to check whether a pointer points to an array */ -static int isinstack (CallInfo *ci, const TObject *o) { +static int isinstack (CallInfo *ci, const TValue *o) { StkId p; for (p = ci->base; p < ci->top; p++) if (o == p) return 1; @@ -512,7 +499,7 @@ static int isinstack (CallInfo *ci, const TObject *o) { } -void luaG_typeerror (lua_State *L, const TObject *o, const char *op) { +void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? @@ -532,15 +519,15 @@ void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { } -void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2) { - TObject temp; +void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { + TValue temp; if (luaV_tonumber(p1, &temp) == NULL) p2 = p1; /* first operand is wrong */ luaG_typeerror(L, p2, "perform arithmetic on"); } -int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) { +int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = luaT_typenames[ttype(p1)]; const char *t2 = luaT_typenames[ttype(p2)]; if (t1[2] == t2[2]) @@ -566,8 +553,8 @@ void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); - setobjs2s(L->top, L->top - 1); /* move argument */ - setobjs2s(L->top - 1, errfunc); /* push function */ + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } diff --git a/src/ldebug.h b/src/ldebug.h index 7ff395839c..d7163f2da4 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 1.32 2002/11/18 11:01:55 roberto Exp $ +** $Id: ldebug.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -18,11 +18,10 @@ #define resethookcount(L) (L->hookcount = L->basehookcount) -void luaG_inithooks (lua_State *L); -void luaG_typeerror (lua_State *L, const TObject *o, const char *opname); +void luaG_typeerror (lua_State *L, const TValue *o, const char *opname); void luaG_concaterror (lua_State *L, StkId p1, StkId p2); -void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2); -int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2); +void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2); +int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); void luaG_runerror (lua_State *L, const char *fmt, ...); void luaG_errormsg (lua_State *L); int luaG_checkcode (const Proto *pt); diff --git a/src/ldo.c b/src/ldo.c index a6d344cd57..b65c5610e0 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.217a 2003/04/03 13:35:34 roberto Exp $ +** $Id: ldo.c,v 2.2 2004/03/23 17:02:58 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -39,6 +39,20 @@ */ +#ifndef LUA_USEEXCEPTIONS + +#define L_THROW(c) longjmp((c)->b, 1) +#define L_TRY(c,a) if (setjmp((c)->b) == 0) { a } + +#else + +#define L_THROW(c) throw(c) +#define L_TRY(c,a) try { a } catch(...) \ + { if ((c)->status == 0) (c)->status = -1; } + +#endif + + /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; @@ -50,16 +64,16 @@ struct lua_longjmp { static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { - setsvalue2s(oldtop, luaS_new(L, MEMERRMSG)); + setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); break; } case LUA_ERRERR: { - setsvalue2s(oldtop, luaS_new(L, "error in error handling")); + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } case LUA_ERRSYNTAX: case LUA_ERRRUN: { - setobjs2s(oldtop, L->top - 1); /* error message on current top */ + setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } } @@ -70,10 +84,10 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; - longjmp(L->errorJmp->b, 1); + L_THROW(L->errorJmp); } else { - G(L)->panic(L); + if (G(L)->panic) G(L)->panic(L); exit(EXIT_FAILURE); } } @@ -84,8 +98,9 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { lj.status = 0; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; - if (setjmp(lj.b) == 0) + L_TRY(&lj, (*f)(L, ud); + ); L->errorJmp = lj.previous; /* restore old error handler */ return lj.status; } @@ -103,12 +118,12 @@ static void restore_stack_limit (lua_State *L) { /* }====================================================== */ -static void correctstack (lua_State *L, TObject *oldstack) { +static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; GCObject *up; L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) - gcotouv(up)->v = (gcotouv(up)->v - oldstack) + L->stack; + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; for (ci = L->base_ci; ci <= L->ci; ci++) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; @@ -118,8 +133,8 @@ static void correctstack (lua_State *L, TObject *oldstack) { void luaD_reallocstack (lua_State *L, int newsize) { - TObject *oldstack = L->stack; - luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject); + TValue *oldstack = L->stack; + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); L->stacksize = newsize; L->stack_last = L->stack+newsize-1-EXTRA_STACK; correctstack(L, oldstack); @@ -183,7 +198,6 @@ void luaD_callhook (lua_State *L, int event, int line) { static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { int i; Table *htab; - TObject nname; int actual = L->top - base; /* actual number of arguments */ if (actual < nfixargs) { luaD_checkstack(L, nfixargs - actual); @@ -193,27 +207,28 @@ static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { actual -= nfixargs; /* number of extra arguments */ htab = luaH_new(L, actual, 1); /* create `arg' table */ for (i=0; itop - actual + i); + setobj2n(L, luaH_setnum(L, htab, i+1), L->top - actual + i); /* store counter in field `n' */ - setsvalue(&nname, luaS_newliteral(L, "n")); - setnvalue(luaH_set(L, htab, &nname), cast(lua_Number, actual)); + setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), + cast(lua_Number, actual)); L->top -= actual; /* remove extra elements from the stack */ - sethvalue(L->top, htab); + sethvalue(L, L->top, htab); + lua_assert(iswhite(obj2gco(htab))); incr_top(L); } static StkId tryfuncTM (lua_State *L, StkId func) { - const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); + const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ - for (p = L->top; p > func; p--) setobjs2s(p, p-1); + for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); incr_top(L); func = restorestack(L, funcr); /* previous call may change stack */ - setobj2s(func, tm); /* tag method is the new function to be called */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ return func; } @@ -228,6 +243,7 @@ StkId luaD_precall (lua_State *L, StkId func) { cl = &clvalue(func)->l; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; + StkId st; Proto *p = cl->p; if (p->is_vararg) /* varargs? */ adjust_varargs(L, p->numparams, func+1); @@ -237,9 +253,8 @@ StkId luaD_precall (lua_State *L, StkId func) { ci->top = L->base + p->maxstacksize; ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.tailcalls = 0; - ci->state = CI_SAVEDPC; - while (L->top < ci->top) - setnilvalue(L->top++); + for (st = L->top; st < ci->top; st++) + setnilvalue(st); L->top = ci->top; return NULL; } @@ -250,14 +265,10 @@ StkId luaD_precall (lua_State *L, StkId func) { ci = ++L->ci; /* now `enter' new function */ L->base = L->ci->base = restorestack(L, funcr) + 1; ci->top = L->top + LUA_MINSTACK; - ci->state = CI_C; /* a C function */ if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); -#ifdef LUA_COMPATUPVALUES - lua_pushupvalues(L); -#endif - n = (*clvalue(L->base - 1)->c.f)(L); /* do the actual call */ + n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); return L->top - n; } @@ -267,7 +278,7 @@ StkId luaD_precall (lua_State *L, StkId func) { static StkId callrethooks (lua_State *L, StkId firstResult) { ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ luaD_callhook(L, LUA_HOOKRET, -1); - if (!(L->ci->state & CI_C)) { /* Lua function? */ + if (f_isLua(L->ci)) { /* Lua function? */ while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ luaD_callhook(L, LUA_HOOKTAILRET, -1); } @@ -284,7 +295,7 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { L->base = L->ci->base; /* restore base */ /* move results to correct place */ while (wanted != 0 && firstResult < L->top) { - setobjs2s(res++, firstResult++); + setobjs2s(L, res++, firstResult++); wanted--; } while (wanted-- > 0) @@ -301,7 +312,6 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { */ void luaD_call (lua_State *L, StkId func, int nResults) { StkId firstResult; - lua_assert(!(L->ci->state & CI_CALLING)); if (++L->nCcalls >= LUA_MAXCCALLS) { if (L->nCcalls == LUA_MAXCCALLS) luaG_runerror(L, "C stack overflow"); @@ -310,7 +320,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { } firstResult = luaD_precall(L, func); if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L); /* call it */ + firstResult = luaV_execute(L, 1); /* call it */ luaD_poscall(L, nResults, firstResult); L->nCcalls--; luaC_checkGC(L); @@ -321,27 +331,23 @@ static void resume (lua_State *L, void *ud) { StkId firstResult; int nargs = *cast(int *, ud); CallInfo *ci = L->ci; - if (ci == L->base_ci) { /* no activation record? */ - lua_assert(nargs < L->top - L->base); + if (!L->isSuspended) { + lua_assert(ci == L->base_ci && nargs < L->top - L->base); luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ } - else { /* inside a yield */ - lua_assert(ci->state & CI_YIELD); - if (ci->state & CI_C) { /* `common' yield? */ + else { /* resuming from previous yield */ + if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ int nresults; - lua_assert((ci-1)->state & CI_SAVEDPC); lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, L->top - nargs); /* complete it */ if (nresults >= 0) L->top = L->ci->top; - } - else { /* yielded inside a hook: just continue its execution */ - ci->state &= ~CI_YIELD; - } + } /* else yielded inside a hook: just continue its execution */ } - firstResult = luaV_execute(L); + L->isSuspended = 0; + firstResult = luaV_execute(L, L->ci - L->base_ci); if (firstResult != NULL) /* return? */ luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ } @@ -349,7 +355,7 @@ static void resume (lua_State *L, void *ud) { static int resume_error (lua_State *L, const char *msg) { L->top = L->ci->base; - setsvalue2s(L->top, luaS_new(L, msg)); + setsvalue2s(L, L->top, luaS_new(L, msg)); incr_top(L); lua_unlock(L); return LUA_ERRRUN; @@ -360,14 +366,16 @@ LUA_API int lua_resume (lua_State *L, int nargs) { int status; lu_byte old_allowhooks; lua_lock(L); - if (L->ci == L->base_ci) { - if (nargs >= L->top - L->base) - return resume_error(L, "cannot resume dead coroutine"); + lua_assert(L->errfunc == 0 && L->nCcalls == 0); + if (!L->isSuspended) { + if (L->ci == L->base_ci) { /* no activation record? */ + if (nargs >= L->top - L->base) + return resume_error(L, "cannot resume dead coroutine"); + } + else + return resume_error(L, "cannot resume non-suspended coroutine"); } - else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ - return resume_error(L, "cannot resume non-suspended coroutine"); old_allowhooks = L->allowhook; - lua_assert(L->errfunc == 0 && L->nCcalls == 0); status = luaD_rawrunprotected(L, resume, &nargs); if (status != 0) { /* error? */ L->ci = L->base_ci; /* go back to initial level */ @@ -389,17 +397,15 @@ LUA_API int lua_yield (lua_State *L, int nresults) { ci = L->ci; if (L->nCcalls > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - if (ci->state & CI_C) { /* usual yield */ - if ((ci-1)->state & CI_C) - luaG_runerror(L, "cannot yield a C function"); + if (!f_isLua(ci)) { /* usual yield */ if (L->top - nresults > L->base) { /* is there garbage in the stack? */ int i; for (i=0; ibase + i, L->top - nresults + i); + setobjs2s(L, L->base + i, L->top - nresults + i); L->top = L->base + nresults; } } /* else it's an yield inside a hook: nothing to do */ - ci->state |= CI_YIELD; + L->isSuspended = 1; lua_unlock(L); return -1; } @@ -436,35 +442,34 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* buffer to be used by the scanner */ - int bin; + const char *name; }; static void f_parser (lua_State *L, void *ud) { - struct SParser *p; + int i; Proto *tf; Closure *cl; + struct SParser *p = cast(struct SParser *, ud); + int c = luaZ_lookahead(p->z); luaC_checkGC(L); - p = cast(struct SParser *, ud); - tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff); - cl = luaF_newLclosure(L, 0, gt(L)); + tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, + &p->buff, p->name); + cl = luaF_newLclosure(L, tf->nups, gt(L)); cl->l.p = tf; - setclvalue(L->top, cl); + for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ + cl->l.upvals[i] = luaF_newupval(L); + setclvalue(L, L->top, cl); incr_top(L); } -int luaD_protectedparser (lua_State *L, ZIO *z, int bin) { +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; - ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */ - p.z = z; p.bin = bin; + p.z = z; p.name = name; luaZ_initbuffer(L, &p.buff); - status = luaD_rawrunprotected(L, f_parser, &p); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); - if (status != 0) { /* error? */ - StkId oldtop = restorestack(L, oldtopr); - seterrorobj(L, status, oldtop); - } return status; } diff --git a/src/ldo.h b/src/ldo.h index 2a61bf5bb2..85511f2cbb 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.56 2002/12/04 17:29:32 roberto Exp $ +** $Id: ldo.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ #define luaD_checkstack(L,n) \ - if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TObject)) \ + if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ luaD_growstack(L, n); \ else condhardstacktests(luaD_reallocstack(L, L->stacksize)); @@ -32,7 +32,7 @@ #define incr_top(L) {luaD_checkstack(L,1); L->top++;} #define savestack(L,p) ((char *)(p) - (char *)L->stack) -#define restorestack(L,n) ((TObject *)((char *)L->stack + (n))) +#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) #define saveci(L,p) ((char *)(p) - (char *)L->base_ci) #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) @@ -42,7 +42,7 @@ typedef void (*Pfunc) (lua_State *L, void *ud); void luaD_resetprotection (lua_State *L); -int luaD_protectedparser (lua_State *L, ZIO *z, int bin); +int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); void luaD_callhook (lua_State *L, int event, int line); StkId luaD_precall (lua_State *L, StkId func); void luaD_call (lua_State *L, StkId func, int nResults); diff --git a/src/ldump.c b/src/ldump.c index 234b011f5f..dc4ebad150 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.4 2003/02/11 23:52:12 lhf Exp $ +** $Id: ldump.c,v 1.6 2004/03/24 00:25:08 lhf Exp $ ** save bytecodes ** See Copyright Notice in lua.h */ @@ -22,6 +22,7 @@ typedef struct { lua_State* L; lua_Chunkwriter write; void* data; + int strip; } DumpState; static void DumpBlock(const void* b, size_t size, DumpState* D) @@ -103,7 +104,7 @@ static void DumpConstants(const Proto* f, DumpState* D) DumpInt(n=f->sizek,D); for (i=0; ik[i]; + const TValue* o=&f->k[i]; DumpByte(ttype(o),D); switch (ttype(o)) { @@ -111,7 +112,7 @@ static void DumpConstants(const Proto* f, DumpState* D) DumpNumber(nvalue(o),D); break; case LUA_TSTRING: - DumpString(tsvalue(o),D); + DumpString(rawtsvalue(o),D); break; case LUA_TNIL: break; @@ -132,9 +133,9 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpByte(f->numparams,D); DumpByte(f->is_vararg,D); DumpByte(f->maxstacksize,D); - DumpLines(f,D); - DumpLocals(f,D); - DumpUpvalues(f,D); + if (D->strip) DumpInt(0,D); else DumpLines(f,D); + if (D->strip) DumpInt(0,D); else DumpLocals(f,D); + if (D->strip) DumpInt(0,D); else DumpUpvalues(f,D); DumpConstants(f,D); DumpCode(f,D); } @@ -147,10 +148,6 @@ static void DumpHeader(DumpState* D) DumpByte(sizeof(int),D); DumpByte(sizeof(size_t),D); DumpByte(sizeof(Instruction),D); - DumpByte(SIZE_OP,D); - DumpByte(SIZE_A,D); - DumpByte(SIZE_B,D); - DumpByte(SIZE_C,D); DumpByte(sizeof(lua_Number),D); DumpNumber(TEST_NUMBER,D); } @@ -158,13 +155,14 @@ static void DumpHeader(DumpState* D) /* ** dump function as precompiled chunk */ -void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data) +int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip) { DumpState D; D.L=L; D.write=w; D.data=data; + D.strip=strip; DumpHeader(&D); DumpFunction(Main,NULL,&D); + return 1; } - diff --git a/src/lfunc.c b/src/lfunc.c index 31044fa56b..d9f4e27ece 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,11 +1,11 @@ /* -** $Id: lfunc.c,v 1.67 2003/03/18 12:50:04 roberto Exp $ +** $Id: lfunc.c,v 2.3 2004/03/15 21:04:33 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ -#include +#include #define lfunc_c @@ -18,65 +18,75 @@ #include "lstate.h" -#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ - cast(int, sizeof(TObject)*((n)-1))) - -#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ - cast(int, sizeof(TObject *)*((n)-1))) - - Closure *luaF_newCclosure (lua_State *L, int nelems) { Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; c->c.nupvalues = cast(lu_byte, nelems); return c; } -Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) { +Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->l.isC = 0; c->l.g = *e; c->l.nupvalues = cast(lu_byte, nelems); + while (nelems--) c->l.upvals[nelems] = NULL; return c; } +UpVal *luaF_newupval (lua_State *L) { + UpVal *uv = luaM_new(L, UpVal); + luaC_link(L, obj2gco(uv), LUA_TUPVAL); + uv->v = &uv->value; + setnilvalue(uv->v); + return uv; +} + + UpVal *luaF_findupval (lua_State *L, StkId level) { GCObject **pp = &L->openupval; UpVal *p; - UpVal *v; + UpVal *uv; while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { if (p->v == level) return p; pp = &p->next; } - v = luaM_new(L, UpVal); /* not found: create a new one */ - v->tt = LUA_TUPVAL; - v->marked = 1; /* open upvalues should not be collected */ - v->v = level; /* current value lives in the stack */ - v->next = *pp; /* chain it in the proper position */ - *pp = valtogco(v); - return v; + uv = luaM_new(L, UpVal); /* not found: create a new one */ + uv->tt = LUA_TUPVAL; + uv->marked = luaC_white(G(L)); + uv->v = level; /* current value lives in the stack */ + uv->next = *pp; /* chain it in the proper position */ + *pp = obj2gco(uv); + return uv; } void luaF_close (lua_State *L, StkId level) { - UpVal *p; - while ((p = ngcotouv(L->openupval)) != NULL && p->v >= level) { - setobj(&p->value, p->v); /* save current value (write barrier) */ - p->v = &p->value; /* now current value lives here */ - L->openupval = p->next; /* remove from `open' list */ - luaC_link(L, valtogco(p), LUA_TUPVAL); + UpVal *uv; + global_State *g = G(L); + while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { + GCObject *o = obj2gco(uv); + lua_assert(!isblack(o)); + L->openupval = uv->next; /* remove from `open' list */ + if (isdead(g, o)) + luaM_freelem(L, uv); /* free upvalue */ + else { + setobj(L, &uv->value, uv->v); + uv->v = &uv->value; /* now current value lives here */ + luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + } } } Proto *luaF_newproto (lua_State *L) { Proto *f = luaM_new(L, Proto); - luaC_link(L, valtogco(f), LUA_TPROTO); + luaC_link(L, obj2gco(f), LUA_TPROTO); f->k = NULL; f->sizek = 0; f->p = NULL; @@ -102,7 +112,7 @@ Proto *luaF_newproto (lua_State *L) { void luaF_freeproto (lua_State *L, Proto *f) { luaM_freearray(L, f->code, f->sizecode, Instruction); luaM_freearray(L, f->p, f->sizep, Proto *); - luaM_freearray(L, f->k, f->sizek, TObject); + luaM_freearray(L, f->k, f->sizek, TValue); luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); diff --git a/src/lfunc.h b/src/lfunc.h index 5d5325076b..044376017d 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 1.21 2003/03/18 12:50:04 roberto Exp $ +** $Id: lfunc.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -11,9 +11,17 @@ #include "lobject.h" +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TValue)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TValue *)*((n)-1))) + + Proto *luaF_newproto (lua_State *L); Closure *luaF_newCclosure (lua_State *L, int nelems); -Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e); +Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e); +UpVal *luaF_newupval (lua_State *L); UpVal *luaF_findupval (lua_State *L, StkId level); void luaF_close (lua_State *L, StkId level); void luaF_freeproto (lua_State *L, Proto *f); diff --git a/src/lgc.c b/src/lgc.c index 5e036d387a..db1b1c8994 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.171a 2003/04/03 13:35:34 roberto Exp $ +** $Id: lgc.c,v 2.6 2004/03/23 12:57:12 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -22,117 +22,130 @@ #include "ltm.h" -typedef struct GCState { - GCObject *tmark; /* list of marked objects to be traversed */ - GCObject *wk; /* list of traversed key-weak tables (to be cleared) */ - GCObject *wv; /* list of traversed value-weak tables */ - GCObject *wkv; /* list of traversed key-value weak tables */ - global_State *g; -} GCState; +#define GCSTEPSIZE (40*sizeof(TValue)) +#define GCFREECOST (sizeof(TValue)/2) +#define GCSWEEPCOST sizeof(TValue) +#define GCFINALIZECOST (10*sizeof(TValue)) -/* -** some userful bit tricks -*/ -#define setbit(x,b) ((x) |= (1<<(b))) -#define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b)))) -#define testbit(x,b) ((x) & (1<<(b))) +#define FIXEDMASK bitmask(FIXEDBIT) + +#define maskmarks \ + cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) -#define unmark(x) resetbit((x)->gch.marked, 0) -#define ismarked(x) ((x)->gch.marked & ((1<<4)|1)) +#define makewhite(g,x) \ + ((x)->gch.marked = ((x)->gch.marked & maskmarks) | g->currentwhite) -#define stringmark(s) setbit((s)->tsv.marked, 0) +#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define gray2black(x) setbit((x)->gch.marked, BLACKBIT) +#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) +#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) -#define isfinalized(u) (!testbit((u)->uv.marked, 1)) -#define markfinalized(u) resetbit((u)->uv.marked, 1) +#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) +#define markfinalized(u) setbit((u)->marked, FINALIZEDBIT) -#define KEYWEAKBIT 1 -#define VALUEWEAKBIT 2 -#define KEYWEAK (1<gch.marked, 0); /* mark object */ +static void removeentry (Node *n) { + setnilvalue(gval(n)); /* remove corresponding value ... */ + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ +} + + +static void reallymarkobject (global_State *g, GCObject *o) { + lua_assert(iswhite(o) && !isdead(g, o)); + white2gray(o); switch (o->gch.tt) { + case LUA_TSTRING: { + return; + } case LUA_TUSERDATA: { - markvalue(st, gcotou(o)->uv.metatable); - break; + Table *mt = gco2u(o)->metatable; + gray2black(o); /* udata are never gray */ + if (mt) markobject(g, mt); + return; + } + case LUA_TUPVAL: { + UpVal *uv = gco2uv(o); + if (uv->v == &uv->value) { /* closed? */ + markvalue(g, uv->v); + gray2black(o); + } + return; } case LUA_TFUNCTION: { - gcotocl(o)->c.gclist = st->tmark; - st->tmark = o; + gco2cl(o)->c.gclist = g->gray; + g->gray = o; break; } case LUA_TTABLE: { - gcotoh(o)->gclist = st->tmark; - st->tmark = o; + gco2h(o)->gclist = g->gray; + g->gray = o; break; } case LUA_TTHREAD: { - gcototh(o)->gclist = st->tmark; - st->tmark = o; + gco2th(o)->gclist = g->gray; + g->gray = o; break; } case LUA_TPROTO: { - gcotop(o)->gclist = st->tmark; - st->tmark = o; + gco2p(o)->gclist = g->gray; + g->gray = o; break; } - default: lua_assert(o->gch.tt == LUA_TSTRING); + default: lua_assert(0); } } -static void marktmu (GCState *st) { +static void marktmu (global_State *g) { GCObject *u; - for (u = st->g->tmudata; u; u = u->gch.next) { - unmark(u); /* may be marked, if left from previous GC */ - reallymarkobject(st, u); + for (u = g->tmudata; u; u = u->gch.next) { + makewhite(g, u); /* may be marked, if left from previous GC */ + reallymarkobject(g, u); } } /* move `dead' udata that need finalization to list `tmudata' */ -size_t luaC_separateudata (lua_State *L) { +size_t luaC_separateudata (lua_State *L, int all) { size_t deadmem = 0; - GCObject **p = &G(L)->rootudata; + GCObject **p = &G(L)->firstudata; GCObject *curr; GCObject *collected = NULL; /* to collect udata with gc event */ GCObject **lastcollected = &collected; - while ((curr = *p) != NULL) { - lua_assert(curr->gch.tt == LUA_TUSERDATA); - if (ismarked(curr) || isfinalized(gcotou(curr))) + while ((curr = *p)->gch.tt == LUA_TUSERDATA) { + if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ - - else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { - markfinalized(gcotou(curr)); /* don't need finalization */ + else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { + markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ - deadmem += sizeudata(gcotou(curr)->uv.len); + deadmem += sizeudata(gco2u(curr)->len); + markfinalized(gco2u(curr)); *p = curr->gch.next; curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ *lastcollected = curr; lastcollected = &curr->gch.next; } } + lua_assert(curr == obj2gco(G(L)->mainthread)); /* insert collected udata with gc event into `tmudata' list */ *lastcollected = G(L)->tmudata; G(L)->tmudata = collected; @@ -140,89 +153,85 @@ size_t luaC_separateudata (lua_State *L) { } -static void removekey (Node *n) { - setnilvalue(gval(n)); /* remove corresponding value ... */ - if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ -} - - -static void traversetable (GCState *st, Table *h) { +static int traversetable (global_State *g, Table *h) { int i; int weakkey = 0; int weakvalue = 0; - const TObject *mode; - markvalue(st, h->metatable); - lua_assert(h->lsizenode || h->node == st->g->dummynode); - mode = gfasttm(st->g, h->metatable, TM_MODE); + const TValue *mode; + if (h->metatable) + markobject(g, h->metatable); + lua_assert(h->lsizenode || h->node == g->dummynode); + mode = gfasttm(g, h->metatable, TM_MODE); if (mode && ttisstring(mode)) { /* is there a weak mode? */ weakkey = (strchr(svalue(mode), 'k') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ - GCObject **weaklist; h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT)); - weaklist = (weakkey && weakvalue) ? &st->wkv : - (weakkey) ? &st->wk : - &st->wv; - h->gclist = *weaklist; /* must be cleared after GC, ... */ - *weaklist = valtogco(h); /* ... so put in the appropriate list */ + h->gclist = g->weak; /* must be cleared after GC, ... */ + g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } + if (weakkey && weakvalue) return 1; if (!weakvalue) { i = h->sizearray; while (i--) - markobject(st, &h->array[i]); + markvalue(g, &h->array[i]); } i = sizenode(h); while (i--) { Node *n = gnode(h, i); - if (!ttisnil(gval(n))) { + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { lua_assert(!ttisnil(gkey(n))); - condmarkobject(st, gkey(n), !weakkey); - condmarkobject(st, gval(n), !weakvalue); + if (!weakkey) markvalue(g, gkey(n)); + if (!weakvalue) markvalue(g, gval(n)); } } + return weakkey || weakvalue; } -static void traverseproto (GCState *st, Proto *f) { +/* +** All marks are conditional because a GC may happen while the +** prototype is still being created +*/ +static void traverseproto (global_State *g, Proto *f) { int i; - stringmark(f->source); - for (i=0; isizek; i++) { /* mark literal strings */ - if (ttisstring(f->k+i)) - stringmark(tsvalue(f->k+i)); + if (f->source) stringmark(f->source); + for (i=0; isizek; i++) /* mark literals */ + markvalue(g, &f->k[i]); + for (i=0; isizeupvalues; i++) { /* mark upvalue names */ + if (f->upvalues[i]) + stringmark(f->upvalues[i]); + } + for (i=0; isizep; i++) { /* mark nested protos */ + if (f->p[i]) + markobject(g, f->p[i]); + } + for (i=0; isizelocvars; i++) { /* mark local-variable names */ + if (f->locvars[i].varname) + stringmark(f->locvars[i].varname); } - for (i=0; isizeupvalues; i++) /* mark upvalue names */ - stringmark(f->upvalues[i]); - for (i=0; isizep; i++) /* mark nested protos */ - markvalue(st, f->p[i]); - for (i=0; isizelocvars; i++) /* mark local-variable names */ - stringmark(f->locvars[i].varname); - lua_assert(luaG_checkcode(f)); } -static void traverseclosure (GCState *st, Closure *cl) { +static void traverseclosure (global_State *g, Closure *cl) { if (cl->c.isC) { int i; for (i=0; ic.nupvalues; i++) /* mark its upvalues */ - markobject(st, &cl->c.upvalue[i]); + markvalue(g, &cl->c.upvalue[i]); } else { int i; lua_assert(cl->l.nupvalues == cl->l.p->nups); - markvalue(st, hvalue(&cl->l.g)); - markvalue(st, cl->l.p); - for (i=0; il.nupvalues; i++) { /* mark its upvalues */ - UpVal *u = cl->l.upvals[i]; - if (!u->marked) { - markobject(st, &u->value); - u->marked = 1; - } - } + markobject(g, hvalue(&cl->l.g)); + markobject(g, cl->l.p); + for (i=0; il.nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->l.upvals[i]); } } @@ -239,101 +248,121 @@ static void checkstacksizes (lua_State *L, StkId max) { } -static void traversestack (GCState *st, lua_State *L1) { +static void traversestack (global_State *g, lua_State *l) { StkId o, lim; CallInfo *ci; - markobject(st, gt(L1)); - lim = L1->top; - for (ci = L1->base_ci; ci <= L1->ci; ci++) { - lua_assert(ci->top <= L1->stack_last); - lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC)); - if (lim < ci->top) - lim = ci->top; + markvalue(g, gt(l)); + lim = l->top; + for (ci = l->base_ci; ci <= l->ci; ci++) { + lua_assert(ci->top <= l->stack_last); + if (lim < ci->top) lim = ci->top; } - for (o = L1->stack; o < L1->top; o++) - markobject(st, o); + for (o = l->stack; o < l->top; o++) + markvalue(g, o); for (; o <= lim; o++) setnilvalue(o); - checkstacksizes(L1, lim); + checkstacksizes(l, lim); } -static void propagatemarks (GCState *st) { - while (st->tmark) { /* traverse marked objects */ - switch (st->tmark->gch.tt) { +/* +** traverse a given `quantity' of gray objects, +** turning them to black. Returns extra `quantity' traversed. +*/ +static l_mem propagatemarks (global_State *g, l_mem lim) { + GCObject *o; + while ((o = g->gray) != NULL) { + lua_assert(isgray(o)); + gray2black(o); + switch (o->gch.tt) { case LUA_TTABLE: { - Table *h = gcotoh(st->tmark); - st->tmark = h->gclist; - traversetable(st, h); + Table *h = gco2h(o); + g->gray = h->gclist; + if (traversetable(g, h)) /* table is weak? */ + black2gray(o); /* keep it gray */ + lim -= sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); break; } case LUA_TFUNCTION: { - Closure *cl = gcotocl(st->tmark); - st->tmark = cl->c.gclist; - traverseclosure(st, cl); + Closure *cl = gco2cl(o); + g->gray = cl->c.gclist; + traverseclosure(g, cl); + lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : + sizeLclosure(cl->l.nupvalues); break; } case LUA_TTHREAD: { - lua_State *th = gcototh(st->tmark); - st->tmark = th->gclist; - traversestack(st, th); + lua_State *th = gco2th(o); + g->gray = th->gclist; + th->gclist = g->grayagain; + g->grayagain = o; + black2gray(o); + traversestack(g, th); + lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->size_ci; break; } case LUA_TPROTO: { - Proto *p = gcotop(st->tmark); - st->tmark = p->gclist; - traverseproto(st, p); + Proto *p = gco2p(o); + g->gray = p->gclist; + traverseproto(g, p); + lim -= sizeof(Proto) + sizeof(Instruction) * p->sizecode + + sizeof(Proto *) * p->sizep + + sizeof(TValue) * p->sizek + + sizeof(int) * p->sizelineinfo + + sizeof(LocVar) * p->sizelocvars + + sizeof(TString *) * p->sizeupvalues; break; } default: lua_assert(0); } + if (lim <= 0) return lim; } -} - - -static int valismarked (const TObject *o) { - if (ttisstring(o)) - stringmark(tsvalue(o)); /* strings are `values', so are never weak */ - return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0); + return lim; } /* -** clear collected keys from weaktables +** The next function tells whether a key or value can be cleared from +** a weak table. Non-collectable objects are never removed from weak +** tables. Strings behave as `values', so are never removed too. for +** other objects: if really collected, cannot keep them; for userdata +** being finalized, keep them in keys, but not in values */ -static void cleartablekeys (GCObject *l) { - while (l) { - Table *h = gcotoh(l); - int i = sizenode(h); - lua_assert(h->marked & KEYWEAK); - while (i--) { - Node *n = gnode(h, i); - if (!valismarked(gkey(n))) /* key was collected? */ - removekey(n); /* remove entry from table */ - } - l = h->gclist; +static int iscleared (const TValue *o, int iskey) { + if (!iscollectable(o)) return 0; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); } /* -** clear collected values from weaktables +** clear collected entries from weaktables */ -static void cleartablevalues (GCObject *l) { +static void cleartable (GCObject *l) { while (l) { - Table *h = gcotoh(l); + Table *h = gco2h(l); int i = h->sizearray; - lua_assert(h->marked & VALUEWEAK); - while (i--) { - TObject *o = &h->array[i]; - if (!valismarked(o)) /* value was collected? */ - setnilvalue(o); /* remove value */ + lua_assert(testbit(h->marked, VALUEWEAKBIT) || + testbit(h->marked, KEYWEAKBIT)); + if (testbit(h->marked, VALUEWEAKBIT)) { + while (i--) { + TValue *o = &h->array[i]; + if (iscleared(o, 0)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } } i = sizenode(h); while (i--) { Node *n = gnode(h, i); - if (!valismarked(gval(n))) /* value was collected? */ - removekey(n); /* remove entry from table */ + if (!ttisnil(gval(n)) && /* non-empty entry? */ + (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) + removeentry(n); /* remove entry from table */ } l = h->gclist; } @@ -342,21 +371,21 @@ static void cleartablevalues (GCObject *l) { static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { - case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break; - case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break; - case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break; - case LUA_TTABLE: luaH_free(L, gcotoh(o)); break; + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; + case LUA_TUPVAL: luaM_freelem(L, gco2uv(o)); break; + case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { - lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread); - luaE_freethread(L, gcototh(o)); + lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); + luaE_freethread(L, gco2th(o)); break; } case LUA_TSTRING: { - luaM_free(L, o, sizestring(gcotots(o)->tsv.len)); + luaM_free(L, o, sizestring(gco2ts(o)->len)); break; } case LUA_TUSERDATA: { - luaM_free(L, o, sizeudata(gcotou(o)->uv.len)); + luaM_free(L, o, sizeudata(gco2u(o)->len)); break; } default: lua_assert(0); @@ -364,135 +393,283 @@ static void freeobj (lua_State *L, GCObject *o) { } -static int sweeplist (lua_State *L, GCObject **p, int limit) { +static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, + lu_int32 *count); + + +static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed, + l_mem *plim, lu_int32 *count) { GCObject *curr; - int count = 0; /* number of collected items */ + global_State *g = G(L); + l_mem lim = *plim; + int deadmask = otherwhite(g); + if (keepfixed) deadmask |= FIXEDMASK; while ((curr = *p) != NULL) { - if (curr->gch.marked > limit) { - unmark(curr); + if (((curr->gch.marked ^ FIXEDMASK) & deadmask) != deadmask) { + makewhite(g, curr); + if (curr->gch.tt == LUA_TTHREAD) + lim -= sweepwholelist(L, &gco2th(curr)->openupval, keepfixed, count); p = &curr->gch.next; + lim -= GCSWEEPCOST; } else { - count++; + lua_assert(iswhite(curr)); *p = curr->gch.next; + if (curr == g->rootgc) /* is the first element of the list? */ + g->rootgc = curr->gch.next; /* adjust first */ freeobj(L, curr); + lim -= GCFREECOST; + if (count) (*count)--; } + if (lim <= 0) break; } - return count; + *plim = lim; + return p; } -static void sweepstrings (lua_State *L, int all) { +static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, + lu_int32 *count) { + l_mem lim = MAXLMEM; + /* empty lists are quite common here, so avoid useless calls */ + if (*p) sweeplist(L, p, keepfixed, &lim, count); + return MAXLMEM - lim; +} + + +static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) { int i; - for (i=0; istrt.size; i++) { /* for each list */ - G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all); + global_State *g = G(L); + for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ + lim -= sweepwholelist(L, &G(L)->strt.hash[i], keepfixed, &g->strt.nuse); + if (lim <= 0) break; } + g->sweepstrgc = i+1; + return lim; } -static void checkSizes (lua_State *L, size_t deadmem) { +static void checkSizes (lua_State *L) { + global_State *g = G(L); /* check size of string hash */ - if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && - G(L)->strt.size > MINSTRTABSIZE*2) - luaS_resize(L, G(L)->strt.size/2); /* table is too big */ + if (g->strt.nuse < cast(lu_int32, G(L)->strt.size/4) && + g->strt.size > MINSTRTABSIZE*2) + luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ - if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2; - luaZ_resizebuffer(L, &G(L)->buff, newsize); + if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ + size_t newsize = luaZ_sizebuffer(&g->buff) / 2; + luaZ_resizebuffer(L, &g->buff, newsize); } - G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ } -static void do1gcTM (lua_State *L, Udata *udata) { - const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC); +static void GCTM (lua_State *L) { + global_State *g = G(L); + GCObject *o = g->tmudata; + Udata *udata = rawgco2u(o); + const TValue *tm; + g->tmudata = udata->uv.next; /* remove udata from `tmudata' */ + udata->uv.next = g->firstudata->uv.next; /* return it to `root' list */ + g->firstudata->uv.next = o; + makewhite(g, o); + tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { - setobj2s(L->top, tm); - setuvalue(L->top+1, udata); + lu_byte oldah = L->allowhook; + L->allowhook = 0; /* stop debug hooks during GC tag method */ + setobj2s(L, L->top, tm); + setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); + L->allowhook = oldah; /* restore hooks */ } } +/* +** Call all GC tag methods +*/ void luaC_callGCTM (lua_State *L) { - lu_byte oldah = L->allowhook; - L->allowhook = 0; /* stop debug hooks during GC tag methods */ - L->top++; /* reserve space to keep udata while runs its gc method */ - while (G(L)->tmudata != NULL) { - GCObject *o = G(L)->tmudata; - Udata *udata = gcotou(o); - G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ - udata->uv.next = G(L)->rootudata; /* return it to `root' list */ - G(L)->rootudata = o; - setuvalue(L->top - 1, udata); /* keep a reference to it */ - unmark(o); - markfinalized(udata); - do1gcTM(L, udata); - } - L->top--; - L->allowhook = oldah; /* restore hooks */ + while (G(L)->tmudata) + GCTM(L); } -void luaC_sweep (lua_State *L, int all) { - if (all) all = 256; /* larger than any mark */ - sweeplist(L, &G(L)->rootudata, all); - sweepstrings(L, all); - sweeplist(L, &G(L)->rootgc, all); +void luaC_sweepall (lua_State *L) { + global_State *g = G(L); + l_mem dummy = MAXLMEM; + /* finish (occasional) current sweep */ + sweepstrings(L, 0, MAXLMEM); + sweeplist(L, &g->rootgc, 0, &dummy, NULL); + /* do a whole new sweep */ + markobject(g, g->mainthread); /* cannot collect main thread */ + g->currentwhite = otherwhite(g); + g->sweepgc = &g->rootgc; + g->sweepstrgc = 0; + sweepstrings(L, 0, MAXLMEM); + sweeplist(L, &g->rootgc, 0, &dummy, NULL); } /* mark root set */ -static void markroot (GCState *st, lua_State *L) { - global_State *g = st->g; - markobject(st, defaultmeta(L)); - markobject(st, registry(L)); - traversestack(st, g->mainthread); - if (L != g->mainthread) /* another thread is running? */ - markvalue(st, L); /* cannot collect it */ +static void markroot (lua_State *L) { + global_State *g = G(L); + lua_assert(g->gray == NULL); + g->grayagain = NULL; + g->weak = NULL; + markobject(g, g->mainthread); + /* make global table be traversed before main stack */ + markvalue(g, gt(g->mainthread)); + markvalue(g, registry(L)); + g->gcstate = GCSpropagate; } -static size_t mark (lua_State *L) { - size_t deadmem; - GCState st; - GCObject *wkv; - st.g = G(L); - st.tmark = NULL; - st.wkv = st.wk = st.wv = NULL; - markroot(&st, L); - propagatemarks(&st); /* mark all reachable objects */ - cleartablevalues(st.wkv); - cleartablevalues(st.wv); - wkv = st.wkv; /* keys must be cleared after preserving udata */ - st.wkv = NULL; - st.wv = NULL; - deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ - marktmu(&st); /* mark `preserved' userdata */ - propagatemarks(&st); /* remark, to propagate `preserveness' */ - cleartablekeys(wkv); - /* `propagatemarks' may resuscitate some weak tables; clear them too */ - cleartablekeys(st.wk); - cleartablevalues(st.wv); - cleartablekeys(st.wkv); - cleartablevalues(st.wkv); - return deadmem; +static void remarkupvals (global_State *g) { + GCObject *o; + for (o = obj2gco(g->mainthread); o; o = o->gch.next) { + if (iswhite(o)) { + GCObject *curr; + for (curr = gco2th(o)->openupval; curr != NULL; curr = curr->gch.next) { + if (isgray(curr)) + markvalue(g, gco2uv(curr)->v); + } + } + } +} + + +static void atomic (lua_State *L) { + global_State *g = G(L); + lua_assert(g->gray == NULL); + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + /* remark weak tables */ + g->gray = g->weak; + g->weak = NULL; + lua_assert(!iswhite(obj2gco(g->mainthread))); + markobject(g, L); /* mark running thread */ + propagatemarks(g, MAXLMEM); + /* remark gray again */ + g->gray = g->grayagain; + g->grayagain = NULL; + propagatemarks(g, MAXLMEM); + luaC_separateudata(L, 0); /* separate userdata to be preserved */ + marktmu(g); /* mark `preserved' userdata */ + propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ + cleartable(g->weak); /* remove collected objects from weak tables */ + /* flip current white */ + g->currentwhite = otherwhite(g); + g->gcstate = GCSsweepstring; +} + + +static l_mem singlestep (lua_State *L, l_mem lim) { + global_State *g = G(L); + switch (g->gcstate) { + case GCSpropagate: { + if (g->gray) + lim = propagatemarks(g, lim); + else { /* no more `gray' objects */ + atomic(L); /* finish mark phase */ + lim = 0; + } + break; + } + case GCSsweepstring: { + lim = sweepstrings(L, 1, lim); + if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ + g->sweepstrgc = 0; + g->gcstate = GCSsweep; /* end sweep-string phase */ + } + break; + } + case GCSsweep: { + g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim, NULL); + if (*g->sweepgc == NULL) { /* nothing more to sweep? */ + checkSizes(L); + g->sweepgc = &g->rootgc; + g->gcstate = GCSfinalize; /* end sweep phase */ + } + break; + } + case GCSfinalize: { + if (g->tmudata) { + GCTM(L); + lim -= GCFINALIZECOST; + } + else { /* no more `udata' to finalize */ + markroot(L); /* may restart collection */ + lim = 0; + } + break; + } + default: lua_assert(0); + } + return lim; +} + + +void luaC_step (lua_State *L) { + global_State *g = G(L); + l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; + do { + lim = singlestep(L, lim); + if (g->gcstate == GCSfinalize && g->tmudata == NULL) + break; /* do not start new collection */ + } while (lim > 0); + g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; + lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/2); } -void luaC_collectgarbage (lua_State *L) { - size_t deadmem = mark(L); - luaC_sweep(L, 0); - checkSizes(L, deadmem); - luaC_callGCTM(L); +void luaC_fullgc (lua_State *L) { + global_State *g = G(L); + while (g->gcstate != GCSfinalize) { + singlestep(L, MAXLMEM); + } + markroot(L); + while (g->gcstate != GCSfinalize) { + singlestep(L, MAXLMEM); + } + g->GCthreshold = g->nblocks + GCSTEPSIZE; + luaC_callGCTM(L); /* call finalizers */ +} + + +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize); + if (g->gcstate != GCSpropagate) /* sweeping phases? */ + black2gray(o); /* just mark as gray to avoid other barriers */ + else /* breaking invariant! */ + reallymarkobject(g, v); /* restore it */ } void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { - o->gch.next = G(L)->rootgc; - G(L)->rootgc = o; - o->gch.marked = 0; + global_State *g = G(L); + o->gch.next = g->rootgc; + g->rootgc = o; + o->gch.marked = luaC_white(g); o->gch.tt = tt; } + +void luaC_linkupval (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = obj2gco(uv); + o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ + g->rootgc = o; + if (isgray(o)) { + if (g->gcstate == GCSpropagate) { + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv->v); + } + else { /* sweep phase: sweep it (turning it into white) */ + makewhite(g, o); + lua_assert(g->gcstate != GCSfinalize); + } + } +} + diff --git a/src/lgc.h b/src/lgc.h index 3f4d7486e9..1ff59860f7 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 1.19a 2003/02/28 19:45:15 roberto Exp $ +** $Id: lgc.h,v 2.5 2004/03/15 21:04:33 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -11,15 +11,84 @@ #include "lobject.h" -#define luaC_checkGC(L) { lua_assert(!(L->ci->state & CI_CALLING)); \ - if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); } +/* +** Possible states of the Garbage Collector +*/ +#define GCSpropagate 0 +#define GCSsweepstring 1 +#define GCSsweep 2 +#define GCSfinalize 3 + + +/* +** some userful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) +#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) +#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) +#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) + + + +/* +** Layout for bit use in `marked' field: +** bit 0 - object is gray +** bit 1 - object is black +** bit 2 - For userdata: is finalized; + for tables: has weak keys +** bit 3 - for tables: has weak values +** bit 4 - object is fixed (should not be collected) +*/ + +#define WHITE0BIT 0 +#define WHITE1BIT 1 +#define BLACKBIT 2 +#define FINALIZEDBIT 3 +#define KEYWEAKBIT 3 +#define VALUEWEAKBIT 4 +#define FIXEDBIT 5 + + +#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#define isgray(x) (!isblack(x) && !iswhite(x)) + +#define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) +#define isdead(g,v) ((v)->gch.marked & otherwhite(g)) + +#define changewhite(x) ((x)->gch.marked ^= bit2mask(WHITE0BIT, WHITE1BIT)) + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite) + + +#define luaC_checkGC(L) { if (G(L)->nblocks >= G(L)->GCthreshold) \ + luaC_step(L); } + + +#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),gcvalue(v)); } +#define luaC_objbarrier(L,p,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),obj2gco(o)); } -size_t luaC_separateudata (lua_State *L); +size_t luaC_separateudata (lua_State *L, int all); void luaC_callGCTM (lua_State *L); -void luaC_sweep (lua_State *L, int all); -void luaC_collectgarbage (lua_State *L); +void luaC_sweepall (lua_State *L); +void luaC_step (lua_State *L); +void luaC_fullgc (lua_State *L); void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +void luaC_linkupval (lua_State *L, UpVal *uv); +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); #endif diff --git a/src/lib/RCS b/src/lib/RCS new file mode 120000 index 0000000000..1ae3893605 --- /dev/null +++ b/src/lib/RCS @@ -0,0 +1 @@ +../RCS \ No newline at end of file diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c index ee2d1339b0..9613101948 100644 --- a/src/lib/lauxlib.c +++ b/src/lib/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.100 2003/04/07 14:35:00 roberto Exp $ +** $Id: lauxlib.c,v 1.110 2004/03/23 16:38:43 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -74,7 +75,7 @@ static void tag_error (lua_State *L, int narg, int tag) { LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ - lua_getinfo(L, "Snl", &ar); /* get info about it */ + lua_getinfo(L, "Sl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; @@ -107,15 +108,13 @@ LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_newtable(L); /* create metatable */ - lua_pushstring(L, tname); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ lua_pushvalue(L, -1); lua_pushstring(L, tname); lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ @@ -124,8 +123,7 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); + lua_getfield(L, LUA_REGISTRYINDEX, tname); } @@ -196,11 +194,25 @@ LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { } +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { + lua_Integer d = lua_tointeger(L, narg); + if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, + lua_Integer def) { + if (lua_isnoneornil(L, narg)) return def; + else return luaL_checkinteger(L, narg); +} + + LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; - lua_pushstring(L, event); - lua_rawget(L, -2); + lua_getfield(L, -1, event); if (lua_isnil(L, -1)) { lua_pop(L, 2); /* remove metatable and metafield */ return 0; @@ -225,24 +237,23 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { LUALIB_API void luaL_openlib (lua_State *L, const char *libname, const luaL_reg *l, int nup) { if (libname) { - lua_pushstring(L, libname); - lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */ + /* check whether lib already exists */ + lua_getglobal(L, libname); if (lua_isnil(L, -1)) { /* no? */ lua_pop(L, 1); lua_newtable(L); /* create it */ - lua_pushstring(L, libname); - lua_pushvalue(L, -2); - lua_settable(L, LUA_GLOBALSINDEX); /* register it with given name */ + lua_pushvalue(L, -1); + /* register it with given name */ + lua_setglobal(L, libname); } lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { int i; - lua_pushstring(L, l->name); for (i=0; ifunc, nup); - lua_settable(L, -(nup+3)); + lua_setfield(L, -(nup+2), l->name); } lua_pop(L, nup); /* remove upvalues */ } @@ -256,8 +267,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, */ static int checkint (lua_State *L, int topop) { - int n = (int)lua_tonumber(L, -1); - if (n == 0 && !lua_isnumber(L, -1)) n = -1; + int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; lua_pop(L, topop); return n; } @@ -270,9 +280,8 @@ static void getsizes (lua_State *L) { lua_newtable(L); /* create it */ lua_pushvalue(L, -1); /* `size' will be its own metatable */ lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(N).__mode = "k" */ + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ lua_pushvalue(L, -1); lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */ } @@ -281,33 +290,23 @@ static void getsizes (lua_State *L) { void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); - lua_pushliteral(L, "n"); - lua_rawget(L, t); - if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ - lua_pushliteral(L, "n"); /* use it */ - lua_pushnumber(L, (lua_Number)n); - lua_rawset(L, t); - } - else { /* use `sizes' */ - getsizes(L); - lua_pushvalue(L, t); - lua_pushnumber(L, (lua_Number)n); - lua_rawset(L, -3); /* sizes[t] = n */ - lua_pop(L, 1); /* remove `sizes' */ - } + getsizes(L); + lua_pushvalue(L, t); + lua_pushinteger(L, n); + lua_rawset(L, -3); /* sizes[t] = n */ + lua_pop(L, 1); /* remove `sizes' */ } int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); - lua_pushliteral(L, "n"); /* try t.n */ - lua_rawget(L, t); - if ((n = checkint(L, 1)) >= 0) return n; - getsizes(L); /* else try sizes[t] */ + getsizes(L); /* try sizes[t] */ lua_pushvalue(L, t); lua_rawget(L, -2); if ((n = checkint(L, 2)) >= 0) return n; + lua_getfield(L, t, "n"); /* else try t.n */ + if ((n = checkint(L, 1)) >= 0) return n; for (n = 1; ; n++) { /* else must count elements */ lua_rawgeti(L, t, n); if (lua_isnil(L, -1)) break; @@ -424,7 +423,7 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { return LUA_REFNIL; /* `nil' has a unique fixed reference */ } lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ - ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */ + ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ @@ -447,7 +446,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { t = abs_index(L, t); lua_rawgeti(L, t, FREELIST_REF); lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ - lua_pushnumber(L, (lua_Number)ref); + lua_pushinteger(L, ref); lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ } } @@ -461,6 +460,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { */ typedef struct LoadF { + int extraline; FILE *f; char buff[LUAL_BUFFERSIZE]; } LoadF; @@ -469,6 +469,11 @@ typedef struct LoadF { static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; + if (lf->extraline) { + lf->extraline = 0; + *size = 1; + return "\n"; + } if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); return (*size > 0) ? lf->buff : NULL; @@ -488,6 +493,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + lf.extraline = 0; if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; @@ -495,14 +501,23 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); + if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ } - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ - c = ungetc(getc(lf.f), lf.f); - if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */ + c = getc(lf.f); + if (c == '#') { /* Unix exec. file? */ + lf.extraline = 1; + while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ + if (c == '\n') c = getc(lf.f); + } + if (c == LUA_SIGNATURE[0] && lf.f != stdin) { /* binary file? */ fclose(lf.f); lf.f = fopen(filename, "rb"); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */ + /* skip eventual `#!...' */ + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + lf.extraline = 0; } + ungetc(c, lf.f); status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ @@ -542,6 +557,22 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, /* }====================================================== */ +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + if (nsize == 0) { + free(ptr); + return NULL; + } + else + return realloc(ptr, nsize); +} + + +LUALIB_API lua_State *luaL_newstate (void) { + return lua_newstate(l_alloc, NULL); +} + + /* ** {====================================================== ** compatibility code diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index b6a4baedc2..42b0355a4e 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.130b 2003/04/03 13:35:34 roberto Exp $ +** $Id: lbaselib.c,v 1.140 2004/03/09 17:34:35 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -78,10 +78,8 @@ static int luaB_tonumber (lua_State *L) { static int luaB_error (lua_State *L) { int level = luaL_optint(L, 2, 1); - luaL_checkany(L, 1); - if (!lua_isstring(L, 1) || level == 0) - lua_pushvalue(L, 1); /* propagate error message without changes */ - else { /* add extra information */ + lua_settop(L, 1); + if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); lua_pushvalue(L, 1); lua_concat(L, 2); @@ -187,15 +185,32 @@ static int luaB_rawset (lua_State *L) { static int luaB_gcinfo (lua_State *L) { - lua_pushnumber(L, (lua_Number)lua_getgccount(L)); - lua_pushnumber(L, (lua_Number)lua_getgcthreshold(L)); - return 2; + lua_pushinteger(L, lua_getgccount(L)); + return 1; } static int luaB_collectgarbage (lua_State *L) { - lua_setgcthreshold(L, luaL_optint(L, 1, 0)); - return 0; + static const char *const opts[] = {"stop", "restart", "collect", "count", + NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, + LUA_GCCOLLECT, LUA_GCCOUNT}; + int o; + int ex; +#if 1 + if (lua_isnumber(L, 1)) { + int v = lua_tointeger(L, 1); + lua_settop(L, 0); + if (v == 0) lua_pushstring(L, "collect"); + else if (v >= 10000) lua_pushstring(L, "stop"); + else lua_pushstring(L, "restart"); + } +#endif + o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); + ex = luaL_optint(L, 2, 0); + luaL_argcheck(L, o >= 0, 1, "invalid option"); + lua_pushinteger(L, lua_gc(L, optsnum[o], ex)); + return 1; } @@ -220,8 +235,7 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - lua_pushliteral(L, "next"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ + lua_getglobal(L, "next"); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushnil(L); /* and initial value */ return 3; @@ -229,19 +243,18 @@ static int luaB_pairs (lua_State *L) { static int luaB_ipairs (lua_State *L) { - lua_Number i = lua_tonumber(L, 2); + int i = (int)lua_tointeger(L, 2); luaL_checktype(L, 1, LUA_TTABLE); if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */ - lua_pushliteral(L, "ipairs"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ + lua_getglobal(L, "ipairs"); /* return generator, */ lua_pushvalue(L, 1); /* state, */ - lua_pushnumber(L, 0); /* and initial value */ + lua_pushinteger(L, 0); /* and initial value */ return 3; } else { /* `for' step */ i++; /* next value */ - lua_pushnumber(L, i); - lua_rawgeti(L, 1, (int)i); + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); return (lua_isnil(L, -1)) ? 0 : 2; } } @@ -272,11 +285,51 @@ static int luaB_loadfile (lua_State *L) { } +struct Aux_load { + int func; + int res; +}; + + +static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + struct Aux_load *al = (struct Aux_load *)ud; + luaL_unref(L, al->res, LUA_REGISTRYINDEX); + lua_getref(L, al->func); + lua_call(L, 0, 1); + if (lua_isnil(L, -1)) { + *size = 0; + return NULL; + } + else if (lua_isstring(L, -1)) { + const char *res = lua_tostring(L, -1); + *size = lua_strlen(L, -1); + al->res = luaL_ref(L, LUA_REGISTRYINDEX); + return res; + } + else luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ +} + + +static int luaB_load (lua_State *L) { + struct Aux_load al; + int status; + const char *cname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); + al.func = luaL_ref(L, LUA_REGISTRYINDEX); + al.res = LUA_REFNIL; + status = lua_load(L, generic_reader, &al, cname); + luaL_unref(L, al.func, LUA_REGISTRYINDEX); + luaL_unref(L, al.res, LUA_REGISTRYINDEX); + return load_aux(L, status); +} + + static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); int n = lua_gettop(L); - int status = luaL_loadfile(L, fname); - if (status != 0) lua_error(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); lua_call(L, 0, LUA_MULTRET); return lua_gettop(L) - n; } @@ -325,7 +378,9 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { - char buff[128]; + char buff[4*sizeof(void *) + 2]; /* enough space for a `%p' */ + const char *tn = ""; + const void *p = NULL; luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ @@ -339,24 +394,29 @@ static int luaB_tostring (lua_State *L) { case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); return 1; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + return 1; case LUA_TTABLE: - sprintf(buff, "table: %p", lua_topointer(L, 1)); + p = lua_topointer(L, 1); + tn = "table"; break; case LUA_TFUNCTION: - sprintf(buff, "function: %p", lua_topointer(L, 1)); + p = lua_topointer(L, 1); + tn = "function"; break; case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: - sprintf(buff, "userdata: %p", lua_touserdata(L, 1)); + p = lua_touserdata(L, 1); + tn = "userdata"; break; case LUA_TTHREAD: - sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1)); + p = lua_tothread(L, 1); + tn = "thread"; break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - return 1; } - lua_pushstring(L, buff); + sprintf(buff, "%p", p); + lua_pushfstring(L, "%s: %s", tn, buff); return 1; } @@ -441,14 +501,14 @@ static void pushcomposename (lua_State *L) { const char *wild; int n = 1; while ((wild = strchr(path, LUA_PATH_MARK)) != NULL) { - /* is there stack space for prefix, name, and eventual last sufix? */ + /* is there stack space for prefix, name, and eventual last suffix? */ luaL_checkstack(L, 3, "too many marks in a path component"); lua_pushlstring(L, path, wild - path); /* push prefix */ lua_pushvalue(L, 1); /* push package name (in place of MARK) */ path = wild + 1; /* continue after MARK */ n += 2; } - lua_pushstring(L, path); /* push last sufix (`n' already includes this) */ + lua_pushstring(L, path); /* push last suffix (`n' already includes this) */ lua_concat(L, n); } @@ -530,6 +590,7 @@ static const luaL_reg base_funcs[] = { {"loadfile", luaB_loadfile}, {"dofile", luaB_dofile}, {"loadstring", luaB_loadstring}, + {"load", luaB_load}, {"require", luaB_require}, {NULL, NULL} }; @@ -645,23 +706,19 @@ static const luaL_reg co_funcs[] = { static void base_open (lua_State *L) { - lua_pushliteral(L, "_G"); lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ - lua_pushliteral(L, "_VERSION"); lua_pushliteral(L, LUA_VERSION); - lua_rawset(L, -3); /* set global _VERSION */ + lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ /* `newproxy' needs a weaktable as upvalue */ - lua_pushliteral(L, "newproxy"); lua_newtable(L); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(w).__mode = "k" */ + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_rawset(L, -3); /* set global `newproxy' */ - lua_rawset(L, -1); /* set global _G */ + lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ + lua_setfield(L, -1, "_G"); /* set global _G */ } @@ -670,6 +727,6 @@ LUALIB_API int luaopen_base (lua_State *L) { luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); lua_newtable(L); lua_setglobal(L, REQTAB); - return 0; + return 2; } diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c index 6dc9b64cfc..dd4e0363df 100644 --- a/src/lib/ldblib.c +++ b/src/lib/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.80 2003/04/03 13:35:34 roberto Exp $ +** $Id: ldblib.c,v 1.84 2003/11/05 11:59:14 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -19,37 +19,50 @@ static void settabss (lua_State *L, const char *i, const char *v) { - lua_pushstring(L, i); lua_pushstring(L, v); - lua_rawset(L, -3); + lua_setfield(L, -2, i); } static void settabsi (lua_State *L, const char *i, int v) { - lua_pushstring(L, i); - lua_pushnumber(L, (lua_Number)v); - lua_rawset(L, -3); + lua_pushinteger(L, v); + lua_setfield(L, -2, i); +} + + +static lua_State *getthread (lua_State *L, int *arg) { + if (lua_isthread(L, 1)) { + *arg = 1; + return lua_tothread(L, 1); + } + else { + *arg = 0; + return L; + } } static int getinfo (lua_State *L) { lua_Debug ar; - const char *options = luaL_optstring(L, 2, "flnSu"); - if (lua_isnumber(L, 1)) { - if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) { + int arg; + lua_State *L1 = getthread(L, &arg); + const char *options = luaL_optstring(L, arg+2, "flnSu"); + if (lua_isnumber(L, arg+1)) { + if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } - else if (lua_isfunction(L, 1)) { + else if (lua_isfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); - lua_pushvalue(L, 1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); } else - return luaL_argerror(L, 1, "function or level expected"); - if (!lua_getinfo(L, options, &ar)) - return luaL_argerror(L, 2, "invalid option"); + return luaL_argerror(L, arg+1, "function or level expected"); + if (!lua_getinfo(L1, options, &ar)) + return luaL_argerror(L, arg+2, "invalid option"); lua_newtable(L); for (; *options; options++) { switch (*options) { @@ -70,9 +83,11 @@ static int getinfo (lua_State *L) { settabss(L, "namewhat", ar.namewhat); break; case 'f': - lua_pushliteral(L, "func"); - lua_pushvalue(L, -3); - lua_rawset(L, -3); + if (L == L1) + lua_pushvalue(L, -2); + else + lua_xmove(L1, L, 1); + lua_setfield(L, -2, "func"); break; } } @@ -81,12 +96,15 @@ static int getinfo (lua_State *L) { static int getlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - name = lua_getlocal(L, &ar, luaL_checkint(L, 2)); + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); if (name) { + lua_xmove(L1, L, 1); lua_pushstring(L, name); lua_pushvalue(L, -2); return 2; @@ -99,11 +117,15 @@ static int getlocal (lua_State *L) { static int setlocal (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - luaL_checkany(L, 3); - lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2))); + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + lua_xmove(L, L1, 1); + lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); return 1; } @@ -141,16 +163,16 @@ static void hookf (lua_State *L, lua_Debug *ar) { {"call", "return", "line", "count", "tail return"}; lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, L); + lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) - lua_pushnumber(L, (lua_Number)ar->currentline); + lua_pushinteger(L, ar->currentline); else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); lua_call(L, 2, 0); } - else - lua_pop(L, 1); /* pop result from gettable */ } @@ -174,36 +196,59 @@ static char *unmakemask (int mask, char *smask) { } +static void gethooktable (lua_State *L) { + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_newtable(L); + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } +} + + static int sethook (lua_State *L) { - if (lua_isnoneornil(L, 1)) { - lua_settop(L, 1); - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + int arg; + lua_State *L1 = getthread(L, &arg); + if (lua_isnoneornil(L, arg+1)) { + lua_settop(L, arg+1); + lua_sethook(L1, NULL, 0, 0); /* turn off hooks */ } else { - const char *smask = luaL_checkstring(L, 2); - int count = luaL_optint(L, 3, 0); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_sethook(L, hookf, makemask(smask, count), count); + const char *smask = luaL_checkstring(L, arg+2); + int count = luaL_optint(L, arg+3, 0); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + lua_sethook(L1, hookf, makemask(smask, count), count); } - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_pushvalue(L, 1); - lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ + gethooktable(L1); + lua_pushlightuserdata(L1, L1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + lua_rawset(L1, -3); /* set new hook */ + lua_pop(L1, 1); /* remove hook table */ return 0; } static int gethook (lua_State *L) { + int arg; + lua_State *L1 = getthread(L, &arg); char buff[5]; - int mask = lua_gethookmask(L); - lua_Hook hook = lua_gethook(L); + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); if (hook != NULL && hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ + gethooktable(L1); + lua_pushlightuserdata(L1, L1); + lua_rawget(L1, -2); /* get hook */ + lua_remove(L1, -2); /* remove hook table */ + lua_xmove(L1, L, 1); } lua_pushstring(L, unmakemask(mask, buff)); - lua_pushnumber(L, (lua_Number)lua_gethookcount(L)); + lua_pushinteger(L, lua_gethookcount(L1)); return 3; } @@ -227,27 +272,29 @@ static int debug (lua_State *L) { static int errorfb (lua_State *L) { int level = 1; /* skip level 0 (it's this function) */ int firstpart = 1; /* still before eventual `...' */ + int arg; + lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (lua_gettop(L) == 0) + if (lua_gettop(L) == arg) lua_pushliteral(L, ""); - else if (!lua_isstring(L, 1)) return 1; /* no string message */ + else if (!lua_isstring(L, arg+1)) return 1; /* no string message */ else lua_pushliteral(L, "\n"); lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L, level++, &ar)) { + while (lua_getstack(L1, level++, &ar)) { if (level > LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L, level+LEVELS2, &ar)) + if (!lua_getstack(L1, level+LEVELS2, &ar)) level--; /* keep going */ else { lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ level++; } firstpart = 0; continue; } lua_pushliteral(L, "\n\t"); - lua_getinfo(L, "Snl", &ar); + lua_getinfo(L1, "Snl", &ar); lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); @@ -268,9 +315,9 @@ static int errorfb (lua_State *L) { ar.short_src, ar.linedefined); } } - lua_concat(L, lua_gettop(L)); + lua_concat(L, lua_gettop(L) - arg); } - lua_concat(L, lua_gettop(L)); + lua_concat(L, lua_gettop(L) - arg); return 1; } @@ -291,9 +338,8 @@ static const luaL_reg dblib[] = { LUALIB_API int luaopen_debug (lua_State *L) { luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); - lua_pushliteral(L, "_TRACEBACK"); lua_pushcfunction(L, errorfb); - lua_settable(L, LUA_GLOBALSINDEX); + lua_setglobal(L, "_TRACEBACK"); return 1; } diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 96b38831d2..1815c96b6d 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.39a 2003/03/19 21:16:12 roberto Exp $ +** $Id: liolib.c,v 2.49 2003/10/10 13:29:28 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -37,16 +37,12 @@ ** by default, posix systems get `popen' */ #ifndef USE_POPEN -#ifdef _POSIX_C_SOURCE -#if _POSIX_C_SOURCE >= 2 +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 2 #define USE_POPEN 1 -#endif -#endif -#endif - -#ifndef USE_POPEN +#else #define USE_POPEN 0 #endif +#endif @@ -65,8 +61,8 @@ #define FILEHANDLE "FILE*" -#define IO_INPUT "_input" -#define IO_OUTPUT "_output" +#define IO_INPUT 1 +#define IO_OUTPUT 2 static int pushresult (lua_State *L, int i, const char *filename) { @@ -80,7 +76,7 @@ static int pushresult (lua_State *L, int i, const char *filename) { lua_pushfstring(L, "%s: %s", filename, strerror(errno)); else lua_pushfstring(L, "%s", strerror(errno)); - lua_pushnumber(L, errno); + lua_pushinteger(L, errno); return 3; } } @@ -127,23 +123,6 @@ static FILE **newfile (lua_State *L) { } -/* -** assumes that top of the stack is the `io' library, and next is -** the `io' metatable -*/ -static void registerfile (lua_State *L, FILE *f, const char *name, - const char *impname) { - lua_pushstring(L, name); - *newfile(L) = f; - if (impname) { - lua_pushstring(L, impname); - lua_pushvalue(L, -2); - lua_settable(L, -6); /* metatable[impname] = file */ - } - lua_settable(L, -3); /* io[name] = file */ -} - - static int aux_close (lua_State *L) { FILE *f = tofile(L, 1); if (f == stdin || f == stdout || f == stderr) @@ -158,10 +137,8 @@ static int aux_close (lua_State *L) { static int io_close (lua_State *L) { - if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { - lua_pushstring(L, IO_OUTPUT); - lua_rawget(L, lua_upvalueindex(1)); - } + if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) + lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); return pushresult(L, aux_close(L), NULL); } @@ -175,7 +152,7 @@ static int io_gc (lua_State *L) { static int io_tostring (lua_State *L) { - char buff[128]; + char buff[4*sizeof(void *) + 2]; /* enough space for a `%p' */ FILE **f = topfile(L, 1); if (*f == NULL) strcpy(buff, "closed"); @@ -216,17 +193,15 @@ static int io_tmpfile (lua_State *L) { } -static FILE *getiofile (lua_State *L, const char *name) { - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); +static FILE *getiofile (lua_State *L, int f) { + lua_rawgeti(L, lua_upvalueindex(1), f); return tofile(L, -1); } -static int g_iofile (lua_State *L, const char *name, const char *mode) { +static int g_iofile (lua_State *L, int f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); - lua_pushstring(L, name); if (filename) { FILE **pf = newfile(L); *pf = fopen(filename, mode); @@ -239,11 +214,10 @@ static int g_iofile (lua_State *L, const char *name, const char *mode) { tofile(L, 1); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } - lua_rawset(L, lua_upvalueindex(1)); + lua_rawseti(L, lua_upvalueindex(1), f); } /* return current value */ - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); + lua_rawgeti(L, lua_upvalueindex(1), f); return 1; } @@ -262,8 +236,7 @@ static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int idx, int close) { - lua_pushliteral(L, FILEHANDLE); - lua_rawget(L, LUA_REGISTRYINDEX); + lua_getfield(L, LUA_REGISTRYINDEX, FILEHANDLE); lua_pushvalue(L, idx); lua_pushboolean(L, close); /* close/not close file when finished */ lua_pushcclosure(L, io_readline, 3); @@ -279,8 +252,8 @@ static int f_lines (lua_State *L) { static int io_lines (lua_State *L) { if (lua_isnoneornil(L, 1)) { /* no arguments? */ - lua_pushstring(L, IO_INPUT); - lua_rawget(L, lua_upvalueindex(1)); /* will iterate over default input */ + /* will iterate over default input */ + lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); return f_lines(L); } else { @@ -372,7 +345,7 @@ static int g_read (lua_State *L, FILE *f, int first) { success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)lua_tonumber(L, n); + size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { @@ -467,18 +440,29 @@ static int f_seek (lua_State *L) { static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L, 1); int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); - long offset = luaL_optlong(L, 3, 0); + lua_Integer offset = luaL_optinteger(L, 3, 0); luaL_argcheck(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ else { - lua_pushnumber(L, ftell(f)); + lua_pushinteger(L, ftell(f)); return 1; } } +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L, 1); + int op = luaL_findstring(luaL_checkstring(L, 2), modenames); + luaL_argcheck(L, op != -1, 2, "invalid mode"); + return pushresult(L, setvbuf(f, NULL, mode[op], 0) == 0, NULL); +} + + + static int io_flush (lua_State *L) { return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } @@ -510,6 +494,7 @@ static const luaL_reg flib[] = { {"read", f_read}, {"lines", f_lines}, {"seek", f_seek}, + {"setvbuf", f_setvbuf}, {"write", f_write}, {"close", io_close}, {"__gc", io_gc}, @@ -520,10 +505,14 @@ static const luaL_reg flib[] = { static void createmeta (lua_State *L) { luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ + /* create (and set) default files */ + *newfile(L) = stdin; + lua_rawseti(L, -2, IO_INPUT); + *newfile(L) = stdout; + lua_rawseti(L, -2, IO_OUTPUT); /* file methods */ - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); /* push metatable */ - lua_rawset(L, -3); /* metatable.__index = metatable */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ luaL_openlib(L, NULL, flib, 0); } @@ -537,7 +526,7 @@ static void createmeta (lua_State *L) { */ static int io_execute (lua_State *L) { - lua_pushnumber(L, system(luaL_checkstring(L, 1))); + lua_pushinteger(L, system(luaL_checkstring(L, 1))); return 1; } @@ -591,7 +580,7 @@ static int io_clock (lua_State *L) { static void setfield (lua_State *L, const char *key, int value) { lua_pushstring(L, key); - lua_pushnumber(L, value); + lua_pushinteger(L, value); lua_rawset(L, -3); } @@ -603,8 +592,7 @@ static void setboolfield (lua_State *L, const char *key, int value) { static int getboolfield (lua_State *L, const char *key) { int res; - lua_pushstring(L, key); - lua_gettable(L, -2); + lua_getfield(L, -1, key); res = lua_toboolean(L, -1); lua_pop(L, 1); return res; @@ -613,12 +601,11 @@ static int getboolfield (lua_State *L, const char *key) { static int getfield (lua_State *L, const char *key, int d) { int res; - lua_pushstring(L, key); - lua_gettable(L, -2); + lua_getfield(L, -1, key); if (lua_isnumber(L, -1)) - res = (int)(lua_tonumber(L, -1)); + res = (int)lua_tointeger(L, -1); else { - if (d == -2) + if (d < 0) return luaL_error(L, "field `%s' missing in date table", key); res = d; } @@ -629,10 +616,9 @@ static int getfield (lua_State *L, const char *key, int d) { static int io_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - time_t t = (time_t)(luaL_optnumber(L, 2, -1)); + lua_Number n = luaL_optnumber(L, 2, -1); + time_t t = (n == -1) ? time(NULL) : (time_t)n; struct tm *stm; - if (t == (time_t)(-1)) /* no time given? */ - t = time(NULL); /* use current time */ if (*s == '!') { /* UTC? */ stm = gmtime(&t); s++; /* skip `!' */ @@ -642,7 +628,7 @@ static int io_date (lua_State *L) { if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { - lua_newtable(L); + lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); @@ -675,9 +661,9 @@ static int io_time (lua_State *L) { ts.tm_sec = getfield(L, "sec", 0); ts.tm_min = getfield(L, "min", 0); ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -2); - ts.tm_mon = getfield(L, "month", -2) - 1; - ts.tm_year = getfield(L, "year", -2) - 1900; + ts.tm_mday = getfield(L, "day", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); if (t == (time_t)(-1)) @@ -742,9 +728,15 @@ LUALIB_API int luaopen_io (lua_State *L) { lua_pushvalue(L, -1); luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* put predefined file handles into `io' table */ - registerfile(L, stdin, "stdin", IO_INPUT); - registerfile(L, stdout, "stdout", IO_OUTPUT); - registerfile(L, stderr, "stderr", NULL); + lua_pushliteral(L, "stdin"); + lua_rawgeti(L, 2, IO_INPUT); + lua_rawset(L, 3); + lua_pushliteral(L, "stdout"); + lua_rawgeti(L, 2, IO_OUTPUT); + lua_rawset(L, 3); + lua_pushliteral(L, "stderr"); + *newfile(L) = stderr; + lua_rawset(L, 3); return 1; } diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c index f074a56ee7..6041b2e3c5 100644 --- a/src/lib/lmathlib.c +++ b/src/lib/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.56 2003/03/11 12:30:37 roberto Exp $ +** $Id: lmathlib.c,v 1.59 2003/11/05 11:59:14 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -128,7 +128,7 @@ static int math_rad (lua_State *L) { static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); - lua_pushnumber(L, e); + lua_pushinteger(L, e); return 2; } @@ -179,14 +179,14 @@ static int math_random (lua_State *L) { case 1: { /* only upper limit */ int u = luaL_checkint(L, 1); luaL_argcheck(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */ + lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ int l = luaL_checkint(L, 1); int u = luaL_checkint(L, 2); luaL_argcheck(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */ + lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); @@ -235,12 +235,10 @@ static const luaL_reg mathlib[] = { */ LUALIB_API int luaopen_math (lua_State *L) { luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); - lua_pushliteral(L, "pi"); lua_pushnumber(L, PI); - lua_settable(L, -3); - lua_pushliteral(L, "__pow"); + lua_setfield(L, -2, "pi"); lua_pushcfunction(L, math_pow); - lua_settable(L, LUA_GLOBALSINDEX); + lua_setglobal(L, "__pow"); return 1; } diff --git a/src/lib/loadlib.c b/src/lib/loadlib.c index ac4d697a68..2a6b39e170 100644 --- a/src/lib/loadlib.c +++ b/src/lib/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.4 2003/04/07 20:11:53 roberto Exp $ +** $Id: loadlib.c,v 1.5 2003/05/14 21:01:53 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h * @@ -136,33 +136,13 @@ static int loadlib(lua_State *L) ** Those systems support dlopen, so they should have defined USE_DLOPEN. ** The default (no)implementation gives them a special error message. */ -#ifdef linux -#define LOADLIB -#endif - -#ifdef sun -#define LOADLIB -#endif - -#ifdef sgi -#define LOADLIB -#endif - -#ifdef BSD -#define LOADLIB -#endif - -#ifdef _WIN32 -#define LOADLIB -#endif - -#ifdef LOADLIB -#undef LOADLIB +#if defined(linux) || defined(sun) || defined(sgi) || defined(BSD) || defined(_WIN32) #define LOADLIB "`loadlib' not installed (check your Lua configuration)" #else #define LOADLIB "`loadlib' not supported" #endif + static int loadlib(lua_State *L) { lua_pushnil(L); diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index 8752e3aba3..36b226d25d 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.98 2003/04/03 13:35:34 roberto Exp $ +** $Id: lstrlib.c,v 1.101 2004/01/02 11:54:14 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -25,13 +25,13 @@ #endif -typedef long sint32; /* a signed version for size_t */ +typedef lua_Integer sint32; /* a signed version for size_t */ static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); - lua_pushnumber(L, (lua_Number)l); + lua_pushinteger(L, l); return 1; } @@ -45,8 +45,8 @@ static sint32 posrelat (sint32 pos, size_t len) { static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 start = posrelat(luaL_checklong(L, 2), l); - sint32 end = posrelat(luaL_optlong(L, 3, -1), l); + sint32 start = posrelat(luaL_checkinteger(L, 2), l); + sint32 end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > (sint32)l) end = (sint32)l; if (start <= end) @@ -56,6 +56,17 @@ static int str_sub (lua_State *L) { } +static int str_reverse (lua_State *L) { + size_t l; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + luaL_buffinit(L, &b); + while (l--) luaL_putchar(&b, s[l]); + luaL_pushresult(&b); + return 1; +} + + static int str_lower (lua_State *L) { size_t l; size_t i; @@ -97,10 +108,10 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 pos = posrelat(luaL_optlong(L, 2, 1), l); + sint32 pos = posrelat(luaL_optinteger(L, 2, 1), l); if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */ return 0; /* no answer */ - lua_pushnumber(L, uchar(s[pos-1])); + lua_pushinteger(L, uchar(s[pos-1])); return 1; } @@ -189,7 +200,7 @@ static const char *luaI_classend (MatchState *ms, const char *p) { switch (*p++) { case ESC: { if (*p == '\0') - luaL_error(ms->L, "malformed pattern (ends with `%')"); + luaL_error(ms->L, "malformed pattern (ends with `%%')"); return p+1; } case '[': { @@ -452,7 +463,7 @@ static void push_onecapture (MatchState *ms, int i) { int l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) - lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1)); + lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } @@ -477,7 +488,7 @@ static int str_find (lua_State *L) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); - sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1; + sint32 init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; if (init < 0) init = 0; else if ((size_t)(init) > l1) init = (sint32)l1; if (lua_toboolean(L, 4) || /* explicit request? */ @@ -485,8 +496,8 @@ static int str_find (lua_State *L) { /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { - lua_pushnumber(L, (lua_Number)(s2-s+1)); - lua_pushnumber(L, (lua_Number)(s2-s+l2)); + lua_pushinteger(L, s2-s+1); + lua_pushinteger(L, s2-s+l2); return 2; } } @@ -501,8 +512,8 @@ static int str_find (lua_State *L) { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { - lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */ - lua_pushnumber(L, (lua_Number)(res-s)); /* end */ + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ return push_captures(&ms, NULL, 0) + 2; } } while (s1++ MAX_FORMAT) /* +2 to include `%' and the specifier */ luaL_error(L, "invalid format (too long)"); - form[0] = '%'; + form[0] = ESC; strncpy(form+1, strfrmt, p-strfrmt+1); form[p-strfrmt+2] = 0; return p; @@ -686,9 +697,9 @@ static int str_format (lua_State *L) { luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { - if (*strfrmt != '%') + if (*strfrmt != ESC) luaL_putchar(&b, *strfrmt++); - else if (*++strfrmt == '%') + else if (*++strfrmt == ESC) luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ @@ -746,6 +757,7 @@ static int str_format (lua_State *L) { static const luaL_reg strlib[] = { {"len", str_len}, {"sub", str_sub}, + {"reverse", str_reverse}, {"lower", str_lower}, {"upper", str_upper}, {"char", str_char}, diff --git a/src/lib/ltablib.c b/src/lib/ltablib.c index c9bb2d1b7e..c38da36ffe 100644 --- a/src/lib/ltablib.c +++ b/src/lib/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.21 2003/04/03 13:35:34 roberto Exp $ +** $Id: ltablib.c,v 1.22 2003/10/07 20:13:41 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ static int luaB_foreachi (lua_State *L) { luaL_checktype(L, 2, LUA_TFUNCTION); for (i=1; i<=n; i++) { lua_pushvalue(L, 2); /* function */ - lua_pushnumber(L, (lua_Number)i); /* 1st argument */ + lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ lua_call(L, 2, 1); if (!lua_isnil(L, -1)) @@ -54,7 +54,7 @@ static int luaB_foreach (lua_State *L) { static int luaB_getn (lua_State *L) { - lua_pushnumber(L, (lua_Number)aux_getn(L, 1)); + lua_pushinteger(L, aux_getn(L, 1)); return 1; } diff --git a/src/llex.c b/src/llex.c index 045e999443..647e77f242 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 1.119 2003/03/24 12:39:34 roberto Exp $ +** $Id: llex.c,v 2.2 2004/03/12 19:53:56 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -22,9 +22,19 @@ -#define next(LS) (LS->current = zgetc(LS->z)) +#define next(ls) (ls->current = zgetc(ls->z)) +#define save(ls,c) { \ + Mbuffer *b = ls->buff; \ + if (b->n + 1 > b->buffsize) \ + luaZ_resizebuffer(ls->L, b, ((b->buffsize*2) + LUA_MINBUFFER)); \ + b->buffer[b->n++] = cast(char, c); } + + + +#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') + /* ORDER RESERVED */ static const char *const token2string [] = { @@ -51,85 +61,75 @@ void luaX_init (lua_State *L) { #define MAXSRC 80 -void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) { - if (val > limit) { - msg = luaO_pushfstring(ls->L, "too many %s (limit=%d)", msg, limit); - luaX_syntaxerror(ls, msg); +const char *luaX_token2str (LexState *ls, int token) { + if (token < FIRST_RESERVED) { + lua_assert(token == (unsigned char)token); + return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : + luaO_pushfstring(ls->L, "%c", token); } + else + return token2string[token-FIRST_RESERVED]; } -void luaX_errorline (LexState *ls, const char *s, const char *token, int line) { - lua_State *L = ls->L; - char buff[MAXSRC]; - luaO_chunkid(buff, getstr(ls->source), MAXSRC); - luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, line, s, token); - luaD_throw(L, LUA_ERRSYNTAX); -} - - -static void luaX_error (LexState *ls, const char *s, const char *token) { - luaX_errorline(ls, s, token, ls->linenumber); -} - - -void luaX_syntaxerror (LexState *ls, const char *msg) { - const char *lasttoken; - switch (ls->t.token) { +static const char *txtToken (LexState *ls, int token) { + switch (token) { case TK_NAME: - lasttoken = getstr(ls->t.seminfo.ts); - break; case TK_STRING: case TK_NUMBER: - lasttoken = luaZ_buffer(ls->buff); - break; + save(ls, '\0'); + return luaZ_buffer(ls->buff); default: - lasttoken = luaX_token2str(ls, ls->t.token); - break; + return luaX_token2str(ls, token); } - luaX_error(ls, msg, lasttoken); } -const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { - lua_assert(token == (unsigned char)token); - return luaO_pushfstring(ls->L, "%c", token); - } - else - return token2string[token-FIRST_RESERVED]; +void luaX_lexerror (LexState *ls, const char *msg, int token) { + char buff[MAXSRC]; + luaO_chunkid(buff, getstr(ls->source), MAXSRC); + msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); + if (token) + luaO_pushfstring(ls->L, "%s near `%s'", msg, txtToken(ls, token)); + luaD_throw(ls->L, LUA_ERRSYNTAX); } -static void luaX_lexerror (LexState *ls, const char *s, int token) { - if (token == TK_EOS) - luaX_error(ls, s, luaX_token2str(ls, token)); - else - luaX_error(ls, s, luaZ_buffer(ls->buff)); +void luaX_syntaxerror (LexState *ls, const char *msg) { + luaX_lexerror(ls, msg, ls->t.token); } -static void inclinenumber (LexState *LS) { - next(LS); /* skip `\n' */ - ++LS->linenumber; - luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk"); +TString *luaX_newstring (LexState *ls, const char *str, size_t l) { + lua_State *L = ls->L; + TString *ts = luaS_newlstr(L, str, l); + TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ + if (ttisnil(o)) + setbvalue(o, 1); /* make sure `str' will not be collected */ + return ts; } -void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { - LS->L = L; - LS->lookahead.token = TK_EOS; /* no look-ahead token */ - LS->z = z; - LS->fs = NULL; - LS->linenumber = 1; - LS->lastline = 1; - LS->source = source; - next(LS); /* read first char */ - if (LS->current == '#') { - do { /* skip first line */ - next(LS); - } while (LS->current != '\n' && LS->current != EOZ); - } +static void inclinenumber (LexState *ls) { + int old = ls->current; + lua_assert(currIsNewline(ls)); + next(ls); /* skip `\n' or `\r' */ + if (currIsNewline(ls) && ls->current != old) + next(ls); /* skip `\n\r' or `\r\n' */ + if (++ls->linenumber >= MAX_INT) + luaX_syntaxerror(ls, "chunk has too many lines"); +} + + +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { + ls->L = L; + ls->lookahead.token = TK_EOS; /* no look-ahead token */ + ls->z = z; + ls->fs = NULL; + ls->linenumber = 1; + ls->lastline = 1; + ls->source = source; + next(ls); /* read first char */ } @@ -141,242 +141,229 @@ void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { */ -/* use buffer to store names, literal strings and numbers */ -/* extra space to allocate when growing buffer */ -#define EXTRABUFF 32 - -/* maximum number of chars that can be read without checking buffer size */ -#define MAXNOCHECK 5 - -#define checkbuffer(LS, len) \ - if (((len)+MAXNOCHECK)*sizeof(char) > luaZ_sizebuffer((LS)->buff)) \ - luaZ_openspace((LS)->L, (LS)->buff, (len)+EXTRABUFF) - -#define save(LS, c, l) \ - (luaZ_buffer((LS)->buff)[l++] = cast(char, c)) -#define save_and_next(LS, l) (save(LS, LS->current, l), next(LS)) - - -static size_t readname (LexState *LS) { - size_t l = 0; - checkbuffer(LS, l); - do { - checkbuffer(LS, l); - save_and_next(LS, l); - } while (isalnum(LS->current) || LS->current == '_'); - save(LS, '\0', l); - return l-1; +static void save_and_next (LexState *ls) { + save(ls, ls->current); + next(ls); } + /* LUA_NUMBER */ -static void read_numeral (LexState *LS, int comma, SemInfo *seminfo) { - size_t l = 0; - checkbuffer(LS, l); - if (comma) save(LS, '.', l); - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); +static void read_numeral (LexState *ls, SemInfo *seminfo) { + while (isdigit(ls->current)) { + save_and_next(ls); } - if (LS->current == '.') { - save_and_next(LS, l); - if (LS->current == '.') { - save_and_next(LS, l); - save(LS, '\0', l); - luaX_lexerror(LS, + if (ls->current == '.') { + save_and_next(ls); + if (ls->current == '.') { + save_and_next(ls); + luaX_lexerror(ls, "ambiguous syntax (decimal point x string concatenation)", TK_NUMBER); } } - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); + while (isdigit(ls->current)) { + save_and_next(ls); } - if (LS->current == 'e' || LS->current == 'E') { - save_and_next(LS, l); /* read `E' */ - if (LS->current == '+' || LS->current == '-') - save_and_next(LS, l); /* optional exponent sign */ - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); + if (ls->current == 'e' || ls->current == 'E') { + save_and_next(ls); /* read `E' */ + if (ls->current == '+' || ls->current == '-') + save_and_next(ls); /* optional exponent sign */ + while (isdigit(ls->current)) { + save_and_next(ls); } } - save(LS, '\0', l); - if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r)) - luaX_lexerror(LS, "malformed number", TK_NUMBER); + save(ls, '\0'); + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) + luaX_lexerror(ls, "malformed number", TK_NUMBER); } -static void read_long_string (LexState *LS, SemInfo *seminfo) { +static int skip_ast (LexState *ls) { + int count = 0; + int s = ls->current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls->current == '*') { + save_and_next(ls); + count++; + } + return (ls->current == s) ? count : (-count) - 1; +} + + +static void read_long_string (LexState *ls, SemInfo *seminfo, int ast) { int cont = 0; - size_t l = 0; - checkbuffer(LS, l); - save(LS, '[', l); /* save first `[' */ - save_and_next(LS, l); /* pass the second `[' */ - if (LS->current == '\n') /* string starts with a newline? */ - inclinenumber(LS); /* skip it */ + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ for (;;) { - checkbuffer(LS, l); - switch (LS->current) { + switch (ls->current) { case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, (seminfo) ? "unfinished long string" : + luaX_lexerror(ls, (seminfo) ? "unfinished long string" : "unfinished long comment", TK_EOS); break; /* to avoid warnings */ case '[': - save_and_next(LS, l); - if (LS->current == '[') { + if (skip_ast(ls) == ast) { + save_and_next(ls); /* skip 2nd `[' */ cont++; - save_and_next(LS, l); } continue; case ']': - save_and_next(LS, l); - if (LS->current == ']') { - if (cont == 0) goto endloop; - cont--; - save_and_next(LS, l); + if (skip_ast(ls) == ast) { + save_and_next(ls); /* skip 2nd `]' */ + if (cont-- == 0) goto endloop; } continue; case '\n': - save(LS, '\n', l); - inclinenumber(LS); - if (!seminfo) l = 0; /* reset buffer to avoid wasting space */ + case '\r': + save(ls, '\n'); + inclinenumber(ls); + if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ continue; default: - save_and_next(LS, l); + if (seminfo) save_and_next(ls); + else next(ls); } } endloop: - save_and_next(LS, l); /* skip the second `]' */ - save(LS, '\0', l); if (seminfo) - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 2, l - 5); + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + ast), + luaZ_bufflen(ls->buff) - 2*(2 + ast)); } -static void read_string (LexState *LS, int del, SemInfo *seminfo) { - size_t l = 0; - checkbuffer(LS, l); - save_and_next(LS, l); - while (LS->current != del) { - checkbuffer(LS, l); - switch (LS->current) { +static void read_string (LexState *ls, int del, SemInfo *seminfo) { + save_and_next(ls); + while (ls->current != del) { + switch (ls->current) { case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_EOS); - break; /* to avoid warnings */ + luaX_lexerror(ls, "unfinished string", TK_EOS); + continue; /* to avoid warnings */ case '\n': - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': - next(LS); /* do not save the `\' */ - switch (LS->current) { - case 'a': save(LS, '\a', l); next(LS); break; - case 'b': save(LS, '\b', l); next(LS); break; - case 'f': save(LS, '\f', l); next(LS); break; - case 'n': save(LS, '\n', l); next(LS); break; - case 'r': save(LS, '\r', l); next(LS); break; - case 't': save(LS, '\t', l); next(LS); break; - case 'v': save(LS, '\v', l); next(LS); break; - case '\n': save(LS, '\n', l); inclinenumber(LS); break; - case EOZ: break; /* will raise an error next loop */ + case '\r': + luaX_lexerror(ls, "unfinished string", TK_STRING); + continue; /* to avoid warnings */ + case '\\': { + int c; + next(ls); /* do not save the `\' */ + switch (ls->current) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\n': /* go through */ + case '\r': save(ls, '\n'); inclinenumber(ls); continue; + case EOZ: continue; /* will raise an error next loop */ default: { - if (!isdigit(LS->current)) - save_and_next(LS, l); /* handles \\, \", \', and \? */ + if (!isdigit(ls->current)) + save_and_next(ls); /* handles \\, \", \', and \? */ else { /* \xxx */ - int c = 0; int i = 0; + c = 0; do { - c = 10*c + (LS->current-'0'); - next(LS); - } while (++i<3 && isdigit(LS->current)); - if (c > UCHAR_MAX) { - save(LS, '\0', l); - luaX_lexerror(LS, "escape sequence too large", TK_STRING); - } - save(LS, c, l); + c = 10*c + (ls->current-'0'); + next(ls); + } while (++i<3 && isdigit(ls->current)); + if (c > UCHAR_MAX) + luaX_lexerror(ls, "escape sequence too large", TK_STRING); + save(ls, c); } + continue; } } - break; + save(ls, c); + next(ls); + continue; + } default: - save_and_next(LS, l); + save_and_next(ls); } } - save_and_next(LS, l); /* skip delimiter */ - save(LS, '\0', l); - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 1, l - 3); + save_and_next(ls); /* skip delimiter */ + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, + luaZ_bufflen(ls->buff) - 2); } -int luaX_lex (LexState *LS, SemInfo *seminfo) { +int luaX_lex (LexState *ls, SemInfo *seminfo) { + luaZ_resetbuffer(ls->buff); for (;;) { - switch (LS->current) { - - case '\n': { - inclinenumber(LS); + switch (ls->current) { + case '\n': + case '\r': { + inclinenumber(ls); continue; } case '-': { - next(LS); - if (LS->current != '-') return '-'; + next(ls); + if (ls->current != '-') return '-'; /* else is a comment */ - next(LS); - if (LS->current == '[' && (next(LS), LS->current == '[')) - read_long_string(LS, NULL); /* long comment */ - else /* short comment */ - while (LS->current != '\n' && LS->current != EOZ) - next(LS); + next(ls); + if (ls->current == '[') { + int ast = skip_ast(ls); + luaZ_resetbuffer(ls->buff); /* `skip_ast' may dirty the buffer */ + if (ast >= 0) { + read_long_string(ls, NULL, ast); /* long comment */ + luaZ_resetbuffer(ls->buff); + continue; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls->current != EOZ) + next(ls); continue; } case '[': { - next(LS); - if (LS->current != '[') return '['; - else { - read_long_string(LS, seminfo); + int ast = skip_ast(ls); + if (ast >= 0) { + read_long_string(ls, seminfo, ast); return TK_STRING; } + else if (ast == -1) return '['; + else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { - next(LS); - if (LS->current != '=') return '='; - else { next(LS); return TK_EQ; } + next(ls); + if (ls->current != '=') return '='; + else { next(ls); return TK_EQ; } } case '<': { - next(LS); - if (LS->current != '=') return '<'; - else { next(LS); return TK_LE; } + next(ls); + if (ls->current != '=') return '<'; + else { next(ls); return TK_LE; } } case '>': { - next(LS); - if (LS->current != '=') return '>'; - else { next(LS); return TK_GE; } + next(ls); + if (ls->current != '=') return '>'; + else { next(ls); return TK_GE; } } case '~': { - next(LS); - if (LS->current != '=') return '~'; - else { next(LS); return TK_NE; } + next(ls); + if (ls->current != '=') return '~'; + else { next(ls); return TK_NE; } } case '"': case '\'': { - read_string(LS, LS->current, seminfo); + read_string(ls, ls->current, seminfo); return TK_STRING; } case '.': { - next(LS); - if (LS->current == '.') { - next(LS); - if (LS->current == '.') { - next(LS); + save_and_next(ls); + if (ls->current == '.') { + next(ls); + if (ls->current == '.') { + next(ls); return TK_DOTS; /* ... */ } else return TK_CONCAT; /* .. */ } - else if (!isdigit(LS->current)) return '.'; + else if (!isdigit(ls->current)) return '.'; else { - read_numeral(LS, 1, seminfo); + read_numeral(ls, seminfo); return TK_NUMBER; } } @@ -384,29 +371,33 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) { return TK_EOS; } default: { - if (isspace(LS->current)) { - next(LS); + if (isspace(ls->current)) { + lua_assert(!currIsNewline(ls)); + next(ls); continue; } - else if (isdigit(LS->current)) { - read_numeral(LS, 0, seminfo); + else if (isdigit(ls->current)) { + read_numeral(ls, seminfo); return TK_NUMBER; } - else if (isalpha(LS->current) || LS->current == '_') { + else if (isalpha(ls->current) || ls->current == '_') { /* identifier or reserved word */ - size_t l = readname(LS); - TString *ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff), l); + TString *ts; + do { + save_and_next(ls); + } while (isalnum(ls->current) || ls->current == '_'); + ts = luaX_newstring(ls, luaZ_buffer(ls->buff), + luaZ_bufflen(ls->buff)); if (ts->tsv.reserved > 0) /* reserved word? */ return ts->tsv.reserved - 1 + FIRST_RESERVED; - seminfo->ts = ts; - return TK_NAME; + else { + seminfo->ts = ts; + return TK_NAME; + } } else { - int c = LS->current; - if (iscntrl(c)) - luaX_error(LS, "invalid control char", - luaO_pushfstring(LS->L, "char(%d)", c)); - next(LS); + int c = ls->current; + next(ls); return c; /* single-char tokens (+ - / ...) */ } } diff --git a/src/llex.h b/src/llex.h index 740e3f6b31..6cfc3fdde8 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.47 2003/02/28 17:19:47 roberto Exp $ +** $Id: llex.h,v 1.50 2004/03/12 19:53:56 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -65,10 +65,10 @@ typedef struct LexState { void luaX_init (lua_State *L); void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source); +TString *luaX_newstring (LexState *LS, const char *str, size_t l); int luaX_lex (LexState *LS, SemInfo *seminfo); -void luaX_checklimit (LexState *ls, int val, int limit, const char *msg); +void luaX_lexerror (LexState *ls, const char *msg, int token); void luaX_syntaxerror (LexState *ls, const char *s); -void luaX_errorline (LexState *ls, const char *s, const char *token, int line); const char *luaX_token2str (LexState *ls, int token); diff --git a/src/llimits.h b/src/llimits.h index 343c922612..6a2e00bdde 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.52 2003/02/20 19:33:23 roberto Exp $ +** $Id: llimits.h,v 1.57 2003/12/01 16:33:30 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -22,15 +22,13 @@ /* avoid overflows in comparison */ #if INT_MAX-20 < 32760 #define BITS_INT 16 -#else -#if INT_MAX > 2147483640L +#elif INT_MAX > 2147483640L /* machine has at least 32 bits */ #define BITS_INT 32 #else #error "you must define BITS_INT with number of bits in an integer" #endif #endif -#endif /* @@ -40,20 +38,43 @@ ** any machine, but may not be optimal. */ -/* an unsigned integer to hold hash values */ -typedef unsigned int lu_hash; -/* its signed equivalent */ -typedef int ls_hash; -/* an unsigned integer big enough to count the total memory used by Lua; */ -/* it should be at least as large as size_t */ -typedef unsigned long lu_mem; +/* +** an unsigned integer with at least 32 bits +*/ +#ifndef LUA_UINT32 +#define LUA_UINT32 unsigned long +#endif + +typedef LUA_UINT32 lu_int32; + + +/* +** a signed integer with at least 32 bits +*/ +#ifndef LUA_INT32 +#define LUA_INT32 long +#define LUA_MAXINT32 LONG_MAX +#endif + +typedef LUA_INT32 l_int32; + -#define MAX_LUMEM ULONG_MAX +/* +** an unsigned integer big enough to count the total memory used by Lua; +** it should be at least as large as `size_t' +*/ +typedef lu_int32 lu_mem; + + +/* +** a signed integer big enough to count the total memory used by Lua; +** it should be at least as large as `size_t' +*/ +typedef l_int32 l_mem; +#define MAXLMEM LUA_MAXINT32 -/* an integer big enough to count the number of strings in use */ -typedef long ls_nstr; /* chars used as small naturals (so that `char' is reserved for characters) */ typedef unsigned char lu_byte; @@ -69,7 +90,7 @@ typedef unsigned char lu_byte; ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ -#define IntPoint(p) ((lu_hash)(p)) +#define IntPoint(p) ((unsigned int)(p)) @@ -114,7 +135,7 @@ typedef LUA_UACNUMBER l_uacNumber; ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ -typedef unsigned long Instruction; +typedef lu_int32 Instruction; /* maximum depth for calls (unsigned short) */ @@ -133,7 +154,7 @@ typedef unsigned long Instruction; #endif -/* maximum size for the C stack */ +/* maximum size for the virtual stack of a C function */ #ifndef LUA_MAXCSTACK #define LUA_MAXCSTACK 2048 #endif @@ -145,19 +166,13 @@ typedef unsigned long Instruction; /* maximum number of variables declared in a function */ #ifndef MAXVARS -#define MAXVARS 200 /* arbitrary limit ( +#include #define lmem_c @@ -20,21 +20,23 @@ /* -** definition for realloc function. It must assure that l_realloc(NULL, -** 0, x) allocates a new block (ANSI C assures that). (`os' is the old -** block size; some allocators may use that.) +** About the realloc function: +** void * realloc (void *ud, void *ptr, size_t osize, size_t nsize); +** (`osize' is the old size, `nsize' is the new size) +** +** Lua ensures that (ptr == NULL) iff (osize == 0). +** +** * realloc(ud, NULL, 0, x) creates a new block of size `x' +** +** * realloc(ud, p, x, 0) frees the block `p' +** (in this specific case, realloc must return NULL). +** particularly, realloc(ud, NULL, 0, 0) does nothing +** (which is equivalent to free(NULL) in ANSI C) +** +** realloc returns NULL if it cannot create or reallocate the area +** (any reallocation to an equal or smaller size cannot fail!) */ -#ifndef l_realloc -#define l_realloc(b,os,s) realloc(b,s) -#endif -/* -** definition for free function. (`os' is the old block size; some -** allocators may use that.) -*/ -#ifndef l_free -#define l_free(b,os) free(b) -#endif #define MINSIZEARRAY 4 @@ -43,13 +45,16 @@ void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, int limit, const char *errormsg) { void *newblock; - int newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - else if (*size >= limit/2) { /* cannot double it? */ - if (*size < limit - MINSIZEARRAY) /* try something smaller... */ - newsize = limit; /* still have at least MINSIZEARRAY free places */ - else luaG_runerror(L, errormsg); + int newsize; + if (*size >= limit/2) { /* cannot double it? */ + if (*size >= limit - MINSIZEARRAY) /* try something smaller... */ + luaG_runerror(L, errormsg); + newsize = limit; /* still have at least MINSIZEARRAY free places */ + } + else { + newsize = (*size)*2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ } newblock = luaM_realloc(L, block, cast(lu_mem, *size)*cast(lu_mem, size_elems), @@ -62,30 +67,17 @@ void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, /* ** generic allocation routine. */ -void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) { - lua_assert((oldsize == 0) == (block == NULL)); - if (size == 0) { - if (block != NULL) { - l_free(block, oldsize); - block = NULL; - } - else return NULL; /* avoid `nblocks' computations when oldsize==size==0 */ - } - else if (size >= MAX_SIZET) +void *luaM_realloc (lua_State *L, void *block, lu_mem osize, lu_mem nsize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + if (nsize >= MAX_SIZET) luaG_runerror(L, "memory allocation error: block too big"); - else { - block = l_realloc(block, oldsize, size); - if (block == NULL) { - if (L) - luaD_throw(L, LUA_ERRMEM); - else return NULL; /* error before creating state! */ - } - } - if (L) { - lua_assert(G(L) != NULL && G(L)->nblocks > 0); - G(L)->nblocks -= oldsize; - G(L)->nblocks += size; - } + block = (*g->realloc)(g->ud, block, osize, nsize); + if (block == NULL && nsize > 0) + luaD_throw(L, LUA_ERRMEM); + lua_assert((nsize == 0) == (block == NULL)); + g->nblocks -= osize; + g->nblocks += nsize; return block; } diff --git a/src/lobject.c b/src/lobject.c index 9522b6e812..f273796b66 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 1.97 2003/04/03 13:35:34 roberto Exp $ +** $Id: lobject.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -27,7 +27,7 @@ #endif -const TObject luaO_nilobject = {LUA_TNIL, {NULL}}; +const TValue luaO_nilobject = {LUA_TNIL, {NULL}}; /* @@ -45,33 +45,24 @@ int luaO_int2fb (unsigned int x) { int luaO_log2 (unsigned int x) { - static const lu_byte log_8[255] = { - 0, - 1,1, - 2,2,2,2, - 3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + static const lu_byte log_2[256] = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; - if (x >= 0x00010000) { - if (x >= 0x01000000) return log_8[((x>>24) & 0xff) - 1]+24; - else return log_8[((x>>16) & 0xff) - 1]+16; - } - else { - if (x >= 0x00000100) return log_8[((x>>8) & 0xff) - 1]+8; - else if (x) return log_8[(x & 0xff) - 1]; - return -1; /* special `log' for 0 */ - } + int l = -1; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; + } -int luaO_rawequalObj (const TObject *t1, const TObject *t2) { +int luaO_rawequalObj (const TValue *t1, const TValue *t2) { if (ttype(t1) != ttype(t2)) return 0; else switch (ttype(t1)) { case LUA_TNIL: @@ -102,7 +93,7 @@ int luaO_str2d (const char *s, lua_Number *result) { static void pushstr (lua_State *L, const char *str) { - setsvalue2s(L->top, luaS_new(L, str)); + setsvalue2s(L, L->top, luaS_new(L, str)); incr_top(L); } @@ -114,7 +105,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - setsvalue2s(L->top, luaS_newlstr(L, fmt, e-fmt)); + setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); incr_top(L); switch (*(e+1)) { case 's': @@ -138,7 +129,14 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { case '%': pushstr(L, "%"); break; - default: lua_assert(0); + default: { + char buff[3]; + buff[0] = '%'; + buff[1] = *(e+1); + buff[2] = '\0'; + pushstr(L, buff); + break; + } } n += 2; fmt = e+2; diff --git a/src/lobject.h b/src/lobject.h index 321a7e06c1..d5176a232d 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,13 +1,17 @@ /* -** $Id: lobject.h,v 1.159 2003/03/18 12:50:04 roberto Exp $ +** $Id: lobject.h,v 2.4 2004/03/15 21:04:33 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ + #ifndef lobject_h #define lobject_h +#include + + #include "llimits.h" #include "lua.h" @@ -58,12 +62,12 @@ typedef union { /* -** Lua values (or `tagged objects') +** Tagged Values */ -typedef struct lua_TObject { +typedef struct lua_TValue { int tt; Value value; -} TObject; +} TValue; /* Macros to test type */ @@ -82,8 +86,10 @@ typedef struct lua_TObject { #define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) #define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) #define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) -#define tsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) -#define uvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#define tsvalue(o) (&rawtsvalue(o)->tsv) +#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define uvalue(o) (&rawuvalue(o)->uv) #define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) #define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) #define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) @@ -91,59 +97,69 @@ typedef struct lua_TObject { #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) +/* +** for internal debug only +*/ +#define checkconsistency(obj) \ + lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) + +#define checkliveness(g,obj) \ + lua_assert(!iscollectable(obj) || \ + ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + + /* Macros to set values */ +#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) + #define setnvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TNUMBER; i_o->value.n=(x); } + { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } #define chgnvalue(obj,x) \ check_exp(ttype(obj)==LUA_TNUMBER, (obj)->value.n=(x)) #define setpvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TLIGHTUSERDATA; i_o->value.p=(x); } + { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } #define setbvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TBOOLEAN; i_o->value.b=(x); } + { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } -#define setsvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TSTRING; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TSTRING); } +#define setsvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ + checkliveness(G(L),i_o); } -#define setuvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TUSERDATA; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TUSERDATA); } +#define setuvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + checkliveness(G(L),i_o); } -#define setthvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TTHREAD; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TTHREAD); } +#define setthvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + checkliveness(G(L),i_o); } -#define setclvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TFUNCTION; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TFUNCTION); } +#define setclvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + checkliveness(G(L),i_o); } -#define sethvalue(obj,x) \ - { TObject *i_o=(obj); i_o->tt=LUA_TTABLE; \ - i_o->value.gc=cast(GCObject *, (x)); \ - lua_assert(i_o->value.gc->gch.tt == LUA_TTABLE); } - -#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) +#define sethvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + checkliveness(G(L),i_o); } +#define setptvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + checkliveness(G(L),i_o); } -/* -** for internal debug only -*/ -#define checkconsistency(obj) \ - lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) -#define setobj(obj1,obj2) \ - { const TObject *o2=(obj2); TObject *o1=(obj1); \ - checkconsistency(o2); \ - o1->tt=o2->tt; o1->value = o2->value; } +#define setobj(L,obj1,obj2) \ + { const TValue *o2=(obj2); TValue *o1=(obj1); \ + o1->tt=o2->tt; o1->value = o2->value; \ + checkliveness(G(L),o1); } /* @@ -155,6 +171,8 @@ typedef struct lua_TObject { /* to stack (not from same stack) */ #define setobj2s setobj #define setsvalue2s setsvalue +#define sethvalue2s sethvalue +#define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj /* to table */ @@ -170,7 +188,7 @@ typedef struct lua_TObject { -typedef TObject *StkId; /* index to stack elements */ +typedef TValue *StkId; /* index to stack elements */ /* @@ -181,7 +199,7 @@ typedef union TString { struct { CommonHeader; lu_byte reserved; - lu_hash hash; + unsigned int hash; size_t len; } tsv; } TString; @@ -209,7 +227,7 @@ typedef union Udata { */ typedef struct Proto { CommonHeader; - TObject *k; /* constants used by the function */ + TValue *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ @@ -245,8 +263,8 @@ typedef struct LocVar { typedef struct UpVal { CommonHeader; - TObject *v; /* points to stack or to its own value */ - TObject value; /* the value (when closed) */ + TValue *v; /* points to stack or to its own value */ + TValue value; /* the value (when closed) */ } UpVal; @@ -260,14 +278,14 @@ typedef struct UpVal { typedef struct CClosure { ClosureHeader; lua_CFunction f; - TObject upvalue[1]; + TValue upvalue[1]; } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; - TObject g; /* global table for this closure */ + TValue g; /* global table for this closure */ UpVal *upvals[1]; } LClosure; @@ -287,8 +305,8 @@ typedef union Closure { */ typedef struct Node { - TObject i_key; - TObject i_val; + TValue i_key; + TValue i_val; struct Node *next; /* for chaining */ } Node; @@ -298,7 +316,7 @@ typedef struct Table { lu_byte flags; /* 1<

        > 3)) -int luaO_rawequalObj (const TObject *t1, const TObject *t2); +int luaO_rawequalObj (const TValue *t1, const TValue *t2); int luaO_str2d (const char *s, lua_Number *result); const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); diff --git a/src/lopcodes.c b/src/lopcodes.c index 993e426d35..3ffda71a56 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,7 +1,5 @@ /* -** $Id: lopcodes.c,v 1.22 2002/12/04 17:38:31 roberto Exp $ -** extracted automatically from lopcodes.h by mkprint.lua -** DO NOT EDIT +** $Id: lopcodes.c,v 1.25 2003/05/14 21:09:53 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -14,9 +12,11 @@ #include "lopcodes.h" +/* ORDER OP */ + #ifdef LUA_OPNAMES -const char *const luaP_opnames[] = { +const char *const luaP_opnames[NUM_OPCODES] = { "MOVE", "LOADK", "LOADBOOL", @@ -46,6 +46,7 @@ const char *const luaP_opnames[] = { "TAILCALL", "RETURN", "FORLOOP", + "FORPREP", "TFORLOOP", "TFORPREP", "SETLIST", @@ -56,47 +57,45 @@ const char *const luaP_opnames[] = { #endif -#define opmode(t,b,bk,ck,sa,k,m) (((t)<> 4) & 3)) +#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) -#ifdef LUA_OPNAMES -extern const char *const luaP_opnames[]; /* opcode names */ -#endif - +extern const char *const luaP_opnames[NUM_OPCODES]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ diff --git a/src/lparser.c b/src/lparser.c index 99bd3020e7..a8dafb6fab 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 1.208a 2003/04/03 13:35:34 roberto Exp $ +** $Id: lparser.c,v 2.2 2004/03/12 19:53:56 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -13,6 +13,7 @@ #include "lcode.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" @@ -27,9 +28,10 @@ #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) +#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) luaY_errorlimit(fs,l,m) -#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ - luaX_syntaxerror(ls, "too many syntax levels"); +#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ + luaX_lexerror(ls, "chunk has too many syntax levels", 0) #define leavelevel(ls) ((ls)->nestlevel--) @@ -39,9 +41,9 @@ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ int breaklist; /* list of jumps out of this loop */ - int nactvar; /* # active local variables outside the breakable structure */ - int upval; /* true if some variable in the block is an upvalue */ - int isbreakable; /* true if `block' is a loop */ + lu_byte nactvar; /* # active locals outside the breakable structure */ + lu_byte upval; /* true if some variable in the block is an upvalue */ + lu_byte isbreakable; /* true if `block' is a loop */ } BlockCnt; @@ -71,12 +73,29 @@ static void lookahead (LexState *ls) { } +static void anchor_token (LexState *ls) { + if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { + TString *ts = ls->t.seminfo.ts; + luaX_newstring(ls, getstr(ts), ts->tsv.len); + } +} + + static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token))); } +static void luaY_errorlimit (FuncState *fs, int limit, const char *what) { + const char *msg = (fs->f->lineDefined == 0) ? + luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : + luaO_pushfstring(fs->L, "function at line %d has more than %d %s", + fs->f->lineDefined, limit, what); + luaX_lexerror(fs->ls, msg, 0); +} + + static int testnext (LexState *ls, int c) { if (ls->t.token == c) { next(ls); @@ -138,17 +157,25 @@ static void checkname(LexState *ls, expdesc *e) { static int luaI_registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; + int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, MAX_INT, ""); + LocVar, USHRT_MAX, "too many local variables"); + while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; + luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; } +#define new_localvarliteral(ls,v,n) \ + new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) + + static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; - luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "local variables"); - fs->actvar[fs->nactvar+n] = luaI_registerlocalvar(ls, name); + luaY_checklimit(fs, fs->nactvar+n+1, MAXVARS, "local variables"); + fs->actvar[fs->nactvar+n] = cast(unsigned short, + luaI_registerlocalvar(ls, name)); } @@ -168,32 +195,26 @@ static void removevars (LexState *ls, int tolevel) { } -static void new_localvarstr (LexState *ls, const char *name, int n) { - new_localvar(ls, luaS_new(ls->L, name), n); -} - - -static void create_local (LexState *ls, const char *name) { - new_localvarstr(ls, name, 0); - adjustlocalvars(ls, 1); -} - - static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { int i; Proto *f = fs->f; + int oldsize = f->sizeupvalues; for (i=0; inups; i++) { if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) { - lua_assert(fs->f->upvalues[i] == name); + lua_assert(f->upvalues[i] == name); return i; } } /* new one */ - luaX_checklimit(fs->ls, f->nups + 1, MAXUPVALUES, "upvalues"); - luaM_growvector(fs->L, fs->f->upvalues, f->nups, fs->f->sizeupvalues, + luaY_checklimit(fs, f->nups + 1, MAXUPVALUES, "upvalues"); + luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, TString *, MAX_INT, ""); - fs->f->upvalues[f->nups] = name; - fs->upvalues[f->nups] = *v; + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; + f->upvalues[f->nups] = name; + luaC_objbarrier(fs->L, f, name); + lua_assert(v->k == VLOCAL || v->k == VUPVAL); + fs->upvalues[f->nups].k = cast(lu_byte, v->k); + fs->upvalues[f->nups].info = cast(lu_byte, v->info); return f->nups++; } @@ -267,18 +288,6 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { } -static void code_params (LexState *ls, int nparams, int dots) { - FuncState *fs = ls->fs; - adjustlocalvars(ls, nparams); - luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters"); - fs->f->numparams = cast(lu_byte, fs->nactvar); - fs->f->is_vararg = cast(lu_byte, dots); - if (dots) - create_local(ls, "arg"); - luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ -} - - static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; @@ -305,10 +314,13 @@ static void leaveblock (FuncState *fs) { static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { FuncState *fs = ls->fs; Proto *f = fs->f; + int oldsize = f->sizep; int i; luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "constant table overflow"); + while (oldsize < f->sizep) f->p[oldsize++] = NULL; f->p[fs->np++] = func->f; + luaC_objbarrier(ls->L, f, func->f); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); for (i=0; if->nups; i++) { OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; @@ -318,24 +330,30 @@ static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { static void open_func (LexState *ls, FuncState *fs) { - Proto *f = luaF_newproto(ls->L); + lua_State *L = ls->L; + Proto *f = luaF_newproto(L); fs->f = f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; - fs->L = ls->L; + fs->L = L; ls->fs = fs; fs->pc = 0; fs->lasttarget = 0; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; - fs->h = luaH_new(ls->L, 0, 0); fs->np = 0; fs->nlocvars = 0; fs->nactvar = 0; fs->bl = NULL; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ + fs->h = luaH_new(L, 0, 0); + /* anchor table of constants and prototype (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); + setptvalue2s(L, L->top, f); + incr_top(L); } @@ -349,7 +367,7 @@ static void close_func (LexState *ls) { f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); f->sizelineinfo = fs->pc; - luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject); + luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); f->sizek = fs->nk; luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); f->sizep = fs->np; @@ -360,15 +378,18 @@ static void close_func (LexState *ls) { lua_assert(luaG_checkcode(f)); lua_assert(fs->bl == NULL); ls->fs = fs->prev; + L->top -= 2; /* remove table and prototype from the stack */ + /* last token read was anchored in defunct function; must reanchor it */ + if (fs) anchor_token(ls); } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; lexstate.nestlevel = 0; - luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); + luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); next(&lexstate); /* read first token */ chunk(&lexstate); @@ -377,6 +398,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.nestlevel == 0); + lua_assert(lexstate.fs == NULL); return funcstate.f; } @@ -429,7 +451,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { int reg = ls->fs->freereg; expdesc key, val; if (ls->t.token == TK_NAME) { - luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor"); + luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); cc->nh++; checkname(ls, &key); } @@ -473,7 +495,7 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { static void listfield (LexState *ls, struct ConsControl *cc) { expr(ls, &cc->v); - luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor"); + luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor"); cc->na++; cc->tostore++; } @@ -527,18 +549,35 @@ static void constructor (LexState *ls, expdesc *t) { static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ + FuncState *fs = ls->fs; + Proto *f = fs->f; int nparams = 0; - int dots = 0; + f->is_vararg = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { - case TK_DOTS: dots = 1; next(ls); break; - case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; + case TK_NAME: { /* param -> NAME [ `=' `...' ] */ + new_localvar(ls, str_checkname(ls), nparams++); + if (testnext(ls, '=')) { + check(ls, TK_DOTS); + f->is_vararg = 1; + } + break; + } + case TK_DOTS: { /* param -> `...' */ + next(ls); + /* use `arg' as default name */ + new_localvarliteral(ls, "arg", nparams++); + f->is_vararg = 1; + break; + } default: luaX_syntaxerror(ls, " or `...' expected"); } - } while (!dots && testnext(ls, ',')); + } while (!f->is_vararg && testnext(ls, ',')); } - code_params(ls, nparams, dots); + adjustlocalvars(ls, nparams); + f->numparams = fs->nactvar - f->is_vararg; + luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -548,8 +587,10 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { open_func(ls, &new_fs); new_fs.f->lineDefined = line; check(ls, '('); - if (needself) - create_local(ls, "self"); + if (needself) { + new_localvarliteral(ls, "self", 0); + adjustlocalvars(ls, 1); + } parlist(ls); check(ls, ')'); chunk(ls); @@ -645,18 +686,6 @@ static void prefixexp (LexState *ls, expdesc *v) { singlevar(ls, v, 1); return; } -#ifdef LUA_COMPATUPSYNTAX - case '%': { /* for compatibility only */ - TString *varname; - int line = ls->linenumber; - next(ls); /* skip `%' */ - varname = singlevar(ls, v, 1); - if (v->k != VUPVAL) - luaX_errorline(ls, "global upvalues are obsolete", - getstr(varname), line); - return; - } -#endif default: { luaX_syntaxerror(ls, "unexpected symbol"); return; @@ -796,7 +825,7 @@ static const struct { ** subexpr -> (simplexep | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ -static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { +static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); @@ -809,13 +838,13 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && cast(int, priority[op].left) > limit) { + while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, cast(int, priority[op].right)); + nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } @@ -825,7 +854,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { static void expr (LexState *ls, expdesc *v) { - subexpr(ls, v, -1); + subexpr(ls, v, 0); } /* }==================================================================== */ @@ -931,12 +960,14 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { } -static void cond (LexState *ls, expdesc *v) { +static int cond (LexState *ls) { /* cond -> exp */ - expr(ls, v); /* read condition */ - if (v->k == VNIL) v->k = VFALSE; /* `falses' are all equal here */ - luaK_goiftrue(ls->fs, v); - luaK_patchtohere(ls->fs, v->t); + expdesc v; + expr(ls, &v); /* read condition */ + if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls->fs, &v); + luaK_patchtohere(ls->fs, v.t); + return v.f; } @@ -1004,14 +1035,14 @@ static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); - expdesc v; + int flist; BlockCnt bl; enterblock(fs, &bl, 1); next(ls); block(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); - cond(ls, &v); - luaK_patchlist(fs, v.f, repeat_init); + flist = cond(ls); + luaK_patchlist(fs, flist, repeat_init); leaveblock(fs); } @@ -1027,30 +1058,34 @@ static int exp1 (LexState *ls) { static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { + /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; - adjustlocalvars(ls, nvars); /* scope for all variables */ + adjustlocalvars(ls, 3); /* control variables */ check(ls, TK_DO); - enterblock(fs, &bl, 1); /* loop block */ - prep = luaK_getlabel(fs); + prep = luaK_codeAsBx(fs, (isnum ? OP_FORPREP : OP_TFORPREP), base, NO_JUMP); + enterblock(fs, &bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); block(ls); - luaK_patchtohere(fs, prep-1); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : - luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); + luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); - leaveblock(fs); + luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); } static void fornum (LexState *ls, TString *varname, int line) { - /* fornum -> NAME = exp1,exp1[,exp1] DO body */ + /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; - new_localvar(ls, varname, 0); - new_localvarstr(ls, "(for limit)", 1); - new_localvarstr(ls, "(for step)", 2); + new_localvarliteral(ls, "(for index)", 0); + new_localvarliteral(ls, "(for limit)", 1); + new_localvarliteral(ls, "(for step)", 2); + new_localvar(ls, varname, 3); check(ls, '='); exp1(ls); /* initial value */ check(ls, ','); @@ -1061,39 +1096,39 @@ static void fornum (LexState *ls, TString *varname, int line) { luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } - luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); - luaK_jump(fs); - forbody(ls, base, line, 3, 1); + forbody(ls, base, line, 1, 1); } static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist1 DO body */ + /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 0; int line; int base = fs->freereg; - new_localvarstr(ls, "(for generator)", nvars++); - new_localvarstr(ls, "(for state)", nvars++); + /* create control variables */ + new_localvarliteral(ls, "(for generator)", nvars++); + new_localvarliteral(ls, "(for state)", nvars++); + new_localvarliteral(ls, "(for control)", nvars++); + /* create declared variables */ new_localvar(ls, indexname, nvars++); while (testnext(ls, ',')) new_localvar(ls, str_checkname(ls), nvars++); check(ls, TK_IN); line = ls->linenumber; - adjust_assign(ls, nvars, explist1(ls, &e), &e); + adjust_assign(ls, 3, explist1(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ - luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); - forbody(ls, base, line, nvars, 0); + forbody(ls, base, line, nvars - 3, 0); } static void forstat (LexState *ls, int line) { - /* forstat -> fornum | forlist */ + /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; - enterblock(fs, &bl, 0); /* block to control variable scope */ + enterblock(fs, &bl, 1); /* scope for loop and control variables */ next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { @@ -1102,38 +1137,40 @@ static void forstat (LexState *ls, int line) { default: luaX_syntaxerror(ls, "`=' or `in' expected"); } check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); + leaveblock(fs); /* loop scope (`break' jumps to this point) */ } -static void test_then_block (LexState *ls, expdesc *v) { +static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ + int flist; next(ls); /* skip IF or ELSEIF */ - cond(ls, v); + flist = cond(ls); check(ls, TK_THEN); block(ls); /* `then' part */ + return flist; } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; - expdesc v; + int flist; int escapelist = NO_JUMP; - test_then_block(ls, &v); /* IF cond THEN block */ + flist = test_then_block(ls); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); - test_then_block(ls, &v); /* ELSEIF cond THEN block */ + luaK_patchtohere(fs, flist); + flist = test_then_block(ls); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); + luaK_patchtohere(fs, flist); next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else - luaK_concat(fs, &escapelist, v.f); + luaK_concat(fs, &escapelist, flist); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); } @@ -1324,7 +1361,8 @@ static void chunk (LexState *ls) { while (!islast && !block_follow(ls->t.token)) { islast = statement(ls); testnext(ls, ';'); - lua_assert(ls->fs->freereg >= ls->fs->nactvar); + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ } leavelevel(ls); diff --git a/src/lparser.h b/src/lparser.h index d6aaaf0e7d..b4652040c4 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.47 2003/02/11 10:46:24 roberto Exp $ +** $Id: lparser.h,v 1.50 2003/08/25 19:51:54 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -41,6 +41,12 @@ typedef struct expdesc { } expdesc; +typedef struct upvaldesc { + lu_byte k; + lu_byte info; +} upvaldesc; + + struct BlockCnt; /* defined in lparser.c */ @@ -59,13 +65,13 @@ typedef struct FuncState { int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ int nlocvars; /* number of elements in `locvars' */ - int nactvar; /* number of active local variables */ - expdesc upvalues[MAXUPVALUES]; /* upvalues */ - int actvar[MAXVARS]; /* declared-variable stack */ + lu_byte nactvar; /* number of active local variables */ + upvaldesc upvalues[MAXUPVALUES]; /* upvalues */ + unsigned short actvar[MAXVARS]; /* declared-variable stack */ } FuncState; -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff); +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name); #endif diff --git a/src/lstate.c b/src/lstate.c index b593658def..d1494b5847 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,11 +1,11 @@ /* -** $Id: lstate.c,v 1.123 2003/04/03 13:35:34 roberto Exp $ +** $Id: lstate.c,v 2.5 2004/03/23 12:57:12 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ -#include +#include #define lstate_c @@ -34,41 +34,28 @@ union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; #endif +#define state_size(x) (sizeof(x) + EXTRASPACE) +#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + EXTRASPACE)) +#define fromstate(l) (cast(lu_byte *, (l)) - EXTRASPACE) + /* -** you can change this function through the official API: -** call `lua_setpanicf' +** Main thread combines a thread state and the global state */ -static int default_panic (lua_State *L) { - UNUSED(L); - return 0; -} - - -static lua_State *mallocstate (lua_State *L) { - lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE); - if (block == NULL) return NULL; - else { - block += EXTRASPACE; - return cast(lua_State *, block); - } -} - - -static void freestate (lua_State *L, lua_State *L1) { - luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE, - sizeof(lua_State) + EXTRASPACE); -} +typedef struct LG { + lua_State l; + global_State g; +} LG; + static void stack_init (lua_State *L1, lua_State *L) { - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject); + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; L1->top = L1->stack; L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); L1->ci = L1->base_ci; - L1->ci->state = CI_C; /* not a Lua function */ setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; @@ -79,7 +66,7 @@ static void stack_init (lua_State *L1, lua_State *L) { static void freestack (lua_State *L, lua_State *L1) { luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); - luaM_freearray(L, L1->stack, L1->stacksize, TObject); + luaM_freearray(L, L1->stack, L1->stacksize, TValue); } @@ -87,54 +74,42 @@ static void freestack (lua_State *L, lua_State *L1) { ** open parts that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { - /* create a new global state */ - global_State *g = luaM_new(NULL, global_State); + Udata *u; /* head of udata list */ UNUSED(ud); - if (g == NULL) luaD_throw(L, LUA_ERRMEM); - L->l_G = g; - g->mainthread = L; - g->GCthreshold = 0; /* mark it as unfinished state */ - g->strt.size = 0; - g->strt.nuse = 0; - g->strt.hash = NULL; - setnilvalue(defaultmeta(L)); - setnilvalue(registry(L)); - luaZ_initbuffer(L, &g->buff); - g->panic = default_panic; - g->rootgc = NULL; - g->rootudata = NULL; - g->tmudata = NULL; - setnilvalue(gkey(g->dummynode)); - setnilvalue(gval(g->dummynode)); - g->dummynode->next = NULL; - g->nblocks = sizeof(lua_State) + sizeof(global_State); + u = cast(Udata *, luaM_malloc(L, sizeudata(0))); + u->uv.len = 0; + u->uv.metatable = NULL; + G(L)->firstudata = obj2gco(u); + luaC_link(L, obj2gco(u), LUA_TUSERDATA); + setbit(u->uv.marked, FIXEDBIT); + setbit(L->marked, FIXEDBIT); stack_init(L, L); /* init stack */ - /* create default meta table with a dummy table, and then close the loop */ - defaultmeta(L)->tt = LUA_TTABLE; - sethvalue(defaultmeta(L), luaH_new(L, 0, 0)); - hvalue(defaultmeta(L))->metatable = hvalue(defaultmeta(L)); - sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */ - sethvalue(registry(L), luaH_new(L, 4, 4)); /* registry */ + sethvalue(L, gt(L), luaH_new(L, 0, 4)); /* table of globals */ + sethvalue(L, registry(L), luaH_new(L, 4, 4)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); luaS_fix(luaS_newliteral(L, MEMERRMSG)); - g->GCthreshold = 4*G(L)->nblocks; + G(L)->GCthreshold = 4*G(L)->nblocks; } -static void preinit_state (lua_State *L) { +static void preinit_state (lua_State *L, global_State *g) { + L->l_G = g; + L->tt = LUA_TTHREAD; + L->marked = luaC_white(g); L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; L->hook = NULL; - L->hookmask = L->hookinit = 0; + L->hookmask = 0; L->basehookcount = 0; L->allowhook = 1; resethookcount(L); L->openupval = NULL; L->size_ci = 0; L->nCcalls = 0; + L->isSuspended = 0; L->base_ci = L->ci = NULL; L->errfunc = 0; setnilvalue(gt(L)); @@ -142,30 +117,26 @@ static void preinit_state (lua_State *L) { static void close_state (lua_State *L) { + global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - if (G(L)) { /* close global state */ - luaC_sweep(L, 1); /* collect all elements */ - lua_assert(G(L)->rootgc == NULL); - lua_assert(G(L)->rootudata == NULL); - luaS_freeall(L); - luaZ_freebuffer(L, &G(L)->buff); - } + luaC_sweepall(L); /* collect all elements */ + lua_assert(g->rootgc == obj2gco(L)); + luaS_freeall(L); + luaZ_freebuffer(L, &g->buff); freestack(L, L); - if (G(L)) { - lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State)); - luaM_freelem(NULL, G(L)); - } - freestate(NULL, L); + lua_assert(g->nblocks == sizeof(LG)); + (*g->realloc)(g->ud, fromstate(L), state_size(LG), 0); } lua_State *luaE_newthread (lua_State *L) { - lua_State *L1 = mallocstate(L); - luaC_link(L, valtogco(L1), LUA_TTHREAD); - preinit_state(L1); - L1->l_G = L->l_G; + lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); + L1->next = L->next; /* link new thread after `L' */ + L->next = obj2gco(L1); + preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ - setobj2n(gt(L1), gt(L)); /* share table of globals */ + setobj2n(L, gt(L1), gt(L)); /* share table of globals */ + lua_assert(iswhite(obj2gco(L1))); return L1; } @@ -174,23 +145,47 @@ void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); freestack(L, L1); - freestate(L, L1); + luaM_free(L, fromstate(L1), state_size(lua_State)); } -LUA_API lua_State *lua_open (void) { - lua_State *L = mallocstate(NULL); - if (L) { /* allocation OK? */ - L->tt = LUA_TTHREAD; - L->marked = 0; - L->next = L->gclist = NULL; - preinit_state(L); - L->l_G = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { - /* memory allocation error: free partial state */ - close_state(L); - L = NULL; - } +LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + lua_State *L; + global_State *g; + void *l = (*f)(ud, NULL, 0, state_size(LG)); + if (l == NULL) return NULL; + L = tostate(l); + g = &((LG *)L)->g; + L->next = NULL; + g->currentwhite = bitmask(WHITE0BIT); + preinit_state(L, g); + g->realloc = f; + g->ud = ud; + g->mainthread = L; + g->GCthreshold = 0; /* mark it as unfinished state */ + g->strt.size = 0; + g->strt.nuse = 0; + g->strt.hash = NULL; + setnilvalue(registry(L)); + luaZ_initbuffer(L, &g->buff); + g->panic = NULL; + g->gcstate = GCSfinalize; + g->rootgc = obj2gco(L); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + g->firstudata = NULL; + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->tmudata = NULL; + setnilvalue(gkey(g->dummynode)); + setnilvalue(gval(g->dummynode)); + g->dummynode->next = NULL; + g->nblocks = sizeof(LG); + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; } lua_userstateopen(L); return L; @@ -207,7 +202,7 @@ LUA_API void lua_close (lua_State *L) { lua_lock(L); L = G(L)->mainthread; /* only the main thread can be closed */ luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_separateudata(L); /* separate udata that have GC metamethods */ + luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ L->errfunc = 0; /* no error function during GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; diff --git a/src/lstate.h b/src/lstate.h index 5422f1b196..ab01d1690f 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.109 2003/02/27 11:52:30 roberto Exp $ +** $Id: lstate.h,v 2.2 2004/03/23 17:02:58 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -42,9 +42,6 @@ struct lua_longjmp; /* defined in ldo.c */ -/* default meta table (both for tables and udata) */ -#define defaultmeta(L) (&G(L)->_defaultmeta) - /* table of globals */ #define gt(L) (&L->_gt) @@ -64,7 +61,7 @@ struct lua_longjmp; /* defined in ldo.c */ typedef struct stringtable { GCObject **hash; - ls_nstr nuse; /* number of elements */ + lu_int32 nuse; /* number of elements */ int size; } stringtable; @@ -75,11 +72,9 @@ typedef struct stringtable { typedef struct CallInfo { StkId base; /* base for called function */ StkId top; /* top for this function */ - int state; /* bit fields; see below */ union { struct { /* for Lua functions */ const Instruction *savedpc; - const Instruction **pc; /* points to `pc' variable in `luaV_execute' */ int tailcalls; /* number of tail calls lost under this entry */ } l; struct { /* for C functions */ @@ -89,20 +84,11 @@ typedef struct CallInfo { } CallInfo; -/* -** bit fields for `CallInfo.state' -*/ -#define CI_C (1<<0) /* 1 if function is a C function */ -/* 1 if (Lua) function has an active `luaV_execute' running it */ -#define CI_HASFRAME (1<<1) -/* 1 if Lua function is calling another Lua function (and therefore its - `pc' is being used by the other, and therefore CI_SAVEDPC is 1 too) */ -#define CI_CALLING (1<<2) -#define CI_SAVEDPC (1<<3) /* 1 if `savedpc' is updated */ -#define CI_YIELD (1<<4) /* 1 if thread is suspended */ - +#define curr_func(L) (clvalue(L->base - 1)) #define ci_func(ci) (clvalue((ci)->base - 1)) +#define f_isLua(ci) (!ci_func(ci)->c.isC) +#define isLua(ci) (ttisfunction((ci)->base - 1) && f_isLua(ci)) /* @@ -110,15 +96,23 @@ typedef struct CallInfo { */ typedef struct global_State { stringtable strt; /* hash table for strings */ - GCObject *rootgc; /* list of (almost) all collectable objects */ - GCObject *rootudata; /* (separated) list of all userdata */ + lua_Alloc realloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to `realloc' */ + int currentwhite; + GCObject *rootgc; /* list of all collectable objects */ + GCObject *firstudata; /* udata go to the end of `rootgc' */ + GCObject **sweepgc; /* position of sweep in `rootgc' */ + int sweepstrgc; /* position of sweep in `strt' */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of weak tables (to be cleared) */ GCObject *tmudata; /* list of userdata to be GC */ + int gcstate; /* state of garbage collector */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; lu_mem nblocks; /* number of `bytes' currently allocated */ lua_CFunction panic; /* to be called in unprotected errors */ - TObject _registry; - TObject _defaultmeta; + TValue _registry; struct lua_State *mainthread; Node dummynode[1]; /* common node array for all empty tables */ TString *tmname[TM_N]; /* array with tag-method names */ @@ -143,11 +137,11 @@ struct lua_State { unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; - lu_byte hookinit; + lu_byte isSuspended; int basehookcount; int hookcount; lua_Hook hook; - TObject _gt; /* table of globals */ + TValue _gt; /* table of globals */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ @@ -174,18 +168,20 @@ union GCObject { /* macros to convert a GCObject into a specific value */ -#define gcotots(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) -#define gcotou(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) -#define gcotocl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) -#define gcotoh(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) -#define gcotop(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) -#define gcotouv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define gco2ts(o) (&rawgco2ts(o)->tsv) +#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) +#define gco2u(o) (&rawgco2u(o)->uv) +#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) +#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) +#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define ngcotouv(o) \ check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) -#define gcototh(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) +#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) -/* macro to convert any value into a GCObject */ -#define valtogco(v) (cast(GCObject *, (v))) +/* macro to convert any Lua object into a GCObject */ +#define obj2gco(v) (cast(GCObject *, (v))) lua_State *luaE_newthread (lua_State *L); diff --git a/src/lstring.c b/src/lstring.c index 8cbddbd218..9a26cf0314 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 1.78 2002/12/04 17:38:31 roberto Exp $ +** $Id: lstring.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -25,16 +25,19 @@ void luaS_freeall (lua_State *L) { void luaS_resize (lua_State *L, int newsize) { - GCObject **newhash = luaM_newvector(L, newsize, GCObject *); - stringtable *tb = &G(L)->strt; + GCObject **newhash; + stringtable *tb; int i; + if (G(L)->sweepstrgc > 0) return; /* cannot resize during GC traverse */ + newhash = luaM_newvector(L, newsize, GCObject *); + tb = &G(L)->strt; for (i=0; isize; i++) { GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ GCObject *next = p->gch.next; /* save next */ - lu_hash h = gcotots(p)->tsv.hash; + unsigned int h = gco2ts(p)->hash; int h1 = lmod(h, newsize); /* new position */ lua_assert(cast(int, h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ @@ -48,12 +51,13 @@ void luaS_resize (lua_State *L, int newsize) { } -static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { +static TString *newlstr (lua_State *L, const char *str, size_t l, + unsigned int h) { TString *ts = cast(TString *, luaM_malloc(L, sizestring(l))); stringtable *tb; ts->tsv.len = l; ts->tsv.hash = h; - ts->tsv.marked = 0; + ts->tsv.marked = luaC_white(G(L)); ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; memcpy(ts+1, str, l*sizeof(char)); @@ -61,9 +65,9 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { tb = &G(L)->strt; h = lmod(h, tb->size); ts->tsv.next = tb->hash[h]; /* chain new entry */ - tb->hash[h] = valtogco(ts); + tb->hash[h] = obj2gco(ts); tb->nuse++; - if (tb->nuse > cast(ls_nstr, tb->size) && tb->size <= MAX_INT/2) + if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) luaS_resize(L, tb->size*2); /* too crowded */ return ts; } @@ -71,7 +75,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { GCObject *o; - lu_hash h = (lu_hash)l; /* seed */ + unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ @@ -79,9 +83,12 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { - TString *ts = gcotots(o); - if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) + TString *ts = rawgco2ts(o); + if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { + /* string may be dead */ + if (isdead(G(L), o)) changewhite(o); return ts; + } } return newlstr(L, str, l, h); /* not found */ } @@ -90,13 +97,13 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { Udata *luaS_newudata (lua_State *L, size_t s) { Udata *u; u = cast(Udata *, luaM_malloc(L, sizeudata(s))); - u->uv.marked = (1<<1); /* is not finalized */ + u->uv.marked = luaC_white(G(L)); /* is not finalized */ u->uv.tt = LUA_TUSERDATA; u->uv.len = s; - u->uv.metatable = hvalue(defaultmeta(L)); + u->uv.metatable = NULL; /* chain it on udata list */ - u->uv.next = G(L)->rootudata; - G(L)->rootudata = valtogco(u); + u->uv.next = G(L)->firstudata->uv.next; + G(L)->firstudata->uv.next = obj2gco(u); return u; } diff --git a/src/lstring.h b/src/lstring.h index be5a1e3767..2ca352c474 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.37 2002/08/16 14:45:55 roberto Exp $ +** $Id: lstring.h,v 1.38 2003/11/17 19:50:05 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -8,11 +8,11 @@ #define lstring_h +#include "lgc.h" #include "lobject.h" #include "lstate.h" - #define sizestring(l) (cast(lu_mem, sizeof(union TString))+ \ (cast(lu_mem, l)+1)*sizeof(char)) @@ -22,7 +22,7 @@ #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s) ((s)->tsv.marked |= (1<<4)) +#define luaS_fix(s) setbit((s)->tsv.marked, FIXEDBIT) void luaS_resize (lua_State *L, int newsize); Udata *luaS_newudata (lua_State *L, size_t s); diff --git a/src/ltable.c b/src/ltable.c index 0c64adb10a..9fc508ba6d 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 1.132 2003/04/03 13:35:34 roberto Exp $ +** $Id: ltable.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,10 +15,7 @@ ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the `original' position that its hash gives ** to it), then the colliding element is in its own main position. -** In other words, there are collisions only when two elements have the -** same main position (i.e. the same hash values for that table size). -** Because of that, the load factor of these tables can be 100% without -** performance penalties. +** Hence even when the load factor reaches 100%, performance remains good. */ #include @@ -45,9 +42,7 @@ #define MAXBITS (BITS_INT-2) #endif -/* check whether `x' < 2^MAXBITS */ -#define toobig(x) ((((x)-1) >> MAXBITS) != 0) - +#define MAXASIZE (1 << MAXBITS) /* function to convert a lua_Number to int (with any rounding method) */ #ifndef lua_number2int @@ -87,7 +82,7 @@ static Node *hashnum (const Table *t, lua_Number n) { lua_assert(sizeof(a) <= sizeof(n)); memcpy(a, &n, sizeof(a)); for (i = 1; i < numints; i++) a[0] += a[i]; - return hashmod(t, cast(lu_hash, a[0])); + return hashmod(t, a[0]); } @@ -96,12 +91,12 @@ static Node *hashnum (const Table *t, lua_Number n) { ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ -Node *luaH_mainposition (const Table *t, const TObject *key) { +Node *luaH_mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); case LUA_TSTRING: - return hashstr(t, tsvalue(key)); + return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: @@ -116,11 +111,13 @@ Node *luaH_mainposition (const Table *t, const TObject *key) { ** returns the index for `key' if `key' is an appropriate key to live in ** the array part of the table, -1 otherwise. */ -static int arrayindex (const TObject *key) { +static int arrayindex (const TValue *key, lua_Number lim) { if (ttisnumber(key)) { + lua_Number n = nvalue(key); int k; - lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k)) + if (n <= 0 || n > lim) return -1; /* out of range? */ + lua_number2int(k, n); + if (cast(lua_Number, k) == nvalue(key)) return k; } return -1; /* `key' did not match some condition */ @@ -135,12 +132,12 @@ static int arrayindex (const TObject *key) { static int luaH_index (lua_State *L, Table *t, StkId key) { int i; if (ttisnil(key)) return -1; /* first iteration */ - i = arrayindex(key); - if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */ + i = arrayindex(key, t->sizearray); + if (0 <= i) { /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ } else { - const TObject *v = luaH_get(t, key); + const TValue *v = luaH_get(t, key); if (v == &luaO_nilobject) luaG_runerror(L, "invalid key for `next'"); i = cast(int, (cast(const lu_byte *, v) - @@ -155,14 +152,14 @@ int luaH_next (lua_State *L, Table *t, StkId key) { for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setnvalue(key, cast(lua_Number, i+1)); - setobj2s(key+1, &t->array[i]); + setobj2s(L, key+1, &t->array[i]); return 1; } } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(key, gkey(gnode(t, i))); - setobj2s(key+1, gval(gnode(t, i))); + setobj2s(L, key, gkey(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } @@ -202,6 +199,7 @@ static void numuse (const Table *t, int *narray, int *nhash) { int nums[MAXBITS+1]; int i, lg; int totaluse = 0; + lua_Number sizelimit; /* an upper bound for the array size */ /* count elements in array part */ for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ int ttlg = twoto(lg); /* 2^lg */ @@ -221,10 +219,13 @@ static void numuse (const Table *t, int *narray, int *nhash) { *narray = totaluse; /* all previous uses were in array part */ /* count elements in hash part */ i = sizenode(t); + /* array part cannot be larger than twice the maximum number of elements */ + sizelimit = cast(lua_Number, totaluse + i) * 2; + if (sizelimit >= MAXASIZE) sizelimit = MAXASIZE; while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { - int k = arrayindex(gkey(n)); + int k = arrayindex(gkey(n), sizelimit); if (k >= 0) { /* is `key' an appropriate array index? */ nums[luaO_log2(k-1)+1]++; /* count as such */ (*narray)++; @@ -238,7 +239,7 @@ static void numuse (const Table *t, int *narray, int *nhash) { static void setarrayvector (lua_State *L, Table *t, int size) { int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TObject); + luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; iarray[i]); t->sizearray = size; @@ -295,16 +296,16 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { /* re-insert elements from vanishing slice */ for (i=nasize; iarray[i])) - setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]); + setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); } /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TObject); + luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements in hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) - setobjt2t(luaH_set(L, t, gkey(old)), gval(old)); + setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); } if (oldhsize) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ @@ -326,8 +327,8 @@ static void rehash (lua_State *L, Table *t) { Table *luaH_new (lua_State *L, int narray, int lnhash) { Table *t = luaM_new(L, Table); - luaC_link(L, valtogco(t), LUA_TTABLE); - t->metatable = hvalue(defaultmeta(L)); + luaC_link(L, obj2gco(t), LUA_TTABLE); + t->metatable = NULL; t->flags = cast(lu_byte, ~0); /* temporary values (kept only if some malloc fails) */ t->array = NULL; @@ -343,7 +344,7 @@ Table *luaH_new (lua_State *L, int narray, int lnhash) { void luaH_free (lua_State *L, Table *t) { if (t->lsizenode) luaM_freearray(L, t->node, sizenode(t), Node); - luaM_freearray(L, t->array, t->sizearray, TObject); + luaM_freearray(L, t->array, t->sizearray, TValue); luaM_freelem(L, t); } @@ -376,8 +377,8 @@ void luaH_remove (Table *t, Node *e) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -static TObject *newkey (lua_State *L, Table *t, const TObject *key) { - TObject *val; +static TValue *newkey (lua_State *L, Table *t, const TValue *key) { + TValue *val; Node *mp = luaH_mainposition(t, key); if (!ttisnil(gval(mp))) { /* main position is not free? */ Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */ @@ -397,7 +398,8 @@ static TObject *newkey (lua_State *L, Table *t, const TObject *key) { mp = n; } } - setobj2t(gkey(mp), key); /* write barrier */ + setobj2t(L, gkey(mp), key); + luaC_barrier(L, t, key); lua_assert(ttisnil(gval(mp))); for (;;) { /* correct `firstfree' */ if (ttisnil(gkey(t->firstfree))) @@ -408,7 +410,7 @@ static TObject *newkey (lua_State *L, Table *t, const TObject *key) { /* no more free places; must create one */ setbvalue(gval(mp), 0); /* avoid new key being removed */ rehash(L, t); /* grow table */ - val = cast(TObject *, luaH_get(t, key)); /* get new position */ + val = cast(TValue *, luaH_get(t, key)); /* get new position */ lua_assert(ttisboolean(val)); setnilvalue(val); return val; @@ -418,23 +420,22 @@ static TObject *newkey (lua_State *L, Table *t, const TObject *key) { /* ** generic search function */ -static const TObject *luaH_getany (Table *t, const TObject *key) { - if (ttisnil(key)) return &luaO_nilobject; - else { +static const TValue *luaH_getany (Table *t, const TValue *key) { + if (!ttisnil(key)) { Node *n = luaH_mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ else n = n->next; } while (n); - return &luaO_nilobject; } + return &luaO_nilobject; } /* ** search function for integers */ -const TObject *luaH_getnum (Table *t, int key) { +const TValue *luaH_getnum (Table *t, int key) { if (1 <= key && key <= t->sizearray) return &t->array[key-1]; else { @@ -453,10 +454,10 @@ const TObject *luaH_getnum (Table *t, int key) { /* ** search function for strings */ -const TObject *luaH_getstr (Table *t, TString *key) { +const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key) + if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) return gval(n); /* that's it */ else n = n->next; } while (n); @@ -467,9 +468,9 @@ const TObject *luaH_getstr (Table *t, TString *key) { /* ** main search function */ -const TObject *luaH_get (Table *t, const TObject *key) { +const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); + case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; lua_number2int(k, (nvalue(key))); @@ -482,11 +483,11 @@ const TObject *luaH_get (Table *t, const TObject *key) { } -TObject *luaH_set (lua_State *L, Table *t, const TObject *key) { - const TObject *p = luaH_get(t, key); +TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { + const TValue *p = luaH_get(t, key); t->flags = 0; if (p != &luaO_nilobject) - return cast(TObject *, p); + return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); else if (ttisnumber(key) && nvalue(key) != nvalue(key)) @@ -496,14 +497,26 @@ TObject *luaH_set (lua_State *L, Table *t, const TObject *key) { } -TObject *luaH_setnum (lua_State *L, Table *t, int key) { - const TObject *p = luaH_getnum(t, key); +TValue *luaH_setnum (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getnum(t, key); if (p != &luaO_nilobject) - return cast(TObject *, p); + return cast(TValue *, p); else { - TObject k; + TValue k; setnvalue(&k, cast(lua_Number, key)); return newkey(L, t, &k); } } + +TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { + const TValue *p = luaH_getstr(t, key); + if (p != &luaO_nilobject) + return cast(TValue *, p); + else { + TValue k; + setsvalue(L, &k, key); + return newkey(L, t, &k); + } +} + diff --git a/src/ltable.h b/src/ltable.h index 3d4d753c3c..566d7cd467 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 1.44 2003/03/18 12:50:04 roberto Exp $ +** $Id: ltable.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,17 +15,18 @@ #define gval(n) (&(n)->i_val) -const TObject *luaH_getnum (Table *t, int key); -TObject *luaH_setnum (lua_State *L, Table *t, int key); -const TObject *luaH_getstr (Table *t, TString *key); -const TObject *luaH_get (Table *t, const TObject *key); -TObject *luaH_set (lua_State *L, Table *t, const TObject *key); +const TValue *luaH_getnum (Table *t, int key); +TValue *luaH_setnum (lua_State *L, Table *t, int key); +const TValue *luaH_getstr (Table *t, TString *key); +TValue *luaH_setstr (lua_State *L, Table *t, TString *key); +const TValue *luaH_get (Table *t, const TValue *key); +TValue *luaH_set (lua_State *L, Table *t, const TValue *key); Table *luaH_new (lua_State *L, int narray, int lnhash); void luaH_free (lua_State *L, Table *t); int luaH_next (lua_State *L, Table *t, StkId key); /* exported only for debugging */ -Node *luaH_mainposition (const Table *t, const TObject *key); +Node *luaH_mainposition (const Table *t, const TValue *key); #endif diff --git a/src/ltm.c b/src/ltm.c index 1b3e515e57..de4bb7af21 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 1.106 2003/04/03 13:35:34 roberto Exp $ +** $Id: ltm.c,v 2.2 2004/02/16 19:09:52 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -21,7 +21,8 @@ const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", - "string", "table", "function", "userdata", "thread" + "string", "table", "function", "userdata", "thread", + "proto", "upval" }; @@ -45,8 +46,8 @@ void luaT_init (lua_State *L) { ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ -const TObject *luaT_gettm (Table *events, TMS event, TString *ename) { - const TObject *tm = luaH_getstr(events, ename); +const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { + const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast(lu_byte, 1u<tmname[event]; +const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { + Table *mt; switch (ttype(o)) { case LUA_TTABLE: - return luaH_getstr(hvalue(o)->metatable, ename); + mt = hvalue(o)->metatable; + break; case LUA_TUSERDATA: - return luaH_getstr(uvalue(o)->uv.metatable, ename); + mt = uvalue(o)->metatable; + break; default: - return &luaO_nilobject; + mt = NULL; } + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : &luaO_nilobject); } diff --git a/src/ltm.h b/src/ltm.h index 8eebfd3dc3..226feb75ea 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 1.41 2002/11/14 11:51:50 roberto Exp $ +** $Id: ltm.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -36,14 +36,14 @@ typedef enum { -#define gfasttm(g,et,e) \ - (((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) #define fasttm(l,et,e) gfasttm(G(l), et, e) -const TObject *luaT_gettm (Table *events, TMS event, TString *ename); -const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event); +const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); void luaT_init (lua_State *L); extern const char *const luaT_typenames[]; diff --git a/src/lua/RCS b/src/lua/RCS new file mode 120000 index 0000000000..1ae3893605 --- /dev/null +++ b/src/lua/RCS @@ -0,0 +1 @@ +../RCS \ No newline at end of file diff --git a/src/lua/README b/src/lua/README index febd229a58..fca1e9008d 100644 --- a/src/lua/README +++ b/src/lua/README @@ -2,7 +2,7 @@ This is lua, a sample Lua interpreter. It can be used as a batch interpreter and also interactively. There are man pages for it in both nroff and html in ../../doc. -Usage: ./lua [options] [script [args]]. Available options are: +Usage: lua [options] [script [args]]. Available options are: - execute stdin as a file -e stat execute string `stat' -i enter interactive mode after executing `script' diff --git a/src/lua/lua.c b/src/lua/lua.c index 28c84cb613..4e669c07f7 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.122 2003/04/03 13:34:42 roberto Exp $ +** $Id: lua.c,v 1.124 2003/10/23 18:06:22 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -117,10 +117,9 @@ static void l_message (const char *pname, const char *msg) { static int report (int status) { - const char *msg; - if (status) { - msg = lua_tostring(L, -1); - if (msg == NULL) msg = "(error with no message)"; + if (status && !lua_isnil(L, -1)) { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); } @@ -155,10 +154,6 @@ static void getargs (char *argv[], int n) { lua_pushstring(L, argv[i]); lua_rawset(L, -3); } - /* arg.n = maximum index in table `arg' */ - lua_pushliteral(L, "n"); - lua_pushnumber(L, i-n-1); - lua_rawset(L, -3); } diff --git a/src/luac/Makefile b/src/luac/Makefile index 9e772b412d..a6c7d38f17 100644 --- a/src/luac/Makefile +++ b/src/luac/Makefile @@ -12,8 +12,8 @@ T= $(BIN)/luac all: $T -$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) +$T: $(OBJS) $(LIB)/liblua.a ../lib/lauxlib.o + $(CC) -o $@ $(MYLDFLAGS) $(OBJS) ../lib/lauxlib.o -L$(LIB) -llua $(EXTRA_LIBS) # print.c needs opcode names from lopcodes.c lopcodes.o: ../lopcodes.c ../lopcodes.h @@ -22,8 +22,8 @@ lopcodes.o: ../lopcodes.c ../lopcodes.h $(LIB)/liblua.a: cd ..; $(MAKE) -$(LIB)/liblualib.a: - cd ../lib; $(MAKE) +../lib/lauxlib.o: + cd ../lib; $(MAKE) lauxlib.o clean: rm -f $(OBJS) $T diff --git a/src/luac/RCS b/src/luac/RCS new file mode 120000 index 0000000000..1ae3893605 --- /dev/null +++ b/src/luac/RCS @@ -0,0 +1 @@ +../RCS \ No newline at end of file diff --git a/src/luac/README b/src/luac/README index ada7bc4b3c..140d94571c 100644 --- a/src/luac/README +++ b/src/luac/README @@ -6,7 +6,7 @@ The main advantages of pre-compiling chunks are: faster loading, protecting source code from user changes, and off-line syntax error detection. luac can also be used to learn about the Lua virtual machine. -Usage: /l/luac/luac [options] [filenames]. Available options are: +Usage: luac [options] [filenames]. Available options are: - process stdin -l list -o name output to file `name' (default is "luac.out") diff --git a/src/luac/luac.c b/src/luac/luac.c index 1aff0bd93f..f634d5f986 100644 --- a/src/luac/luac.c +++ b/src/luac/luac.c @@ -1,9 +1,10 @@ /* -** $Id: luac.c,v 1.44a 2003/04/07 20:34:20 lhf Exp $ +** $Id: luac.c,v 1.47 2004/03/24 00:25:08 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ +#include #include #include #include @@ -11,6 +12,7 @@ #include "lua.h" #include "lauxlib.h" +#include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" @@ -18,21 +20,19 @@ #include "lstring.h" #include "lundump.h" -#ifndef LUA_DEBUG -#define luaB_opentests(L) -#endif - #ifndef PROGNAME -#define PROGNAME "luac" /* program name */ +#define PROGNAME "luac" /* default program name */ #endif +#ifndef OUTPUT #define OUTPUT "luac.out" /* default output file */ +#endif static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ static int stripping=0; /* strip debug information? */ static char Output[]={ OUTPUT }; /* default output file name */ -static const char* output=Output; /* output file name */ +static const char* output=Output; /* actual output file name */ static const char* progname=PROGNAME; /* actual program name */ static void fatal(const char* message) @@ -41,29 +41,30 @@ static void fatal(const char* message) exit(EXIT_FAILURE); } -static void cannot(const char* name, const char* what, const char* mode) +static void cannot(const char* what) { - fprintf(stderr,"%s: cannot %s %sput file ",progname,what,mode); - perror(name); + fprintf(stderr,"%s: cannot %s output file %s: %s\n", + progname,what,output,strerror(errno)); exit(EXIT_FAILURE); } -static void usage(const char* message, const char* arg) +static void usage(const char* message) { - if (message!=NULL) - { - fprintf(stderr,"%s: ",progname); fprintf(stderr,message,arg); fprintf(stderr,"\n"); - } + if (*message=='-') + fprintf(stderr,"%s: unrecognized option `%s'\n",progname,message); + else + fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, - "usage: %s [options] [filenames]. Available options are:\n" + "usage: %s [options] [filenames].\n" + "Available options are:\n" " - process stdin\n" " -l list\n" - " -o name output to file `name' (default is \"" OUTPUT "\")\n" + " -o name output to file `name' (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" " -- stop handling options\n", - progname); + progname,Output); exit(EXIT_FAILURE); } @@ -89,7 +90,7 @@ static int doargs(int argc, char* argv[]) else if (IS("-o")) /* output file */ { output=argv[++i]; - if (output==NULL || *output==0) usage("`-o' needs argument",NULL); + if (output==NULL || *output==0) usage("`-o' needs argument"); } else if (IS("-p")) /* parse only */ dumping=0; @@ -101,7 +102,7 @@ static int doargs(int argc, char* argv[]) if (argc==2) exit(EXIT_SUCCESS); } else /* unknown option */ - usage("unrecognized option `%s'",argv[i]); + usage(argv[i]); } if (i==argc && (listing || !dumping)) { @@ -125,6 +126,7 @@ static Proto* combine(lua_State* L, int n) { int i,pc=0; Proto* f=luaF_newproto(L); + setptvalue2s(L,L->top,f); incr_top(L); f->source=luaS_newliteral(L,"=(" PROGNAME ")"); f->maxstacksize=1; f->p=luaM_newvector(L,n,Proto*); @@ -142,23 +144,17 @@ static Proto* combine(lua_State* L, int n) } } -static void strip(lua_State* L, Proto* f) +static int writer(lua_State* L, const void* p, size_t size, void* u) { - int i,n=f->sizep; - luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); - luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); - luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); - f->lineinfo=NULL; f->sizelineinfo=0; - f->locvars=NULL; f->sizelocvars=0; - f->upvalues=NULL; f->sizeupvalues=0; - f->source=luaS_newliteral(L,"=(none)"); - for (i=0; ip[i]); + UNUSED(L); + return fwrite(p,size,1,(FILE*)u)==1; } -static int writer(lua_State* L, const void* p, size_t size, void* u) +static int panic(lua_State *L) { UNUSED(L); - return fwrite(p,size,1,(FILE*)u)==1; + fatal("not enough memory!"); + return 0; } int main(int argc, char* argv[]) @@ -167,9 +163,11 @@ int main(int argc, char* argv[]) Proto* f; int i=doargs(argc,argv); argc-=i; argv+=i; - if (argc<=0) usage("no input files given",NULL); + if (argc<=0) usage("no input files given"); L=lua_open(); - luaB_opentests(L); + if (L==NULL) fatal("not enough memory for state"); + lua_atpanic(L,panic); + if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i -#if 0 +#if 1 #define DEBUG_PRINT #endif @@ -46,7 +46,7 @@ static void PrintString(const Proto* f, int n) static void PrintConstant(const Proto* f, int i) { - const TObject* o=&f->k[i]; + const TValue* o=&f->k[i]; switch (ttype(o)) { case LUA_TNUMBER: @@ -75,8 +75,8 @@ static void PrintCode(const Proto* f) int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); - int bc=GETARG_Bx(i); - int sbc=GETARG_sBx(i); + int bx=GETARG_Bx(i); + int sbx=GETARG_sBx(i); int line=getline(f,pc); #if 0 printf("%0*lX",Sizeof(i)*2,i); @@ -86,14 +86,24 @@ static void PrintCode(const Proto* f) printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { - case iABC: printf("%d %d %d",a,b,c); break; - case iABx: printf("%d %d",a,bc); break; - case iAsBx: printf("%d %d",a,sbc); break; + case iABC: + printf("%d",a); + if (getBMode(o)!=OpArgN) + { if (b>=MAXSTACK) printf(" #%d",b-MAXSTACK); else printf(" %d",b); } + if (getCMode(o)!=OpArgN) + { if (c>=MAXSTACK) printf(" #%d",c-MAXSTACK); else printf(" %d",c); } + break; + case iABx: + if (getBMode(o)==OpArgK) printf("%d #%d",a,bx); else printf("%d %d",a,bx); + break; + case iAsBx: + if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); + break; } switch (o) { case OP_LOADK: - printf("\t; "); PrintConstant(f,bc); + printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: @@ -101,7 +111,7 @@ static void PrintCode(const Proto* f) break; case OP_GETGLOBAL: case OP_SETGLOBAL: - printf("\t; %s",svalue(&f->k[bc])); + printf("\t; %s",svalue(&f->k[bx])); break; case OP_GETTABLE: case OP_SELF: @@ -121,16 +131,17 @@ static void PrintCode(const Proto* f) printf("\t; "); if (b>=MAXSTACK) PrintConstant(f,b-MAXSTACK); else printf("-"); printf(" "); - if (c>=MAXSTACK) PrintConstant(f,c-MAXSTACK); + if (c>=MAXSTACK) PrintConstant(f,c-MAXSTACK); else printf("-"); } break; case OP_JMP: case OP_FORLOOP: + case OP_FORPREP: case OP_TFORPREP: - printf("\t; to %d",sbc+pc+2); + printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: - printf("\t; %p",VOID(f->p[bc])); + printf("\t; %p",VOID(f->p[bx])); break; default: break; @@ -187,7 +198,7 @@ static void PrintLocals(const Proto* f) for (i=0; ilocvars[i].varname),f->locvars[i].startpc,f->locvars[i].endpc); + i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); } } diff --git a/src/lundump.c b/src/lundump.c index 151a8507cc..d79dd89844 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,14 +1,18 @@ /* -** $Id: lundump.c,v 1.49 2003/04/07 20:34:20 lhf Exp $ +** $Id: lundump.c,v 1.51 2004/03/24 00:25:08 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ +#include +#include + #define lundump_c #include "lua.h" #include "ldebug.h" +#include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lopcodes.h" @@ -26,22 +30,28 @@ typedef struct { const char* name; } LoadState; -static void unexpectedEOZ (LoadState* S) +static void error (LoadState* S, const char* fmt, ...) { - luaG_runerror(S->L,"unexpected end of file in %s",S->name); + const char *msg; + va_list argp; + va_start(argp,fmt); + msg=luaO_pushvfstring(S->L,fmt,argp); + va_end(argp); + luaO_pushfstring(S->L,"%s: %s",S->name,msg); + luaD_throw(S->L,LUA_ERRSYNTAX); } static int ezgetc (LoadState* S) { int c=zgetc(S->Z); - if (c==EOZ) unexpectedEOZ(S); + if (c==EOZ) error(S,"unexpected end of file"); return c; } static void ezread (LoadState* S, void* b, int n) { int r=luaZ_read(S->Z,b,n); - if (r!=0) unexpectedEOZ(S); + if (r!=0) error(S,"unexpected end of file"); } static void LoadBlock (LoadState* S, void* b, size_t size) @@ -77,7 +87,7 @@ static int LoadInt (LoadState* S) { int x; LoadBlock(S,&x,sizeof(x)); - if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name); + if (x<0) error(S,"bad integer"); return x; } @@ -113,7 +123,7 @@ static void LoadCode (LoadState* S, Proto* f) int size=LoadInt(S); f->code=luaM_newvector(S->L,size,Instruction); f->sizecode=size; - LoadVector(S,f->code,size,sizeof(*f->code)); + LoadVector(S,f->code,size,sizeof(Instruction)); } static void LoadLocals (LoadState* S, Proto* f) @@ -122,6 +132,7 @@ static void LoadLocals (LoadState* S, Proto* f) n=LoadInt(S); f->locvars=luaM_newvector(S->L,n,LocVar); f->sizelocvars=n; + for (i=0; ilocvars[i].varname=NULL; for (i=0; ilocvars[i].varname=LoadString(S); @@ -135,18 +146,18 @@ static void LoadLines (LoadState* S, Proto* f) int size=LoadInt(S); f->lineinfo=luaM_newvector(S->L,size,int); f->sizelineinfo=size; - LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo)); + LoadVector(S,f->lineinfo,size,sizeof(int)); } static void LoadUpvalues (LoadState* S, Proto* f) { int i,n; n=LoadInt(S); - if (n!=0 && n!=f->nups) - luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d", - S->name,n,f->nups); + if (n!=0 && n!=f->nups) + error(S,"bad nupvalues (read %d; expected %d)",n,f->nups); f->upvalues=luaM_newvector(S->L,n,TString*); f->sizeupvalues=n; + for (i=0; iupvalues[i]=NULL; for (i=0; iupvalues[i]=LoadString(S); } @@ -156,11 +167,12 @@ static void LoadConstants (LoadState* S, Proto* f) { int i,n; n=LoadInt(S); - f->k=luaM_newvector(S->L,n,TObject); + f->k=luaM_newvector(S->L,n,TValue); f->sizek=n; + for (i=0; ik[i]); for (i=0; ik[i]; + TValue* o=&f->k[i]; int t=LoadByte(S); switch (t) { @@ -168,25 +180,27 @@ static void LoadConstants (LoadState* S, Proto* f) setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: - setsvalue2n(o,LoadString(S)); + setsvalue2n(S->L,o,LoadString(S)); break; case LUA_TNIL: setnilvalue(o); break; default: - luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name); + error(S,"bad constant type (%d)",t); break; } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; + for (i=0; ip[i]=NULL; for (i=0; ip[i]=LoadFunction(S,f->source); } static Proto* LoadFunction (LoadState* S, TString* p) { Proto* f=luaF_newproto(S->L); + setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; f->lineDefined=LoadInt(S); f->nups=LoadByte(S); @@ -199,8 +213,9 @@ static Proto* LoadFunction (LoadState* S, TString* p) LoadConstants(S,f); LoadCode(S,f); #ifndef TRUST_BINARIES - if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name); + if (!luaG_checkcode(f)) error(S,"bad code"); #endif + S->L->top--; return f; } @@ -209,18 +224,16 @@ static void LoadSignature (LoadState* S) const char* s=LUA_SIGNATURE; while (*s!=0 && ezgetc(S)==*s) ++s; - if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name); + if (*s!=0) error(S,"bad signature"); } static void TestSize (LoadState* S, int s, const char* what) { int r=LoadByte(S); if (r!=s) - luaG_runerror(S->L,"virtual machine mismatch in %s: " - "size of %s is %d but read %d",S->name,what,s,r); + error(S,"bad size of %s (read %d; expected %d)",what,r,s); } -#define TESTSIZE(s,w) TestSize(S,s,w) #define V(v) v/16,v%16 static void LoadHeader (LoadState* S) @@ -230,40 +243,27 @@ static void LoadHeader (LoadState* S) LoadSignature(S); version=LoadByte(S); if (version>VERSION) - luaG_runerror(S->L,"%s too new: " - "read version %d.%d; expected at most %d.%d", - S->name,V(version),V(VERSION)); + error(S,"bad version (read %d.%d; expected at %s %d.%d)", + V(version),"most",V(VERSION)); if (versionL,"%s too old: " - "read version %d.%d; expected at least %d.%d", - S->name,V(version),V(VERSION0)); + error(S,"bad version (read %d.%d; expected at %s %d.%d)", + V(version),"least",V(VERSION0)); S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */ - TESTSIZE(sizeof(int),"int"); - TESTSIZE(sizeof(size_t), "size_t"); - TESTSIZE(sizeof(Instruction), "Instruction"); - TESTSIZE(SIZE_OP, "OP"); - TESTSIZE(SIZE_A, "A"); - TESTSIZE(SIZE_B, "B"); - TESTSIZE(SIZE_C, "C"); - TESTSIZE(sizeof(lua_Number), "number"); + TestSize(S,sizeof(int),"int"); + TestSize(S,sizeof(size_t),"size_t"); + TestSize(S,sizeof(Instruction),"instruction"); + TestSize(S,sizeof(lua_Number),"number"); x=LoadNumber(S); if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */ - luaG_runerror(S->L,"unknown number format in %s",S->name); -} - -static Proto* LoadChunk (LoadState* S) -{ - LoadHeader(S); - return LoadFunction(S,NULL); + error(S,"unknown number format"); } /* ** load precompiled chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff) +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* s) { LoadState S; - const char* s=zname(Z); if (*s=='@' || *s=='=') S.name=s+1; else if (*s==LUA_SIGNATURE[0]) @@ -273,7 +273,8 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff) S.L=L; S.Z=Z; S.b=buff; - return LoadChunk(&S); + LoadHeader(&S); + return LoadFunction(&S,NULL); } /* diff --git a/src/lundump.h b/src/lundump.h index c7e6959b30..26c792a895 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.30 2003/04/07 20:34:20 lhf Exp $ +** $Id: lundump.h,v 1.32 2003/12/09 19:22:19 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -11,21 +11,20 @@ #include "lzio.h" /* load one chunk; from lundump.c */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff); +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char *name); /* find byte order; from lundump.c */ int luaU_endianness (void); /* dump one chunk; from ldump.c */ -void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data); +int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip); /* print one chunk; from print.c */ void luaU_print (const Proto* Main); /* definitions for headers of binary files */ -#define LUA_SIGNATURE "\033Lua" /* binary files start with "Lua" */ -#define VERSION 0x50 /* last format change was in 5.0 */ -#define VERSION0 0x50 /* last major change was in 5.0 */ +#define VERSION 0x51 /* last format change was in 5.1 */ +#define VERSION0 0x51 /* last major change was in 5.1 */ /* a multiple of PI for testing native format */ /* multiplying by 1E7 gives non-trivial integer values */ diff --git a/src/lvm.c b/src/lvm.c index 94e2802d86..bfbe8bf2c8 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,11 +1,10 @@ /* -** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $ +** $Id: lvm.c,v 2.2 2004/03/16 12:31:40 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ -#include #include #include @@ -40,7 +39,7 @@ #define MAXTAGLOOP 100 -const TObject *luaV_tonumber (const TObject *obj, TObject *n) { +const TValue *luaV_tonumber (const TValue *obj, TValue *n) { lua_Number num; if (ttisnumber(obj)) return obj; if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { @@ -58,15 +57,18 @@ int luaV_tostring (lua_State *L, StkId obj) { else { char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ lua_number2str(s, nvalue(obj)); - setsvalue2s(obj, luaS_new(L, s)); + setsvalue2s(L, obj, luaS_new(L, s)); return 1; } } -static void traceexec (lua_State *L) { +static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; - if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ + CallInfo *ci = L->ci; + const Instruction *oldpc = ci->u.l.savedpc; + ci->u.l.savedpc = pc; + if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); @@ -74,108 +76,82 @@ static void traceexec (lua_State *L) { } } if (mask & LUA_MASKLINE) { - CallInfo *ci = L->ci; Proto *p = ci_func(ci)->l.p; - int newline = getline(p, pcRel(*ci->u.l.pc, p)); - if (!L->hookinit) { - luaG_inithooks(L); - return; - } - lua_assert(ci->state & CI_HASFRAME); - if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */ - ci->u.l.savedpc = *ci->u.l.pc; /* initialize `savedpc' */ - /* calls linehook when enters a new line or jumps back (loop) */ - if (*ci->u.l.pc <= ci->u.l.savedpc || - newline != getline(p, pcRel(ci->u.l.savedpc, p))) { + int npc = pcRel(pc, p); + int newline = getline(p, npc); + /* call linehook when enter a new function, when jump back (loop), + or when enter a new line */ + if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); - ci = L->ci; /* previous call may reallocate `ci' */ - } - ci->u.l.savedpc = *ci->u.l.pc; } } -static void callTMres (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - luaD_checkstack(L, 3); /* cannot check before (could invalidate p1, p2) */ +static void prepTMcall (lua_State *L, const TValue *f, + const TValue *p1, const TValue *p2) { + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ +} + + +static void callTMres (lua_State *L, StkId res) { + ptrdiff_t result = savestack(L, res); + luaD_checkstack(L, 3); L->top += 3; luaD_call(L, L->top - 3, 1); - L->top--; /* result will be in L->top */ + res = restorestack(L, result); + L->top--; + setobjs2s(L, res, L->top); } -static void callTM (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2, const TObject *p3) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - setobj2s(L->top+3, p3); /* 3th argument */ - luaD_checkstack(L, 4); /* cannot check before (could invalidate p1...p3) */ +static void callTM (lua_State *L) { + luaD_checkstack(L, 4); L->top += 4; luaD_call(L, L->top - 4, 0); } -static const TObject *luaV_index (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); - if (tm == NULL) return &luaO_nilobject; /* no TM */ - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - -static const TObject *luaV_getnotable (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (ttisnil(tm)) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - - -/* -** Function to index a table. -** Receives the table at `t' and the key at `key'. -** leaves the result at `res'. -*/ -const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, - int loop) { - if (loop > MAXTAGLOOP) - luaG_runerror(L, "loop in gettable"); - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - const TObject *v = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(v)) return v; - else return luaV_index(L, t, key, loop+1); +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; + if (ttistable(t)) { /* `t' is a table? */ + Table *h = hvalue(t); + const TValue *res = luaH_get(h, key); /* do a primitive set */ + if (!ttisnil(res) || /* result is no nil? */ + (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ + setobj2s(L, val, res); + return; + } + /* else will try the tag method */ + } + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + luaG_typeerror(L, t, "index"); + if (ttisfunction(tm)) { + prepTMcall(L, tm, t, key); + callTMres(L, val); + return; + } + t = tm; /* else repeat with `tm' */ } - else return luaV_getnotable(L, t, key, loop+1); + luaG_runerror(L, "loop in gettable"); } -/* -** Receives table at `t', key at `key' and value at `val'. -*/ -void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { - const TObject *tm; - int loop = 0; - do { +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { + int loop; + for (loop = 0; loop < MAXTAGLOOP; loop++) { + const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); - TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ + TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ - setobj2t(oldval, val); /* write barrier */ + setobj2t(L, oldval, val); + luaC_barrier(L, h, val); return; } /* else will try the tag method */ @@ -183,33 +159,33 @@ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { - callTM(L, tm, t, key, val); + prepTMcall(L, tm, t, key); + setobj2s(L, L->top+3, val); /* 3th argument */ + callTM(L); return; } t = tm; /* else repeat with `tm' */ - } while (++loop <= MAXTAGLOOP); + } luaG_runerror(L, "loop in settable"); } -static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, +static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { - ptrdiff_t result = savestack(L, res); - const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (!ttisfunction(tm)) return 0; - callTMres(L, tm, p1, p2); - res = restorestack(L, result); /* previous call may change stack */ - setobjs2s(res, L->top); + prepTMcall(L, tm, p1, p2); + callTMres(L, res); return 1; } -static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, +static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { - const TObject *tm1 = fasttm(L, mt1, event); - const TObject *tm2; + const TValue *tm1 = fasttm(L, mt1, event); + const TValue *tm2; if (tm1 == NULL) return NULL; /* no metamethod */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); @@ -220,15 +196,16 @@ static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, } -static int call_orderTM (lua_State *L, const TObject *p1, const TObject *p2, +static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { - const TObject *tm1 = luaT_gettmbyobj(L, p1, event); - const TObject *tm2; + const TValue *tm1 = luaT_gettmbyobj(L, p1, event); + const TValue *tm2; if (ttisnil(tm1)) return -1; /* no metamethod? */ tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; - callTMres(L, tm1, p1, p2); + prepTMcall(L, tm1, p1, p2); + callTMres(L, L->top); return !l_isfalse(L->top); } @@ -255,28 +232,28 @@ static int luaV_strcmp (const TString *ls, const TString *rs) { } -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return nvalue(l) < nvalue(r); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0; + return luaV_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; return luaG_ordererror(L, l, r); } -static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { +static int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return nvalue(l) <= nvalue(r); else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0; + return luaV_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ @@ -285,8 +262,8 @@ static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { } -int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { - const TObject *tm; +int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { + const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; @@ -295,7 +272,7 @@ int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->uv.metatable, uvalue(t2)->uv.metatable, + tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } @@ -307,7 +284,8 @@ int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ - callTMres(L, tm, t1, t2); /* call TM */ + prepTMcall(L, tm, t1, t2); + callTMres(L, L->top); /* call TM */ return !l_isfalse(L->top); } @@ -319,25 +297,25 @@ void luaV_concat (lua_State *L, int total, int last) { if (!tostring(L, top-2) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ + } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ - lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + - cast(lu_mem, tsvalue(top-2)->tsv.len); + lu_mem tl = cast(lu_mem, tsvalue(top-1)->len) + + cast(lu_mem, tsvalue(top-2)->len); char *buffer; int i; while (n < total && tostring(L, top-n-1)) { /* collect total length */ - tl += tsvalue(top-n-1)->tsv.len; + tl += tsvalue(top-n-1)->len; n++; } if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ - size_t l = tsvalue(top-i)->tsv.len; + size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } - setsvalue2s(top-n, luaS_newlstr(L, buffer, tl)); + setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; @@ -345,10 +323,11 @@ void luaV_concat (lua_State *L, int total, int last) { } -static void Arith (lua_State *L, StkId ra, - const TObject *rb, const TObject *rc, TMS op) { - TObject tempb, tempc; - const TObject *b, *c; +static StkId Arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op, const Instruction *pc) { + TValue tempb, tempc; + const TValue *b, *c; + L->ci->u.l.savedpc = pc; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { switch (op) { @@ -357,13 +336,11 @@ static void Arith (lua_State *L, StkId ra, case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; case TM_POW: { - const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); - ptrdiff_t res = savestack(L, ra); + const TValue *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); if (!ttisfunction(f)) luaG_runerror(L, "`__pow' (`^' operator) is not a function"); - callTMres(L, f, b, c); - ra = restorestack(L, res); /* previous call may change stack */ - setobjs2s(ra, L->top); + prepTMcall(L, f, b, c); + callTMres(L, ra); break; } default: lua_assert(0); break; @@ -371,6 +348,7 @@ static void Arith (lua_State *L, StkId ra, } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); + return L->base; } @@ -383,63 +361,58 @@ static void Arith (lua_State *L, StkId ra, #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ -#define XRA(i) (L->base+GETARG_A(i)) -#define RB(i) (base+GETARG_B(i)) -#define RKB(i) ((GETARG_B(i) < MAXSTACK) ? RB(i) : k+GETARG_B(i)-MAXSTACK) -#define RC(i) (base+GETARG_C(i)) -#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? RC(i) : k+GETARG_C(i)-MAXSTACK) -#define KBx(i) (k+GETARG_Bx(i)) +#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) +#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) +#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ + (GETARG_B(i) < MAXSTACK) ? base+GETARG_B(i) : k+GETARG_B(i)-MAXSTACK) +#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ + (GETARG_C(i) < MAXSTACK) ? base+GETARG_C(i) : k+GETARG_C(i)-MAXSTACK) +#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) #define dojump(pc, i) ((pc) += (i)) -StkId luaV_execute (lua_State *L) { +StkId luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; - TObject *k; + TValue *k; + StkId base; const Instruction *pc; callentry: /* entry point when calling new functions */ - if (L->hookmask & LUA_MASKCALL) { - L->ci->u.l.pc = &pc; + if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); - } retentry: /* entry point when returning to old functions */ - L->ci->u.l.pc = &pc; - lua_assert(L->ci->state == CI_SAVEDPC || - L->ci->state == (CI_SAVEDPC | CI_CALLING)); - L->ci->state = CI_HASFRAME; /* activate frame */ pc = L->ci->u.l.savedpc; - cl = &clvalue(L->base - 1)->l; + base = L->base; + cl = &clvalue(base - 1)->l; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; - StkId base, ra; + StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L); - if (L->ci->state & CI_YIELD) { /* did hook yield? */ + traceexec(L, pc); /***/ + if (L->isSuspended) { /* did hook yield? */ L->ci->u.l.savedpc = pc - 1; - L->ci->state = CI_YIELD | CI_SAVEDPC; return NULL; } + base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ - base = L->base; ra = RA(i); - lua_assert(L->ci->state & CI_HASFRAME); - lua_assert(base == L->ci->base); + lua_assert(base == L->ci->base && base == L->base); lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); switch (GET_OPCODE(i)) { case OP_MOVE: { - setobjs2s(ra, RB(i)); + setobjs2s(L, ra, RB(i)); break; } case OP_LOADK: { - setobj2s(ra, KBx(i)); + setobj2s(L, ra, KBx(i)); break; } case OP_LOADBOOL: { @@ -448,7 +421,7 @@ StkId luaV_execute (lua_State *L) { break; } case OP_LOADNIL: { - TObject *rb = RB(i); + TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); @@ -456,122 +429,115 @@ StkId luaV_execute (lua_State *L) { } case OP_GETUPVAL: { int b = GETARG_B(i); - setobj2s(ra, cl->upvals[b]->v); + setobj2s(L, ra, cl->upvals[b]->v); break; } case OP_GETGLOBAL: { - TObject *rb = KBx(i); - const TObject *v; + TValue *rb = KBx(i); lua_assert(ttisstring(rb) && ttistable(&cl->g)); - v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); + L->ci->u.l.savedpc = pc; + luaV_gettable(L, &cl->g, rb, ra); /***/ + base = L->base; break; } case OP_GETTABLE: { - StkId rb = RB(i); - TObject *rc = RKC(i); - if (ttistable(rb)) { - const TObject *v = luaH_get(hvalue(rb), rc); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); + L->ci->u.l.savedpc = pc; + luaV_gettable(L, RB(i), RKC(i), ra); /***/ + base = L->base; break; } case OP_SETGLOBAL: { lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - luaV_settable(L, &cl->g, KBx(i), ra); + L->ci->u.l.savedpc = pc; + luaV_settable(L, &cl->g, KBx(i), ra); /***/ + base = L->base; break; } case OP_SETUPVAL: { - int b = GETARG_B(i); - setobj(cl->upvals[b]->v, ra); /* write barrier */ + UpVal *uv = cl->upvals[GETARG_B(i)]; + setobj(L, uv->v, ra); + luaC_barrier(L, uv, ra); break; } case OP_SETTABLE: { - luaV_settable(L, ra, RKB(i), RKC(i)); + L->ci->u.l.savedpc = pc; + luaV_settable(L, ra, RKB(i), RKC(i)); /***/ + base = L->base; break; } case OP_NEWTABLE: { int b = GETARG_B(i); b = fb2int(b); - sethvalue(ra, luaH_new(L, b, GETARG_C(i))); - luaC_checkGC(L); + sethvalue(L, ra, luaH_new(L, b, GETARG_C(i))); + L->ci->u.l.savedpc = pc; + luaC_checkGC(L); /***/ + base = L->base; break; } case OP_SELF: { StkId rb = RB(i); - TObject *rc = RKC(i); - runtime_check(L, ttisstring(rc)); - setobjs2s(ra+1, rb); - if (ttistable(rb)) { - const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); + setobjs2s(L, ra+1, rb); + L->ci->u.l.savedpc = pc; + luaV_gettable(L, rb, RKC(i), ra); /***/ + base = L->base; break; } case OP_ADD: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) + nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_ADD); + base = Arith(L, ra, rb, rc, TM_ADD, pc); /***/ break; } case OP_SUB: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) - nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_SUB); + base = Arith(L, ra, rb, rc, TM_SUB, pc); /***/ break; } case OP_MUL: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) * nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_MUL); + base = Arith(L, ra, rb, rc, TM_MUL, pc); /***/ break; } case OP_DIV: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) / nvalue(rc)); } else - Arith(L, ra, rb, rc, TM_DIV); + base = Arith(L, ra, rb, rc, TM_DIV, pc); /***/ break; } case OP_POW: { - Arith(L, ra, RKB(i), RKC(i), TM_POW); + base = Arith(L, ra, RKB(i), RKC(i), TM_POW, pc); /***/ break; } case OP_UNM: { - const TObject *rb = RB(i); - TObject temp; + const TValue *rb = RB(i); + TValue temp; if (tonumber(rb, &temp)) { setnvalue(ra, -nvalue(rb)); } else { setnilvalue(&temp); - if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) + L->ci->u.l.savedpc = pc; + if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) /***/ luaG_aritherror(L, RB(i), &temp); + base = L->base; } break; } @@ -583,10 +549,11 @@ StkId luaV_execute (lua_State *L) { case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); - luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ + L->ci->u.l.savedpc = pc; + luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ /***/ + luaC_checkGC(L); /***/ base = L->base; - setobjs2s(RA(i), base+b); - luaC_checkGC(L); + setobjs2s(L, RA(i), base+b); break; } case OP_JMP: { @@ -594,42 +561,46 @@ StkId luaV_execute (lua_State *L) { break; } case OP_EQ: { - if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; + L->ci->u.l.savedpc = pc; + if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ else dojump(pc, GETARG_sBx(*pc) + 1); + base = L->base; break; } case OP_LT: { - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; + L->ci->u.l.savedpc = pc; + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ else dojump(pc, GETARG_sBx(*pc) + 1); + base = L->base; break; } case OP_LE: { - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; + L->ci->u.l.savedpc = pc; + if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ else dojump(pc, GETARG_sBx(*pc) + 1); + base = L->base; break; } case OP_TEST: { - TObject *rb = RB(i); + TValue *rb = RB(i); if (l_isfalse(rb) == GETARG_C(i)) pc++; else { - setobjs2s(ra, rb); + setobjs2s(L, ra, rb); dojump(pc, GETARG_sBx(*pc) + 1); } break; } case OP_CALL: - case OP_TAILCALL: { + case OP_TAILCALL: { /***/ StkId firstResult; int b = GETARG_B(i); - int nresults; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - nresults = GETARG_C(i) - 1; + L->ci->u.l.savedpc = pc; firstResult = luaD_precall(L, ra); if (firstResult) { + int nresults = GETARG_C(i) - 1; if (firstResult > L->top) { /* yield? */ - lua_assert(L->ci->state == (CI_C | CI_YIELD)); (L->ci - 1)->u.l.savedpc = pc; - (L->ci - 1)->state = CI_SAVEDPC; return NULL; } /* it was a C function (`precall' called it); adjust results */ @@ -637,45 +608,37 @@ StkId luaV_execute (lua_State *L) { if (nresults >= 0) L->top = L->ci->top; } else { /* it is a Lua function */ - if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ - (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ - (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); - } + if (GET_OPCODE(i) == OP_CALL) /* regular call? */ + nexeccalls++; else { /* tail call: put new frame in place of previous one */ int aux; base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ ra = RA(i); if (L->openupval) luaF_close(L, base); for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ - setobjs2s(base+aux-1, ra+aux); + setobjs2s(L, base+aux-1, ra+aux); (L->ci - 1)->top = L->top = base+aux; /* correct top */ - lua_assert(L->ci->state & CI_SAVEDPC); (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ - (L->ci - 1)->state = CI_SAVEDPC; L->ci--; /* remove new frame */ L->base = L->ci->base; } goto callentry; } + base = L->base; break; } case OP_RETURN: { CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; - lua_assert(L->ci->state & CI_HASFRAME); if (L->openupval) luaF_close(L, base); - L->ci->state = CI_SAVEDPC; /* deactivate current function */ L->ci->u.l.savedpc = pc; - /* previous function was running `here'? */ - if (!(ci->state & CI_CALLING)) { - lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); + if (--nexeccalls == 0) /* was previous function running `here'? */ return ra; /* no: return */ - } else { /* yes: continue its execution */ int nresults; - lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); + lua_assert(isLua(ci)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); @@ -684,49 +647,54 @@ StkId luaV_execute (lua_State *L) { } } case OP_FORLOOP: { - lua_Number step, idx, limit; - const TObject *plimit = ra+1; - const TObject *pstep = ra+2; - if (!ttisnumber(ra)) - luaG_runerror(L, "`for' initial value must be a number"); - if (!tonumber(plimit, ra+1)) - luaG_runerror(L, "`for' limit must be a number"); - if (!tonumber(pstep, ra+2)) - luaG_runerror(L, "`for' step must be a number"); - step = nvalue(pstep); - idx = nvalue(ra) + step; /* increment index */ - limit = nvalue(plimit); + lua_Number step = nvalue(ra+2); + lua_Number idx = nvalue(ra) + step; /* increment index */ + lua_Number limit = nvalue(ra+1); if (step > 0 ? idx <= limit : idx >= limit) { dojump(pc, GETARG_sBx(i)); /* jump back */ - chgnvalue(ra, idx); /* update index */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ } break; } + case OP_FORPREP: { /***/ + const TValue *init = ra; + const TValue *plimit = ra+1; + const TValue *pstep = ra+2; + L->ci->u.l.savedpc = pc; + if (!tonumber(init, ra)) + luaG_runerror(L, "`for' initial value must be a number"); + else if (!tonumber(plimit, ra+1)) + luaG_runerror(L, "`for' limit must be a number"); + else if (!tonumber(pstep, ra+2)) + luaG_runerror(L, "`for' step must be a number"); + setnvalue(ra, nvalue(ra) - nvalue(pstep)); + dojump(pc, GETARG_sBx(i)); + break; + } case OP_TFORLOOP: { - int nvar = GETARG_C(i) + 1; - StkId cb = ra + nvar + 2; /* call base */ - setobjs2s(cb, ra); - setobjs2s(cb+1, ra+1); - setobjs2s(cb+2, ra+2); + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ - luaD_call(L, cb, nvar); + L->ci->u.l.savedpc = pc; + luaD_call(L, cb, GETARG_C(i)); /***/ L->top = L->ci->top; - ra = XRA(i) + 2; /* final position of first result */ - cb = ra + nvar; - do { /* move results to proper positions */ - nvar--; - setobjs2s(ra+nvar, cb+nvar); - } while (nvar > 0); - if (ttisnil(ra)) /* break loop? */ + base = L->base; + cb = RA(i) + 3; /* previous call may change the stack */ + if (ttisnil(cb)) /* break loop? */ pc++; /* skip jump (break loop) */ - else + else { + setobjs2s(L, cb-1, cb); /* save control variable */ dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ + } break; } case OP_TFORPREP: { /* for compatibility only */ if (ttistable(ra)) { - setobjs2s(ra+1, ra); - setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); + setobjs2s(L, ra+1, ra); + setobj2s(L, ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } dojump(pc, GETARG_sBx(i)); break; @@ -746,8 +714,11 @@ StkId luaV_execute (lua_State *L) { L->top = L->ci->top; } bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ - for (; n > 0; n--) - setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ + for (; n > 0; n--) { + TValue *val = ra+n; + setobj2t(L, luaH_setnum(L, h, bc+n), val); + luaC_barrier(L, h, val); + } break; } case OP_CLOSE: { @@ -770,12 +741,13 @@ StkId luaV_execute (lua_State *L) { ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } - setclvalue(ra, ncl); - luaC_checkGC(L); + setclvalue(L, ra, ncl); + L->ci->u.l.savedpc = pc; + luaC_checkGC(L); /***/ + base = L->base; break; } } } } - diff --git a/src/lvm.h b/src/lvm.h index 19cce200b6..64bba1280e 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 1.47 2002/11/14 16:16:21 roberto Exp $ +** $Id: lvm.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -22,14 +22,13 @@ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r); -int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2); -const TObject *luaV_tonumber (const TObject *obj, TObject *n); +int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +const TValue *luaV_tonumber (const TValue *obj, TValue *n); int luaV_tostring (lua_State *L, StkId obj); -const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, - int loop); -void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val); -StkId luaV_execute (lua_State *L); +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); +StkId luaV_execute (lua_State *L, int nexeccalls); void luaV_concat (lua_State *L, int total, int last); #endif diff --git a/src/lzio.c b/src/lzio.c index 3aeca1c588..f538ea7544 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.24 2003/03/20 16:00:56 roberto Exp $ +** $Id: lzio.c,v 1.28 2003/11/18 10:44:53 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -13,12 +13,17 @@ #include "llimits.h" #include "lmem.h" +#include "lstate.h" #include "lzio.h" int luaZ_fill (ZIO *z) { size_t size; - const char *buff = z->reader(NULL, z->data, &size); + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); if (buff == NULL || size == 0) return EOZ; z->n = size - 1; z->p = buff; @@ -37,10 +42,10 @@ int luaZ_lookahead (ZIO *z) { } -void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { +void luaZ_init (lua_State *L, ZIO *z, lua_Chunkreader reader, void *data) { + z->L = L; z->reader = reader; z->data = data; - z->name = name; z->n = 0; z->p = NULL; } @@ -72,8 +77,7 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) { char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { if (n > buff->buffsize) { if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaM_reallocvector(L, buff->buffer, buff->buffsize, n, char); - buff->buffsize = n; + luaZ_resizebuffer(L, buff, n); } return buff->buffer; } diff --git a/src/lzio.h b/src/lzio.h index 5e73615cc0..4b64256e40 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.15 2003/03/20 16:00:56 roberto Exp $ +** $Id: lzio.h,v 1.19 2003/10/03 16:05:34 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -10,6 +10,8 @@ #include "lua.h" +#include "lmem.h" + #define EOZ (-1) /* end of stream */ @@ -20,9 +22,7 @@ typedef struct Zio ZIO; #define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) -#define zname(z) ((z)->name) - -void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name); +void luaZ_init (lua_State *L, ZIO *z, lua_Chunkreader reader, void *data); size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ int luaZ_lookahead (ZIO *z); @@ -30,6 +30,7 @@ int luaZ_lookahead (ZIO *z); typedef struct Mbuffer { char *buffer; + size_t n; size_t buffsize; } Mbuffer; @@ -38,8 +39,12 @@ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) -#define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_buffer(buff) ((buff)->buffer) +#define luaZ_sizebuffer(buff) ((buff)->buffsize) +#define luaZ_bufflen(buff) ((buff)->n) + +#define luaZ_resetbuffer(buff) ((buff)->n = 0) + #define luaZ_resizebuffer(L, buff, size) \ (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ @@ -48,6 +53,7 @@ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) + /* --------- Private Part ------------------ */ struct Zio { @@ -55,7 +61,7 @@ struct Zio { const char *p; /* current position in buffer */ lua_Chunkreader reader; void* data; /* additional data */ - const char *name; + lua_State *L; /* Lua state (for reader) */ }; diff --git a/test/fibfor.lua b/test/fibfor.lua index 19bb34b40e..8bbba39cd7 100644 --- a/test/fibfor.lua +++ b/test/fibfor.lua @@ -7,7 +7,7 @@ function generatefib (n) coroutine.yield(a) a, b = b, a+b end - end, n) + end) end for i in generatefib(1000) do print(i) end diff --git a/test/trace-calls.lua b/test/trace-calls.lua index 63c8b8f3eb..5613c2cbfc 100644 --- a/test/trace-calls.lua +++ b/test/trace-calls.lua @@ -3,7 +3,7 @@ local level=0 -function hook(event) +local function hook(event) local t=debug.getinfo(3) io.write(level," >>> ",string.rep(" ",level)) if t~=nil and t.currentline>=0 then io.write(t.short_src,":",t.currentline," ") end From 5d480731503a315eab9d6ab9426e3d4cfd5e52f8 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Thu, 2 Sep 2004 12:00:00 +0000 Subject: [PATCH 18/97] Lua 5.1-work1 --- HISTORY | 2 +- INSTALL | 22 +- MANIFEST | 114 ++++++ RCS | 1 - README | 2 +- build | 9 +- config | 53 +-- configure | 9 - etc/Makefile | 19 +- etc/RCS | 1 - etc/README | 4 + etc/all.c | 41 +++ etc/min.c | 46 ++- etc/noparser.c | 3 + include/Makefile | 2 +- include/RCS | 1 - include/lauxlib.h | 33 +- include/lua.h | 69 +--- include/luaconf.h | 312 +++++++++++++++++ include/lualib.h | 25 +- src/RCS | 1 - src/README | 4 +- src/lapi.c | 88 +++-- src/lcode.c | 41 ++- src/lcode.h | 7 +- src/ldebug.c | 39 ++- src/ldebug.h | 4 +- src/ldo.c | 124 ++++--- src/ldo.h | 10 +- src/ldump.c | 30 +- src/lfunc.c | 3 +- src/lgc.c | 310 +++++++++-------- src/lgc.h | 32 +- src/lib/Makefile | 4 +- src/lib/RCS | 1 - src/lib/lauxlib.c | 159 +++++---- src/lib/lbaselib.c | 296 +++++++--------- src/lib/ldblib.c | 33 +- src/lib/linit.c | 38 ++ src/lib/liolib.c | 378 ++++---------------- src/lib/lmathlib.c | 30 +- src/lib/loadlib.c | 5 +- src/lib/loslib.c | 241 +++++++++++++ src/lib/lstrlib.c | 30 +- src/lib/ltablib.c | 47 +-- src/llex.c | 3 +- src/llimits.h | 97 +----- src/lmem.c | 6 +- src/lobject.c | 30 +- src/lobject.h | 6 +- src/lopcodes.c | 10 +- src/lopcodes.h | 58 ++- src/lparser.c | 68 ++-- src/lparser.h | 5 +- src/lstate.c | 32 +- src/lstate.h | 56 +-- src/lstring.c | 12 +- src/lstring.h | 3 +- src/ltable.c | 63 +--- src/ltable.h | 3 +- src/ltests.c | 852 --------------------------------------------- src/ltm.c | 3 +- src/lua/RCS | 1 - src/lua/README | 4 +- src/lua/lua.c | 247 ++++++------- src/luac/Makefile | 6 +- src/luac/RCS | 1 - src/luac/README | 2 +- src/luac/luac.c | 75 ++-- src/luac/print.c | 52 ++- src/lundump.c | 13 +- src/lundump.h | 6 +- src/lvm.c | 304 ++++++++-------- src/lvm.h | 8 +- src/lzio.c | 3 +- 75 files changed, 2140 insertions(+), 2612 deletions(-) create mode 100644 MANIFEST delete mode 120000 RCS delete mode 100755 configure delete mode 120000 etc/RCS create mode 100644 etc/all.c delete mode 120000 include/RCS create mode 100644 include/luaconf.h delete mode 120000 src/RCS delete mode 120000 src/lib/RCS create mode 100644 src/lib/linit.c create mode 100644 src/lib/loslib.c delete mode 100644 src/ltests.c delete mode 120000 src/lua/RCS delete mode 120000 src/luac/RCS diff --git a/HISTORY b/HISTORY index cf6e1c019d..dd29bc7c8f 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,4 @@ -This is Lua 5.0. +This is Lua 5.1 (work). * Changes from version 4.0 to 5.0 ------------------------------- diff --git a/INSTALL b/INSTALL index 6828f23cbd..9d4893012c 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -This is Lua 5.0. +This is Lua 5.1 (work). * Installation ------------ @@ -7,8 +7,9 @@ This is Lua 5.0. 1. Read "config" and edit it to suit your platform and needs. We strongly recommend that you enable support for dynamic loading, if your platform allows it. - 2. Do "make". - 3. If you want to install Lua in an "official" place in your system, + 2. Do the same for include/luaconf.h. + 3. Do "make". + 4. If you want to install Lua in an "official" place in your system, then do "make install". The official place and the way to install files are defined in "config". You may have to be root to do this. @@ -53,27 +54,26 @@ This is Lua 5.0. /usr/local/lib may not be a place that is checked for shared libraries. In Linux, the places checked are in /etc/ld.so.conf. Try also "man ld.so". - Building shared libraries in other systems is similar but details differ; + Building shared libraries on other systems is similar but details differ; you may need to fix a few details in the top-level Makefile. * Installation on Windows and other systems ----------------------------------------- - The instructions for building Lua on other systems machine depend on the - particular compiler you are using. The simplest way is to create a folder - with all .c and .h files, and then create projects for the core library, - the standard library, the interpreter, and the compiler, as follows: + The instructions for building Lua on other systems depend on the particular + compiler you are using. The simplest way is to create a folder with all .c + and .h files, and then create projects for the core library, the standard + library, the interpreter, and the compiler, as follows: core lib: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c - standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c ltablib.c - lstrlib.c loadlib.c + standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c + ltablib.c lstrlib.c loadlib.c interpreter: core lib, standard lib, lua.c compiler: core lib, lauxlib.c luac.c print.c - and also lopcodes.c (with LUA_OPNAMES defined) from core. Of course, to use Lua as a library, you'll have to know how to create and use libraries with your compiler. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000000..fdb5d2a2ec --- /dev/null +++ b/MANIFEST @@ -0,0 +1,114 @@ +MANIFEST contents of Lua 5.1 (work1) distribution on Wed Sep 1 22:19:31 BRT 2004 +lua-5.1-work1 +lua-5.1-work1/COPYRIGHT +lua-5.1-work1/HISTORY +lua-5.1-work1/INSTALL +lua-5.1-work1/MANIFEST +lua-5.1-work1/Makefile +lua-5.1-work1/README +lua-5.1-work1/bin +lua-5.1-work1/build +lua-5.1-work1/config +lua-5.1-work1/etc +lua-5.1-work1/etc/Makefile +lua-5.1-work1/etc/README +lua-5.1-work1/etc/all.c +lua-5.1-work1/etc/lua.ico +lua-5.1-work1/etc/min.c +lua-5.1-work1/etc/noparser.c +lua-5.1-work1/etc/saconfig.c +lua-5.1-work1/include +lua-5.1-work1/include/Makefile +lua-5.1-work1/include/lauxlib.h +lua-5.1-work1/include/lua.h +lua-5.1-work1/include/luaconf.h +lua-5.1-work1/include/lualib.h +lua-5.1-work1/lib +lua-5.1-work1/src +lua-5.1-work1/src/Makefile +lua-5.1-work1/src/README +lua-5.1-work1/src/lapi.c +lua-5.1-work1/src/lapi.h +lua-5.1-work1/src/lcode.c +lua-5.1-work1/src/lcode.h +lua-5.1-work1/src/ldebug.c +lua-5.1-work1/src/ldebug.h +lua-5.1-work1/src/ldo.c +lua-5.1-work1/src/ldo.h +lua-5.1-work1/src/ldump.c +lua-5.1-work1/src/lfunc.c +lua-5.1-work1/src/lfunc.h +lua-5.1-work1/src/lgc.c +lua-5.1-work1/src/lgc.h +lua-5.1-work1/src/lib +lua-5.1-work1/src/lib/Makefile +lua-5.1-work1/src/lib/README +lua-5.1-work1/src/lib/lauxlib.c +lua-5.1-work1/src/lib/lbaselib.c +lua-5.1-work1/src/lib/ldblib.c +lua-5.1-work1/src/lib/linit.c +lua-5.1-work1/src/lib/liolib.c +lua-5.1-work1/src/lib/lmathlib.c +lua-5.1-work1/src/lib/loadlib.c +lua-5.1-work1/src/lib/loslib.c +lua-5.1-work1/src/lib/lstrlib.c +lua-5.1-work1/src/lib/ltablib.c +lua-5.1-work1/src/llex.c +lua-5.1-work1/src/llex.h +lua-5.1-work1/src/llimits.h +lua-5.1-work1/src/lmem.c +lua-5.1-work1/src/lmem.h +lua-5.1-work1/src/lobject.c +lua-5.1-work1/src/lobject.h +lua-5.1-work1/src/lopcodes.c +lua-5.1-work1/src/lopcodes.h +lua-5.1-work1/src/lparser.c +lua-5.1-work1/src/lparser.h +lua-5.1-work1/src/lstate.c +lua-5.1-work1/src/lstate.h +lua-5.1-work1/src/lstring.c +lua-5.1-work1/src/lstring.h +lua-5.1-work1/src/ltable.c +lua-5.1-work1/src/ltable.h +lua-5.1-work1/src/ltm.c +lua-5.1-work1/src/ltm.h +lua-5.1-work1/src/lua +lua-5.1-work1/src/lua/Makefile +lua-5.1-work1/src/lua/README +lua-5.1-work1/src/lua/lua.c +lua-5.1-work1/src/luac +lua-5.1-work1/src/luac/Makefile +lua-5.1-work1/src/luac/README +lua-5.1-work1/src/luac/luac.c +lua-5.1-work1/src/luac/print.c +lua-5.1-work1/src/lundump.c +lua-5.1-work1/src/lundump.h +lua-5.1-work1/src/lvm.c +lua-5.1-work1/src/lvm.h +lua-5.1-work1/src/lzio.c +lua-5.1-work1/src/lzio.h +lua-5.1-work1/test +lua-5.1-work1/test/README +lua-5.1-work1/test/bisect.lua +lua-5.1-work1/test/cf.lua +lua-5.1-work1/test/echo.lua +lua-5.1-work1/test/env.lua +lua-5.1-work1/test/factorial.lua +lua-5.1-work1/test/fib.lua +lua-5.1-work1/test/fibfor.lua +lua-5.1-work1/test/globals.lua +lua-5.1-work1/test/hello.lua +lua-5.1-work1/test/life.lua +lua-5.1-work1/test/lua +lua-5.1-work1/test/luac +lua-5.1-work1/test/luac.lua +lua-5.1-work1/test/printf.lua +lua-5.1-work1/test/readonly.lua +lua-5.1-work1/test/sieve.lua +lua-5.1-work1/test/sort.lua +lua-5.1-work1/test/table.lua +lua-5.1-work1/test/trace-calls.lua +lua-5.1-work1/test/trace-globals.lua +lua-5.1-work1/test/undefined.lua +lua-5.1-work1/test/xd.lua +END OF MANIFEST diff --git a/RCS b/RCS deleted file mode 120000 index 1ae3893605..0000000000 --- a/RCS +++ /dev/null @@ -1 +0,0 @@ -../RCS \ No newline at end of file diff --git a/README b/README index 4aaaba5286..8f4aa49ac2 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Lua 5.0. +This is Lua 5.1 (work). See HISTORY for a summary of changes since the last released version. * What is Lua? diff --git a/build b/build index 6faed3710c..a0e3fb3f0b 100755 --- a/build +++ b/build @@ -1,9 +1,12 @@ -# If you don't want to use make, run this script. -# But make sure you read config to see what can be customized. +#!/bin/sh +# +# If you don't want to use make, run this script to build Lua. +# Read config and include/luaconf.h to see what can be customized. # Easiest way to build bin/lua: # cc -O2 -o bin/lua -Iinclude -Isrc src/*.c src/lib/*.c src/lua/*.c -lm -ldl +# bin/lua test/hello.lua # Easiest way to build Lua libraries and executables: @@ -25,7 +28,7 @@ cc -O2 -o ../../bin/lua -I../../include *.c ../../lib/*.a -lm -ldl echo -n 'luac... ' cd ../luac -cc -O2 -o ../../bin/luac -I../../include -I.. *.c -DLUA_OPNAMES ../lopcodes.c ../../lib/*.a +cc -O2 -o ../../bin/luac -I../../include -I.. *.c ../../lib/*.a echo 'done' diff --git a/config b/config index 2700e6d93f..fe39c134f4 100644 --- a/config +++ b/config @@ -1,14 +1,10 @@ -# configuration file for making Lua 5.0 +# configuration file for making Lua 5.1 (work) # see INSTALL for installation instructions # These are default values. Skip this section and see the explanations below. LOADLIB= DLLIB= -NUMBER= -POPEN= -TMPNAM= -DEGREES= USERCONF= # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= @@ -42,50 +38,11 @@ USERCONF= # --------------------------------------------------------------- Lua libraries -# The Lua IO library (src/lib/liolib.c) has support for pipes using popen and -# pclose. This support is enabled by default on POSIX systems. -# If your system is not POSIX but has popen and pclose, define USE_POPEN=1. -# If you don't want to support pipes, define USE_POPEN=0. -# -#POPEN= -DUSE_POPEN=1 -#POPEN= -DUSE_POPEN=0 -# -# The form below will probably work on (some) Windows systems. -# -#POPEN= -DUSE_POPEN=1 -Dpopen=_popen -Dpclose=_pclose - -# The Lua OS library (src/lib/liolib.c) exports an interface to the C function -# tmpnam, which gcc now thinks is `dangerous'. So, support for tmpnam is -# disabled by default when compiling with gcc. -# If you still want to use tmpnam, define USE_TMPNAME=1. If you don't want to -# use tmpnam even if you're not compiling with gcc, define USE_TMPNAME=0. -# -#TMPNAM= -DUSE_TMPNAME=1 -#TMPNAM= -DUSE_TMPNAME=0 - -# The Lua math library (src/lib/lmathlib.c) now operates in radians, unlike -# previous versions of Lua, which used degrees. To use degrees instead of -# radians, define USE_DEGREES. -# -#DEGREES= -DUSE_DEGREES +# See include/luaconf.h. # ------------------------------------------------------------------ Lua core -# Lua uses double for numbers. To change this, uncomment and edit the following -# line, changing USE_XXX to one of USE_DOUBLE, USE_FLOAT, USE_LONG, USE_INT. -# -#NUMBER= -DLUA_USER_H='"../etc/luser_number.h"' -DUSE_XXX - -# When compiling Lua with gcc on a Pentium machine, using a fast rounding -# method for the conversion of doubles to ints can give around 20% speed -# improvement. To use this rounding method, uncomment the following line. -#NUMBER= -DLUA_USER_H='"../etc/luser_number.h"' -DUSE_FASTROUND - -# For partial compatibility with old upvalue syntax, define LUA_COMPATUPSYNTAX. -# For partial compatibility with old upvalue behavior in C functions, define -# LUA_COMPATUPVALUES. Add these definitions to MYCFLAGS. -# -# -DLUA_COMPATUPSYNTAX -DLUA_COMPATUPVALUES +# See include/luaconf.h. # ------------------------------------------------------------- Lua interpreter @@ -165,14 +122,14 @@ INSTALL_DATA= cp # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= -V= 5.0 +V= 5.1 BIN= $(LUA)/bin INC= $(LUA)/include LIB= $(LUA)/lib INCS= -I$(INC) $(EXTRA_INCS) -DEFS= $(NUMBER) $(EXTRA_DEFS) +DEFS= $(EXTRA_DEFS) CFLAGS= $(MYCFLAGS) $(WARN) $(INCS) $(DEFS) diff --git a/configure b/configure deleted file mode 100755 index 0aa89712fb..0000000000 --- a/configure +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# Lua does not use GNU autoconf; just edit ./config if needed to suit your -# platform and then run make. - -# This shows the parameters currently set in ./config: -make echo - -# If you want config as a Lua program, run "make lecho". diff --git a/etc/Makefile b/etc/Makefile index 0fc318cdaa..805df1d21d 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -4,32 +4,29 @@ LUA= .. include $(LUA)/config -LIBLUA=$(LIB)/liblua.a -ALL= bin2c min noparser luab +ALL= min noparser luab 1 all: @echo 'choose a target:' $(ALL) -bin2c: bin2c.c - $(CC) $(CFLAGS) -o $@ $@.c - min: min.c $(LIBLUA) - $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua + $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib noparser: noparser.c $(CC) $(CFLAGS) -I$(LUA)/src -o $@.o -c $@.c -luab: noparser $(LIBLUA) - $(CC) -o $@ noparser.o $(LUA)/src/lua/lua.o -L$(LIB) -llua -llualib $(EXTRA_LIBS) +luab: noparser + $(CC) -o $@ noparser.o $(LUA)/src/lua/lua.o -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) $(BIN)/luac $(LUA)/test/hello.lua $@ luac.out -$@ -e'a=1' +1: + $(CC) $(CFLAGS) -I../src -I../src/lib -I../src/lua all.c $(EXTRA_LIBS) $(DLLIB) + ./a.out $(LUA)/test/hello.lua + flat: cd ..; mkdir flat; mv include/*.h src/*.[ch] src/*/*.[ch] flat -$(LIBLUA): - cd ../src; $(MAKE) - clean: rm -f $(ALL) a.out core *.o luac.out diff --git a/etc/RCS b/etc/RCS deleted file mode 120000 index 1ae3893605..0000000000 --- a/etc/RCS +++ /dev/null @@ -1 +0,0 @@ -../RCS \ No newline at end of file diff --git a/etc/README b/etc/README index 6a383ef80d..01df94c42d 100644 --- a/etc/README +++ b/etc/README @@ -1,6 +1,10 @@ This directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. +all.c + Full Lua interpreter in a single file. + Do "make 1". + lua.ico A Lua icon for Windows (and web sites, as favicon.ico). Drawn by hand by Markus Gritsch . diff --git a/etc/all.c b/etc/all.c new file mode 100644 index 0000000000..fc4b045a89 --- /dev/null +++ b/etc/all.c @@ -0,0 +1,41 @@ +/* +* all.c -- Lua core, libraries and interpreter in a single file +*/ + +#define LUA_CORE +#define LUA_LIB +#define lua_c + +#include "lapi.c" +#include "lcode.c" +#include "ldebug.c" +#include "ldo.c" +#include "ldump.c" +#include "lfunc.c" +#include "lgc.c" +#include "llex.c" +#include "lmem.c" +#include "lobject.c" +#include "lopcodes.c" +#include "lparser.c" +#include "lstate.c" +#include "lstring.c" +#include "ltable.c" +#include "ltm.c" +#include "lundump.c" +#include "lvm.c" +#include "lzio.c" + +#include "lauxlib.c" +#include "lbaselib.c" +#include "ldblib.c" +#include "liolib.c" +#include "linit.c" +#include "lmathlib.c" +#include "loadlib.c" +#define pushresult pushresult2 +#include "loslib.c" +#include "lstrlib.c" +#include "ltablib.c" + +#include "lua.c" diff --git a/etc/min.c b/etc/min.c index bc1c682141..dfcc805a27 100644 --- a/etc/min.c +++ b/etc/min.c @@ -1,37 +1,47 @@ /* * min.c -- a minimal Lua interpreter -* only dynamic loading is enabled -- all libraries must be dynamically loaded -* no interaction, only batch execution +* loads stdin only with minimal error handling. +* no interaction, and no standard library, only a "print" function. */ #include #include "lua.h" -#include "lualib.h" #include "lauxlib.h" -static int run(lua_State *L) +static int print(lua_State *L) { - char **argv=lua_touserdata(L,1); - lua_register(L,"error",lua_error); - luaopen_loadlib(L); - while (*++argv) + int n=lua_gettop(L); + int i; + for (i=1; i<=n; i++) { - if (luaL_loadfile(L,*argv)) lua_error(L); else lua_call(L,0,0); + if (i>1) printf("\t"); + if (lua_isstring(L,i)) + printf("%s",lua_tostring(L,i)); + else if (lua_isnil(L,i)) + printf("%s","nil"); + else if (lua_isboolean(L,i)) + printf("%s",lua_toboolean(L,i) ? "true" : "false"); + else + printf("%s:%p",lua_typename(L,lua_type(L,i)),lua_topointer(L,i)); } + printf("\n"); return 0; } -#define report(s) fprintf(stderr,"%s\n",s) +static const char *getF(lua_State *L, void *ud, size_t *size) +{ + FILE *f=(FILE *)ud; + static char buff[512]; + if (feof(f)) return NULL; + *size=fread(buff,1,sizeof(buff),f); + return (*size>0) ? buff : NULL; +} -int main(int argc, char *argv[]) +int main(void) { lua_State *L=lua_open(); - if (L==NULL) - { - report("not enough memory for state"); - return 1; - } - if (lua_cpcall(L,run,argv)) report(lua_tostring(L,-1)); - lua_close(L); + lua_register(L,"print",print); + if (lua_load(L,getF,stdin,"=stdin") || lua_pcall(L,0,0,0)) + fprintf(stderr,"%s\n",lua_tostring(L,-1)); return 0; } diff --git a/etc/noparser.c b/etc/noparser.c index 9d52f7c0c6..dc58faffa7 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -9,6 +9,8 @@ * load the parsing modules. To try it, do "make luab". */ +#define LUA_CORE + #include "llex.h" #include "lparser.h" #include "lzio.h" @@ -28,6 +30,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { /* * If you also want to avoid the dump module, ldump.o, enable the code below. */ +#define NODUMP #ifdef NODUMP #include "lundump.h" diff --git a/include/Makefile b/include/Makefile index d75997d9f0..687cf383de 100644 --- a/include/Makefile +++ b/include/Makefile @@ -4,7 +4,7 @@ LUA= .. include $(LUA)/config -SRCS= lua.h lualib.h lauxlib.h +SRCS= lua.h lualib.h lauxlib.h luaconf.h all: diff --git a/include/RCS b/include/RCS deleted file mode 120000 index 1ae3893605..0000000000 --- a/include/RCS +++ /dev/null @@ -1 +0,0 @@ -../RCS \ No newline at end of file diff --git a/include/lauxlib.h b/include/lauxlib.h index 58f250052d..22afc245b9 100644 --- a/include/lauxlib.h +++ b/include/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.63 2004/03/13 13:32:09 roberto Exp $ +** $Id: lauxlib.h,v 1.70 2004/07/09 18:23:17 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -15,10 +15,8 @@ #include "lua.h" -#ifndef LUALIB_API -#define LUALIB_API LUA_API -#endif - +/* extra error code for `luaL_load' */ +#define LUA_ERRFILE (LUA_ERRERR+1) typedef struct luaL_reg { @@ -56,6 +54,9 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...); LUALIB_API int luaL_findstring (const char *st, const char *const lst[]); +LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, + const char *path); + LUALIB_API int luaL_ref (lua_State *L, int t); LUALIB_API void luaL_unref (lua_State *L, int t, int ref); @@ -85,6 +86,7 @@ LUALIB_API lua_State *(luaL_newstate) (void); #define luaL_checklong(L,n) ((long)luaL_checkinteger(L, n)) #define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, n,d)) +#define luaL_typename(L,i) lua_typename(L,lua_type(L,(i))) /* ** {====================================================== @@ -93,10 +95,6 @@ LUALIB_API lua_State *(luaL_newstate) (void); */ -#ifndef LUAL_BUFFERSIZE -#define LUAL_BUFFERSIZE BUFSIZ -#endif - typedef struct luaL_Buffer { char *p; /* current position in buffer */ @@ -122,15 +120,18 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B); /* }====================================================== */ +/* compatibility with ref system */ -/* -** Compatibility macros and functions -*/ +/* pre-defined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ + (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) + +#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) -LUALIB_API int lua_dofile (lua_State *L, const char *filename); -LUALIB_API int lua_dostring (lua_State *L, const char *str); -LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t sz, - const char *n); +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, ref) #endif diff --git a/include/lua.h b/include/lua.h index bcb37a0608..e513dc3c55 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.187 2004/03/09 17:34:35 roberto Exp $ +** $Id: lua.h,v 1.192 2004/06/04 15:30:53 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -14,7 +14,10 @@ #include -#define LUA_VERSION "Lua 5.1 (work)" +#include "luaconf.h" + + +#define LUA_VERSION "Lua 5.1 (work1)" #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -34,12 +37,11 @@ #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) -/* error codes for `lua_load' and `lua_pcall' */ +/* error codes for `lua_pcall' */ #define LUA_ERRRUN 1 -#define LUA_ERRFILE 2 -#define LUA_ERRSYNTAX 3 -#define LUA_ERRMEM 4 -#define LUA_ERRERR 5 +#define LUA_ERRSYNTAX 2 +#define LUA_ERRMEM 3 +#define LUA_ERRERR 4 typedef struct lua_State lua_State; @@ -91,26 +93,13 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* type of numbers in Lua */ -#ifndef LUA_NUMBER -typedef double lua_Number; -#else typedef LUA_NUMBER lua_Number; -#endif /* type for integer functions */ -#ifndef LUA_INTEGER -typedef long lua_Integer; -#else typedef LUA_INTEGER lua_Integer; -#endif -/* mark for all API functions */ -#ifndef LUA_API -#define LUA_API extern -#endif - /* ** state manipulation @@ -155,7 +144,7 @@ LUA_API lua_Number lua_tonumber (lua_State *L, int idx); LUA_API lua_Integer lua_tointeger (lua_State *L, int idx); LUA_API int lua_toboolean (lua_State *L, int idx); LUA_API const char *lua_tostring (lua_State *L, int idx); -LUA_API size_t lua_strlen (lua_State *L, int idx); +LUA_API size_t lua_objsize (lua_State *L, int idx); LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx); LUA_API void *lua_touserdata (lua_State *L, int idx); LUA_API lua_State *lua_tothread (lua_State *L, int idx); @@ -228,6 +217,7 @@ LUA_API int lua_resume (lua_State *L, int narg); #define LUA_GCRESTART 1 #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 +#define LUA_GCSTEP 4 LUA_API int lua_gc (lua_State *L, int what, int data); @@ -254,11 +244,6 @@ LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud); ** =============================================================== */ -#define lua_boxpointer(L,u) \ - (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u)) - -#define lua_unboxpointer(L,i) (*(void **)(lua_touserdata(L, i))) - #define lua_pop(L,n) lua_settop(L, -(n)-1) #define lua_newtable(L) lua_createtable(L, 0, 0) @@ -267,6 +252,8 @@ LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud); #define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) +#define lua_strlen(L,i) lua_objsize(L,i) + #define lua_isfunction(L,n) (lua_type(L,n) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L,n) == LUA_TTABLE) #define lua_islightuserdata(L,n) (lua_type(L,n) == LUA_TLIGHTUSERDATA) @@ -295,39 +282,9 @@ LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud); #define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) -/* compatibility with ref system */ - -/* pre-defined references */ -#define LUA_NOREF (-2) -#define LUA_REFNIL (-1) - -#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ - (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) - -#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) - -#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, ref) -/* -** {====================================================================== -** useful definitions for Lua kernel and libraries -** ======================================================================= -*/ - -/* formats for Lua numbers */ -#ifndef LUA_NUMBER_SCAN -#define LUA_NUMBER_SCAN "%lf" -#endif - -#ifndef LUA_NUMBER_FMT -#define LUA_NUMBER_FMT "%.14g" -#endif - -/* }====================================================================== */ - - /* ** {====================================================================== ** Debug API diff --git a/include/luaconf.h b/include/luaconf.h new file mode 100644 index 0000000000..56567c008a --- /dev/null +++ b/include/luaconf.h @@ -0,0 +1,312 @@ +/* +** $Id: luaconf.h,v 1.11 2004/08/30 18:35:14 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef lconfig_h +#define lconfig_h + +#include +#include + + +/* +** {====================================================== +** Index (search for keyword to find corresponding entry) +** ======================================================= +*/ + + +/* }====================================================== */ + + + + +/* +** {====================================================== +** Generic configuration +** ======================================================= +*/ + +/* default path */ +#define LUA_PATH_DEFAULT "?;?.lua" + + +/* type of numbers in Lua */ +#define LUA_NUMBER double + +/* formats for Lua numbers */ +#define LUA_NUMBER_SCAN "%lf" +#define LUA_NUMBER_FMT "%.14g" + + +/* type for integer functions */ +#define LUA_INTEGER long + + +/* mark for all API functions */ +#define LUA_API extern + +/* mark for auxlib functions */ +#define LUALIB_API extern + +/* buffer size used by lauxlib buffer system */ +#define LUAL_BUFFERSIZE BUFSIZ + + +/* first index for arrays */ +#define LUA_FIRSTINDEX 1 + +/* assertions in Lua (mainly for internal debugging) */ +#define lua_assert(c) /* empty */ + +/* }====================================================== */ + + + +/* +** {====================================================== +** Stand-alone configuration +** ======================================================= +*/ + +#ifdef lua_c + +/* definition of `isatty' */ +#ifdef _POSIX_C_SOURCE +#include +#define stdin_is_tty() isatty(0) +#else +#define stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + + +#define PROMPT "> " +#define PROMPT2 ">> " +#define PROGNAME "lua" + + +/* +** this macro allows you to open other libraries when starting the +** stand-alone interpreter +*/ +#define lua_userinit(L) luaopen_stdlibs(L) +/* +** #define lua_userinit(L) { int luaopen_mylibs(lua_State *L); \ +** luaopen_stdlibs(L); luaopen_mylibs(L); } +*/ + + + +/* +** this macro can be used by some `history' system to save lines +** read in manual input +*/ +#define lua_saveline(L,line) /* empty */ + + + +#endif + +/* }====================================================== */ + + + +/* +** {====================================================== +** Core configuration +** ======================================================= +*/ + +#ifdef LUA_CORE + +/* LUA-C API assertions */ +#define api_check(L, o) /* empty */ + + +/* an unsigned integer with at least 32 bits */ +#define LUA_UINT32 unsigned long + +/* a signed integer with at least 32 bits */ +#define LUA_INT32 long +#define LUA_MAXINT32 LONG_MAX + + +/* maximum depth for calls (unsigned short) */ +#define LUA_MAXCALLS 4096 + +/* +** maximum depth for C calls (unsigned short): Not too big, or may +** overflow the C stack... +*/ +#define LUA_MAXCCALLS 200 + + +/* maximum size for the virtual stack of a C function */ +#define MAXCSTACK 2048 + + +/* +** maximum number of syntactical nested non-terminals: Not too big, +** or may overflow the C stack... +*/ +#define LUA_MAXPARSERLEVEL 200 + + +/* maximum number of variables declared in a function */ +#define MAXVARS 200 /* +#define lua_number2int(i,d) ((i)=lrint(d)) +#else +#define lua_number2int(i,d) ((i)=(int)(d)) +#endif + +/* function to convert a lua_Number to lua_Integer (with any rounding method) */ +#define lua_number2integer(i,n) lua_number2int(i,n) + + +/* function to convert a lua_Number to a string */ +#include +#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) + +/* function to convert a string to a lua_Number */ +#define lua_str2number(s,p) strtod((s), (p)) + + + +/* result of a `usual argument conversion' over lua_Number */ +#define LUA_UACNUMBER double + + +/* number of bits in an `int' */ +/* avoid overflows in comparison */ +#if INT_MAX-20 < 32760 +#define LUA_BITSINT 16 +#elif INT_MAX > 2147483640L +/* machine has at least 32 bits */ +#define LUA_BITSINT 32 +#else +#error "you must define LUA_BITSINT with number of bits in an integer" +#endif + + +/* type to ensure maximum alignment */ +#define LUSER_ALIGNMENT_T union { double u; void *s; long l; } + + +/* exception handling */ +#ifndef __cplusplus +/* default handling with long jumps */ +#include +#define L_THROW(c) longjmp((c)->b, 1) +#define L_TRY(c,a) if (setjmp((c)->b) == 0) { a } +#define l_jmpbuf jmp_buf + +#else +/* C++ exceptions */ +#define L_THROW(c) throw(c) +#define L_TRY(c,a) try { a } catch(...) \ + { if ((c)->status == 0) (c)->status = -1; } +#define l_jmpbuf int /* dummy variable */ +#endif + + + +/* +** macros for thread synchronization inside Lua core machine: +** all accesses to the global state and to global objects are synchronized. +** Because threads can read the stack of other threads +** (when running garbage collection), +** a thread must also synchronize any write-access to its own stack. +** Unsynchronized accesses are allowed only when reading its own stack, +** or when reading immutable fields from global objects +** (such as string values and udata values). +*/ +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) + +/* +** this macro allows a thread switch in appropriate places in the Lua +** core +*/ +#define lua_threadyield(L) {lua_unlock(L); lua_lock(L);} + + + +/* allows user-specific initialization on new threads */ +#define lua_userstateopen(l) /* empty */ + + +#endif + +/* }====================================================== */ + + + +/* +** {====================================================== +** Library configuration +** ======================================================= +*/ + +#ifdef LUA_LIB + + + +/* `assert' options */ + +/* environment variable that holds the search path for packages */ +#define LUA_PATH "LUA_PATH" + +/* separator of templates in a path */ +#define LUA_PATH_SEP ';' + +/* wild char in each template */ +#define LUA_PATH_MARK "?" + + +/* maximum number of captures in pattern-matching */ +#define MAX_CAPTURES 32 /* arbitrary limit */ + + +/* +** by default, gcc does not get `tmpname' +*/ +#ifdef __GNUC__ +#define USE_TMPNAME 0 +#else +#define USE_TMPNAME 1 +#endif + + + +#endif + +/* }====================================================== */ + + + + +/* Local configuration */ + +#undef USE_TMPNAME +#define USE_TMPNAME 1 + +#endif diff --git a/include/lualib.h b/include/lualib.h index e22c4c3063..c8114ed259 100644 --- a/include/lualib.h +++ b/include/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.28 2003/03/18 12:24:26 roberto Exp $ +** $Id: lualib.h,v 1.32 2004/07/09 15:47:48 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -11,9 +11,8 @@ #include "lua.h" -#ifndef LUALIB_API -#define LUALIB_API LUA_API -#endif +/* Key to file-handle type */ +#define LUA_FILEHANDLE "FILE*" #define LUA_COLIBNAME "coroutine" @@ -23,9 +22,11 @@ LUALIB_API int luaopen_base (lua_State *L); LUALIB_API int luaopen_table (lua_State *L); #define LUA_IOLIBNAME "io" -#define LUA_OSLIBNAME "os" LUALIB_API int luaopen_io (lua_State *L); +#define LUA_OSLIBNAME "os" +LUALIB_API int luaopen_os (lua_State *L); + #define LUA_STRLIBNAME "string" LUALIB_API int luaopen_string (lua_State *L); @@ -39,18 +40,8 @@ LUALIB_API int luaopen_debug (lua_State *L); LUALIB_API int luaopen_loadlib (lua_State *L); -/* to help testing the libraries */ -#ifndef lua_assert -#define lua_assert(c) /* empty */ -#endif - +/* open all previous libraries */ +LUALIB_API int luaopen_stdlibs (lua_State *L); -/* compatibility code */ -#define lua_baselibopen luaopen_base -#define lua_tablibopen luaopen_table -#define lua_iolibopen luaopen_io -#define lua_strlibopen luaopen_string -#define lua_mathlibopen luaopen_math -#define lua_dblibopen luaopen_debug #endif diff --git a/src/RCS b/src/RCS deleted file mode 120000 index 1ae3893605..0000000000 --- a/src/RCS +++ /dev/null @@ -1 +0,0 @@ -../RCS \ No newline at end of file diff --git a/src/README b/src/README index e5375981f6..915f30b411 100644 --- a/src/README +++ b/src/README @@ -1,5 +1,5 @@ This is the Lua core. The standard Lua library are in lib/. -A sample interpreter is in lua/. -A standalone compiler is in luac/. +The standalone interpreter is in lua/. +The standalone compiler is in luac/. diff --git a/src/lapi.c b/src/lapi.c index 1b086a0b8d..eb2c266ea8 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.5 2004/03/23 17:07:34 roberto Exp $ +** $Id: lapi.c,v 2.18 2004/08/30 13:44:44 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include #define lapi_c +#define LUA_CORE #include "lua.h" @@ -28,11 +29,6 @@ #include "lvm.h" -/* function to convert a lua_Number to lua_Integer (with any rounding method) */ -#ifndef lua_number2integer -#define lua_number2integer(i,n) ((i)=(lua_Integer)(n)) -#endif - const char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" @@ -41,10 +37,6 @@ const char lua_ident[] = -#ifndef api_check -#define api_check(L, o) lua_assert(o) -#endif - #define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) #define api_checkvalidindex(L, i) api_check(L, (i) != &luaO_nilobject) @@ -56,7 +48,7 @@ const char lua_ident[] = static TValue *luaA_index (lua_State *L, int idx) { if (idx > 0) { TValue *o = L->base + (idx - 1); - api_check(L, idx <= L->stack_last - L->base); + api_check(L, idx <= L->ci->top - L->base); if (o >= L->top) return cast(TValue *, &luaO_nilobject); else return o; } @@ -87,7 +79,7 @@ void luaA_pushobject (lua_State *L, const TValue *o) { LUA_API int lua_checkstack (lua_State *L, int size) { int res; lua_lock(L); - if ((L->top - L->base + size) > LUA_MAXCSTACK) + if ((L->top - L->base + size) > MAXCSTACK) res = 0; /* stack overflow */ else { luaD_checkstack(L, size); @@ -331,10 +323,12 @@ LUA_API const char *lua_tostring (lua_State *L, int idx) { } -LUA_API size_t lua_strlen (lua_State *L, int idx) { +LUA_API size_t lua_objsize (lua_State *L, int idx) { StkId o = luaA_index(L, idx); if (ttisstring(o)) return tsvalue(o)->len; + else if (ttisuserdata(o)) + return uvalue(o)->len; else { size_t l; lua_lock(L); /* `luaV_tostring' may create a new string */ @@ -496,7 +490,7 @@ LUA_API void lua_gettable (lua_State *L, int idx) { lua_lock(L); t = luaA_index(L, idx); api_checkvalidindex(L, t); - luaV_gettable(L, t, L->top - 1, L->top - 1); + luaV_gettable(L, t, L->top - 1, L->top - 1, NULL); lua_unlock(L); } @@ -508,7 +502,7 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { t = luaA_index(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_gettable(L, t, &key, L->top); + luaV_gettable(L, t, &key, L->top, NULL); api_incr_top(L); lua_unlock(L); } @@ -592,7 +586,7 @@ LUA_API void lua_settable (lua_State *L, int idx) { api_checknelems(L, 2); t = luaA_index(L, idx); api_checkvalidindex(L, t); - luaV_settable(L, t, L->top - 2, L->top - 1); + luaV_settable(L, t, L->top - 2, L->top - 1, NULL); L->top -= 2; /* pop index and value */ lua_unlock(L); } @@ -606,7 +600,7 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { t = luaA_index(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_settable(L, t, &key, L->top - 1); + luaV_settable(L, t, &key, L->top - 1, NULL); L->top--; /* pop value */ lua_unlock(L); } @@ -619,7 +613,7 @@ LUA_API void lua_rawset (lua_State *L, int idx) { t = luaA_index(L, idx); api_check(L, ttistable(t)); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); - luaC_barrier(L, hvalue(t), L->top-1); + luaC_barriert(L, hvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } @@ -632,7 +626,7 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { o = luaA_index(L, idx); api_check(L, ttistable(o)); setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); - luaC_barrier(L, hvalue(o), L->top-1); + luaC_barriert(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } @@ -683,12 +677,13 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { api_checknelems(L, 1); o = luaA_index(L, idx); api_checkvalidindex(L, o); - L->top--; - api_check(L, ttistable(L->top)); + api_check(L, ttistable(L->top - 1)); if (isLfunction(o)) { res = 1; - clvalue(o)->l.g = *(L->top); + clvalue(o)->l.g = *(L->top - 1); + luaC_objbarrier(L, clvalue(o), hvalue(L->top - 1)); } + L->top--; lua_unlock(L); return res; } @@ -698,12 +693,23 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { ** `load' and `call' functions (run Lua code) */ + +#define adjustresults(L,nres) \ + { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } + + +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) + + LUA_API void lua_call (lua_State *L, int nargs, int nresults) { StkId func; lua_lock(L); api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); func = L->top - (nargs+1); luaD_call(L, func, nresults); + adjustresults(L, nresults); lua_unlock(L); } @@ -730,6 +736,8 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { int status; ptrdiff_t func; lua_lock(L); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); if (errfunc == 0) func = 0; else { @@ -740,6 +748,7 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + adjustresults(L, nresults); lua_unlock(L); return status; } @@ -812,28 +821,41 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { */ LUA_API int lua_gc (lua_State *L, int what, int data) { - global_State *g = G(L); + int res = 0; + global_State *g; + lua_lock(L); + g = G(L); switch (what) { case LUA_GCSTOP: { g->GCthreshold = MAXLMEM; - return 0; + break; } case LUA_GCRESTART: { - g->GCthreshold = g->nblocks; - return 0; + g->GCthreshold = g->totalbytes; + break; } case LUA_GCCOLLECT: { - lua_lock(L); luaC_fullgc(L); - lua_unlock(L); - return 0; + break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ - return cast(int, g->nblocks >> 10); + res = cast(int, g->totalbytes >> 10); + break; + } + case LUA_GCSTEP: { + lu_mem a = (cast(lu_mem, data) << 10); + if (a <= g->totalbytes) + g->GCthreshold = g->totalbytes - a; + else + g->GCthreshold = 0; + luaC_step(L); + break; } - default: return -1; /* invalid option */ + default: res = -1; /* invalid option */ } + lua_unlock(L); + return res; } @@ -916,13 +938,13 @@ static const char *aux_upvalue (lua_State *L, StkId fi, int n, TValue **val) { if (!ttisfunction(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { - if (n > f->c.nupvalues) return NULL; + if (!(1 <= n && n <= f->c.nupvalues)) return NULL; *val = &f->c.upvalue[n-1]; return ""; } else { Proto *p = f->l.p; - if (n > p->sizeupvalues) return NULL; + if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; return getstr(p->upvalues[n-1]); } diff --git a/src/lcode.c b/src/lcode.c index de6939bb48..54ef058112 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: lcode.c,v 2.6 2004/08/24 20:09:11 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define lcode_c +#define LUA_CORE #include "lua.h" @@ -194,7 +195,7 @@ void luaK_reserveregs (FuncState *fs, int n) { static void freereg (FuncState *fs, int reg) { - if (reg >= fs->nactvar && reg < MAXSTACK) { + if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; lua_assert(reg == fs->freereg); } @@ -222,7 +223,7 @@ static int addk (FuncState *fs, TValue *k, TValue *v) { MAXARG_Bx, "constant table overflow"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[fs->nk], v); - luaC_barrier(L, f, v); + luaC_barriert(L, f, v); return fs->nk++; } } @@ -251,13 +252,26 @@ static int nil_constant (FuncState *fs) { } -void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) { +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ SETARG_C(getcode(fs, e), nresults+1); - if (nresults == 1) { /* `regular' expression? */ - e->k = VNONRELOC; - e->info = GETARG_A(getcode(fs, e)); - } + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), nresults+1); + SETARG_A(getcode(fs, e), fs->freereg); + luaK_reserveregs(fs, 1); + } +} + + +void luaK_setoneret (FuncState *fs, expdesc *e) { + if (e->k == VCALL) { /* expression is an open function call? */ + e->k = VNONRELOC; + e->info = GETARG_A(getcode(fs, e)); + } + else if (e->k == VVARARG) { + SETARG_B(getcode(fs, e), 2); + e->k = VRELOCABLE; /* can relocate its simple result */ } } @@ -285,8 +299,9 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { e->k = VRELOCABLE; break; } + case VVARARG: case VCALL: { - luaK_setcallreturns(fs, e, 1); + luaK_setoneret(fs, e); break; } default: break; /* there is one value available (somewhere) */ @@ -403,16 +418,16 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { case VNIL: { - if (fs->nk + MAXSTACK <= MAXARG_C) { /* constant fit in argC? */ + if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ e->info = nil_constant(fs); e->k = VK; - return e->info + MAXSTACK; + return RKASK(e->info); } else break; } case VK: { - if (e->info + MAXSTACK <= MAXARG_C) /* constant fit in argC? */ - return e->info + MAXSTACK; + if (e->info <= MAXINDEXRK) /* constant fit in argC? */ + return RKASK(e->info); else break; } default: break; diff --git a/src/lcode.h b/src/lcode.h index 74908c6580..b854d5cdf2 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.38 2002/12/11 12:34:22 roberto Exp $ +** $Id: lcode.h,v 1.39 2004/05/31 18:51:50 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -41,6 +41,8 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) +#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) + int luaK_code (FuncState *fs, Instruction i, int line); int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); @@ -60,7 +62,8 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); void luaK_goiftrue (FuncState *fs, expdesc *e); void luaK_goiffalse (FuncState *fs, expdesc *e); void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); -void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults); +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +void luaK_setoneret (FuncState *fs, expdesc *e); int luaK_jump (FuncState *fs); void luaK_patchlist (FuncState *fs, int list, int target); void luaK_patchtohere (FuncState *fs, int list); diff --git a/src/ldebug.c b/src/ldebug.c index 42080ccde6..139e4cdb62 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.3 2004/03/23 13:10:16 roberto Exp $ +** $Id: ldebug.c,v 2.8 2004/09/01 13:47:31 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -11,6 +11,7 @@ #define ldebug_c +#define LUA_CORE #include "lua.h" @@ -34,7 +35,7 @@ static const char *getfuncname (CallInfo *ci, const char **name); static int currentpc (CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ - return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); + return pcRel(ci->savedpc, ci_func(ci)->l.p); } @@ -85,7 +86,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { level--; if (f_isLua(ci)) /* Lua function? */ - level -= ci->u.l.tailcalls; /* skip lost tail calls */ + level -= ci->tailcalls; /* skip lost tail calls */ } if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ else if (level < 0) { /* level is of a lost tail call */ @@ -220,8 +221,8 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { } else if (ar->i_ci != 0) { /* no tail call? */ CallInfo *ci = L->base_ci + ar->i_ci; - lua_assert(ttisfunction(ci->base - 1)); - status = auxgetinfo(L, what, ar, ci->base - 1, ci); + lua_assert(ttisfunction(ci->func)); + status = auxgetinfo(L, what, ar, ci->func, ci); } else info_tailcall(L, ar); @@ -254,8 +255,9 @@ static int precheck (const Proto *pt) { } -static int checkopenop (const Proto *pt, int pc) { - Instruction i = pt->code[pc+1]; +#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) + +int luaG_checkopenop (Instruction i) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: @@ -274,8 +276,8 @@ static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { case OpArgN: check(r == 0); break; case OpArgU: break; case OpArgR: checkreg(pt, r); break; - case OpArgK: - check(r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); + case OpArgK: + check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); break; } return 1; @@ -355,7 +357,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { } case OP_TFORLOOP: { checkreg(pt, a+5); /* space for control variables */ - if (reg >= a) last = pc; /* affect all registers above base */ + if (reg >= a+3) last = pc; /* affect all regs above its call base */ break; } case OP_TFORPREP: @@ -404,6 +406,13 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { } break; } + case OP_VARARG: { + check(pt->is_vararg & NEWSTYLEVARARG); + b--; + if (b == LUA_MULTRET) check(checkopenop(pt, pc)); + checkreg(pt, a+b-1); + break; + } default: break; } } @@ -423,9 +432,8 @@ int luaG_checkcode (const Proto *pt) { static const char *kname (Proto *p, int c) { - c = c - MAXSTACK; - if (c >= 0 && ttisstring(&p->k[c])) - return svalue(&p->k[c]); + if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + return svalue(&p->k[INDEXK(c)]); else return "?"; } @@ -479,11 +487,12 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { static const char *getfuncname (CallInfo *ci, const char **name) { Instruction i; - if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci - 1)) + if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) return NULL; /* calling function is not Lua (or is unknown) */ ci--; /* calling function */ i = ci_func(ci)->l.p->code[currentpc(ci)]; - if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL) + if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || + GET_OPCODE(i) == OP_TFORLOOP) return getobjname(ci, GETARG_A(i), name); else return NULL; /* no useful name can be found */ diff --git a/src/ldebug.h b/src/ldebug.h index d7163f2da4..5d8d2c2ee4 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: ldebug.h,v 2.2 2004/06/02 19:07:55 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -25,6 +25,6 @@ int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); void luaG_runerror (lua_State *L, const char *fmt, ...); void luaG_errormsg (lua_State *L); int luaG_checkcode (const Proto *pt); - +int luaG_checkopenop (Instruction i); #endif diff --git a/src/ldo.c b/src/ldo.c index b65c5610e0..46ad459a32 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,15 +1,15 @@ /* -** $Id: ldo.c,v 2.2 2004/03/23 17:02:58 roberto Exp $ +** $Id: ldo.c,v 2.7 2004/06/02 19:07:55 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ -#include #include #include #define ldo_c +#define LUA_CORE #include "lua.h" @@ -34,29 +34,15 @@ /* ** {====================================================== -** Error-recovery functions (based on long jumps) +** Error-recovery functions ** ======================================================= */ -#ifndef LUA_USEEXCEPTIONS - -#define L_THROW(c) longjmp((c)->b, 1) -#define L_TRY(c,a) if (setjmp((c)->b) == 0) { a } - -#else - -#define L_THROW(c) throw(c) -#define L_TRY(c,a) try { a } catch(...) \ - { if ((c)->status == 0) (c)->status = -1; } - -#endif - - /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; - jmp_buf b; + l_jmpbuf b; volatile int status; /* error code */ }; @@ -127,6 +113,7 @@ static void correctstack (lua_State *L, TValue *oldstack) { for (ci = L->base_ci; ci <= L->ci; ci++) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; } L->base = L->ci->base; } @@ -195,26 +182,37 @@ void luaD_callhook (lua_State *L, int event, int line) { } -static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { +static StkId adjust_varargs (lua_State *L, int nfixargs, int actual, + int style) { int i; - Table *htab; - int actual = L->top - base; /* actual number of arguments */ + Table *htab = NULL; + StkId base, fixed; if (actual < nfixargs) { - luaD_checkstack(L, nfixargs - actual); for (; actual < nfixargs; ++actual) setnilvalue(L->top++); } - actual -= nfixargs; /* number of extra arguments */ - htab = luaH_new(L, actual, 1); /* create `arg' table */ - for (i=0; itop - actual + i); - /* store counter in field `n' */ - setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), - cast(lua_Number, actual)); - L->top -= actual; /* remove extra elements from the stack */ - sethvalue(L, L->top, htab); - lua_assert(iswhite(obj2gco(htab))); - incr_top(L); + if (style != NEWSTYLEVARARG) { /* compatibility with old-style vararg */ + int nvar = actual - nfixargs; /* number of extra arguments */ + htab = luaH_new(L, nvar, 1); /* create `arg' table */ + for (i=0; itop - nvar + i); + /* store counter in field `n' */ + setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), + cast(lua_Number, nvar)); + } + /* move fixed parameters to final position */ + fixed = L->top - actual; /* first fixed argument */ + base = L->top; /* final position of first argument */ + for (i=0; itop++, fixed+i); + setnilvalue(fixed+i); + } + /* add `arg' parameter */ + if (htab) { + sethvalue(L, L->top++, htab); + lua_assert(iswhite(obj2gco(htab))); + } + return base; } @@ -233,44 +231,60 @@ static StkId tryfuncTM (lua_State *L, StkId func) { } -StkId luaD_precall (lua_State *L, StkId func) { +int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; - ptrdiff_t funcr = savestack(L, func); + ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ + funcr = savestack(L, func); if (L->ci + 1 == L->end_ci) luaD_growCI(L); else condhardstacktests(luaD_reallocCI(L, L->size_ci)); cl = &clvalue(func)->l; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; - StkId st; + StkId st, base; Proto *p = cl->p; - if (p->is_vararg) /* varargs? */ - adjust_varargs(L, p->numparams, func+1); luaD_checkstack(L, p->maxstacksize); + func = restorestack(L, funcr); + if (p->is_vararg) { /* varargs? */ + int nargs = L->top - func - 1; + base = adjust_varargs(L, p->numparams, nargs, p->is_vararg); + } + else + base = func + 1; ci = ++L->ci; /* now `enter' new function */ - L->base = L->ci->base = restorestack(L, funcr) + 1; + ci->func = func; + L->base = ci->base = base; ci->top = L->base + p->maxstacksize; - ci->u.l.savedpc = p->code; /* starting point */ - ci->u.l.tailcalls = 0; + ci->savedpc = p->code; /* starting point */ + ci->tailcalls = 0; + ci->nresults = nresults; for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; - return NULL; + return PCRLUA; } else { /* if is a C function, call it */ CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ ci = ++L->ci; /* now `enter' new function */ - L->base = L->ci->base = restorestack(L, funcr) + 1; + ci->func = restorestack(L, funcr); + L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); - return L->top - n; + if (n >= 0) { /* no yielding? */ + luaD_poscall(L, nresults, L->top - n); + return PCRC; + } + else { + ci->nresults = nresults; + return PCRYIELD; + } } } @@ -279,7 +293,7 @@ static StkId callrethooks (lua_State *L, StkId firstResult) { ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ luaD_callhook(L, LUA_HOOKRET, -1); if (f_isLua(L->ci)) { /* Lua function? */ - while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ + while (L->ci->tailcalls--) /* call hook for eventual tail calls */ luaD_callhook(L, LUA_HOOKTAILRET, -1); } return restorestack(L, fr); @@ -290,7 +304,7 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { StkId res; if (L->hookmask & LUA_MASKRET) firstResult = callrethooks(L, firstResult); - res = L->base - 1; /* res == final position of 1st result */ + res = L->ci->func; /* res == final position of 1st result */ L->ci--; L->base = L->ci->base; /* restore base */ /* move results to correct place */ @@ -311,17 +325,16 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults) { - StkId firstResult; if (++L->nCcalls >= LUA_MAXCCALLS) { if (L->nCcalls == LUA_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - firstResult = luaD_precall(L, func); - if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L, 1); /* call it */ - luaD_poscall(L, nResults, firstResult); + if (luaD_precall(L, func, nResults) == PCRLUA) { /* is a Lua function? */ + StkId firstResult = luaV_execute(L, 1); /* call it */ + luaD_poscall(L, nResults, firstResult); + } L->nCcalls--; luaC_checkGC(L); } @@ -333,15 +346,14 @@ static void resume (lua_State *L, void *ud) { CallInfo *ci = L->ci; if (!L->isSuspended) { lua_assert(ci == L->base_ci && nargs < L->top - L->base); - luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ + luaD_precall(L, L->top - (nargs + 1), LUA_MULTRET); /* start coroutine */ } else { /* resuming from previous yield */ if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ - int nresults; - lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); - nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; + int nresults = ci->nresults; + lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || + GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); luaD_poscall(L, nresults, L->top - nargs); /* complete it */ if (nresults >= 0) L->top = L->ci->top; } /* else yielded inside a hook: just continue its execution */ diff --git a/src/ldo.h b/src/ldo.h index 85511f2cbb..d4072b6005 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: ldo.h,v 2.2 2004/05/14 19:25:09 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -38,13 +38,19 @@ #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) +/* results from luaD_precall */ +#define PCRLUA 0 /* initiated a call to a Lua function */ +#define PCRC 1 /* did a call to a C function */ +#define PCRYIELD 2 /* C funtion yielded */ + + /* type of protected functions, to be ran by `runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); void luaD_resetprotection (lua_State *L); int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); void luaD_callhook (lua_State *L, int event, int line); -StkId luaD_precall (lua_State *L, StkId func); +int luaD_precall (lua_State *L, StkId func, int nresults); void luaD_call (lua_State *L, StkId func, int nResults); int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); diff --git a/src/ldump.c b/src/ldump.c index dc4ebad150..bd0becb91e 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,12 +1,13 @@ /* -** $Id: ldump.c,v 1.6 2004/03/24 00:25:08 lhf Exp $ -** save bytecodes +** $Id: ldump.c,v 1.8 2004/09/01 21:22:34 lhf Exp $ +** save pre-compiled Lua chunks ** See Copyright Notice in lua.h */ #include #define ldump_c +#define LUA_CORE #include "lua.h" @@ -20,16 +21,20 @@ typedef struct { lua_State* L; - lua_Chunkwriter write; + lua_Chunkwriter writer; void* data; int strip; + int status; } DumpState; static void DumpBlock(const void* b, size_t size, DumpState* D) { - lua_unlock(D->L); - (*D->write)(D->L,b,size,D->data); - lua_lock(D->L); + if (D->status==0) + { + lua_unlock(D->L); + D->status=(*D->writer)(D->L,b,size,D->data); + lua_lock(D->L); + } } static void DumpByte(int y, DumpState* D) @@ -53,7 +58,7 @@ static void DumpNumber(lua_Number x, DumpState* D) DumpBlock(&x,sizeof(x),D); } -static void DumpString(TString* s, DumpState* D) +static void DumpString(const TString* s, DumpState* D) { if (s==NULL || getstr(s)==NULL) DumpSize(0,D); @@ -153,16 +158,17 @@ static void DumpHeader(DumpState* D) } /* -** dump function as precompiled chunk +** dump Lua function as precompiled chunk */ -int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip) +int luaU_dump (lua_State* L, const Proto* f, lua_Chunkwriter w, void* data, int strip) { DumpState D; D.L=L; - D.write=w; + D.writer=w; D.data=data; D.strip=strip; + D.status=0; DumpHeader(&D); - DumpFunction(Main,NULL,&D); - return 1; + DumpFunction(f,NULL,&D); + return D.status; } diff --git a/src/lfunc.c b/src/lfunc.c index d9f4e27ece..7d4fbf2015 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.3 2004/03/15 21:04:33 roberto Exp $ +** $Id: lfunc.c,v 2.4 2004/04/30 20:13:38 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define lfunc_c +#define LUA_CORE #include "lua.h" diff --git a/src/lgc.c b/src/lgc.c index db1b1c8994..67a5f1f607 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.6 2004/03/23 12:57:12 roberto Exp $ +** $Id: lgc.c,v 2.10 2004/08/30 13:44:44 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -7,6 +7,7 @@ #include #define lgc_c +#define LUA_CORE #include "lua.h" @@ -22,10 +23,11 @@ #include "ltm.h" -#define GCSTEPSIZE (40*sizeof(TValue)) -#define GCFREECOST (sizeof(TValue)/2) -#define GCSWEEPCOST sizeof(TValue) -#define GCFINALIZECOST (10*sizeof(TValue)) +#define GCSTEPSIZE 1000 +#define STEPMUL 2 +#define GCSWEEPMAX 10 +#define GCSWEEPCOST 30 +#define GCFINALIZECOST 100 #define FIXEDMASK bitmask(FIXEDBIT) @@ -266,60 +268,61 @@ static void traversestack (global_State *g, lua_State *l) { /* -** traverse a given `quantity' of gray objects, -** turning them to black. Returns extra `quantity' traversed. +** traverse one gray object, turning it to black. +** Returns `quantity' traversed. */ -static l_mem propagatemarks (global_State *g, l_mem lim) { - GCObject *o; - while ((o = g->gray) != NULL) { - lua_assert(isgray(o)); - gray2black(o); - switch (o->gch.tt) { - case LUA_TTABLE: { - Table *h = gco2h(o); - g->gray = h->gclist; - if (traversetable(g, h)) /* table is weak? */ - black2gray(o); /* keep it gray */ - lim -= sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * sizenode(h); - break; - } - case LUA_TFUNCTION: { - Closure *cl = gco2cl(o); - g->gray = cl->c.gclist; - traverseclosure(g, cl); - lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : - sizeLclosure(cl->l.nupvalues); - break; - } - case LUA_TTHREAD: { - lua_State *th = gco2th(o); - g->gray = th->gclist; - th->gclist = g->grayagain; - g->grayagain = o; - black2gray(o); - traversestack(g, th); - lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize + - sizeof(CallInfo) * th->size_ci; - break; - } - case LUA_TPROTO: { - Proto *p = gco2p(o); - g->gray = p->gclist; - traverseproto(g, p); - lim -= sizeof(Proto) + sizeof(Instruction) * p->sizecode + - sizeof(Proto *) * p->sizep + - sizeof(TValue) * p->sizek + - sizeof(int) * p->sizelineinfo + - sizeof(LocVar) * p->sizelocvars + - sizeof(TString *) * p->sizeupvalues; - break; - } - default: lua_assert(0); +static l_mem propagatemark (global_State *g) { + GCObject *o = g->gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o->gch.tt) { + case LUA_TTABLE: { + Table *h = gco2h(o); + g->gray = h->gclist; + if (traversetable(g, h)) /* table is weak? */ + black2gray(o); /* keep it gray */ + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); + break; + } + case LUA_TFUNCTION: { + Closure *cl = gco2cl(o); + g->gray = cl->c.gclist; + traverseclosure(g, cl); + return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : + sizeLclosure(cl->l.nupvalues); + break; + } + case LUA_TTHREAD: { + lua_State *th = gco2th(o); + g->gray = th->gclist; + th->gclist = g->grayagain; + g->grayagain = o; + black2gray(o); + traversestack(g, th); + return sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->size_ci; + break; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + g->gray = p->gclist; + traverseproto(g, p); + return sizeof(Proto) + sizeof(Instruction) * p->sizecode + + sizeof(Proto *) * p->sizep + + sizeof(TValue) * p->sizek + + sizeof(int) * p->sizelineinfo + + sizeof(LocVar) * p->sizelocvars + + sizeof(TString *) * p->sizeupvalues; + break; } - if (lim <= 0) return lim; + default: lua_assert(0); return 0; } - return lim; +} + + +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); } @@ -381,6 +384,7 @@ static void freeobj (lua_State *L, GCObject *o) { break; } case LUA_TSTRING: { + G(L)->strt.nuse--; luaM_free(L, o, sizestring(gco2ts(o)->len)); break; } @@ -393,59 +397,45 @@ static void freeobj (lua_State *L, GCObject *o) { } -static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, - lu_int32 *count); + +#define sweepwholelist(L,p) sweeplist(L,p,LUA_MAXINT32) -static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed, - l_mem *plim, lu_int32 *count) { +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) { GCObject *curr; global_State *g = G(L); - l_mem lim = *plim; - int deadmask = otherwhite(g); - if (keepfixed) deadmask |= FIXEDMASK; - while ((curr = *p) != NULL) { - if (((curr->gch.marked ^ FIXEDMASK) & deadmask) != deadmask) { - makewhite(g, curr); + int whitebit = otherwhite(g); + int deadmask = whitebit | FIXEDMASK; + int generational = g->gcgenerational; + while ((curr = *p) != NULL && count-- > 0) { + if ((curr->gch.marked ^ whitebit) & deadmask) { + lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); + if (!generational || isdead(g, curr)) + makewhite(g, curr); if (curr->gch.tt == LUA_TTHREAD) - lim -= sweepwholelist(L, &gco2th(curr)->openupval, keepfixed, count); + sweepwholelist(L, &gco2th(curr)->openupval); p = &curr->gch.next; - lim -= GCSWEEPCOST; } else { - lua_assert(iswhite(curr)); + lua_assert(isdead(g, curr)); *p = curr->gch.next; if (curr == g->rootgc) /* is the first element of the list? */ g->rootgc = curr->gch.next; /* adjust first */ freeobj(L, curr); - lim -= GCFREECOST; - if (count) (*count)--; } - if (lim <= 0) break; } - *plim = lim; return p; } -static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, - lu_int32 *count) { - l_mem lim = MAXLMEM; - /* empty lists are quite common here, so avoid useless calls */ - if (*p) sweeplist(L, p, keepfixed, &lim, count); - return MAXLMEM - lim; -} - -static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) { - int i; - global_State *g = G(L); - for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ - lim -= sweepwholelist(L, &G(L)->strt.hash[i], keepfixed, &g->strt.nuse); - if (lim <= 0) break; +static void freelist (lua_State *L, GCObject **p) { + while (*p) { + GCObject *curr = *p; + *p = (*p)->gch.next; + if (curr != obj2gco(L)) + freeobj(L, curr); } - g->sweepstrgc = i+1; - return lim; } @@ -494,19 +484,12 @@ void luaC_callGCTM (lua_State *L) { } -void luaC_sweepall (lua_State *L) { +void luaC_freeall (lua_State *L) { global_State *g = G(L); - l_mem dummy = MAXLMEM; - /* finish (occasional) current sweep */ - sweepstrings(L, 0, MAXLMEM); - sweeplist(L, &g->rootgc, 0, &dummy, NULL); - /* do a whole new sweep */ - markobject(g, g->mainthread); /* cannot collect main thread */ - g->currentwhite = otherwhite(g); - g->sweepgc = &g->rootgc; - g->sweepstrgc = 0; - sweepstrings(L, 0, MAXLMEM); - sweeplist(L, &g->rootgc, 0, &dummy, NULL); + int i; + freelist(L, &g->rootgc); + for (i = 0; i < g->strt.size; i++) /* free all string lists */ + freelist(L, &G(L)->strt.hash[i]); } @@ -530,8 +513,10 @@ static void remarkupvals (global_State *g) { if (iswhite(o)) { GCObject *curr; for (curr = gco2th(o)->openupval; curr != NULL; curr = curr->gch.next) { - if (isgray(curr)) - markvalue(g, gco2uv(curr)->v); + if (isgray(curr)) { + UpVal *uv = gco2uv(curr); + markvalue(g, uv->v); + } } } } @@ -540,6 +525,7 @@ static void remarkupvals (global_State *g) { static void atomic (lua_State *L) { global_State *g = G(L); + int aux; lua_assert(g->gray == NULL); /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); @@ -548,90 +534,130 @@ static void atomic (lua_State *L) { g->weak = NULL; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ - propagatemarks(g, MAXLMEM); + propagateall(g); /* remark gray again */ g->gray = g->grayagain; g->grayagain = NULL; - propagatemarks(g, MAXLMEM); + propagateall(g); luaC_separateudata(L, 0); /* separate userdata to be preserved */ marktmu(g); /* mark `preserved' userdata */ - propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ + propagateall(g); /* remark, to propagate `preserveness' */ cleartable(g->weak); /* remove collected objects from weak tables */ /* flip current white */ g->currentwhite = otherwhite(g); + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; g->gcstate = GCSsweepstring; + aux = g->gcgenerational; + g->gcgenerational = (g->estimate <= 4*g->prevestimate/2); + if (!aux) /* last collection was full? */ + g->prevestimate = g->estimate; /* keep estimate of last full collection */ + g->estimate = g->totalbytes; /* first estimate */ } -static l_mem singlestep (lua_State *L, l_mem lim) { +static l_mem singlestep (lua_State *L) { global_State *g = G(L); + /*lua_checkmemory(L);*/ switch (g->gcstate) { + case GCSpause: { + /* start a new collection */ + if (g->gcgenerational) + atomic(L); + else + markroot(L); + return 0; + } case GCSpropagate: { if (g->gray) - lim = propagatemarks(g, lim); + return propagatemark(g); else { /* no more `gray' objects */ atomic(L); /* finish mark phase */ - lim = 0; + return 0; } - break; } case GCSsweepstring: { - lim = sweepstrings(L, 1, lim); - if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ - g->sweepstrgc = 0; + lu_mem old = g->totalbytes; + sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); + if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ g->gcstate = GCSsweep; /* end sweep-string phase */ - } - break; + g->estimate -= old - g->totalbytes; + return GCSWEEPCOST; } case GCSsweep: { - g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim, NULL); + lu_mem old = g->totalbytes; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); if (*g->sweepgc == NULL) { /* nothing more to sweep? */ checkSizes(L); - g->sweepgc = &g->rootgc; g->gcstate = GCSfinalize; /* end sweep phase */ } - break; + g->estimate -= old - g->totalbytes; + return GCSWEEPMAX*GCSWEEPCOST; } case GCSfinalize: { if (g->tmudata) { GCTM(L); - lim -= GCFINALIZECOST; + return GCFINALIZECOST; } - else { /* no more `udata' to finalize */ - markroot(L); /* may restart collection */ - lim = 0; + else { + g->gcstate = GCSpause; /* end collection */ + return 0; } - break; } - default: lua_assert(0); + default: lua_assert(0); return 0; } - return lim; } void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; + l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL; +/*printf("step(%c): ", g->gcgenerational?'g':' ');*/ do { - lim = singlestep(L, lim); - if (g->gcstate == GCSfinalize && g->tmudata == NULL) - break; /* do not start new collection */ + /*printf("%c", "_pswf"[g->gcstate]);*/ + lim -= singlestep(L); + if (g->gcstate == GCSpause) + break; } while (lim > 0); - g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; - lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/2); +/*printf("\n");*/ + if (g->gcstate != GCSpause) + g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/STEPMUL; */ + else { +/*printf("---\n");*/ + lua_assert(g->totalbytes >= g->estimate); + g->GCthreshold = 2*g->estimate; + if (g->GCthreshold < g->totalbytes + GCSTEPSIZE) + g->GCthreshold = g->totalbytes + GCSTEPSIZE; + } } void luaC_fullgc (lua_State *L) { global_State *g = G(L); + if (g->gcstate <= GCSpropagate || g->gcgenerational) { + g->gcgenerational = 0; + /* reset sweep marks to sweep all elements (returning them to white) */ + g->sweepstrgc = 0; + g->sweepgc = &g->rootgc; + /* reset other collector lists */ + g->gray = NULL; + g->grayagain = NULL; + g->weak = NULL; + g->gcstate = GCSsweepstring; + } + /* finish any pending sweep phase */ while (g->gcstate != GCSfinalize) { - singlestep(L, MAXLMEM); + lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); + singlestep(L); } markroot(L); + lua_assert(!g->gcgenerational); while (g->gcstate != GCSfinalize) { - singlestep(L, MAXLMEM); + singlestep(L); + g->gcgenerational = 0; /* keep it in this mode */ } - g->GCthreshold = g->nblocks + GCSTEPSIZE; + lua_assert(g->estimate == g->totalbytes); + g->GCthreshold = 2*g->estimate; luaC_callGCTM(L); /* call finalizers */ } @@ -639,7 +665,7 @@ void luaC_fullgc (lua_State *L) { void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize); + lua_assert(g->gcgenerational || g->gcstate != GCSfinalize); if (g->gcstate != GCSpropagate) /* sweeping phases? */ black2gray(o); /* just mark as gray to avoid other barriers */ else /* breaking invariant! */ @@ -647,6 +673,16 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { } +void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcgenerational || g->gcstate != GCSfinalize); + black2gray(o); /* make table gray (again) */ + gco2h(o)->gclist = g->grayagain; + g->grayagain = o; +} + + void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { global_State *g = G(L); o->gch.next = g->rootgc; @@ -662,13 +698,13 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ g->rootgc = o; if (isgray(o)) { - if (g->gcstate == GCSpropagate) { + if (g->gcstate == GCSpropagate || g->gcgenerational) { gray2black(o); /* closed upvalues need barrier */ luaC_barrier(L, uv, uv->v); } else { /* sweep phase: sweep it (turning it into white) */ makewhite(g, o); - lua_assert(g->gcstate != GCSfinalize); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); } } } diff --git a/src/lgc.h b/src/lgc.h index 1ff59860f7..47a5e932a2 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.5 2004/03/15 21:04:33 roberto Exp $ +** $Id: lgc.h,v 2.8 2004/08/30 13:44:44 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -14,10 +14,11 @@ /* ** Possible states of the Garbage Collector */ -#define GCSpropagate 0 -#define GCSsweepstring 1 -#define GCSsweep 2 -#define GCSfinalize 3 +#define GCSpause 0 +#define GCSpropagate 1 +#define GCSsweepstring 2 +#define GCSsweep 3 +#define GCSfinalize 4 /* @@ -39,12 +40,13 @@ /* ** Layout for bit use in `marked' field: -** bit 0 - object is gray -** bit 1 - object is black -** bit 2 - For userdata: is finalized; - for tables: has weak keys -** bit 3 - for tables: has weak values -** bit 4 - object is fixed (should not be collected) +** bit 0 - object is white (type 0) +** bit 1 - object is white (type 1) +** bit 2 - object is black +** bit 3 - for userdata: has been finalized +** bit 3 - for tables: has weak keys +** bit 4 - for tables: has weak values +** bit 5 - object is fixed (should not be collected) */ #define WHITE0BIT 0 @@ -70,25 +72,29 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite) -#define luaC_checkGC(L) { if (G(L)->nblocks >= G(L)->GCthreshold) \ +#define luaC_checkGC(L) { if (G(L)->totalbytes >= G(L)->GCthreshold) \ luaC_step(L); } #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),gcvalue(v)); } +#define luaC_barriert(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierback(L,obj2gco(p),gcvalue(v)); } + #define luaC_objbarrier(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),obj2gco(o)); } size_t luaC_separateudata (lua_State *L, int all); void luaC_callGCTM (lua_State *L); -void luaC_sweepall (lua_State *L); +void luaC_freeall (lua_State *L); void luaC_step (lua_State *L); void luaC_fullgc (lua_State *L); void luaC_link (lua_State *L, GCObject *o, lu_byte tt); void luaC_linkupval (lua_State *L, UpVal *uv); void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); +void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v); #endif diff --git a/src/lib/Makefile b/src/lib/Makefile index 3c6c07ab2f..74f652157c 100644 --- a/src/lib/Makefile +++ b/src/lib/Makefile @@ -6,8 +6,8 @@ include $(LUA)/config EXTRA_DEFS= $(POPEN) $(TMPNAM) $(DEGREES) $(LOADLIB) -OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o ltablib.o lstrlib.o loadlib.o -SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c ltablib.c lstrlib.c loadlib.c +OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o lstrlib.o loadlib.o linit.o +SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c lstrlib.c loadlib.c linit.c T= $(LIB)/liblualib.a diff --git a/src/lib/RCS b/src/lib/RCS deleted file mode 120000 index 1ae3893605..0000000000 --- a/src/lib/RCS +++ /dev/null @@ -1 +0,0 @@ -../RCS \ No newline at end of file diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c index 9613101948..cd4e75f820 100644 --- a/src/lib/lauxlib.c +++ b/src/lib/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.110 2004/03/23 16:38:43 roberto Exp $ +** $Id: lauxlib.c,v 1.123 2004/08/30 18:35:14 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -18,6 +18,7 @@ */ #define lauxlib_c +#define LUA_LIB #include "lua.h" @@ -62,7 +63,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", - tname, lua_typename(L, lua_type(L,narg))); + tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); } @@ -242,6 +243,8 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, if (lua_isnil(L, -1)) { /* no? */ lua_pop(L, 1); lua_newtable(L); /* create it */ + if (lua_getmetatable(L, LUA_GLOBALSINDEX)) + lua_setmetatable(L, -2); /* share metatable with global table */ lua_pushvalue(L, -1); /* register it with given name */ lua_setglobal(L, libname); @@ -288,7 +291,7 @@ static void getsizes (lua_State *L) { } -void luaL_setn (lua_State *L, int t, int n) { +LUALIB_API void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); getsizes(L); lua_pushvalue(L, t); @@ -298,7 +301,32 @@ void luaL_setn (lua_State *L, int t, int n) { } -int luaL_getn (lua_State *L, int t) { +/* find an `n' such that t[n] ~= nil and t[n+1] == nil */ +static int countn (lua_State *L, int t) { + int i = LUA_FIRSTINDEX - 1; + int j = 2; + /* find `i' such that i <= n < i*2 (= j) */ + for (;;) { + lua_rawgeti(L, t, j); + if (lua_isnil(L, -1)) break; + lua_pop(L, 1); + i = j; + j = i*2; + } + lua_pop(L, 1); + /* i <= n < j; do a binary search */ + while (i < j-1) { + int m = (i+j)/2; + lua_rawgeti(L, t, m); + if (lua_isnil(L, -1)) j = m; + else i = m; + lua_pop(L, 1); + } + return i - LUA_FIRSTINDEX + 1; +} + + +LUALIB_API int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); getsizes(L); /* try sizes[t] */ @@ -307,18 +335,61 @@ int luaL_getn (lua_State *L, int t) { if ((n = checkint(L, 2)) >= 0) return n; lua_getfield(L, t, "n"); /* else try t.n */ if ((n = checkint(L, 1)) >= 0) return n; - for (n = 1; ; n++) { /* else must count elements */ - lua_rawgeti(L, t, n); - if (lua_isnil(L, -1)) break; - lua_pop(L, 1); - } - lua_pop(L, 1); - return n - 1; + return countn(L, t); } /* }====================================================== */ +static const char *pushnexttemplate (lua_State *L, const char *path) { + const char *l; + if (*path == '\0') return NULL; /* no more templates */ + if (*path == LUA_PATH_SEP) path++; /* skip separator */ + l = strchr(path, LUA_PATH_SEP); /* find next separator */ + if (l == NULL) l = path+strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} + + +static const char *luaL_gsub (lua_State *L, const char *s, + const char *p, const char *r) { + const char *wild; + int l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after `p' */ + } + luaL_addstring(&b, s); /* push last suffix (`n' already includes this) */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, + const char *path) { + FILE *f; + const char *p = path; + for (;;) { + const char *fname; + if ((p = pushnexttemplate(L, p)) == NULL) { + lua_pushfstring(L, "no readable `%s' in path `%s'", name, path); + return NULL; + } + fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + f = fopen(fname, "r"); /* try to read it */ + if (f) { + fclose(f); + return fname; + } + lua_pop(L, 1); /* remove file name */ + } +} + /* ** {====================================================== @@ -480,9 +551,10 @@ static const char *getF (lua_State *L, void *ud, size_t *size) { } -static int errfile (lua_State *L, int fnameindex) { +static int errfile (lua_State *L, const char *what, int fnameindex) { + const char *serr = strerror(errno); const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno)); + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); lua_remove(L, fnameindex); return LUA_ERRFILE; } @@ -501,7 +573,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ + if (lf.f == NULL) return errfile(L, "open", fnameindex); } c = getc(lf.f); if (c == '#') { /* Unix exec. file? */ @@ -512,7 +584,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { if (c == LUA_SIGNATURE[0] && lf.f != stdin) { /* binary file? */ fclose(lf.f); lf.f = fopen(filename, "rb"); /* reopen in binary mode */ - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); /* skip eventual `#!...' */ while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; lf.extraline = 0; @@ -523,7 +595,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { lua_settop(L, fnameindex); /* ignore results from `lua_load' */ - return errfile(L, fnameindex); + return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); return status; @@ -554,6 +626,7 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, return lua_load(L, getS, &ls, name); } + /* }====================================================== */ @@ -568,55 +641,15 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { } -LUALIB_API lua_State *luaL_newstate (void) { - return lua_newstate(l_alloc, NULL); -} - - -/* -** {====================================================== -** compatibility code -** ======================================================= -*/ - - -static void callalert (lua_State *L, int status) { - if (status != 0) { - lua_getglobal(L, "_ALERT"); - if (lua_isfunction(L, -1)) { - lua_insert(L, -2); - lua_call(L, 1, 0); - } - else { /* no _ALERT function; print it on stderr */ - fprintf(stderr, "%s\n", lua_tostring(L, -2)); - lua_pop(L, 2); /* remove error message and _ALERT */ - } - } +static int panic (lua_State *L) { + fprintf(stderr, "PANIC: unprotected error during Lua-API call\n"); + return 0; } -static int aux_do (lua_State *L, int status) { - if (status == 0) { /* parse OK? */ - status = lua_pcall(L, 0, LUA_MULTRET, 0); /* call main */ - } - callalert(L, status); - return status; -} - - -LUALIB_API int lua_dofile (lua_State *L, const char *filename) { - return aux_do(L, luaL_loadfile(L, filename)); -} - - -LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, - const char *name) { - return aux_do(L, luaL_loadbuffer(L, buff, size, name)); -} - - -LUALIB_API int lua_dostring (lua_State *L, const char *str) { - return lua_dobuffer(L, str, strlen(str), str); +LUALIB_API lua_State *luaL_newstate (void) { + lua_State *L = lua_newstate(l_alloc, NULL); + lua_atpanic(L, &panic); + return L; } -/* }====================================================== */ diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index 42b0355a4e..f734f35838 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.140 2004/03/09 17:34:35 roberto Exp $ +** $Id: lbaselib.c,v 1.156 2004/08/30 18:35:14 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include #define lbaselib_c +#define LUA_LIB #include "lua.h" @@ -128,18 +129,9 @@ static void getfunc (lua_State *L) { } -static int aux_getfenv (lua_State *L) { - lua_getfenv(L, -1); - lua_pushliteral(L, "__fenv"); - lua_rawget(L, -2); - return !lua_isnil(L, -1); -} - - static int luaB_getfenv (lua_State *L) { getfunc(L); - if (!aux_getfenv(L)) /* __fenv not defined? */ - lua_pop(L, 1); /* remove it, to return real environment */ + lua_getfenv(L, -1); return 1; } @@ -147,16 +139,14 @@ static int luaB_getfenv (lua_State *L) { static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); getfunc(L); - if (aux_getfenv(L)) /* __fenv defined? */ - luaL_error(L, "`setfenv' cannot change a protected environment"); - else - lua_pop(L, 2); /* remove __fenv and real environment table */ lua_pushvalue(L, 2); - if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) + if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { lua_replace(L, LUA_GLOBALSINDEX); + return 0; + } else if (lua_setfenv(L, -2) == 0) luaL_error(L, "`setfenv' cannot change environment of given function"); - return 0; + return 1; } @@ -192,22 +182,11 @@ static int luaB_gcinfo (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", - NULL}; + "step", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, - LUA_GCCOLLECT, LUA_GCCOUNT}; - int o; - int ex; -#if 1 - if (lua_isnumber(L, 1)) { - int v = lua_tointeger(L, 1); - lua_settop(L, 0); - if (v == 0) lua_pushstring(L, "collect"); - else if (v >= 10000) lua_pushstring(L, "stop"); - else lua_pushstring(L, "restart"); - } -#endif - o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); - ex = luaL_optint(L, 2, 0); + LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP}; + int o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); + int ex = luaL_optint(L, 2, 0); luaL_argcheck(L, o >= 0, 1, "invalid option"); lua_pushinteger(L, lua_gc(L, optsnum[o], ex)); return 1; @@ -216,7 +195,7 @@ static int luaB_collectgarbage (lua_State *L) { static int luaB_type (lua_State *L) { luaL_checkany(L, 1); - lua_pushstring(L, lua_typename(L, lua_type(L, 1))); + lua_pushstring(L, luaL_typename(L, 1)); return 1; } @@ -235,28 +214,29 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - lua_getglobal(L, "next"); /* return generator, */ + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushnil(L); /* and initial value */ return 3; } +static int ipairsaux (lua_State *L) { + int i = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + i++; /* next value */ + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); + return (lua_isnil(L, -1)) ? 0 : 2; +} + + static int luaB_ipairs (lua_State *L) { - int i = (int)lua_tointeger(L, 2); luaL_checktype(L, 1, LUA_TTABLE); - if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */ - lua_getglobal(L, "ipairs"); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushinteger(L, 0); /* and initial value */ - return 3; - } - else { /* `for' step */ - i++; /* next value */ - lua_pushinteger(L, i); - lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 0 : 2; - } + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushinteger(L, LUA_FIRSTINDEX - 1); /* and initial value */ + return 3; } @@ -281,7 +261,15 @@ static int luaB_loadstring (lua_State *L) { static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); - return load_aux(L, luaL_loadfile(L, fname)); + const char *path = luaL_optstring(L, 2, NULL); + int status; + if (path == NULL) + status = luaL_loadfile(L, fname); + else { + fname = luaL_searchpath(L, fname, path); + status = (fname) ? luaL_loadfile(L, fname) : 1; + } + return load_aux(L, status); } @@ -339,22 +327,41 @@ static int luaB_assert (lua_State *L) { luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); - lua_settop(L, 1); - return 1; + return lua_gettop(L); } static int luaB_unpack (lua_State *L) { - int n, i; + int i = luaL_optint(L, 2, LUA_FIRSTINDEX); + int e = luaL_optint(L, 3, -1); + int n; luaL_checktype(L, 1, LUA_TTABLE); - n = luaL_getn(L, 1); + if (e == -1) + e = luaL_getn(L, 1) + LUA_FIRSTINDEX - 1; + n = e - i + 1; /* number of elements */ + if (n <= 0) return 0; /* empty range */ luaL_checkstack(L, n, "table too big to unpack"); - for (i=1; i<=n; i++) /* push arg[1...n] */ + for (; i<=e; i++) /* push arg[i...e] */ lua_rawgeti(L, 1, i); return n; } +static int luaB_select (lua_State *L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + int i = luaL_checkint(L, 1); + if (i <= 0) i = 1; + else if (i >= n) i = n; + return n - i; + } +} + + static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); @@ -378,45 +385,36 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { - char buff[4*sizeof(void *) + 2]; /* enough space for a `%p' */ - const char *tn = ""; - const void *p = NULL; luaL_checkany(L, 1); if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ return 1; /* use its value */ switch (lua_type(L, 1)) { case LUA_TNUMBER: lua_pushstring(L, lua_tostring(L, 1)); - return 1; + break; case LUA_TSTRING: lua_pushvalue(L, 1); - return 1; + break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); - return 1; + break; case LUA_TNIL: lua_pushliteral(L, "nil"); - return 1; + break; case LUA_TTABLE: - p = lua_topointer(L, 1); - tn = "table"; + lua_pushfstring(L, "table: %p", lua_topointer(L, 1)); break; case LUA_TFUNCTION: - p = lua_topointer(L, 1); - tn = "function"; + lua_pushfstring(L, "function: %p", lua_topointer(L, 1)); break; case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: - p = lua_touserdata(L, 1); - tn = "userdata"; + lua_pushfstring(L, "userdata: %p", lua_topointer(L, 1)); break; case LUA_TTHREAD: - p = lua_tothread(L, 1); - tn = "thread"; + lua_pushfstring(L, "thread: %p", lua_topointer(L, 1)); break; } - sprintf(buff, "%p", p); - lua_pushfstring(L, "%s: %s", tn, buff); return 1; } @@ -454,112 +452,38 @@ static int luaB_newproxy (lua_State *L) { */ -/* name of global that holds table with loaded packages */ -#define REQTAB "_LOADED" - -/* name of global that holds the search path for packages */ -#define LUA_PATH "LUA_PATH" - -#ifndef LUA_PATH_SEP -#define LUA_PATH_SEP ';' -#endif - -#ifndef LUA_PATH_MARK -#define LUA_PATH_MARK '?' -#endif - -#ifndef LUA_PATH_DEFAULT -#define LUA_PATH_DEFAULT "?;?.lua" -#endif - - static const char *getpath (lua_State *L) { - const char *path; - lua_getglobal(L, LUA_PATH); /* try global variable */ - path = lua_tostring(L, -1); - lua_pop(L, 1); - if (path) return path; - path = getenv(LUA_PATH); /* else try environment variable */ - if (path) return path; - return LUA_PATH_DEFAULT; /* else use default */ -} - - -static const char *pushnextpath (lua_State *L, const char *path) { - const char *l; - if (*path == '\0') return NULL; /* no more paths */ - if (*path == LUA_PATH_SEP) path++; /* skip separator */ - l = strchr(path, LUA_PATH_SEP); /* find next separator */ - if (l == NULL) l = path+strlen(path); - lua_pushlstring(L, path, l - path); /* directory name */ - return l; -} - - -static void pushcomposename (lua_State *L) { - const char *path = lua_tostring(L, -1); - const char *wild; - int n = 1; - while ((wild = strchr(path, LUA_PATH_MARK)) != NULL) { - /* is there stack space for prefix, name, and eventual last suffix? */ - luaL_checkstack(L, 3, "too many marks in a path component"); - lua_pushlstring(L, path, wild - path); /* push prefix */ - lua_pushvalue(L, 1); /* push package name (in place of MARK) */ - path = wild + 1; /* continue after MARK */ - n += 2; + /* try first `LUA_PATH' for compatibility */ + lua_getfield(L, LUA_GLOBALSINDEX, "LUA_PATH"); + if (!lua_isstring(L, -1)) { + lua_pop(L, 1); + lua_getfield(L, LUA_GLOBALSINDEX, "_PATH"); } - lua_pushstring(L, path); /* push last suffix (`n' already includes this) */ - lua_concat(L, n); + if (!lua_isstring(L, -1)) + luaL_error(L, "global _PATH must be a string"); + return lua_tostring(L, -1); } static int luaB_require (lua_State *L) { - const char *path; - int status = LUA_ERRFILE; /* not found (yet) */ - luaL_checkstring(L, 1); - lua_settop(L, 1); - lua_getglobal(L, REQTAB); - if (!lua_istable(L, 2)) return luaL_error(L, "`" REQTAB "' is not a table"); - path = getpath(L); - lua_pushvalue(L, 1); /* check package's name in book-keeping table */ - lua_rawget(L, 2); + const char *name = luaL_checkstring(L, 1); + const char *fname; + lua_getfield(L, lua_upvalueindex(1), name); if (lua_toboolean(L, -1)) /* is it there? */ return 1; /* package is already loaded; return its result */ - else { /* must load it */ - while (status == LUA_ERRFILE) { - lua_settop(L, 3); /* reset stack position */ - if ((path = pushnextpath(L, path)) == NULL) break; - pushcomposename(L); - status = luaL_loadfile(L, lua_tostring(L, -1)); /* try to load it */ - } - } - switch (status) { - case 0: { - lua_getglobal(L, "_REQUIREDNAME"); /* save previous name */ - lua_insert(L, -2); /* put it below function */ - lua_pushvalue(L, 1); - lua_setglobal(L, "_REQUIREDNAME"); /* set new name */ - lua_call(L, 0, 1); /* run loaded module */ - lua_insert(L, -2); /* put result below previous name */ - lua_setglobal(L, "_REQUIREDNAME"); /* reset to previous name */ - if (lua_isnil(L, -1)) { /* no/nil return? */ - lua_pushboolean(L, 1); - lua_replace(L, -2); /* replace to true */ - } - lua_pushvalue(L, 1); - lua_pushvalue(L, -2); - lua_rawset(L, 2); /* mark it as loaded */ - return 1; /* return value */ - } - case LUA_ERRFILE: { /* file not found */ - return luaL_error(L, "could not load package `%s' from path `%s'", - lua_tostring(L, 1), getpath(L)); - } - default: { - return luaL_error(L, "error loading package `%s' (%s)", - lua_tostring(L, 1), lua_tostring(L, -1)); - } - } + /* else must load it; first mark it as loaded */ + lua_pushboolean(L, 1); + lua_setfield(L, lua_upvalueindex(1), name); /* _LOADED[name] = true */ + fname = luaL_searchpath(L, name, getpath(L)); + if (fname == NULL || luaL_loadfile(L, fname) != 0) + return luaL_error(L, "error loading package `%s' (%s)", name, + lua_tostring(L, -1)); + lua_pushvalue(L, 1); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* nil return? */ + lua_setfield(L, lua_upvalueindex(1), name); + lua_getfield(L, lua_upvalueindex(1), name); /* return _LOADED[name] */ + return 1; } /* }====================================================== */ @@ -572,14 +496,13 @@ static const luaL_reg base_funcs[] = { {"getfenv", luaB_getfenv}, {"setfenv", luaB_setfenv}, {"next", luaB_next}, - {"ipairs", luaB_ipairs}, - {"pairs", luaB_pairs}, {"print", luaB_print}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, {"assert", luaB_assert}, {"unpack", luaB_unpack}, + {"select", luaB_select}, {"rawequal", luaB_rawequal}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, @@ -591,7 +514,6 @@ static const luaL_reg base_funcs[] = { {"dofile", luaB_dofile}, {"loadstring", luaB_loadstring}, {"load", luaB_load}, - {"require", luaB_require}, {NULL, NULL} }; @@ -704,12 +626,23 @@ static const luaL_reg co_funcs[] = { /* }====================================================== */ +static void auxopen (lua_State *L, const char *name, + lua_CFunction f, lua_CFunction u) { + lua_pushcfunction(L, u); + lua_pushcclosure(L, f, 1); + lua_setfield(L, -2, name); +} + static void base_open (lua_State *L) { + const char *path; lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ + lua_setfield(L, LUA_GLOBALSINDEX, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + auxopen(L, "ipairs", luaB_ipairs, ipairsaux); + auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ lua_newtable(L); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ @@ -717,16 +650,27 @@ static void base_open (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ - lua_setfield(L, -1, "_G"); /* set global _G */ + lua_setfield(L, LUA_GLOBALSINDEX, "newproxy"); /* set global `newproxy' */ + /* `require' needs a table to keep loaded chunks */ + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "_LOADED"); + lua_pushcclosure(L, luaB_require, 1); + lua_setfield(L, LUA_GLOBALSINDEX, "require"); + /* set global _G */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, LUA_GLOBALSINDEX, "_G"); + /* set global _PATH */ + path = getenv(LUA_PATH); + if (path == NULL) path = LUA_PATH_DEFAULT; + lua_pushstring(L, path); + lua_setfield(L, LUA_GLOBALSINDEX, "_PATH"); } LUALIB_API int luaopen_base (lua_State *L) { base_open(L); luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); - lua_newtable(L); - lua_setglobal(L, REQTAB); return 2; } diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c index dd4e0363df..4ec5f3933d 100644 --- a/src/lib/ldblib.c +++ b/src/lib/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.84 2003/11/05 11:59:14 roberto Exp $ +** $Id: ldblib.c,v 1.87 2004/08/13 18:02:36 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include #define ldblib_c +#define LUA_LIB #include "lua.h" @@ -260,7 +261,11 @@ static int debug (lua_State *L) { if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; - lua_dostring(L, buffer); + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=debug command") || + lua_pcall(L, 0, 0, 0)) { + fputs(lua_tostring(L, -1), stderr); + fputs("\n", stderr); + } lua_settop(L, 0); /* remove eventual returns */ } } @@ -298,22 +303,16 @@ static int errorfb (lua_State *L) { lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); - switch (*ar.namewhat) { - case 'g': /* global */ - case 'l': /* local */ - case 'f': /* field */ - case 'm': /* method */ + if (*ar.namewhat != '\0') /* is there a name? */ lua_pushfstring(L, " in function `%s'", ar.name); - break; - default: { - if (*ar.what == 'm') /* main? */ - lua_pushfstring(L, " in main chunk"); - else if (*ar.what == 'C' || *ar.what == 't') - lua_pushliteral(L, " ?"); /* C function or tail call */ - else - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } + else { + if (*ar.what == 'm') /* main? */ + lua_pushfstring(L, " in main chunk"); + else if (*ar.what == 'C' || *ar.what == 't') + lua_pushliteral(L, " ?"); /* C function or tail call */ + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); } lua_concat(L, lua_gettop(L) - arg); } diff --git a/src/lib/linit.c b/src/lib/linit.c new file mode 100644 index 0000000000..0d5f9cd48a --- /dev/null +++ b/src/lib/linit.c @@ -0,0 +1,38 @@ +/* +** $Id: linit.c,v 1.8 2004/07/09 15:47:48 roberto Exp $ +** Initialization of libraries for lua.c +** See Copyright Notice in lua.h +*/ + + +#define linit_c +#define LUA_LIB + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" + + +static const luaL_reg lualibs[] = { + {"", luaopen_base}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {"", luaopen_loadlib}, + {NULL, NULL} +}; + + +LUALIB_API int luaopen_stdlibs (lua_State *L) { + const luaL_reg *lib = lualibs; + for (; lib->func; lib++) { + lib->func(L); /* open library */ + lua_settop(L, 0); /* discard any results */ + } + return 0; +} + diff --git a/src/lib/liolib.c b/src/lib/liolib.c index 1815c96b6d..ca9b80258b 100644 --- a/src/lib/liolib.c +++ b/src/lib/liolib.c @@ -1,18 +1,17 @@ /* -** $Id: liolib.c,v 2.49 2003/10/10 13:29:28 roberto Exp $ +** $Id: liolib.c,v 2.57 2004/08/13 19:52:13 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ #include -#include #include #include #include -#include #define liolib_c +#define LUA_LIB #include "lua.h" @@ -21,50 +20,13 @@ -/* -** by default, gcc does not get `tmpname' -*/ -#ifndef USE_TMPNAME -#ifdef __GNUC__ -#define USE_TMPNAME 0 -#else -#define USE_TMPNAME 1 -#endif -#endif - - -/* -** by default, posix systems get `popen' -*/ -#ifndef USE_POPEN -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 2 -#define USE_POPEN 1 -#else -#define USE_POPEN 0 -#endif -#endif - - - - -/* -** {====================================================== -** FILE Operations -** ======================================================= -*/ - - -#if !USE_POPEN -#define pclose(f) (-1) -#endif - - -#define FILEHANDLE "FILE*" - #define IO_INPUT 1 #define IO_OUTPUT 2 +static const char *const fnames[] = {"input", "output"}; + + static int pushresult (lua_State *L, int i, const char *filename) { if (i) { lua_pushboolean(L, 1); @@ -82,15 +44,21 @@ static int pushresult (lua_State *L, int i, const char *filename) { } -static FILE **topfile (lua_State *L, int findex) { - FILE **f = (FILE **)luaL_checkudata(L, findex, FILEHANDLE); - if (f == NULL) luaL_argerror(L, findex, "bad file"); +static void fileerror (lua_State *L, int arg, const char *filename) { + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + luaL_argerror(L, arg, lua_tostring(L, -1)); +} + + +static FILE **topfile (lua_State *L) { + FILE **f = (FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE); + if (f == NULL) luaL_argerror(L, 1, "bad file"); return f; } static int io_type (lua_State *L) { - FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE); + FILE **f = (FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE); if (f == NULL) lua_pushnil(L); else if (*f == NULL) lua_pushliteral(L, "closed file"); @@ -100,8 +68,8 @@ static int io_type (lua_State *L) { } -static FILE *tofile (lua_State *L, int findex) { - FILE **f = topfile(L, findex); +static FILE *tofile (lua_State *L) { + FILE **f = topfile(L); if (*f == NULL) luaL_error(L, "attempt to use a closed file"); return *f; @@ -117,18 +85,18 @@ static FILE *tofile (lua_State *L, int findex) { static FILE **newfile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ - luaL_getmetatable(L, FILEHANDLE); + luaL_getmetatable(L, LUA_FILEHANDLE); lua_setmetatable(L, -2); return pf; } static int aux_close (lua_State *L) { - FILE *f = tofile(L, 1); + FILE *f = tofile(L); if (f == stdin || f == stdout || f == stderr) return 0; /* file cannot be closed */ else { - int ok = (pclose(f) != -1) || (fclose(f) == 0); + int ok = (fclose(f) == 0); if (ok) *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ return ok; @@ -144,7 +112,7 @@ static int io_close (lua_State *L) { static int io_gc (lua_State *L) { - FILE **f = topfile(L, 1); + FILE **f = topfile(L); if (*f != NULL) /* ignore closed files */ aux_close(L); return 0; @@ -152,13 +120,11 @@ static int io_gc (lua_State *L) { static int io_tostring (lua_State *L) { - char buff[4*sizeof(void *) + 2]; /* enough space for a `%p' */ - FILE **f = topfile(L, 1); - if (*f == NULL) - strcpy(buff, "closed"); + FILE *f = *topfile(L); + if (f == NULL) + lua_pushstring(L, "file (closed)"); else - sprintf(buff, "%p", lua_touserdata(L, 1)); - lua_pushfstring(L, "file (%s)", buff); + lua_pushfstring(L, "file (%p)", f); return 1; } @@ -172,20 +138,6 @@ static int io_open (lua_State *L) { } -static int io_popen (lua_State *L) { -#if !USE_POPEN - luaL_error(L, "`popen' not supported"); - return 0; -#else - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - FILE **pf = newfile(L); - *pf = popen(filename, mode); - return (*pf == NULL) ? pushresult(L, 0, filename) : 1; -#endif -} - - static int io_tmpfile (lua_State *L) { FILE **pf = newfile(L); *pf = tmpfile(); @@ -193,9 +145,14 @@ static int io_tmpfile (lua_State *L) { } -static FILE *getiofile (lua_State *L, int f) { - lua_rawgeti(L, lua_upvalueindex(1), f); - return tofile(L, -1); +static FILE *getiofile (lua_State *L, int findex) { + FILE *f; + lua_rawgeti(L, lua_upvalueindex(1), findex); + lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); + f = *(FILE **)lua_touserdata(L, -1); + if (f == NULL) + luaL_error(L, "standard %s file is closed", fnames[findex - 1]); + return f; } @@ -205,15 +162,14 @@ static int g_iofile (lua_State *L, int f, const char *mode) { if (filename) { FILE **pf = newfile(L); *pf = fopen(filename, mode); - if (*pf == NULL) { - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); - luaL_argerror(L, 1, lua_tostring(L, -1)); - } + if (*pf == NULL) + fileerror(L, 1, filename); } else { - tofile(L, 1); /* check that it's a valid file handle */ + tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } + lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); lua_rawseti(L, lua_upvalueindex(1), f); } /* return current value */ @@ -236,7 +192,7 @@ static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int idx, int close) { - lua_getfield(L, LUA_REGISTRYINDEX, FILEHANDLE); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); lua_pushvalue(L, idx); lua_pushboolean(L, close); /* close/not close file when finished */ lua_pushcclosure(L, io_readline, 3); @@ -244,7 +200,7 @@ static void aux_lines (lua_State *L, int idx, int close) { static int f_lines (lua_State *L) { - tofile(L, 1); /* check that it's a valid file handle */ + tofile(L); /* check that it's a valid file handle */ aux_lines(L, 1, 0); return 1; } @@ -260,7 +216,8 @@ static int io_lines (lua_State *L) { const char *filename = luaL_checkstring(L, 1); FILE **pf = newfile(L); *pf = fopen(filename, "r"); - luaL_argcheck(L, *pf, 1, strerror(errno)); + if (*pf == NULL) + fileerror(L, 1, filename); aux_lines(L, lua_gettop(L), 1); return 1; } @@ -336,6 +293,7 @@ static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; + clearerr(f); if (nargs == 0) { /* no arguments? */ success = read_line(L, f); n = first+1; /* to return 1 result */ @@ -370,6 +328,8 @@ static int g_read (lua_State *L, FILE *f, int first) { } } } + if (ferror(f)) + return pushresult(L, 0, NULL); if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ @@ -384,15 +344,19 @@ static int io_read (lua_State *L) { static int f_read (lua_State *L) { - return g_read(L, tofile(L, 1), 2); + return g_read(L, tofile(L), 2); } static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2)); + int sucess; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); - if (read_line(L, f)) return 1; + sucess = read_line(L, f); + if (ferror(f)) + luaL_error(L, "%s", strerror(errno)); + if (sucess) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ lua_settop(L, 0); @@ -431,14 +395,14 @@ static int io_write (lua_State *L) { static int f_write (lua_State *L) { - return g_write(L, tofile(L, 1), 2); + return g_write(L, tofile(L), 2); } static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; - FILE *f = tofile(L, 1); + FILE *f = tofile(L); int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); lua_Integer offset = luaL_optinteger(L, 3, 0); luaL_argcheck(L, op != -1, 2, "invalid mode"); @@ -455,7 +419,7 @@ static int f_seek (lua_State *L) { static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; - FILE *f = tofile(L, 1); + FILE *f = tofile(L); int op = luaL_findstring(luaL_checkstring(L, 2), modenames); luaL_argcheck(L, op != -1, 2, "invalid mode"); return pushresult(L, setvbuf(f, NULL, mode[op], 0) == 0, NULL); @@ -469,7 +433,7 @@ static int io_flush (lua_State *L) { static int f_flush (lua_State *L) { - return pushresult(L, fflush(tofile(L, 1)) == 0, NULL); + return pushresult(L, fflush(tofile(L)) == 0, NULL); } @@ -480,7 +444,6 @@ static const luaL_reg iolib[] = { {"close", io_close}, {"flush", io_flush}, {"open", io_open}, - {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, {"type", io_type}, @@ -504,239 +467,36 @@ static const luaL_reg flib[] = { static void createmeta (lua_State *L) { - luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ - /* create (and set) default files */ - *newfile(L) = stdin; - lua_rawseti(L, -2, IO_INPUT); - *newfile(L) = stdout; - lua_rawseti(L, -2, IO_OUTPUT); - /* file methods */ + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_openlib(L, NULL, flib, 0); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Other O.S. Operations -** ======================================================= -*/ - -static int io_execute (lua_State *L) { - lua_pushinteger(L, system(luaL_checkstring(L, 1))); - return 1; -} - - -static int io_remove (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - return pushresult(L, remove(filename) == 0, filename); -} - - -static int io_rename (lua_State *L) { - const char *fromname = luaL_checkstring(L, 1); - const char *toname = luaL_checkstring(L, 2); - return pushresult(L, rename(fromname, toname) == 0, fromname); -} - - -static int io_tmpname (lua_State *L) { -#if !USE_TMPNAME - luaL_error(L, "`tmpname' not supported"); - return 0; -#else - char buff[L_tmpnam]; - if (tmpnam(buff) != buff) - return luaL_error(L, "unable to generate a unique filename in `tmpname'"); - lua_pushstring(L, buff); - return 1; -#endif + luaL_openlib(L, NULL, flib, 0); /* file methods */ } -static int io_getenv (lua_State *L) { - lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ - return 1; -} - - -static int io_clock (lua_State *L) { - lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); - return 1; -} - - -/* -** {====================================================== -** Time/Date operations -** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, -** wday=%w+1, yday=%j, isdst=? } -** ======================================================= -*/ - -static void setfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); - lua_pushinteger(L, value); - lua_rawset(L, -3); -} - -static void setboolfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); - lua_pushboolean(L, value); - lua_rawset(L, -3); -} - -static int getboolfield (lua_State *L, const char *key) { - int res; - lua_getfield(L, -1, key); - res = lua_toboolean(L, -1); - lua_pop(L, 1); - return res; -} - - -static int getfield (lua_State *L, const char *key, int d) { - int res; - lua_getfield(L, -1, key); - if (lua_isnumber(L, -1)) - res = (int)lua_tointeger(L, -1); - else { - if (d < 0) - return luaL_error(L, "field `%s' missing in date table", key); - res = d; - } - lua_pop(L, 1); - return res; -} - - -static int io_date (lua_State *L) { - const char *s = luaL_optstring(L, 1, "%c"); - lua_Number n = luaL_optnumber(L, 2, -1); - time_t t = (n == -1) ? time(NULL) : (time_t)n; - struct tm *stm; - if (*s == '!') { /* UTC? */ - stm = gmtime(&t); - s++; /* skip `!' */ - } - else - stm = localtime(&t); - if (stm == NULL) /* invalid date? */ - lua_pushnil(L); - else if (strcmp(s, "*t") == 0) { - lua_createtable(L, 0, 9); /* 9 = number of fields */ - setfield(L, "sec", stm->tm_sec); - setfield(L, "min", stm->tm_min); - setfield(L, "hour", stm->tm_hour); - setfield(L, "day", stm->tm_mday); - setfield(L, "month", stm->tm_mon+1); - setfield(L, "year", stm->tm_year+1900); - setfield(L, "wday", stm->tm_wday+1); - setfield(L, "yday", stm->tm_yday+1); - setboolfield(L, "isdst", stm->tm_isdst); - } - else { - char b[256]; - if (strftime(b, sizeof(b), s, stm)) - lua_pushstring(L, b); - else - return luaL_error(L, "`date' format too long"); - } - return 1; -} - - -static int io_time (lua_State *L) { - if (lua_isnoneornil(L, 1)) /* called without args? */ - lua_pushnumber(L, time(NULL)); /* return current time */ - else { - time_t t; - struct tm ts; - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0); - ts.tm_min = getfield(L, "min", 0); - ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -1); - ts.tm_mon = getfield(L, "month", -1) - 1; - ts.tm_year = getfield(L, "year", -1) - 1900; - ts.tm_isdst = getboolfield(L, "isdst"); - t = mktime(&ts); - if (t == (time_t)(-1)) - lua_pushnil(L); - else - lua_pushnumber(L, t); - } - return 1; -} - - -static int io_difftime (lua_State *L) { - lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), - (time_t)(luaL_optnumber(L, 2, 0)))); - return 1; -} - -/* }====================================================== */ - - -static int io_setloc (lua_State *L) { - static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, - LC_NUMERIC, LC_TIME}; - static const char *const catnames[] = {"all", "collate", "ctype", "monetary", - "numeric", "time", NULL}; - const char *l = lua_tostring(L, 1); - int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames); - luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); - luaL_argcheck(L, op != -1, 2, "invalid option"); - lua_pushstring(L, setlocale(cat[op], l)); - return 1; -} - - -static int io_exit (lua_State *L) { - exit(luaL_optint(L, 1, EXIT_SUCCESS)); - return 0; /* to avoid warnings */ +static void createupval (lua_State *L) { + lua_newtable(L); + /* create (and set) default files */ + *newfile(L) = stdin; + lua_rawseti(L, -2, IO_INPUT); + *newfile(L) = stdout; + lua_rawseti(L, -2, IO_OUTPUT); } -static const luaL_reg syslib[] = { - {"clock", io_clock}, - {"date", io_date}, - {"difftime", io_difftime}, - {"execute", io_execute}, - {"exit", io_exit}, - {"getenv", io_getenv}, - {"remove", io_remove}, - {"rename", io_rename}, - {"setlocale", io_setloc}, - {"time", io_time}, - {"tmpname", io_tmpname}, - {NULL, NULL} -}; - -/* }====================================================== */ - LUALIB_API int luaopen_io (lua_State *L) { - luaL_openlib(L, LUA_OSLIBNAME, syslib, 0); createmeta(L); + createupval(L); lua_pushvalue(L, -1); luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* put predefined file handles into `io' table */ - lua_pushliteral(L, "stdin"); - lua_rawgeti(L, 2, IO_INPUT); - lua_rawset(L, 3); - lua_pushliteral(L, "stdout"); - lua_rawgeti(L, 2, IO_OUTPUT); - lua_rawset(L, 3); - lua_pushliteral(L, "stderr"); + lua_rawgeti(L, -2, IO_INPUT); /* get current input from metatable */ + lua_setfield(L, -2, "stdin"); /* io.stdin = metatable[IO_INPUT] */ + lua_rawgeti(L, -2, IO_OUTPUT); /* get current output from metatable */ + lua_setfield(L, -2, "stdout"); /* io.stdout = metatable[IO_OUTPUT] */ *newfile(L) = stderr; - lua_rawset(L, 3); + lua_setfield(L, -2, "stderr"); /* io.stderr = newfile(stderr) */ return 1; } diff --git a/src/lib/lmathlib.c b/src/lib/lmathlib.c index 6041b2e3c5..fcd2eefb98 100644 --- a/src/lib/lmathlib.c +++ b/src/lib/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.59 2003/11/05 11:59:14 roberto Exp $ +** $Id: lmathlib.c,v 1.61 2004/05/10 18:11:32 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -9,6 +9,7 @@ #include #define lmathlib_c +#define LUA_LIB #include "lua.h" @@ -22,56 +23,43 @@ -/* -** If you want Lua to operate in degrees (instead of radians), -** define USE_DEGREES -*/ -#ifdef USE_DEGREES -#define FROMRAD(a) ((a)/RADIANS_PER_DEGREE) -#define TORAD(a) ((a)*RADIANS_PER_DEGREE) -#else -#define FROMRAD(a) (a) -#define TORAD(a) (a) -#endif - - static int math_abs (lua_State *L) { lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { - lua_pushnumber(L, sin(TORAD(luaL_checknumber(L, 1)))); + lua_pushnumber(L, sin(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { - lua_pushnumber(L, cos(TORAD(luaL_checknumber(L, 1)))); + lua_pushnumber(L, cos(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { - lua_pushnumber(L, tan(TORAD(luaL_checknumber(L, 1)))); + lua_pushnumber(L, tan(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { - lua_pushnumber(L, FROMRAD(asin(luaL_checknumber(L, 1)))); + lua_pushnumber(L, asin(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { - lua_pushnumber(L, FROMRAD(acos(luaL_checknumber(L, 1)))); + lua_pushnumber(L, acos(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan(luaL_checknumber(L, 1)))); + lua_pushnumber(L, atan(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)))); + lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } diff --git a/src/lib/loadlib.c b/src/lib/loadlib.c index 2a6b39e170..8b98a2bf72 100644 --- a/src/lib/loadlib.c +++ b/src/lib/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.5 2003/05/14 21:01:53 roberto Exp $ +** $Id: loadlib.c,v 1.6 2004/04/30 20:13:38 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h * @@ -26,6 +26,9 @@ * */ +#define loadlib_c +#define LUA_LIB + #include "lua.h" #include "lauxlib.h" #include "lualib.h" diff --git a/src/lib/loslib.c b/src/lib/loslib.c new file mode 100644 index 0000000000..c5726cfe77 --- /dev/null +++ b/src/lib/loslib.c @@ -0,0 +1,241 @@ +/* +** $Id: loslib.c,v 1.2 2004/08/05 19:30:37 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include + +#define loslib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int pushresult (lua_State *L, int i, const char *filename) { + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (filename) + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + else + lua_pushfstring(L, "%s", strerror(errno)); + lua_pushinteger(L, errno); + return 3; + } +} + + +static int io_execute (lua_State *L) { + lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); + return 1; +} + + +static int io_remove (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + return pushresult(L, remove(filename) == 0, filename); +} + + +static int io_rename (lua_State *L) { + const char *fromname = luaL_checkstring(L, 1); + const char *toname = luaL_checkstring(L, 2); + return pushresult(L, rename(fromname, toname) == 0, fromname); +} + + +static int io_tmpname (lua_State *L) { +#if !USE_TMPNAME + luaL_error(L, "`tmpname' not supported"); + return 0; +#else + char buff[L_tmpnam]; + if (tmpnam(buff) != buff) + return luaL_error(L, "unable to generate a unique filename in `tmpname'"); + lua_pushstring(L, buff); + return 1; +#endif +} + + +static int io_getenv (lua_State *L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ + return 1; +} + + +static int io_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushstring(L, key); + lua_pushinteger(L, value); + lua_rawset(L, -3); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + lua_pushstring(L, key); + lua_pushboolean(L, value); + lua_rawset(L, -3); +} + +static int getboolfield (lua_State *L, const char *key) { + int res; + lua_getfield(L, -1, key); + res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d) { + int res; + lua_getfield(L, -1, key); + if (lua_isnumber(L, -1)) + res = (int)lua_tointeger(L, -1); + else { + if (d < 0) + return luaL_error(L, "field `%s' missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + +static int io_date (lua_State *L) { + const char *s = luaL_optstring(L, 1, "%c"); + lua_Number n = luaL_optnumber(L, 2, -1); + time_t t = (n == -1) ? time(NULL) : (time_t)n; + struct tm *stm; + if (*s == '!') { /* UTC? */ + stm = gmtime(&t); + s++; /* skip `!' */ + } + else + stm = localtime(&t); + if (stm == NULL) /* invalid date? */ + lua_pushnil(L); + else if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon+1); + setfield(L, "year", stm->tm_year+1900); + setfield(L, "wday", stm->tm_wday+1); + setfield(L, "yday", stm->tm_yday+1); + setboolfield(L, "isdst", stm->tm_isdst); + } + else { + char b[256]; + if (strftime(b, sizeof(b), s, stm)) + lua_pushstring(L, b); + else + return luaL_error(L, "`date' format too long"); + } + return 1; +} + + +static int io_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0); + ts.tm_min = getfield(L, "min", 0); + ts.tm_hour = getfield(L, "hour", 12); + ts.tm_mday = getfield(L, "day", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + } + if (t == (time_t)(-1)) + lua_pushnil(L); + else + lua_pushnumber(L, t); + return 1; +} + + +static int io_difftime (lua_State *L) { + lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), + (time_t)(luaL_optnumber(L, 2, 0)))); + return 1; +} + +/* }====================================================== */ + + +static int io_setloc (lua_State *L) { + static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static const char *const catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + const char *l = lua_tostring(L, 1); + int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames); + luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); + luaL_argcheck(L, op != -1, 2, "invalid option"); + lua_pushstring(L, setlocale(cat[op], l)); + return 1; +} + + +static int io_exit (lua_State *L) { + exit(luaL_optint(L, 1, EXIT_SUCCESS)); + return 0; /* to avoid warnings */ +} + +static const luaL_reg syslib[] = { + {"clock", io_clock}, + {"date", io_date}, + {"difftime", io_difftime}, + {"execute", io_execute}, + {"exit", io_exit}, + {"getenv", io_getenv}, + {"remove", io_remove}, + {"rename", io_rename}, + {"setlocale", io_setloc}, + {"time", io_time}, + {"tmpname", io_tmpname}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUALIB_API int luaopen_os (lua_State *L) { + luaL_openlib(L, LUA_OSLIBNAME, syslib, 0); + return 1; +} + diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index 36b226d25d..7fa205c074 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.101 2004/01/02 11:54:14 roberto Exp $ +** $Id: lstrlib.c,v 1.106 2004/08/09 13:30:33 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include #define lstrlib_c +#define LUA_LIB #include "lua.h" @@ -20,9 +21,7 @@ /* macro to `unsign' a character */ -#ifndef uchar #define uchar(c) ((unsigned char)(c)) -#endif typedef lua_Integer sint32; /* a signed version for size_t */ @@ -108,11 +107,17 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 pos = posrelat(luaL_optinteger(L, 2, 1), l); - if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */ - return 0; /* no answer */ - lua_pushinteger(L, uchar(s[pos-1])); - return 1; + sint32 posi = posrelat(luaL_optinteger(L, 2, 1), l); + sint32 pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi <= 0) posi = 1; + if ((size_t)pose > l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + n = pose - posi + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i #define ltablib_c +#define LUA_LIB #include "lua.h" @@ -22,7 +23,7 @@ static int luaB_foreachi (lua_State *L) { int i; int n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); - for (i=1; i<=n; i++) { + for (i=LUA_FIRSTINDEX; i < n+LUA_FIRSTINDEX; i++) { lua_pushvalue(L, 2); /* function */ lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ @@ -62,25 +63,26 @@ static int luaB_getn (lua_State *L) { static int luaB_setn (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_setn(L, 1, luaL_checkint(L, 2)); - return 0; + lua_pushvalue(L, 1); + return 1; } static int luaB_tinsert (lua_State *L) { int v = lua_gettop(L); /* number of arguments */ - int n = aux_getn(L, 1) + 1; + int e = aux_getn(L, 1) + LUA_FIRSTINDEX; /* first empty element */ int pos; /* where to insert new element */ if (v == 2) /* called with only 2 arguments */ - pos = n; /* insert new element at the end */ + pos = e; /* insert new element at the end */ else { pos = luaL_checkint(L, 2); /* 2nd argument is the position */ - if (pos > n) n = pos; /* `grow' array if necessary */ + if (pos > e) e = pos; /* `grow' array if necessary */ v = 3; /* function may be called with more than 3 args */ } - luaL_setn(L, 1, n); /* new size */ - while (--n >= pos) { /* move up elements */ - lua_rawgeti(L, 1, n); - lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ + luaL_setn(L, 1, e - LUA_FIRSTINDEX + 1); /* new size */ + while (--e >= pos) { /* move up elements */ + lua_rawgeti(L, 1, e); + lua_rawseti(L, 1, e+1); /* t[e+1] = t[e] */ } lua_pushvalue(L, v); lua_rawseti(L, 1, pos); /* t[pos] = v */ @@ -89,17 +91,17 @@ static int luaB_tinsert (lua_State *L) { static int luaB_tremove (lua_State *L) { - int n = aux_getn(L, 1); - int pos = luaL_optint(L, 2, n); - if (n <= 0) return 0; /* table is `empty' */ - luaL_setn(L, 1, n-1); /* t.n = n-1 */ + int e = aux_getn(L, 1) + LUA_FIRSTINDEX - 1; + int pos = luaL_optint(L, 2, e); + if (e < LUA_FIRSTINDEX) return 0; /* table is `empty' */ + luaL_setn(L, 1, e - LUA_FIRSTINDEX); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos #define llex_c +#define LUA_CORE #include "lua.h" diff --git a/src/llimits.h b/src/llimits.h index 6a2e00bdde..ea0caf7bd1 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.57 2003/12/01 16:33:30 roberto Exp $ +** $Id: llimits.h,v 1.59 2004/06/23 15:57:29 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -15,48 +15,9 @@ #include "lua.h" -/* -** try to find number of bits in an integer -*/ -#ifndef BITS_INT -/* avoid overflows in comparison */ -#if INT_MAX-20 < 32760 -#define BITS_INT 16 -#elif INT_MAX > 2147483640L -/* machine has at least 32 bits */ -#define BITS_INT 32 -#else -#error "you must define BITS_INT with number of bits in an integer" -#endif -#endif - - -/* -** the following types define integer types for values that may not -** fit in a `small int' (16 bits), but may waste space in a -** `large long' (64 bits). The current definitions should work in -** any machine, but may not be optimal. -*/ - - -/* -** an unsigned integer with at least 32 bits -*/ -#ifndef LUA_UINT32 -#define LUA_UINT32 unsigned long -#endif typedef LUA_UINT32 lu_int32; - -/* -** a signed integer with at least 32 bits -*/ -#ifndef LUA_INT32 -#define LUA_INT32 long -#define LUA_MAXINT32 LONG_MAX -#endif - typedef LUA_INT32 l_int32; @@ -95,24 +56,11 @@ typedef unsigned char lu_byte; /* type to ensure maximum alignment */ -#ifndef LUSER_ALIGNMENT_T -typedef union { double u; void *s; long l; } L_Umaxalign; -#else typedef LUSER_ALIGNMENT_T L_Umaxalign; -#endif -/* result of `usual argument conversion' over lua_Number */ -#ifndef LUA_UACNUMBER -typedef double l_uacNumber; -#else +/* result of a `usual argument conversion' over lua_Number */ typedef LUA_UACNUMBER l_uacNumber; -#endif - - -#ifndef lua_assert -#define lua_assert(c) /* empty */ -#endif #ifndef check_exp @@ -138,43 +86,11 @@ typedef LUA_UACNUMBER l_uacNumber; typedef lu_int32 Instruction; -/* maximum depth for calls (unsigned short) */ -#ifndef LUA_MAXCALLS -#define LUA_MAXCALLS 4096 -#endif - - -/* -** maximum depth for C calls (unsigned short): Not too big, or may -** overflow the C stack... -*/ - -#ifndef LUA_MAXCCALLS -#define LUA_MAXCCALLS 200 -#endif - - -/* maximum size for the virtual stack of a C function */ -#ifndef LUA_MAXCSTACK -#define LUA_MAXCSTACK 2048 -#endif - /* maximum stack for a Lua function */ #define MAXSTACK 250 -/* maximum number of variables declared in a function */ -#ifndef MAXVARS -#define MAXVARS 200 /* #define lmem_c +#define LUA_CORE #include "lua.h" @@ -76,8 +77,7 @@ void *luaM_realloc (lua_State *L, void *block, lu_mem osize, lu_mem nsize) { if (block == NULL && nsize > 0) luaD_throw(L, LUA_ERRMEM); lua_assert((nsize == 0) == (block == NULL)); - g->nblocks -= osize; - g->nblocks += nsize; + g->totalbytes = (g->totalbytes - osize) + nsize; return block; } diff --git a/src/lobject.c b/src/lobject.c index f273796b66..1e24bb5df6 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: lobject.c,v 2.4 2004/07/09 16:01:38 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -10,6 +10,7 @@ #include #define lobject_c +#define LUA_CORE #include "lua.h" @@ -21,11 +22,6 @@ #include "lvm.h" -/* function to convert a string to a lua_Number */ -#ifndef lua_str2number -#define lua_str2number(s,p) strtod((s), (p)) -#endif - const TValue luaO_nilobject = {LUA_TNIL, {NULL}}; @@ -98,7 +94,7 @@ static void pushstr (lua_State *L, const char *str) { } -/* this function handles only `%d', `%c', %f, and `%s' formats */ +/* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 1; pushstr(L, ""); @@ -108,9 +104,10 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); incr_top(L); switch (*(e+1)) { - case 's': + case 's': { pushstr(L, va_arg(argp, char *)); break; + } case 'c': { char buff[2]; buff[0] = cast(char, va_arg(argp, int)); @@ -118,17 +115,26 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { pushstr(L, buff); break; } - case 'd': + case 'd': { setnvalue(L->top, cast(lua_Number, va_arg(argp, int))); incr_top(L); break; - case 'f': + } + case 'f': { setnvalue(L->top, cast(lua_Number, va_arg(argp, l_uacNumber))); incr_top(L); break; - case '%': + } + case 'p': { + char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ + sprintf(buff, "%p", va_arg(argp, void *)); + pushstr(L, buff); + break; + } + case '%': { pushstr(L, "%"); break; + } default: { char buff[3]; buff[0] = '%'; @@ -177,7 +183,7 @@ void luaO_chunkid (char *out, const char *source, int bufflen) { strcat(out, source); } else { /* out = [string "string"] */ - int len = strcspn(source, "\n"); /* stop at first newline */ + int len = strcspn(source, "\n\r"); /* stop at first newline */ bufflen -= sizeof(" [string \"...\"] "); if (len > bufflen) len = bufflen; strcpy(out, "[string \""); diff --git a/src/lobject.h b/src/lobject.h index d5176a232d..4b6a684b73 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.4 2004/03/15 21:04:33 roberto Exp $ +** $Id: lobject.h,v 2.5 2004/05/31 18:51:50 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -249,6 +249,10 @@ typedef struct Proto { } Proto; +/* mask for new-style vararg */ +#define NEWSTYLEVARARG 2 + + typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ diff --git a/src/lopcodes.c b/src/lopcodes.c index 3ffda71a56..87ec8939c1 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,10 +1,11 @@ /* -** $Id: lopcodes.c,v 1.25 2003/05/14 21:09:53 roberto Exp $ +** $Id: lopcodes.c,v 1.28 2004/07/16 13:15:32 roberto Exp $ ** See Copyright Notice in lua.h */ #define lopcodes_c +#define LUA_CORE #include "lua.h" @@ -14,8 +15,6 @@ /* ORDER OP */ -#ifdef LUA_OPNAMES - const char *const luaP_opnames[NUM_OPCODES] = { "MOVE", "LOADK", @@ -52,10 +51,10 @@ const char *const luaP_opnames[NUM_OPCODES] = { "SETLIST", "SETLISTO", "CLOSE", - "CLOSURE" + "CLOSURE", + "VARARG" }; -#endif #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) @@ -97,5 +96,6 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 0, OpArgU, OpArgN, iABx) /* OP_SETLISTO */ ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ }; diff --git a/src/lopcodes.h b/src/lopcodes.h index 28df697dc4..d3429a597b 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.106 2003/05/15 19:46:03 roberto Exp $ +** $Id: lopcodes.h,v 1.111 2004/08/04 20:18:13 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -41,18 +41,19 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ #define SIZE_OP 6 -#define POS_C SIZE_OP +#define POS_OP 0 +#define POS_A (POS_OP + SIZE_OP) +#define POS_C (POS_A + SIZE_A) #define POS_B (POS_C + SIZE_C) #define POS_Bx POS_C -#define POS_A (POS_B + SIZE_B) /* ** limits for opcode arguments. ** we use (signed) int to manipulate most arguments, -** so they must fit in BITS_INT-1 bits (-1 for sign) +** so they must fit in LUA_BITSINT-1 bits (-1 for sign) */ -#if SIZE_Bx < BITS_INT-1 +#if SIZE_Bx < LUA_BITSINT-1 #define MAXARG_Bx ((1<>1) /* `sBx' is signed */ #else @@ -76,10 +77,11 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ ** the following macros help to manipulate instructions */ -#define GET_OPCODE(i) (cast(OpCode, (i)&MASK1(SIZE_OP,0))) -#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,0)) | cast(Instruction, o))) +#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<>POS_A)) +#define GETARG_A(i) (cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0))) #define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ ((cast(Instruction, u)<=) R(A)*/ -OP_CLOSURE/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ + +OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ } OpCode; -#define NUM_OPCODES (cast(int, OP_CLOSURE+1)) +#define NUM_OPCODES (cast(int, OP_VARARG+1)) /*=========================================================================== Notes: - (1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, + (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, and can be 0: OP_CALL then sets `top' to last_result+1, so next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. - (2) In OP_RETURN, if (B == 0) then return up to `top' + (*) In OP_VARARG, if (B == 0) then use actual number of varargs and + set top (like in OP_CALL). + + (*) In OP_RETURN, if (B == 0) then return up to `top' - (3) For comparisons, B specifies what conditions the test should accept. + (*) For comparisons, B specifies what conditions the test should accept. - (4) All `skips' (pc++) assume that next instruction is a jump + (*) All `skips' (pc++) assume that next instruction is a jump ===========================================================================*/ diff --git a/src/lparser.c b/src/lparser.c index a8dafb6fab..c0fc1579e3 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.2 2004/03/12 19:53:56 roberto Exp $ +** $Id: lparser.c,v 2.5 2004/05/31 18:51:50 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define lparser_c +#define LUA_CORE #include "lua.h" @@ -26,6 +27,8 @@ +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) + #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) #define luaY_checklimit(fs,v,l,m) if ((v)>(l)) luaY_errorlimit(fs,l,m) @@ -271,11 +274,11 @@ static TString *singlevar (LexState *ls, expdesc *var, int base) { static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int extra = nvars - nexps; - if (e->k == VCALL) { + if (hasmultret(e->k)) { extra++; /* includes call itself */ - if (extra <= 0) extra = 0; - else luaK_reserveregs(fs, extra-1); - luaK_setcallreturns(fs, e, extra); /* call provides the difference */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra-1); } else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ @@ -391,6 +394,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { lexstate.nestlevel = 0; luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); + funcstate.f->is_vararg = NEWSTYLEVARARG; next(&lexstate); /* read first token */ chunk(&lexstate); check_condition(&lexstate, (lexstate.t.token == TK_EOS), " expected"); @@ -480,9 +484,10 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) { static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; - if (cc->v.k == VCALL) { - luaK_setcallreturns(fs, &cc->v, LUA_MULTRET); + if (hasmultret(cc->v.k)) { + luaK_setmultret(fs, &cc->v); luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1); + cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) @@ -556,12 +561,8 @@ static void parlist (LexState *ls) { if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { - case TK_NAME: { /* param -> NAME [ `=' `...' ] */ + case TK_NAME: { /* param -> NAME */ new_localvar(ls, str_checkname(ls), nparams++); - if (testnext(ls, '=')) { - check(ls, TK_DOTS); - f->is_vararg = 1; - } break; } case TK_DOTS: { /* param -> `...' */ @@ -627,7 +628,7 @@ static void funcargs (LexState *ls, expdesc *f) { args.k = VVOID; else { explist1(ls, &args); - luaK_setcallreturns(fs, &args, LUA_MULTRET); + luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; @@ -648,7 +649,7 @@ static void funcargs (LexState *ls, expdesc *f) { } lua_assert(f->k == VNONRELOC); base = f->info; /* base register for call */ - if (args.k == VCALL) + if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) @@ -737,43 +738,47 @@ static void simpleexp (LexState *ls, expdesc *v) { switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r)); - next(ls); /* must use `seminfo' before `next' */ break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); - next(ls); /* must use `seminfo' before `next' */ break; } case TK_NIL: { init_exp(v, VNIL, 0); - next(ls); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); - next(ls); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); - next(ls); + break; + } + case TK_DOTS: { /* vararg */ + FuncState *fs = ls->fs; + check_condition(ls, fs->f->is_vararg, + "cannot use `...' outside a vararg function"); + fs->f->is_vararg = NEWSTYLEVARARG; + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); - break; + return; } case TK_FUNCTION: { next(ls); body(ls, v, 0, ls->linenumber); - break; + return; } default: { primaryexp(ls, v); - break; + return; } } + next(ls); } @@ -950,7 +955,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { - luaK_setcallreturns(ls->fs, &e, 1); /* close last expression */ + luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e); return; /* avoid default */ } @@ -976,12 +981,6 @@ static int cond (LexState *ls) { ** after its body (and thus avoiding one jump in the loop). */ -/* -** maximum size of expressions for optimizing `while' code -*/ -#ifndef MAXEXPWHILE -#define MAXEXPWHILE 100 -#endif /* ** the call `luaK_goiffalse' may grow the size of an expression by @@ -1240,9 +1239,8 @@ static void exprstat (LexState *ls) { FuncState *fs = ls->fs; struct LHS_assign v; primaryexp(ls, &v.v); - if (v.v.k == VCALL) { /* stat -> func */ - luaK_setcallreturns(fs, &v.v, 0); /* call statement uses no results */ - } + if (v.v.k == VCALL) /* stat -> func */ + SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ else { /* stat -> assignment */ v.prev = NULL; assignment(ls, &v, 1); @@ -1260,9 +1258,9 @@ static void retstat (LexState *ls) { first = nret = 0; /* return no values */ else { nret = explist1(ls, &e); /* optional return values */ - if (e.k == VCALL) { - luaK_setcallreturns(fs, &e, LUA_MULTRET); - if (nret == 1) { /* tail call? */ + if (hasmultret(e.k)) { + luaK_setmultret(fs, &e); + if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } diff --git a/src/lparser.h b/src/lparser.h index b4652040c4..582b48784e 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.50 2003/08/25 19:51:54 roberto Exp $ +** $Id: lparser.h,v 1.51 2004/05/31 18:51:50 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -30,7 +30,8 @@ typedef enum { VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ VNONRELOC, /* info = result register */ - VCALL /* info = result register */ + VCALL, /* info = instruction pc */ + VVARARG /* info = instruction pc */ } expkind; typedef struct expdesc { diff --git a/src/lstate.c b/src/lstate.c index d1494b5847..e0a439b1da 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.5 2004/03/23 12:57:12 roberto Exp $ +** $Id: lstate.c,v 2.12 2004/08/30 13:44:44 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define lstate_c +#define LUA_CORE #include "lua.h" @@ -56,6 +57,7 @@ static void stack_init (lua_State *L1, lua_State *L) { L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); L1->ci = L1->base_ci; + L1->ci->func = L1->top; setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; @@ -75,22 +77,25 @@ static void freestack (lua_State *L, lua_State *L1) { */ static void f_luaopen (lua_State *L, void *ud) { Udata *u; /* head of udata list */ + global_State *g = G(L); UNUSED(ud); u = cast(Udata *, luaM_malloc(L, sizeudata(0))); u->uv.len = 0; u->uv.metatable = NULL; - G(L)->firstudata = obj2gco(u); + g->firstudata = obj2gco(u); luaC_link(L, obj2gco(u), LUA_TUSERDATA); setbit(u->uv.marked, FIXEDBIT); setbit(L->marked, FIXEDBIT); stack_init(L, L); /* init stack */ sethvalue(L, gt(L), luaH_new(L, 0, 4)); /* table of globals */ + hvalue(gt(L))->metatable = luaH_new(L, 0, 0); /* globals metatable */ sethvalue(L, registry(L), luaH_new(L, 4, 4)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); luaS_fix(luaS_newliteral(L, MEMERRMSG)); - G(L)->GCthreshold = 4*G(L)->nblocks; + g->GCthreshold = 4*g->totalbytes; + g->prevestimate = g->estimate = g->totalbytes; } @@ -119,12 +124,13 @@ static void preinit_state (lua_State *L, global_State *g) { static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_sweepall(L); /* collect all elements */ - lua_assert(g->rootgc == obj2gco(L)); - luaS_freeall(L); + luaC_freeall(L); /* collect all objects */ + lua_assert(g->rootgc == NULL); + lua_assert(g->strt.nuse == 0); + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); luaZ_freebuffer(L, &g->buff); freestack(L, L); - lua_assert(g->nblocks == sizeof(LG)); + lua_assert(g->totalbytes == sizeof(LG)); (*g->realloc)(g->ud, fromstate(L), state_size(LG), 0); } @@ -136,6 +142,10 @@ lua_State *luaE_newthread (lua_State *L) { preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ setobj2n(L, gt(L1), gt(L)); /* share table of globals */ + L1->hookmask = L->hookmask; + L1->basehookcount = L->basehookcount; + L1->hook = L->hook; + resethookcount(L1); lua_assert(iswhite(obj2gco(L1))); return L1; } @@ -169,7 +179,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { setnilvalue(registry(L)); luaZ_initbuffer(L, &g->buff); g->panic = NULL; - g->gcstate = GCSfinalize; + g->gcstate = GCSpause; + g->gcgenerational = 0; g->rootgc = obj2gco(L); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; @@ -181,13 +192,14 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { setnilvalue(gkey(g->dummynode)); setnilvalue(gval(g->dummynode)); g->dummynode->next = NULL; - g->nblocks = sizeof(LG); + g->totalbytes = sizeof(LG); if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); L = NULL; } - lua_userstateopen(L); + else + lua_userstateopen(L); return L; } diff --git a/src/lstate.h b/src/lstate.h index ab01d1690f..0a178fefc6 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.2 2004/03/23 17:02:58 roberto Exp $ +** $Id: lstate.h,v 2.7 2004/08/30 13:44:44 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -14,30 +14,6 @@ #include "lzio.h" -/* -** macros for thread synchronization inside Lua core machine: -** all accesses to the global state and to global objects are synchronized. -** Because threads can read the stack of other threads -** (when running garbage collection), -** a thread must also synchronize any write-access to its own stack. -** Unsynchronized accesses are allowed only when reading its own stack, -** or when reading immutable fields from global objects -** (such as string values and udata values). -*/ -#ifndef lua_lock -#define lua_lock(L) ((void) 0) -#endif - -#ifndef lua_unlock -#define lua_unlock(L) ((void) 0) -#endif - - -#ifndef lua_userstateopen -#define lua_userstateopen(l) -#endif - - struct lua_longjmp; /* defined in ldo.c */ @@ -70,25 +46,20 @@ typedef struct stringtable { ** informations about a call */ typedef struct CallInfo { - StkId base; /* base for called function */ + StkId base; /* base for this function */ + StkId func; /* function index in the stack */ StkId top; /* top for this function */ - union { - struct { /* for Lua functions */ - const Instruction *savedpc; - int tailcalls; /* number of tail calls lost under this entry */ - } l; - struct { /* for C functions */ - int dummy; /* just to avoid an empty struct */ - } c; - } u; + int nresults; /* expected number of results from this function */ + const Instruction *savedpc; + int tailcalls; /* number of tail calls lost under this entry */ } CallInfo; -#define curr_func(L) (clvalue(L->base - 1)) -#define ci_func(ci) (clvalue((ci)->base - 1)) +#define curr_func(L) (clvalue(L->ci->func)) +#define ci_func(ci) (clvalue((ci)->func)) #define f_isLua(ci) (!ci_func(ci)->c.isC) -#define isLua(ci) (ttisfunction((ci)->base - 1) && f_isLua(ci)) +#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) /* @@ -98,7 +69,9 @@ typedef struct global_State { stringtable strt; /* hash table for strings */ lua_Alloc realloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `realloc' */ - int currentwhite; + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + lu_byte gcgenerational; GCObject *rootgc; /* list of all collectable objects */ GCObject *firstudata; /* udata go to the end of `rootgc' */ GCObject **sweepgc; /* position of sweep in `rootgc' */ @@ -107,10 +80,11 @@ typedef struct global_State { GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of weak tables (to be cleared) */ GCObject *tmudata; /* list of userdata to be GC */ - int gcstate; /* state of garbage collector */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; - lu_mem nblocks; /* number of `bytes' currently allocated */ + lu_mem totalbytes; /* number of bytes currently allocated */ + lu_mem estimate; /* an estimate of number of bytes actually in use */ + lu_mem prevestimate; /* previous estimate */ lua_CFunction panic; /* to be called in unprotected errors */ TValue _registry; struct lua_State *mainthread; diff --git a/src/lstring.c b/src/lstring.c index 9a26cf0314..4c34dc9b31 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: lstring.c,v 2.3 2004/08/24 20:12:06 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define lstring_c +#define LUA_CORE #include "lua.h" @@ -18,17 +19,12 @@ -void luaS_freeall (lua_State *L) { - lua_assert(G(L)->strt.nuse==0); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); -} - - void luaS_resize (lua_State *L, int newsize) { GCObject **newhash; stringtable *tb; int i; - if (G(L)->sweepstrgc > 0) return; /* cannot resize during GC traverse */ + if (G(L)->gcstate == GCSsweepstring) + return; /* cannot resize during GC traverse */ newhash = luaM_newvector(L, newsize, GCObject *); tb = &G(L)->strt; for (i=0; i #define ltable_c +#define LUA_CORE #include "lua.h" @@ -36,19 +37,14 @@ /* ** max size of array part is 2^MAXBITS */ -#if BITS_INT > 26 +#if LUA_BITSINT > 26 #define MAXBITS 24 #else -#define MAXBITS (BITS_INT-2) +#define MAXBITS (LUA_BITSINT-2) #endif #define MAXASIZE (1 << MAXBITS) -/* function to convert a lua_Number to int (with any rounding method) */ -#ifndef lua_number2int -#define lua_number2int(i,n) ((i)=(int)(n)) -#endif - #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) @@ -270,7 +266,7 @@ static void setnodevector (lua_State *L, Table *t, int lsize) { } -static void resize (lua_State *L, Table *t, int nasize, int nhsize) { +void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; @@ -315,7 +311,7 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { static void rehash (lua_State *L, Table *t) { int nasize, nhsize; numuse(t, &nasize, &nhsize); /* compute new sizes for array and hash parts */ - resize(L, t, nasize, luaO_log2(nhsize)+1); + luaH_resize(L, t, nasize, luaO_log2(nhsize)+1); } @@ -349,26 +345,6 @@ void luaH_free (lua_State *L, Table *t) { } -#if 0 -/* -** try to remove an element from a hash table; cannot move any element -** (because gc can call `remove' during a table traversal) -*/ -void luaH_remove (Table *t, Node *e) { - Node *mp = luaH_mainposition(t, gkey(e)); - if (e != mp) { /* element not in its main position? */ - while (mp->next != e) mp = mp->next; /* find previous */ - mp->next = e->next; /* remove `e' from its list */ - } - else { - if (e->next != NULL) ?? - } - lua_assert(ttisnil(gval(node))); - setnilvalue(gkey(e)); /* clear node `e' */ - e->next = NULL; -} -#endif - /* ** inserts a new key into a hash table; first, check whether key's main @@ -399,7 +375,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { } } setobj2t(L, gkey(mp), key); - luaC_barrier(L, t, key); + luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); for (;;) { /* correct `firstfree' */ if (ttisnil(gkey(t->firstfree))) @@ -417,21 +393,6 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { } -/* -** generic search function -*/ -static const TValue *luaH_getany (Table *t, const TValue *key) { - if (!ttisnil(key)) { - Node *n = luaH_mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ - else n = n->next; - } while (n); - } - return &luaO_nilobject; -} - - /* ** search function for integers */ @@ -470,6 +431,7 @@ const TValue *luaH_getstr (Table *t, TString *key) { */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { + case LUA_TNIL: return &luaO_nilobject; case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; @@ -478,7 +440,14 @@ const TValue *luaH_get (Table *t, const TValue *key) { return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } - default: return luaH_getany(t, key); + default: { + Node *n = luaH_mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ + else n = n->next; + } while (n); + return &luaO_nilobject; + } } } diff --git a/src/ltable.h b/src/ltable.h index 566d7cd467..d72cf9f52e 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: ltable.h,v 2.2 2004/03/26 14:02:41 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -22,6 +22,7 @@ TValue *luaH_setstr (lua_State *L, Table *t, TString *key); const TValue *luaH_get (Table *t, const TValue *key); TValue *luaH_set (lua_State *L, Table *t, const TValue *key); Table *luaH_new (lua_State *L, int narray, int lnhash); +void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); void luaH_free (lua_State *L, Table *t); int luaH_next (lua_State *L, Table *t, StkId key); diff --git a/src/ltests.c b/src/ltests.c deleted file mode 100644 index 649b14e0d4..0000000000 --- a/src/ltests.c +++ /dev/null @@ -1,852 +0,0 @@ -/* -** $Id: ltests.c,v 1.158 2003/04/07 14:35:00 roberto Exp $ -** Internal Module for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - - -#include -#include -#include -#include -#include - -#define ltests_c - -#include "lua.h" - -#include "lapi.h" -#include "lauxlib.h" -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lmem.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "lualib.h" - - - -/* -** The whole module only makes sense with LUA_DEBUG on -*/ -#ifdef LUA_DEBUG - - -#define lua_pushintegral(L,i) lua_pushnumber(L, cast(lua_Number, (i))) - - -static lua_State *lua_state = NULL; - -int islocked = 0; - - -#define func_at(L,k) (L->ci->base+(k) - 1) - - -static void setnameval (lua_State *L, const char *name, int val) { - lua_pushstring(L, name); - lua_pushintegral(L, val); - lua_settable(L, -3); -} - - -/* -** {====================================================================== -** Controlled version for realloc. -** ======================================================================= -*/ - -#define MARK 0x55 /* 01010101 (a nice pattern) */ - -#ifndef EXTERNMEMCHECK -/* full memory check */ -#define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */ -#define MARKSIZE 16 /* size of marks after each block */ -#define blockhead(b) (cast(char *, b) - HEADER) -#define setsize(newblock, size) (*cast(size_t *, newblock) = size) -#define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b)))) -#define fillmem(mem,size) memset(mem, -MARK, size) -#else -/* external memory check: don't do it twice */ -#define HEADER 0 -#define MARKSIZE 0 -#define blockhead(b) (b) -#define setsize(newblock, size) /* empty */ -#define checkblocksize(b,size) (1) -#define fillmem(mem,size) /* empty */ -#endif - -unsigned long memdebug_numblocks = 0; -unsigned long memdebug_total = 0; -unsigned long memdebug_maxmem = 0; -unsigned long memdebug_memlimit = ULONG_MAX; - - -static void *checkblock (void *block, size_t size) { - void *b = blockhead(block); - int i; - for (i=0;i 0); - if (size == 0) { - freeblock(block, oldsize); - return NULL; - } - else if (size > oldsize && memdebug_total+size-oldsize > memdebug_memlimit) - return NULL; /* to test memory allocation errors */ - else { - void *newblock; - int i; - size_t realsize = HEADER+size+MARKSIZE; - size_t commonsize = (oldsize < size) ? oldsize : size; - if (realsize < size) return NULL; /* overflow! */ - newblock = malloc(realsize); /* alloc a new block */ - if (newblock == NULL) return NULL; - if (block) { - memcpy(cast(char *, newblock)+HEADER, block, commonsize); - freeblock(block, oldsize); /* erase (and check) old copy */ - } - /* initialize new part of the block with something `weird' */ - fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize); - memdebug_total += size; - if (memdebug_total > memdebug_maxmem) - memdebug_maxmem = memdebug_total; - memdebug_numblocks++; - setsize(newblock, size); - for (i=0;icode[pc]; - OpCode o = GET_OPCODE(i); - const char *name = luaP_opnames[o]; - int line = getline(p, pc); - sprintf(buff, "(%4d) %4d - ", line, pc); - switch (getOpMode(o)) { - case iABC: - sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name, - GETARG_A(i), GETARG_B(i), GETARG_C(i)); - break; - case iABx: - sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); - break; - case iAsBx: - sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); - break; - } - return buff; -} - - -#if 0 -void luaI_printcode (Proto *pt, int size) { - int pc; - for (pc=0; pcl.p; - lua_newtable(L); - setnameval(L, "maxstack", p->maxstacksize); - setnameval(L, "numparams", p->numparams); - for (pc=0; pcsizecode; pc++) { - char buff[100]; - lua_pushintegral(L, pc+1); - lua_pushstring(L, buildop(p, pc, buff)); - lua_settable(L, -3); - } - return 1; -} - - -static int listk (lua_State *L) { - Proto *p; - int i; - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), - 1, "Lua function expected"); - p = clvalue(func_at(L, 1))->l.p; - lua_newtable(L); - for (i=0; isizek; i++) { - lua_pushintegral(L, i+1); - luaA_pushobject(L, p->k+i); - lua_settable(L, -3); - } - return 1; -} - - -static int listlocals (lua_State *L) { - Proto *p; - int pc = luaL_checkint(L, 2) - 1; - int i = 0; - const char *name; - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), - 1, "Lua function expected"); - p = clvalue(func_at(L, 1))->l.p; - while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) - lua_pushstring(L, name); - return i-1; -} - -/* }====================================================== */ - - - - -static int get_limits (lua_State *L) { - lua_newtable(L); - setnameval(L, "BITS_INT", BITS_INT); - setnameval(L, "LFPF", LFIELDS_PER_FLUSH); - setnameval(L, "MAXVARS", MAXVARS); - setnameval(L, "MAXPARAMS", MAXPARAMS); - setnameval(L, "MAXSTACK", MAXSTACK); - setnameval(L, "MAXUPVALUES", MAXUPVALUES); - return 1; -} - - -static int mem_query (lua_State *L) { - if (lua_isnone(L, 1)) { - lua_pushintegral(L, memdebug_total); - lua_pushintegral(L, memdebug_numblocks); - lua_pushintegral(L, memdebug_maxmem); - return 3; - } - else { - memdebug_memlimit = luaL_checkint(L, 1); - return 0; - } -} - - -static int hash_query (lua_State *L) { - if (lua_isnone(L, 2)) { - luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); - lua_pushintegral(L, tsvalue(func_at(L, 1))->tsv.hash); - } - else { - TObject *o = func_at(L, 1); - Table *t; - luaL_checktype(L, 2, LUA_TTABLE); - t = hvalue(func_at(L, 2)); - lua_pushintegral(L, luaH_mainposition(t, o) - t->node); - } - return 1; -} - - -static int stacklevel (lua_State *L) { - unsigned long a = 0; - lua_pushintegral(L, (int)(L->top - L->stack)); - lua_pushintegral(L, (int)(L->stack_last - L->stack)); - lua_pushintegral(L, (int)(L->ci - L->base_ci)); - lua_pushintegral(L, (int)(L->end_ci - L->base_ci)); - lua_pushintegral(L, (unsigned long)&a); - return 5; -} - - -static int table_query (lua_State *L) { - const Table *t; - int i = luaL_optint(L, 2, -1); - luaL_checktype(L, 1, LUA_TTABLE); - t = hvalue(func_at(L, 1)); - if (i == -1) { - lua_pushintegral(L, t->sizearray); - lua_pushintegral(L, sizenode(t)); - lua_pushintegral(L, t->firstfree - t->node); - } - else if (i < t->sizearray) { - lua_pushintegral(L, i); - luaA_pushobject(L, &t->array[i]); - lua_pushnil(L); - } - else if ((i -= t->sizearray) < sizenode(t)) { - if (!ttisnil(gval(gnode(t, i))) || - ttisnil(gkey(gnode(t, i))) || - ttisnumber(gkey(gnode(t, i)))) { - luaA_pushobject(L, gkey(gnode(t, i))); - } - else - lua_pushstring(L, ""); - luaA_pushobject(L, gval(gnode(t, i))); - if (t->node[i].next) - lua_pushintegral(L, t->node[i].next - t->node); - else - lua_pushnil(L); - } - return 3; -} - - -static int string_query (lua_State *L) { - stringtable *tb = &G(L)->strt; - int s = luaL_optint(L, 2, 0) - 1; - if (s==-1) { - lua_pushintegral(L ,tb->nuse); - lua_pushintegral(L ,tb->size); - return 2; - } - else if (s < tb->size) { - GCObject *ts; - int n = 0; - for (ts = tb->hash[s]; ts; ts = ts->gch.next) { - setsvalue2s(L->top, gcotots(ts)); - incr_top(L); - n++; - } - return n; - } - return 0; -} - - -static int tref (lua_State *L) { - int level = lua_gettop(L); - int lock = luaL_optint(L, 2, 1); - luaL_checkany(L, 1); - lua_pushvalue(L, 1); - lua_pushintegral(L, lua_ref(L, lock)); - assert(lua_gettop(L) == level+1); /* +1 for result */ - return 1; -} - -static int getref (lua_State *L) { - int level = lua_gettop(L); - lua_getref(L, luaL_checkint(L, 1)); - assert(lua_gettop(L) == level+1); - return 1; -} - -static int unref (lua_State *L) { - int level = lua_gettop(L); - lua_unref(L, luaL_checkint(L, 1)); - assert(lua_gettop(L) == level); - return 0; -} - -static int metatable (lua_State *L) { - luaL_checkany(L, 1); - if (lua_isnone(L, 2)) { - if (lua_getmetatable(L, 1) == 0) - lua_pushnil(L); - } - else { - lua_settop(L, 2); - luaL_checktype(L, 2, LUA_TTABLE); - lua_setmetatable(L, 1); - } - return 1; -} - - -static int upvalue (lua_State *L) { - int n = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TFUNCTION); - if (lua_isnone(L, 3)) { - const char *name = lua_getupvalue(L, 1, n); - if (name == NULL) return 0; - lua_pushstring(L, name); - return 2; - } - else { - const char *name = lua_setupvalue(L, 1, n); - lua_pushstring(L, name); - return 1; - } -} - - -static int newuserdata (lua_State *L) { - size_t size = luaL_checkint(L, 1); - char *p = cast(char *, lua_newuserdata(L, size)); - while (size--) *p++ = '\0'; - return 1; -} - - -static int pushuserdata (lua_State *L) { - lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1))); - return 1; -} - - -static int udataval (lua_State *L) { - lua_pushintegral(L, cast(int, lua_touserdata(L, 1))); - return 1; -} - - -static int doonnewstack (lua_State *L) { - lua_State *L1 = lua_newthread(L); - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - int status = luaL_loadbuffer(L1, s, l, s); - if (status == 0) - status = lua_pcall(L1, 0, 0, 0); - lua_pushintegral(L, status); - return 1; -} - - -static int s2d (lua_State *L) { - lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1))); - return 1; -} - -static int d2s (lua_State *L) { - double d = luaL_checknumber(L, 1); - lua_pushlstring(L, cast(char *, &d), sizeof(d)); - return 1; -} - - -static int newstate (lua_State *L) { - lua_State *L1 = lua_open(); - if (L1) { - lua_userstateopen(L1); /* init lock */ - lua_pushintegral(L, (unsigned long)L1); - } - else - lua_pushnil(L); - return 1; -} - - -static int loadlib (lua_State *L) { - static const luaL_reg libs[] = { - {"mathlibopen", luaopen_math}, - {"strlibopen", luaopen_string}, - {"iolibopen", luaopen_io}, - {"tablibopen", luaopen_table}, - {"dblibopen", luaopen_debug}, - {"baselibopen", luaopen_base}, - {NULL, NULL} - }; - lua_State *L1 = cast(lua_State *, - cast(unsigned long, luaL_checknumber(L, 1))); - lua_pushvalue(L1, LUA_GLOBALSINDEX); - luaL_openlib(L1, NULL, libs, 0); - return 0; -} - -static int closestate (lua_State *L) { - lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1))); - lua_close(L1); - lua_unlock(L); /* close cannot unlock that */ - return 0; -} - -static int doremote (lua_State *L) { - lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1))); - size_t lcode; - const char *code = luaL_checklstring(L, 2, &lcode); - int status; - lua_settop(L1, 0); - status = luaL_loadbuffer(L1, code, lcode, code); - if (status == 0) - status = lua_pcall(L1, 0, LUA_MULTRET, 0); - if (status != 0) { - lua_pushnil(L); - lua_pushintegral(L, status); - lua_pushstring(L, lua_tostring(L1, -1)); - return 3; - } - else { - int i = 0; - while (!lua_isnone(L1, ++i)) - lua_pushstring(L, lua_tostring(L1, i)); - lua_pop(L1, i-1); - return i-1; - } -} - - -static int log2_aux (lua_State *L) { - lua_pushintegral(L, luaO_log2(luaL_checkint(L, 1))); - return 1; -} - -static int int2fb_aux (lua_State *L) { - int b = luaO_int2fb(luaL_checkint(L, 1)); - lua_pushintegral(L, b); - lua_pushintegral(L, fb2int(b)); - return 2; -} - - -static int test_do (lua_State *L) { - const char *p = luaL_checkstring(L, 1); - if (*p == '@') - lua_dofile(L, p+1); - else - lua_dostring(L, p); - return lua_gettop(L); -} - - - -/* -** {====================================================== -** function to test the API with C. It interprets a kind of assembler -** language with calls to the API, so the test can be driven by Lua code -** ======================================================= -*/ - -static const char *const delimits = " \t\n,;"; - -static void skip (const char **pc) { - while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; -} - -static int getnum_aux (lua_State *L, const char **pc) { - int res = 0; - int sig = 1; - skip(pc); - if (**pc == '.') { - res = cast(int, lua_tonumber(L, -1)); - lua_pop(L, 1); - (*pc)++; - return res; - } - else if (**pc == '-') { - sig = -1; - (*pc)++; - } - while (isdigit(cast(int, **pc))) res = res*10 + (*(*pc)++) - '0'; - return sig*res; -} - -static const char *getname_aux (char *buff, const char **pc) { - int i = 0; - skip(pc); - while (**pc != '\0' && !strchr(delimits, **pc)) - buff[i++] = *(*pc)++; - buff[i] = '\0'; - return buff; -} - - -#define EQ(s1) (strcmp(s1, inst) == 0) - -#define getnum (getnum_aux(L, &pc)) -#define getname (getname_aux(buff, &pc)) - - -static int testC (lua_State *L) { - char buff[30]; - const char *pc = luaL_checkstring(L, 1); - for (;;) { - const char *inst = getname; - if EQ("") return 0; - else if EQ("isnumber") { - lua_pushintegral(L, lua_isnumber(L, getnum)); - } - else if EQ("isstring") { - lua_pushintegral(L, lua_isstring(L, getnum)); - } - else if EQ("istable") { - lua_pushintegral(L, lua_istable(L, getnum)); - } - else if EQ("iscfunction") { - lua_pushintegral(L, lua_iscfunction(L, getnum)); - } - else if EQ("isfunction") { - lua_pushintegral(L, lua_isfunction(L, getnum)); - } - else if EQ("isuserdata") { - lua_pushintegral(L, lua_isuserdata(L, getnum)); - } - else if EQ("isudataval") { - lua_pushintegral(L, lua_islightuserdata(L, getnum)); - } - else if EQ("isnil") { - lua_pushintegral(L, lua_isnil(L, getnum)); - } - else if EQ("isnull") { - lua_pushintegral(L, lua_isnone(L, getnum)); - } - else if EQ("tonumber") { - lua_pushnumber(L, lua_tonumber(L, getnum)); - } - else if EQ("tostring") { - const char *s = lua_tostring(L, getnum); - lua_pushstring(L, s); - } - else if EQ("strlen") { - lua_pushintegral(L, lua_strlen(L, getnum)); - } - else if EQ("tocfunction") { - lua_pushcfunction(L, lua_tocfunction(L, getnum)); - } - else if EQ("return") { - return getnum; - } - else if EQ("gettop") { - lua_pushintegral(L, lua_gettop(L)); - } - else if EQ("settop") { - lua_settop(L, getnum); - } - else if EQ("pop") { - lua_pop(L, getnum); - } - else if EQ("pushnum") { - lua_pushintegral(L, getnum); - } - else if EQ("pushnil") { - lua_pushnil(L); - } - else if EQ("pushbool") { - lua_pushboolean(L, getnum); - } - else if EQ("tobool") { - lua_pushintegral(L, lua_toboolean(L, getnum)); - } - else if EQ("pushvalue") { - lua_pushvalue(L, getnum); - } - else if EQ("pushcclosure") { - lua_pushcclosure(L, testC, getnum); - } - else if EQ("pushupvalues") { - lua_pushupvalues(L); - } - else if EQ("remove") { - lua_remove(L, getnum); - } - else if EQ("insert") { - lua_insert(L, getnum); - } - else if EQ("replace") { - lua_replace(L, getnum); - } - else if EQ("gettable") { - lua_gettable(L, getnum); - } - else if EQ("settable") { - lua_settable(L, getnum); - } - else if EQ("next") { - lua_next(L, -2); - } - else if EQ("concat") { - lua_concat(L, getnum); - } - else if EQ("lessthan") { - int a = getnum; - lua_pushboolean(L, lua_lessthan(L, a, getnum)); - } - else if EQ("equal") { - int a = getnum; - lua_pushboolean(L, lua_equal(L, a, getnum)); - } - else if EQ("rawcall") { - int narg = getnum; - int nres = getnum; - lua_call(L, narg, nres); - } - else if EQ("call") { - int narg = getnum; - int nres = getnum; - lua_pcall(L, narg, nres, 0); - } - else if EQ("loadstring") { - size_t sl; - const char *s = luaL_checklstring(L, getnum, &sl); - luaL_loadbuffer(L, s, sl, s); - } - else if EQ("loadfile") { - luaL_loadfile(L, luaL_checkstring(L, getnum)); - } - else if EQ("setmetatable") { - lua_setmetatable(L, getnum); - } - else if EQ("getmetatable") { - if (lua_getmetatable(L, getnum) == 0) - lua_pushnil(L); - } - else if EQ("type") { - lua_pushstring(L, lua_typename(L, lua_type(L, getnum))); - } - else if EQ("getn") { - int i = getnum; - lua_pushintegral(L, luaL_getn(L, i)); - } - else if EQ("setn") { - int i = getnum; - int n = cast(int, lua_tonumber(L, -1)); - luaL_setn(L, i, n); - lua_pop(L, 1); - } - else luaL_error(L, "unknown instruction %s", buff); - } - return 0; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** tests for yield inside hooks -** ======================================================= -*/ - -static void yieldf (lua_State *L, lua_Debug *ar) { - lua_yield(L, 0); -} - -static int setyhook (lua_State *L) { - if (lua_isnoneornil(L, 1)) - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ - else { - const char *smask = luaL_checkstring(L, 1); - int count = luaL_optint(L, 2, 0); - int mask = 0; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - lua_sethook(L, yieldf, mask, count); - } - return 0; -} - - -static int coresume (lua_State *L) { - int status; - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - status = lua_resume(co, 0); - if (status != 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - return 1; - } -} - -/* }====================================================== */ - - - -static const struct luaL_reg tests_funcs[] = { - {"hash", hash_query}, - {"limits", get_limits}, - {"listcode", listcode}, - {"listk", listk}, - {"listlocals", listlocals}, - {"loadlib", loadlib}, - {"stacklevel", stacklevel}, - {"querystr", string_query}, - {"querytab", table_query}, - {"doit", test_do}, - {"testC", testC}, - {"ref", tref}, - {"getref", getref}, - {"unref", unref}, - {"d2s", d2s}, - {"s2d", s2d}, - {"metatable", metatable}, - {"upvalue", upvalue}, - {"newuserdata", newuserdata}, - {"pushuserdata", pushuserdata}, - {"udataval", udataval}, - {"doonnewstack", doonnewstack}, - {"newstate", newstate}, - {"closestate", closestate}, - {"doremote", doremote}, - {"log2", log2_aux}, - {"int2fb", int2fb_aux}, - {"totalmem", mem_query}, - {"resume", coresume}, - {"setyhook", setyhook}, - {NULL, NULL} -}; - - -static void fim (void) { - if (!islocked) - lua_close(lua_state); - lua_assert(memdebug_numblocks == 0); - lua_assert(memdebug_total == 0); -} - - -static int l_panic (lua_State *L) { - UNUSED(L); - fprintf(stderr, "unable to recover; exiting\n"); - return 0; -} - - -int luaB_opentests (lua_State *L) { - lua_atpanic(L, l_panic); - lua_userstateopen(L); /* init lock */ - lua_state = L; /* keep first state to be opened */ - luaL_openlib(L, "T", tests_funcs, 0); - atexit(fim); - return 0; -} - - -#undef main -int main (int argc, char *argv[]) { - char *limit = getenv("MEMLIMIT"); - if (limit) - memdebug_memlimit = strtoul(limit, NULL, 10); - l_main(argc, argv); - return 0; -} - -#endif diff --git a/src/ltm.c b/src/ltm.c index de4bb7af21..4515efc6d3 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.2 2004/02/16 19:09:52 roberto Exp $ +** $Id: ltm.c,v 2.3 2004/04/30 20:13:38 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define ltm_c +#define LUA_CORE #include "lua.h" diff --git a/src/lua/RCS b/src/lua/RCS deleted file mode 120000 index 1ae3893605..0000000000 --- a/src/lua/RCS +++ /dev/null @@ -1 +0,0 @@ -../RCS \ No newline at end of file diff --git a/src/lua/README b/src/lua/README index fca1e9008d..1bd07af6e7 100644 --- a/src/lua/README +++ b/src/lua/README @@ -1,4 +1,4 @@ -This is lua, a sample Lua interpreter. +This is lua, the stand-alone Lua interpreter. It can be used as a batch interpreter and also interactively. There are man pages for it in both nroff and html in ../../doc. @@ -10,7 +10,7 @@ Usage: lua [options] [script [args]]. Available options are: -v show version information -- stop handling options -This interpreter is suitable for using Lua as a standalone language; it loads +This interpreter is suitable for using Lua as a stand-alone language; it loads all standard libraries. For a minimal interpreter, see ../../etc/min.c. If your application simply exports new functions to Lua (which is common), diff --git a/src/lua/lua.c b/src/lua/lua.c index 4e669c07f7..6fe479b309 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.124 2003/10/23 18:06:22 roberto Exp $ +** $Id: lua.c,v 1.132 2004/08/30 18:35:14 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -26,73 +26,25 @@ #endif -/* -** definition of `isatty' -*/ -#ifdef _POSIX_C_SOURCE -#include -#define stdin_is_tty() isatty(0) -#else -#define stdin_is_tty() 1 /* assume stdin is a tty */ -#endif - - - -#ifndef PROMPT -#define PROMPT "> " -#endif - - -#ifndef PROMPT2 -#define PROMPT2 ">> " -#endif - -#ifndef PROGNAME -#define PROGNAME "lua" -#endif - -#ifndef lua_userinit -#define lua_userinit(L) openstdlibs(L) -#endif - - -#ifndef LUA_EXTRALIBS -#define LUA_EXTRALIBS /* empty */ -#endif -static lua_State *L = NULL; +static lua_State *globalL = NULL; static const char *progname = PROGNAME; -static const luaL_reg lualibs[] = { - {"base", luaopen_base}, - {"table", luaopen_table}, - {"io", luaopen_io}, - {"string", luaopen_string}, - {"math", luaopen_math}, - {"debug", luaopen_debug}, - {"loadlib", luaopen_loadlib}, - /* add your libraries here */ - LUA_EXTRALIBS - {NULL, NULL} -}; - - - -static void lstop (lua_State *l, lua_Debug *ar) { +static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ - lua_sethook(l, NULL, 0, 0); - luaL_error(l, "interrupted!"); + lua_sethook(L, NULL, 0, 0); + luaL_error(L, "interrupted!"); } static void laction (int i) { signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ - lua_sethook(L, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } @@ -116,7 +68,7 @@ static void l_message (const char *pname, const char *msg) { } -static int report (int status) { +static int report (lua_State *L, int status) { if (status && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; @@ -127,7 +79,7 @@ static int report (int status) { } -static int lcall (int narg, int clear) { +static int docall (lua_State *L, int narg, int clear) { int status; int base = lua_gettop(L) - narg; /* function index */ lua_pushliteral(L, "_TRACEBACK"); @@ -146,55 +98,46 @@ static void print_version (void) { } -static void getargs (char *argv[], int n) { - int i; +static int getargs (lua_State *L, char *argv[], int n) { + int i, narg; + for (i=n+1; argv[i]; i++) { + luaL_checkstack(L, 1, "too many arguments to script"); + lua_pushstring(L, argv[i]); + } + narg = i-(n+1); /* number of arguments to the script (not to `lua.c') */ lua_newtable(L); for (i=0; argv[i]; i++) { - lua_pushnumber(L, i - n); lua_pushstring(L, argv[i]); - lua_rawset(L, -3); + lua_rawseti(L, -2, i - n); } + return narg; } -static int docall (int status) { - if (status == 0) status = lcall(0, 1); - return report(status); -} - - -static int file_input (const char *name) { - return docall(luaL_loadfile(L, name)); +static int dofile (lua_State *L, const char *name) { + int status = luaL_loadfile(L, name) || docall(L, 0, 1); + return report(L, status); } -static int dostring (const char *s, const char *name) { - return docall(luaL_loadbuffer(L, s, strlen(s), name)); +static int dostring (lua_State *L, const char *s, const char *name) { + int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); + return report(L, status); } -static int load_file (const char *name) { - lua_pushliteral(L, "require"); - lua_rawget(L, LUA_GLOBALSINDEX); - if (!lua_isfunction(L, -1)) { /* no `require' defined? */ - lua_pop(L, 1); - return file_input(name); - } - else { - lua_pushstring(L, name); - return report(lcall(1, 1)); +static int dolibrary (lua_State *L, const char *name) { + lua_getfield(L, LUA_GLOBALSINDEX, "_PATH"); + if (!lua_isstring(L, -1)) { + l_message(progname, "global _PATH must be a string"); + return 1; } + name = luaL_searchpath(L, name, lua_tostring(L, -1)); + if (name == NULL) return report(L, 1); + else return dofile(L, name); } -/* -** this macro can be used by some `history' system to save lines -** read in manual input -*/ -#ifndef lua_saveline -#define lua_saveline(L,line) /* empty */ -#endif - /* ** this macro defines a function to show the prompt and reads the @@ -209,7 +152,7 @@ static int load_file (const char *name) { #endif -static int readline (lua_State *l, const char *prompt) { +static int readline (lua_State *L, const char *prompt) { static char buffer[MAXINPUT]; if (prompt) { fputs(prompt, stdout); @@ -218,7 +161,7 @@ static int readline (lua_State *l, const char *prompt) { if (fgets(buffer, sizeof(buffer), stdin) == NULL) return 0; /* read fails */ else { - lua_pushstring(l, buffer); + lua_pushstring(L, buffer); return 1; } } @@ -226,7 +169,7 @@ static int readline (lua_State *l, const char *prompt) { #endif -static const char *get_prompt (int firstline) { +static const char *get_prompt (lua_State *L, int firstline) { const char *p = NULL; lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2"); lua_rawget(L, LUA_GLOBALSINDEX); @@ -237,7 +180,7 @@ static const char *get_prompt (int firstline) { } -static int incomplete (int status) { +static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX && strstr(lua_tostring(L, -1), "near `'") != NULL) { lua_pop(L, 1); @@ -248,10 +191,10 @@ static int incomplete (int status) { } -static int load_string (void) { +static int loadline (lua_State *L) { int status; lua_settop(L, 0); - if (lua_readline(L, get_prompt(1)) == 0) /* no input? */ + if (lua_readline(L, get_prompt(L, 1)) == 0) /* no input? */ return -1; if (lua_tostring(L, -1)[0] == '=') { /* line starts with `=' ? */ lua_pushfstring(L, "return %s", lua_tostring(L, -1)+1);/* `=' -> `return' */ @@ -259,8 +202,8 @@ static int load_string (void) { } for (;;) { /* repeat until gets a complete line */ status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); - if (!incomplete(status)) break; /* cannot try to add lines? */ - if (lua_readline(L, get_prompt(0)) == 0) /* no more input? */ + if (!incomplete(L, status)) break; /* cannot try to add lines? */ + if (lua_readline(L, get_prompt(L, 0)) == 0) /* no more input? */ return -1; lua_concat(L, lua_gettop(L)); /* join lines */ } @@ -270,13 +213,14 @@ static int load_string (void) { } -static void manual_input (void) { +static void dotty (lua_State *L) { int status; const char *oldprogname = progname; progname = NULL; - while ((status = load_string()) != -1) { - if (status == 0) status = lcall(0, 0); - report(status); + print_version(); + while ((status = loadline(L)) != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ lua_getglobal(L, "print"); lua_insert(L, 1); @@ -291,14 +235,23 @@ static void manual_input (void) { } -static int handle_argv (char *argv[], int *interactive) { - if (argv[1] == NULL) { /* no more arguments? */ - if (stdin_is_tty()) { - print_version(); - manual_input(); - } +static int checkvar (lua_State *L) { + const char *name = lua_tostring(L, 2); + if (name) + luaL_error(L, "attempt to access undefined variable `%s'", name); + return 0; +} + + +#define clearinteractive(i) (*i &= 2) + +static int handle_argv (lua_State *L, char *argv[], int *interactive) { + if (argv[1] == NULL) { /* no arguments? */ + *interactive = 0; + if (stdin_is_tty()) + dotty(L); else - file_input(NULL); /* executes stdin as a file */ + dofile(L, NULL); /* executes stdin as a file */ } else { /* other arguments; loop over them */ int i; @@ -314,25 +267,35 @@ static int handle_argv (char *argv[], int *interactive) { goto endloop; /* stop handling arguments */ } case '\0': { - file_input(NULL); /* executes stdin as a file */ + clearinteractive(interactive); + dofile(L, NULL); /* executes stdin as a file */ break; } case 'i': { - *interactive = 1; + *interactive = 2; /* force interactive mode after arguments */ break; } case 'v': { + clearinteractive(interactive); print_version(); break; } + case 'w': { + if (lua_getmetatable(L, LUA_GLOBALSINDEX)) { + lua_pushcfunction(L, checkvar); + lua_setfield(L, -2, "__index"); + } + break; + } case 'e': { const char *chunk = argv[i] + 2; + clearinteractive(interactive); if (*chunk == '\0') chunk = argv[++i]; if (chunk == NULL) { print_usage(); return 1; } - if (dostring(chunk, "=") != 0) + if (dostring(L, chunk, "=") != 0) return 1; break; } @@ -343,19 +306,12 @@ static int handle_argv (char *argv[], int *interactive) { print_usage(); return 1; } - if (load_file(filename)) + if (dolibrary(L, filename)) return 1; /* stop if file fails */ break; } - case 'c': { - l_message(progname, "option `-c' is deprecated"); - break; - } - case 's': { - l_message(progname, "option `-s' is deprecated"); - break; - } default: { + clearinteractive(interactive); print_usage(); return 1; } @@ -363,31 +319,30 @@ static int handle_argv (char *argv[], int *interactive) { } endloop: if (argv[i] != NULL) { const char *filename = argv[i]; - getargs(argv, i); /* collect arguments */ + int narg = getargs(L, argv, i); /* collect arguments */ + int status; lua_setglobal(L, "arg"); - return file_input(filename); /* stop scanning arguments */ + clearinteractive(interactive); + status = luaL_loadfile(L, filename); + lua_insert(L, -(narg+1)); + if (status == 0) + status = docall(L, narg, 0); + else + lua_pop(L, narg); + return report(L, status); } } return 0; } -static void openstdlibs (lua_State *l) { - const luaL_reg *lib = lualibs; - for (; lib->func; lib++) { - lib->func(l); /* open library */ - lua_settop(l, 0); /* discard any results */ - } -} - - -static int handle_luainit (void) { +static int handle_luainit (lua_State *L) { const char *init = getenv("LUA_INIT"); if (init == NULL) return 0; /* status OK */ else if (init[0] == '@') - return file_input(init+1); + return dofile(L, init+1); else - return dostring(init, "=LUA_INIT"); + return dostring(L, init, "=LUA_INIT"); } @@ -398,17 +353,17 @@ struct Smain { }; -static int pmain (lua_State *l) { - struct Smain *s = (struct Smain *)lua_touserdata(l, 1); +static int pmain (lua_State *L) { + struct Smain *s = (struct Smain *)lua_touserdata(L, 1); int status; - int interactive = 0; + int interactive = 1; if (s->argv[0] && s->argv[0][0]) progname = s->argv[0]; - L = l; - lua_userinit(l); /* open libraries */ - status = handle_luainit(); + globalL = L; + lua_userinit(L); /* open libraries */ + status = handle_luainit(L); if (status == 0) { - status = handle_argv(s->argv, &interactive); - if (status == 0 && interactive) manual_input(); + status = handle_argv(L, s->argv, &interactive); + if (status == 0 && interactive) dotty(L); } s->status = status; return 0; @@ -418,16 +373,16 @@ static int pmain (lua_State *l) { int main (int argc, char *argv[]) { int status; struct Smain s; - lua_State *l = lua_open(); /* create state */ - if (l == NULL) { + lua_State *L = lua_open(); /* create state */ + if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } s.argc = argc; s.argv = argv; - status = lua_cpcall(l, &pmain, &s); - report(status); - lua_close(l); + status = lua_cpcall(L, &pmain, &s); + report(L, status); + lua_close(L); return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/luac/Makefile b/src/luac/Makefile index a6c7d38f17..509577bb6f 100644 --- a/src/luac/Makefile +++ b/src/luac/Makefile @@ -5,7 +5,7 @@ LUA= ../.. include $(LUA)/config INCS= -I$(INC) -I.. $(EXTRA_INCS) -OBJS= luac.o print.o lopcodes.o +OBJS= luac.o print.o SRCS= luac.c print.c T= $(BIN)/luac @@ -15,10 +15,6 @@ all: $T $T: $(OBJS) $(LIB)/liblua.a ../lib/lauxlib.o $(CC) -o $@ $(MYLDFLAGS) $(OBJS) ../lib/lauxlib.o -L$(LIB) -llua $(EXTRA_LIBS) -# print.c needs opcode names from lopcodes.c -lopcodes.o: ../lopcodes.c ../lopcodes.h - $(CC) -o $@ -c $(CFLAGS) -DLUA_OPNAMES ../lopcodes.c - $(LIB)/liblua.a: cd ..; $(MAKE) diff --git a/src/luac/RCS b/src/luac/RCS deleted file mode 120000 index 1ae3893605..0000000000 --- a/src/luac/RCS +++ /dev/null @@ -1 +0,0 @@ -../RCS \ No newline at end of file diff --git a/src/luac/README b/src/luac/README index 140d94571c..00dd1cd479 100644 --- a/src/luac/README +++ b/src/luac/README @@ -1,7 +1,7 @@ This is luac, the Lua compiler. There are man pages for it in both nroff and html in ../../doc. -luac translates Lua programs into binary files that can be loaded latter. +luac translates Lua programs into binary files that can be loaded later. The main advantages of pre-compiling chunks are: faster loading, protecting source code from user changes, and off-line syntax error detection. luac can also be used to learn about the Lua virtual machine. diff --git a/src/luac/luac.c b/src/luac/luac.c index f634d5f986..dfbcab0550 100644 --- a/src/luac/luac.c +++ b/src/luac/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.47 2004/03/24 00:25:08 lhf Exp $ +** $Id: luac.c,v 1.49 2004/09/01 21:22:34 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -9,6 +9,9 @@ #include #include +#define luac_c +#define LUA_CORE + #include "lua.h" #include "lauxlib.h" @@ -43,8 +46,7 @@ static void fatal(const char* message) static void cannot(const char* what) { - fprintf(stderr,"%s: cannot %s output file %s: %s\n", - progname,what,output,strerror(errno)); + fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); exit(EXIT_FAILURE); } @@ -84,13 +86,14 @@ static int doargs(int argc, char* argv[]) break; } else if (IS("-")) /* end of options; use stdin */ - return i; + break; else if (IS("-l")) /* list */ - listing=1; + ++listing; else if (IS("-o")) /* output file */ { output=argv[++i]; if (output==NULL || *output==0) usage("`-o' needs argument"); + if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ dumping=0; @@ -112,11 +115,7 @@ static int doargs(int argc, char* argv[]) return i; } -static Proto* toproto(lua_State* L, int i) -{ - const Closure* c=(const Closure*)lua_topointer(L,i); - return c->l.p; -} +#define toproto(L,i) (clvalue(L->top+(i))->l.p) static Proto* combine(lua_State* L, int n) { @@ -124,18 +123,20 @@ static Proto* combine(lua_State* L, int n) return toproto(L,-1); else { - int i,pc=0; + int i,pc; Proto* f=luaF_newproto(L); setptvalue2s(L,L->top,f); incr_top(L); f->source=luaS_newliteral(L,"=(" PROGNAME ")"); f->maxstacksize=1; + pc=2*n+1; + f->code=luaM_newvector(L,pc,Instruction); + f->sizecode=pc; f->p=luaM_newvector(L,n,Proto*); f->sizep=n; - f->sizecode=2*n+1; - f->code=luaM_newvector(L,f->sizecode,Instruction); + pc=0; for (i=0; ip[i]=toproto(L,i-n); + f->p[i]=toproto(L,i-n-1); f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); } @@ -147,26 +148,23 @@ static Proto* combine(lua_State* L, int n) static int writer(lua_State* L, const void* p, size_t size, void* u) { UNUSED(L); - return fwrite(p,size,1,(FILE*)u)==1; + return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } -static int panic(lua_State *L) -{ - UNUSED(L); - fatal("not enough memory!"); - return 0; -} +void unprint(lua_State* L, const char* name); -int main(int argc, char* argv[]) +struct Smain { + int argc; + char **argv; +}; + +static int pmain(lua_State *L) { - lua_State* L; + struct Smain *s = (struct Smain *)lua_touserdata(L, 1); + int argc=s->argc; + char **argv=s->argv; Proto* f; - int i=doargs(argc,argv); - argc-=i; argv+=i; - if (argc<=0) usage("no input files given"); - L=lua_open(); - if (L==NULL) fatal("not enough memory for state"); - lua_atpanic(L,panic); + int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i1); if (dumping) { - FILE* D=fopen(output,"wb"); + FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); if (D==NULL) cannot("open"); lua_lock(L); luaU_dump(L,f,writer,D,stripping); @@ -185,6 +183,21 @@ int main(int argc, char* argv[]) if (ferror(D)) cannot("write"); if (fclose(D)) cannot("close"); } + return 0; +} + +int main(int argc, char* argv[]) +{ + lua_State* L; + struct Smain s; + int i=doargs(argc,argv); + argc-=i; argv+=i; + if (argc<=0) usage("no input files given"); + L=lua_open(); + if (L==NULL) fatal("not enough memory for state"); + s.argc=argc; + s.argv=argv; + if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; } diff --git a/src/luac/print.c b/src/luac/print.c index 2f9e7d1206..0d3f18bfc8 100644 --- a/src/luac/print.c +++ b/src/luac/print.c @@ -1,18 +1,13 @@ /* -** $Id: print.c,v 1.46 2004/03/24 00:25:08 lhf Exp $ +** $Id: print.c,v 1.48 2004/09/01 21:22:34 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ +#include #include -#if 1 -#define DEBUG_PRINT -#endif - -#ifndef LUA_OPNAMES -#define LUA_OPNAMES -#endif +#define LUA_CORE #include "ldebug.h" #include "lobject.h" @@ -38,7 +33,7 @@ static void PrintString(const Proto* f, int n) case '\r': printf("\\r"); break; case '\t': printf("\\t"); break; case '\v': printf("\\v"); break; - default: putchar(*s); break; + default: printf(isprint(*s) ? "%c" : "\\%03d",*s); } } putchar('"'); @@ -88,13 +83,11 @@ static void PrintCode(const Proto* f) { case iABC: printf("%d",a); - if (getBMode(o)!=OpArgN) - { if (b>=MAXSTACK) printf(" #%d",b-MAXSTACK); else printf(" %d",b); } - if (getCMode(o)!=OpArgN) - { if (c>=MAXSTACK) printf(" #%d",c-MAXSTACK); else printf(" %d",c); } + if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); break; case iABx: - if (getBMode(o)==OpArgK) printf("%d #%d",a,bx); else printf("%d %d",a,bx); + if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); break; case iAsBx: if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); @@ -115,7 +108,7 @@ static void PrintCode(const Proto* f) break; case OP_GETTABLE: case OP_SELF: - if (c>=MAXSTACK) { printf("\t; "); PrintConstant(f,c-MAXSTACK); } + if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABLE: case OP_ADD: @@ -126,12 +119,12 @@ static void PrintCode(const Proto* f) case OP_EQ: case OP_LT: case OP_LE: - if (b>=MAXSTACK || c>=MAXSTACK) + if (ISK(b) || ISK(c)) { printf("\t; "); - if (b>=MAXSTACK) PrintConstant(f,b-MAXSTACK); else printf("-"); + if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); printf(" "); - if (c>=MAXSTACK) PrintConstant(f,c-MAXSTACK); else printf("-"); + if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); } break; case OP_JMP: @@ -161,15 +154,13 @@ static const char* Source(const Proto* f) return "(string)"; } -#define IsMain(f) (f->lineDefined==0) - #define SS(x) (x==1)?"":"s" #define S(x) x,SS(x) static void PrintHeader(const Proto* f) { printf("\n%s <%s:%d> (%d instruction%s, %d bytes at %p)\n", - IsMain(f)?"main":"function",Source(f),f->lineDefined, + (f->lineDefined==0)?"main":"function",Source(f),f->lineDefined, S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); printf("%d%s param%s, %d stack%s, %d upvalue%s, ", f->numparams,f->is_vararg?"+":"",SS(f->numparams),S(f->maxstacksize), @@ -178,14 +169,13 @@ static void PrintHeader(const Proto* f) S(f->sizelocvars),S(f->sizek),S(f->sizep)); } -#ifdef DEBUG_PRINT static void PrintConstants(const Proto* f) { int i,n=f->sizek; printf("constants (%d) for %p:\n",n,VOID(f)); for (i=0; iupvalues[i])); } } -#endif -void luaU_print(const Proto* f) +void luaU_print(const Proto* f, int full) { int i,n=f->sizep; PrintHeader(f); PrintCode(f); -#ifdef DEBUG_PRINT - PrintConstants(f); - PrintLocals(f); - PrintUpvalues(f); -#endif - for (i=0; ip[i]); + if (full) + { + PrintConstants(f); + PrintLocals(f); + PrintUpvalues(f); + } + for (i=0; ip[i],full); } diff --git a/src/lundump.c b/src/lundump.c index d79dd89844..ee09160254 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.51 2004/03/24 00:25:08 lhf Exp $ +** $Id: lundump.c,v 1.53 2004/09/01 21:22:34 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -8,6 +8,7 @@ #include #define lundump_c +#define LUA_CORE #include "lua.h" @@ -261,15 +262,15 @@ static void LoadHeader (LoadState* S) /* ** load precompiled chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* s) +Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) { LoadState S; - if (*s=='@' || *s=='=') - S.name=s+1; - else if (*s==LUA_SIGNATURE[0]) + if (*name=='@' || *name=='=') + S.name=name+1; + else if (*name==LUA_SIGNATURE[0]) S.name="binary string"; else - S.name=s; + S.name=name; S.L=L; S.Z=Z; S.b=buff; diff --git a/src/lundump.h b/src/lundump.h index 26c792a895..4628b81d52 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.32 2003/12/09 19:22:19 lhf Exp $ +** $Id: lundump.h,v 1.33 2004/06/09 21:03:53 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -17,10 +17,10 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char *name); int luaU_endianness (void); /* dump one chunk; from ldump.c */ -int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip); +int luaU_dump (lua_State* L, const Proto* f, lua_Chunkwriter w, void* data, int strip); /* print one chunk; from print.c */ -void luaU_print (const Proto* Main); +void luaU_print (const Proto* f, int full); /* definitions for headers of binary files */ #define VERSION 0x51 /* last format change was in 5.1 */ diff --git a/src/lvm.c b/src/lvm.c index bfbe8bf2c8..05af9df156 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.2 2004/03/16 12:31:40 roberto Exp $ +** $Id: lvm.c,v 2.13 2004/08/12 14:19:51 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -8,10 +8,8 @@ #include #include -/* needed only when `lua_number2str' uses `sprintf' */ -#include - #define lvm_c +#define LUA_CORE #include "lua.h" @@ -29,12 +27,6 @@ -/* function to convert a lua_Number to a string */ -#ifndef lua_number2str -#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) -#endif - - /* limit for table tag-method chains (to avoid loops) */ #define MAXTAGLOOP 100 @@ -66,8 +58,8 @@ int luaV_tostring (lua_State *L, StkId obj) { static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; CallInfo *ci = L->ci; - const Instruction *oldpc = ci->u.l.savedpc; - ci->u.l.savedpc = pc; + const Instruction *oldpc = ci->savedpc; + ci->savedpc = pc; if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); @@ -114,7 +106,8 @@ static void callTM (lua_State *L) { } -void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { +StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, + const Instruction *pc) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; @@ -124,24 +117,30 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); - return; + return L->base; } /* else will try the tag method */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) { + L->ci->savedpc = pc; luaG_typeerror(L, t, "index"); + } if (ttisfunction(tm)) { + L->ci->savedpc = pc; prepTMcall(L, tm, t, key); callTMres(L, val); - return; + return L->base; } t = tm; /* else repeat with `tm' */ } + L->ci->savedpc = pc; luaG_runerror(L, "loop in gettable"); + return NULL; /* to avoid warnings */ } -void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { +StkId luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val, + const Instruction *pc) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; @@ -151,22 +150,27 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); - luaC_barrier(L, h, val); - return; + luaC_barriert(L, h, val); + return L->base; } /* else will try the tag method */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) { + L->ci->savedpc = pc; luaG_typeerror(L, t, "index"); + } if (ttisfunction(tm)) { + L->ci->savedpc = pc; prepTMcall(L, tm, t, key); setobj2s(L, L->top+3, val); /* 3th argument */ callTM(L); - return; + return L->base; } t = tm; /* else repeat with `tm' */ } + L->ci->savedpc = pc; luaG_runerror(L, "loop in settable"); + return NULL; /* to avoid warnings */ } @@ -304,10 +308,11 @@ void luaV_concat (lua_State *L, int total, int last) { char *buffer; int i; while (n < total && tostring(L, top-n-1)) { /* collect total length */ - tl += tsvalue(top-n-1)->len; + size_t l = tsvalue(top-n-1)->len; + if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); + tl += l; n++; } - if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ @@ -327,7 +332,7 @@ static StkId Arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op, const Instruction *pc) { TValue tempb, tempc; const TValue *b, *c; - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { switch (op) { @@ -364,13 +369,13 @@ static StkId Arith (lua_State *L, StkId ra, const TValue *rb, #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ - (GETARG_B(i) < MAXSTACK) ? base+GETARG_B(i) : k+GETARG_B(i)-MAXSTACK) + ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ - (GETARG_C(i) < MAXSTACK) ? base+GETARG_C(i) : k+GETARG_C(i)-MAXSTACK) + ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) #define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) -#define dojump(pc, i) ((pc) += (i)) +#define dojump(L,pc,i) {(pc) += (i); lua_threadyield(L);} StkId luaV_execute (lua_State *L, int nexeccalls) { @@ -382,9 +387,9 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ - pc = L->ci->u.l.savedpc; + pc = L->ci->savedpc; + cl = &clvalue(L->ci->func)->l; base = L->base; - cl = &clvalue(base - 1)->l; k = cl->p->k; /* main loop of interpreter */ for (;;) { @@ -394,7 +399,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); /***/ if (L->isSuspended) { /* did hook yield? */ - L->ci->u.l.savedpc = pc - 1; + L->ci->savedpc = pc - 1; return NULL; } base = L->base; @@ -402,85 +407,73 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == L->ci->base && base == L->base); - lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); - lua_assert(L->top == L->ci->top || - GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || - GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); + lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); + lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); - break; + continue; } case OP_LOADK: { setobj2s(L, ra, KBx(i)); - break; + continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ - break; + continue; } case OP_LOADNIL: { TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); - break; + continue; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); - break; + continue; } case OP_GETGLOBAL: { TValue *rb = KBx(i); lua_assert(ttisstring(rb) && ttistable(&cl->g)); - L->ci->u.l.savedpc = pc; - luaV_gettable(L, &cl->g, rb, ra); /***/ - base = L->base; - break; + base = luaV_gettable(L, &cl->g, rb, ra, pc); /***/ + continue; } case OP_GETTABLE: { - L->ci->u.l.savedpc = pc; - luaV_gettable(L, RB(i), RKC(i), ra); /***/ - base = L->base; - break; + base = luaV_gettable(L, RB(i), RKC(i), ra, pc); /***/ + continue; } case OP_SETGLOBAL: { lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - L->ci->u.l.savedpc = pc; - luaV_settable(L, &cl->g, KBx(i), ra); /***/ - base = L->base; - break; + base = luaV_settable(L, &cl->g, KBx(i), ra, pc); /***/ + continue; } case OP_SETUPVAL: { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); - break; + continue; } case OP_SETTABLE: { - L->ci->u.l.savedpc = pc; - luaV_settable(L, ra, RKB(i), RKC(i)); /***/ - base = L->base; - break; + base = luaV_settable(L, ra, RKB(i), RKC(i), pc); /***/ + continue; } case OP_NEWTABLE: { int b = GETARG_B(i); b = fb2int(b); sethvalue(L, ra, luaH_new(L, b, GETARG_C(i))); - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; luaC_checkGC(L); /***/ base = L->base; - break; + continue; } case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); - L->ci->u.l.savedpc = pc; - luaV_gettable(L, rb, RKC(i), ra); /***/ - base = L->base; - break; + base = luaV_gettable(L, rb, RKC(i), ra, pc); /***/ + continue; } case OP_ADD: { TValue *rb = RKB(i); @@ -490,7 +483,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } else base = Arith(L, ra, rb, rc, TM_ADD, pc); /***/ - break; + continue; } case OP_SUB: { TValue *rb = RKB(i); @@ -500,7 +493,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } else base = Arith(L, ra, rb, rc, TM_SUB, pc); /***/ - break; + continue; } case OP_MUL: { TValue *rb = RKB(i); @@ -510,7 +503,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } else base = Arith(L, ra, rb, rc, TM_MUL, pc); /***/ - break; + continue; } case OP_DIV: { TValue *rb = RKB(i); @@ -520,11 +513,11 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } else base = Arith(L, ra, rb, rc, TM_DIV, pc); /***/ - break; + continue; } case OP_POW: { base = Arith(L, ra, RKB(i), RKC(i), TM_POW, pc); /***/ - break; + continue; } case OP_UNM: { const TValue *rb = RB(i); @@ -534,113 +527,131 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } else { setnilvalue(&temp); - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) /***/ luaG_aritherror(L, RB(i), &temp); base = L->base; } - break; + continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); - break; + continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ /***/ luaC_checkGC(L); /***/ base = L->base; setobjs2s(L, RA(i), base+b); - break; + continue; } case OP_JMP: { - dojump(pc, GETARG_sBx(i)); - break; + dojump(L, pc, GETARG_sBx(i)); + continue; } case OP_EQ: { - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ - else dojump(pc, GETARG_sBx(*pc) + 1); + else dojump(L, pc, GETARG_sBx(*pc) + 1); base = L->base; - break; + continue; } case OP_LT: { - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ - else dojump(pc, GETARG_sBx(*pc) + 1); + else dojump(L, pc, GETARG_sBx(*pc) + 1); base = L->base; - break; + continue; } case OP_LE: { - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ - else dojump(pc, GETARG_sBx(*pc) + 1); + else dojump(L, pc, GETARG_sBx(*pc) + 1); base = L->base; - break; + continue; } case OP_TEST: { TValue *rb = RB(i); if (l_isfalse(rb) == GETARG_C(i)) pc++; else { setobjs2s(L, ra, rb); - dojump(pc, GETARG_sBx(*pc) + 1); + dojump(L, pc, GETARG_sBx(*pc) + 1); } - break; + continue; } - case OP_CALL: - case OP_TAILCALL: { /***/ - StkId firstResult; + case OP_CALL: { /***/ + int pcr; int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->ci->u.l.savedpc = pc; - firstResult = luaD_precall(L, ra); - if (firstResult) { - int nresults = GETARG_C(i) - 1; - if (firstResult > L->top) { /* yield? */ - (L->ci - 1)->u.l.savedpc = pc; - return NULL; - } + L->ci->savedpc = pc; + pcr = luaD_precall(L, ra, nresults); + if (pcr == PCRLUA) { + nexeccalls++; + goto callentry; /* restart luaV_execute over new Lua function */ + } + else if (pcr == PCRC) { /* it was a C function (`precall' called it); adjust results */ - luaD_poscall(L, nresults, firstResult); if (nresults >= 0) L->top = L->ci->top; + base = L->base; + continue; } - else { /* it is a Lua function */ - if (GET_OPCODE(i) == OP_CALL) /* regular call? */ - nexeccalls++; - else { /* tail call: put new frame in place of previous one */ - int aux; - base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ - ra = RA(i); - if (L->openupval) luaF_close(L, base); - for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ - setobjs2s(L, base+aux-1, ra+aux); - (L->ci - 1)->top = L->top = base+aux; /* correct top */ - (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; - (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ - L->ci--; /* remove new frame */ - L->base = L->ci->base; - } + else { + lua_assert(pcr == PCRYIELD); + return NULL; + } + } + case OP_TAILCALL: { /***/ + int pcr; + int b = GETARG_B(i); + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + L->ci->savedpc = pc; + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + pcr = luaD_precall(L, ra, LUA_MULTRET); + if (pcr == PCRLUA) { + /* tail call: put new frame in place of previous one */ + CallInfo *ci = L->ci - 1; /* previous frame */ + int aux; + StkId func = ci->func; + StkId pfunc = (ci+1)->func; /* previous function index */ + base = ci->base = ci->func + ((ci+1)->base - pfunc); + L->base = base; + if (L->openupval) luaF_close(L, base); + for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ + setobjs2s(L, func+aux, pfunc+aux); + ci->top = L->top = func+aux; /* correct top */ + lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); + ci->savedpc = L->ci->savedpc; + ci->tailcalls++; /* one more call lost */ + L->ci--; /* remove new frame */ goto callentry; } - base = L->base; - break; + else if (pcr == PCRC) { + /* it was a C function (`precall' called it) */ + base = L->base; + continue; + } + else { + lua_assert(pcr == PCRYIELD); + return NULL; + } } case OP_RETURN: { CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; if (--nexeccalls == 0) /* was previous function running `here'? */ return ra; /* no: return */ else { /* yes: continue its execution */ - int nresults; + int nresults = (ci+1)->nresults; lua_assert(isLua(ci)); - lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); - nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; + lua_assert(GET_OPCODE(*(ci->savedpc - 1)) == OP_CALL); luaD_poscall(L, nresults, ra); if (nresults >= 0) L->top = L->ci->top; goto retentry; @@ -651,17 +662,17 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { lua_Number idx = nvalue(ra) + step; /* increment index */ lua_Number limit = nvalue(ra+1); if (step > 0 ? idx <= limit : idx >= limit) { - dojump(pc, GETARG_sBx(i)); /* jump back */ + dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } - break; + continue; } case OP_FORPREP: { /***/ const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; if (!tonumber(init, ra)) luaG_runerror(L, "`for' initial value must be a number"); else if (!tonumber(plimit, ra+1)) @@ -669,8 +680,8 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { else if (!tonumber(pstep, ra+2)) luaG_runerror(L, "`for' step must be a number"); setnvalue(ra, nvalue(ra) - nvalue(pstep)); - dojump(pc, GETARG_sBx(i)); - break; + dojump(L, pc, GETARG_sBx(i)); + continue; } case OP_TFORLOOP: { StkId cb = ra + 3; /* call base */ @@ -678,7 +689,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; luaD_call(L, cb, GETARG_C(i)); /***/ L->top = L->ci->top; base = L->base; @@ -687,26 +698,25 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { pc++; /* skip jump (break loop) */ else { setobjs2s(L, cb-1, cb); /* save control variable */ - dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ + dojump(L, pc, GETARG_sBx(*pc) + 1); /* jump back */ } - break; + continue; } case OP_TFORPREP: { /* for compatibility only */ if (ttistable(ra)) { setobjs2s(L, ra+1, ra); setobj2s(L, ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } - dojump(pc, GETARG_sBx(i)); - break; + dojump(L, pc, GETARG_sBx(i)); + continue; } case OP_SETLIST: case OP_SETLISTO: { - int bc; - int n; + int bc = GETARG_Bx(i); + int n, last; Table *h; runtime_check(L, ttistable(ra)); h = hvalue(ra); - bc = GETARG_Bx(i); if (GET_OPCODE(i) == OP_SETLIST) n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; else { @@ -714,16 +724,19 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { L->top = L->ci->top; } bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ + last = bc + n + LUA_FIRSTINDEX - 1; + if (last > h->sizearray) /* needs more space? */ + luaH_resize(L, h, last, h->lsizenode); /* pre-alloc it at once */ for (; n > 0; n--) { TValue *val = ra+n; - setobj2t(L, luaH_setnum(L, h, bc+n), val); - luaC_barrier(L, h, val); + setobj2t(L, luaH_setnum(L, h, last--), val); + luaC_barriert(L, h, val); } - break; + continue; } case OP_CLOSE: { luaF_close(L, ra); - break; + continue; } case OP_CLOSURE: { Proto *p; @@ -742,10 +755,25 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } } setclvalue(L, ra, ncl); - L->ci->u.l.savedpc = pc; + L->ci->savedpc = pc; luaC_checkGC(L); /***/ base = L->base; - break; + continue; + } + case OP_VARARG: { + int b = GETARG_B(i) - 1; + int j; + CallInfo *ci = L->ci; + int n = ci->base - ci->func - cl->p->numparams - 1; + if (b == LUA_MULTRET) { + b = n; + L->top = ra + n; + } + for (j=0; jbase - n + j); + for (; j #define lzio_c +#define LUA_CORE #include "lua.h" From d8fd22e11b391cf183068049bebbee9702c8f78f Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 21 Sep 2004 12:00:00 +0000 Subject: [PATCH 19/97] Lua 5.1-work2 --- MANIFEST | 226 ++++++++++++++++++++++----------------------- include/lua.h | 17 ++-- include/luaconf.h | 6 +- src/lapi.c | 19 +++- src/ldo.c | 76 ++++++++------- src/ldo.h | 6 +- src/lgc.c | 33 ++++--- src/lgc.h | 6 +- src/lib/lauxlib.c | 3 +- src/lib/lbaselib.c | 75 +++++++++------ src/llimits.h | 6 +- src/lstate.c | 6 +- src/lstate.h | 4 +- src/lua/README | 23 +++-- src/lvm.c | 4 +- 15 files changed, 289 insertions(+), 221 deletions(-) diff --git a/MANIFEST b/MANIFEST index fdb5d2a2ec..7c81b9342d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,114 +1,114 @@ -MANIFEST contents of Lua 5.1 (work1) distribution on Wed Sep 1 22:19:31 BRT 2004 -lua-5.1-work1 -lua-5.1-work1/COPYRIGHT -lua-5.1-work1/HISTORY -lua-5.1-work1/INSTALL -lua-5.1-work1/MANIFEST -lua-5.1-work1/Makefile -lua-5.1-work1/README -lua-5.1-work1/bin -lua-5.1-work1/build -lua-5.1-work1/config -lua-5.1-work1/etc -lua-5.1-work1/etc/Makefile -lua-5.1-work1/etc/README -lua-5.1-work1/etc/all.c -lua-5.1-work1/etc/lua.ico -lua-5.1-work1/etc/min.c -lua-5.1-work1/etc/noparser.c -lua-5.1-work1/etc/saconfig.c -lua-5.1-work1/include -lua-5.1-work1/include/Makefile -lua-5.1-work1/include/lauxlib.h -lua-5.1-work1/include/lua.h -lua-5.1-work1/include/luaconf.h -lua-5.1-work1/include/lualib.h -lua-5.1-work1/lib -lua-5.1-work1/src -lua-5.1-work1/src/Makefile -lua-5.1-work1/src/README -lua-5.1-work1/src/lapi.c -lua-5.1-work1/src/lapi.h -lua-5.1-work1/src/lcode.c -lua-5.1-work1/src/lcode.h -lua-5.1-work1/src/ldebug.c -lua-5.1-work1/src/ldebug.h -lua-5.1-work1/src/ldo.c -lua-5.1-work1/src/ldo.h -lua-5.1-work1/src/ldump.c -lua-5.1-work1/src/lfunc.c -lua-5.1-work1/src/lfunc.h -lua-5.1-work1/src/lgc.c -lua-5.1-work1/src/lgc.h -lua-5.1-work1/src/lib -lua-5.1-work1/src/lib/Makefile -lua-5.1-work1/src/lib/README -lua-5.1-work1/src/lib/lauxlib.c -lua-5.1-work1/src/lib/lbaselib.c -lua-5.1-work1/src/lib/ldblib.c -lua-5.1-work1/src/lib/linit.c -lua-5.1-work1/src/lib/liolib.c -lua-5.1-work1/src/lib/lmathlib.c -lua-5.1-work1/src/lib/loadlib.c -lua-5.1-work1/src/lib/loslib.c -lua-5.1-work1/src/lib/lstrlib.c -lua-5.1-work1/src/lib/ltablib.c -lua-5.1-work1/src/llex.c -lua-5.1-work1/src/llex.h -lua-5.1-work1/src/llimits.h -lua-5.1-work1/src/lmem.c -lua-5.1-work1/src/lmem.h -lua-5.1-work1/src/lobject.c -lua-5.1-work1/src/lobject.h -lua-5.1-work1/src/lopcodes.c -lua-5.1-work1/src/lopcodes.h -lua-5.1-work1/src/lparser.c -lua-5.1-work1/src/lparser.h -lua-5.1-work1/src/lstate.c -lua-5.1-work1/src/lstate.h -lua-5.1-work1/src/lstring.c -lua-5.1-work1/src/lstring.h -lua-5.1-work1/src/ltable.c -lua-5.1-work1/src/ltable.h -lua-5.1-work1/src/ltm.c -lua-5.1-work1/src/ltm.h -lua-5.1-work1/src/lua -lua-5.1-work1/src/lua/Makefile -lua-5.1-work1/src/lua/README -lua-5.1-work1/src/lua/lua.c -lua-5.1-work1/src/luac -lua-5.1-work1/src/luac/Makefile -lua-5.1-work1/src/luac/README -lua-5.1-work1/src/luac/luac.c -lua-5.1-work1/src/luac/print.c -lua-5.1-work1/src/lundump.c -lua-5.1-work1/src/lundump.h -lua-5.1-work1/src/lvm.c -lua-5.1-work1/src/lvm.h -lua-5.1-work1/src/lzio.c -lua-5.1-work1/src/lzio.h -lua-5.1-work1/test -lua-5.1-work1/test/README -lua-5.1-work1/test/bisect.lua -lua-5.1-work1/test/cf.lua -lua-5.1-work1/test/echo.lua -lua-5.1-work1/test/env.lua -lua-5.1-work1/test/factorial.lua -lua-5.1-work1/test/fib.lua -lua-5.1-work1/test/fibfor.lua -lua-5.1-work1/test/globals.lua -lua-5.1-work1/test/hello.lua -lua-5.1-work1/test/life.lua -lua-5.1-work1/test/lua -lua-5.1-work1/test/luac -lua-5.1-work1/test/luac.lua -lua-5.1-work1/test/printf.lua -lua-5.1-work1/test/readonly.lua -lua-5.1-work1/test/sieve.lua -lua-5.1-work1/test/sort.lua -lua-5.1-work1/test/table.lua -lua-5.1-work1/test/trace-calls.lua -lua-5.1-work1/test/trace-globals.lua -lua-5.1-work1/test/undefined.lua -lua-5.1-work1/test/xd.lua +MANIFEST contents of Lua 5.1 (work2) distribution on Mon Sep 20 21:28:06 BRT 2004 +lua-5.1-work2 +lua-5.1-work2/COPYRIGHT +lua-5.1-work2/HISTORY +lua-5.1-work2/INSTALL +lua-5.1-work2/MANIFEST +lua-5.1-work2/Makefile +lua-5.1-work2/README +lua-5.1-work2/bin +lua-5.1-work2/build +lua-5.1-work2/config +lua-5.1-work2/etc +lua-5.1-work2/etc/Makefile +lua-5.1-work2/etc/README +lua-5.1-work2/etc/all.c +lua-5.1-work2/etc/lua.ico +lua-5.1-work2/etc/min.c +lua-5.1-work2/etc/noparser.c +lua-5.1-work2/etc/saconfig.c +lua-5.1-work2/include +lua-5.1-work2/include/Makefile +lua-5.1-work2/include/lauxlib.h +lua-5.1-work2/include/lua.h +lua-5.1-work2/include/luaconf.h +lua-5.1-work2/include/lualib.h +lua-5.1-work2/lib +lua-5.1-work2/src +lua-5.1-work2/src/Makefile +lua-5.1-work2/src/README +lua-5.1-work2/src/lapi.c +lua-5.1-work2/src/lapi.h +lua-5.1-work2/src/lcode.c +lua-5.1-work2/src/lcode.h +lua-5.1-work2/src/ldebug.c +lua-5.1-work2/src/ldebug.h +lua-5.1-work2/src/ldo.c +lua-5.1-work2/src/ldo.h +lua-5.1-work2/src/ldump.c +lua-5.1-work2/src/lfunc.c +lua-5.1-work2/src/lfunc.h +lua-5.1-work2/src/lgc.c +lua-5.1-work2/src/lgc.h +lua-5.1-work2/src/lib +lua-5.1-work2/src/lib/Makefile +lua-5.1-work2/src/lib/README +lua-5.1-work2/src/lib/lauxlib.c +lua-5.1-work2/src/lib/lbaselib.c +lua-5.1-work2/src/lib/ldblib.c +lua-5.1-work2/src/lib/linit.c +lua-5.1-work2/src/lib/liolib.c +lua-5.1-work2/src/lib/lmathlib.c +lua-5.1-work2/src/lib/loadlib.c +lua-5.1-work2/src/lib/loslib.c +lua-5.1-work2/src/lib/lstrlib.c +lua-5.1-work2/src/lib/ltablib.c +lua-5.1-work2/src/llex.c +lua-5.1-work2/src/llex.h +lua-5.1-work2/src/llimits.h +lua-5.1-work2/src/lmem.c +lua-5.1-work2/src/lmem.h +lua-5.1-work2/src/lobject.c +lua-5.1-work2/src/lobject.h +lua-5.1-work2/src/lopcodes.c +lua-5.1-work2/src/lopcodes.h +lua-5.1-work2/src/lparser.c +lua-5.1-work2/src/lparser.h +lua-5.1-work2/src/lstate.c +lua-5.1-work2/src/lstate.h +lua-5.1-work2/src/lstring.c +lua-5.1-work2/src/lstring.h +lua-5.1-work2/src/ltable.c +lua-5.1-work2/src/ltable.h +lua-5.1-work2/src/ltm.c +lua-5.1-work2/src/ltm.h +lua-5.1-work2/src/lua +lua-5.1-work2/src/lua/Makefile +lua-5.1-work2/src/lua/README +lua-5.1-work2/src/lua/lua.c +lua-5.1-work2/src/luac +lua-5.1-work2/src/luac/Makefile +lua-5.1-work2/src/luac/README +lua-5.1-work2/src/luac/luac.c +lua-5.1-work2/src/luac/print.c +lua-5.1-work2/src/lundump.c +lua-5.1-work2/src/lundump.h +lua-5.1-work2/src/lvm.c +lua-5.1-work2/src/lvm.h +lua-5.1-work2/src/lzio.c +lua-5.1-work2/src/lzio.h +lua-5.1-work2/test +lua-5.1-work2/test/README +lua-5.1-work2/test/bisect.lua +lua-5.1-work2/test/cf.lua +lua-5.1-work2/test/echo.lua +lua-5.1-work2/test/env.lua +lua-5.1-work2/test/factorial.lua +lua-5.1-work2/test/fib.lua +lua-5.1-work2/test/fibfor.lua +lua-5.1-work2/test/globals.lua +lua-5.1-work2/test/hello.lua +lua-5.1-work2/test/life.lua +lua-5.1-work2/test/lua +lua-5.1-work2/test/luac +lua-5.1-work2/test/luac.lua +lua-5.1-work2/test/printf.lua +lua-5.1-work2/test/readonly.lua +lua-5.1-work2/test/sieve.lua +lua-5.1-work2/test/sort.lua +lua-5.1-work2/test/table.lua +lua-5.1-work2/test/trace-calls.lua +lua-5.1-work2/test/trace-globals.lua +lua-5.1-work2/test/undefined.lua +lua-5.1-work2/test/xd.lua END OF MANIFEST diff --git a/include/lua.h b/include/lua.h index e513dc3c55..ac5435e723 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.192 2004/06/04 15:30:53 roberto Exp $ +** $Id: lua.h,v 1.193 2004/09/15 20:39:42 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -17,7 +17,7 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (work1)" +#define LUA_VERSION "Lua 5.1 (work2)" #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -37,11 +37,12 @@ #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) -/* error codes for `lua_pcall' */ -#define LUA_ERRRUN 1 -#define LUA_ERRSYNTAX 2 -#define LUA_ERRMEM 3 -#define LUA_ERRERR 4 +/* return codes for `lua_pcall', `lua_resume', and `lua_threadstatus' */ +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 typedef struct lua_State lua_State; @@ -165,6 +166,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...); LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); LUA_API void lua_pushboolean (lua_State *L, int b); LUA_API void lua_pushlightuserdata (lua_State *L, void *p); +LUA_API int lua_pushthread (lua_State *L); /* @@ -208,6 +210,7 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data); */ LUA_API int lua_yield (lua_State *L, int nresults); LUA_API int lua_resume (lua_State *L, int narg); +LUA_API int lua_threadstatus (lua_State *L); /* ** garbage-collection function and options diff --git a/include/luaconf.h b/include/luaconf.h index 56567c008a..7ef4cedfb9 100644 --- a/include/luaconf.h +++ b/include/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.11 2004/08/30 18:35:14 roberto Exp $ +** $Id: luaconf.h,v 1.12 2004/09/10 17:30:46 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -60,7 +60,7 @@ #define LUA_FIRSTINDEX 1 /* assertions in Lua (mainly for internal debugging) */ -#define lua_assert(c) /* empty */ +#define lua_assert(c) ((void)0) /* }====================================================== */ @@ -123,7 +123,7 @@ #ifdef LUA_CORE /* LUA-C API assertions */ -#define api_check(L, o) /* empty */ +#define api_check(L, o) lua_assert(o) /* an unsigned integer with at least 32 bits */ diff --git a/src/lapi.c b/src/lapi.c index eb2c266ea8..ce32f3b083 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.18 2004/08/30 13:44:44 roberto Exp $ +** $Id: lapi.c,v 2.19 2004/09/15 20:39:42 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -97,6 +97,7 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { if (from == to) return; lua_lock(to); api_checknelems(from, n); + api_check(L, G(from) == G(to)); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top, from->top + i); @@ -479,6 +480,15 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { } +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + /* ** get functions (Lua -> stack) @@ -650,7 +660,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) - luaC_objbarrier(L, hvalue(obj), mt); + luaC_objbarriert(L, hvalue(obj), mt); break; } case LUA_TUSERDATA: { @@ -816,6 +826,11 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { } +LUA_API int lua_threadstatus (lua_State *L) { + return L->status; +} + + /* ** Garbage-collection function */ diff --git a/src/ldo.c b/src/ldo.c index 46ad459a32..ad9cbc3d29 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.7 2004/06/02 19:07:55 roberto Exp $ +** $Id: ldo.c,v 2.10 2004/09/15 20:39:42 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -93,7 +93,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { static void restore_stack_limit (lua_State *L) { - L->stack_last = L->stack+L->stacksize-1; + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */ int inuse = (L->ci - L->base_ci); if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */ @@ -121,9 +121,11 @@ static void correctstack (lua_State *L, TValue *oldstack) { void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; - luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); - L->stacksize = newsize; - L->stack_last = L->stack+newsize-1-EXTRA_STACK; + int realsize = newsize + 1 + EXTRA_STACK; + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); + L->stacksize = realsize; + L->stack_last = L->stack+newsize; correctstack(L, oldstack); } @@ -133,7 +135,7 @@ void luaD_reallocCI (lua_State *L, int newsize) { luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); L->size_ci = cast(unsigned short, newsize); L->ci = (L->ci - oldci) + L->base_ci; - L->end_ci = L->base_ci + L->size_ci; + L->end_ci = L->base_ci + L->size_ci - 1; } @@ -141,11 +143,11 @@ void luaD_growstack (lua_State *L, int n) { if (n <= L->stacksize) /* double size is enough? */ luaD_reallocstack(L, 2*L->stacksize); else - luaD_reallocstack(L, L->stacksize + n + EXTRA_STACK); + luaD_reallocstack(L, L->stacksize + n); } -static void luaD_growCI (lua_State *L) { +static CallInfo *luaD_growCI (lua_State *L) { if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */ luaD_throw(L, LUA_ERRERR); else { @@ -153,6 +155,7 @@ static void luaD_growCI (lua_State *L) { if (L->size_ci > LUA_MAXCALLS) luaG_runerror(L, "stack overflow"); } + return ++L->ci; } @@ -170,6 +173,7 @@ void luaD_callhook (lua_State *L, int event, int line) { ar.i_ci = L->ci - L->base_ci; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; + lua_assert(L->ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ lua_unlock(L); (*hook)(L, &ar); @@ -193,6 +197,7 @@ static StkId adjust_varargs (lua_State *L, int nfixargs, int actual, } if (style != NEWSTYLEVARARG) { /* compatibility with old-style vararg */ int nvar = actual - nfixargs; /* number of extra arguments */ + luaC_checkGC(L); htab = luaH_new(L, nvar, 1); /* create `arg' table */ for (i=0; itop - nvar + i); @@ -231,31 +236,39 @@ static StkId tryfuncTM (lua_State *L, StkId func) { } + +#define inc_ci(L) \ + ((L->ci == L->end_ci) ? luaD_growCI(L) : \ + (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) + + int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); - if (L->ci + 1 == L->end_ci) luaD_growCI(L); - else condhardstacktests(luaD_reallocCI(L, L->size_ci)); cl = &clvalue(func)->l; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; StkId st, base; Proto *p = cl->p; - luaD_checkstack(L, p->maxstacksize); - func = restorestack(L, funcr); if (p->is_vararg) { /* varargs? */ - int nargs = L->top - func - 1; + int nargs = L->top - restorestack(L, funcr) - 1; + luaD_checkstack(L, p->maxstacksize + nargs); base = adjust_varargs(L, p->numparams, nargs, p->is_vararg); + func = restorestack(L, funcr); } - else + else { + luaD_checkstack(L, p->maxstacksize); + func = restorestack(L, funcr); base = func + 1; - ci = ++L->ci; /* now `enter' new function */ + } + ci = inc_ci(L); /* now `enter' new function */ ci->func = func; L->base = ci->base = base; ci->top = L->base + p->maxstacksize; + lua_assert(ci->top <= L->stack_last); ci->savedpc = p->code; /* starting point */ ci->tailcalls = 0; ci->nresults = nresults; @@ -268,10 +281,11 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = ++L->ci; /* now `enter' new function */ + ci = inc_ci(L); /* now `enter' new function */ ci->func = restorestack(L, funcr); L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); @@ -344,7 +358,7 @@ static void resume (lua_State *L, void *ud) { StkId firstResult; int nargs = *cast(int *, ud); CallInfo *ci = L->ci; - if (!L->isSuspended) { + if (L->status != LUA_YIELD) { lua_assert(ci == L->base_ci && nargs < L->top - L->base); luaD_precall(L, L->top - (nargs + 1), LUA_MULTRET); /* start coroutine */ } @@ -358,10 +372,11 @@ static void resume (lua_State *L, void *ud) { if (nresults >= 0) L->top = L->ci->top; } /* else yielded inside a hook: just continue its execution */ } - L->isSuspended = 0; + L->status = 0; firstResult = luaV_execute(L, L->ci - L->base_ci); - if (firstResult != NULL) /* return? */ + if (firstResult != NULL) { /* return? */ luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ + } } @@ -379,25 +394,20 @@ LUA_API int lua_resume (lua_State *L, int nargs) { lu_byte old_allowhooks; lua_lock(L); lua_assert(L->errfunc == 0 && L->nCcalls == 0); - if (!L->isSuspended) { - if (L->ci == L->base_ci) { /* no activation record? */ - if (nargs >= L->top - L->base) - return resume_error(L, "cannot resume dead coroutine"); - } - else + if (L->status != LUA_YIELD) { + if (L->status != 0) + return resume_error(L, "cannot resume dead coroutine"); + else if (L->ci != L->base_ci) return resume_error(L, "cannot resume non-suspended coroutine"); } old_allowhooks = L->allowhook; status = luaD_rawrunprotected(L, resume, &nargs); if (status != 0) { /* error? */ - L->ci = L->base_ci; /* go back to initial level */ - L->base = L->ci->base; - L->nCcalls = 0; - luaF_close(L, L->base); /* close eventual pending closures */ - seterrorobj(L, status, L->base); - L->allowhook = old_allowhooks; - restore_stack_limit(L); + L->status = status; /* mark thread as `dead' */ + seterrorobj(L, status, L->top); } + else + status = L->status; lua_unlock(L); return status; } @@ -417,7 +427,7 @@ LUA_API int lua_yield (lua_State *L, int nresults) { L->top = L->base + nresults; } } /* else it's an yield inside a hook: nothing to do */ - L->isSuspended = 1; + L->status = LUA_YIELD; lua_unlock(L); return -1; } diff --git a/src/ldo.h b/src/ldo.h index d4072b6005..ff5b652c36 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.2 2004/05/14 19:25:09 roberto Exp $ +** $Id: ldo.h,v 2.3 2004/09/08 14:23:09 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -17,7 +17,7 @@ ** macro to control inclusion of some hard tests on stack reallocation */ #ifndef HARDSTACKTESTS -#define condhardstacktests(x) { /* empty */ } +#define condhardstacktests(x) ((void)0) #else #define condhardstacktests(x) x #endif @@ -26,7 +26,7 @@ #define luaD_checkstack(L,n) \ if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ luaD_growstack(L, n); \ - else condhardstacktests(luaD_reallocstack(L, L->stacksize)); + else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); #define incr_top(L) {luaD_checkstack(L,1); L->top++;} diff --git a/src/lgc.c b/src/lgc.c index 67a5f1f607..b3661fd7a1 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.10 2004/08/30 13:44:44 roberto Exp $ +** $Id: lgc.c,v 2.12 2004/09/15 20:38:15 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -239,14 +239,17 @@ static void traverseclosure (global_State *g, Closure *cl) { static void checkstacksizes (lua_State *L, StkId max) { - int used = L->ci - L->base_ci; /* number of `ci' in use */ - if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) + int ci_used = L->ci - L->base_ci; /* number of `ci' in use */ + int s_used = max - L->stack; /* part of stack in use */ + if (L->size_ci > LUA_MAXCALLS) /* handling overflow? */ + return; /* do not touch the stacks */ + if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ - else condhardstacktests(luaD_reallocCI(L, L->size_ci)); - used = max - L->stack; /* part of stack in use */ - if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) + condhardstacktests(luaD_reallocCI(L, ci_used + 1)); + if (4*s_used < L->stacksize && + 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ - else condhardstacktests(luaD_reallocstack(L, L->stacksize)); + condhardstacktests(luaD_reallocstack(L, s_used)); } @@ -496,7 +499,7 @@ void luaC_freeall (lua_State *L) { /* mark root set */ static void markroot (lua_State *L) { global_State *g = G(L); - lua_assert(g->gray == NULL); + g->gray = NULL; g->grayagain = NULL; g->weak = NULL; markobject(g, g->mainthread); @@ -510,6 +513,7 @@ static void markroot (lua_State *L) { static void remarkupvals (global_State *g) { GCObject *o; for (o = obj2gco(g->mainthread); o; o = o->gch.next) { + lua_assert(!isblack(o)); if (iswhite(o)) { GCObject *curr; for (curr = gco2th(o)->openupval; curr != NULL; curr = curr->gch.next) { @@ -526,7 +530,8 @@ static void remarkupvals (global_State *g) { static void atomic (lua_State *L) { global_State *g = G(L); int aux; - lua_assert(g->gray == NULL); + /* remark objects cautch by write barrier */ + propagateall(g); /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); /* remark weak tables */ @@ -666,10 +671,12 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(g->gcgenerational || g->gcstate != GCSfinalize); - if (g->gcstate != GCSpropagate) /* sweeping phases? */ - black2gray(o); /* just mark as gray to avoid other barriers */ - else /* breaking invariant! */ - reallymarkobject(g, v); /* restore it */ + lua_assert(ttype(&o->gch) != LUA_TTABLE); + /* must keep invariant? */ + if (g->gcstate == GCSpropagate || g->gcgenerational) + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ + makewhite(g, o); /* mark as white just to avoid other barriers */ } diff --git a/src/lgc.h b/src/lgc.h index 47a5e932a2..81f6da5f81 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.8 2004/08/30 13:44:44 roberto Exp $ +** $Id: lgc.h,v 2.9 2004/09/15 20:38:15 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -86,6 +86,10 @@ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),obj2gco(o)); } +#define luaC_objbarriert(L,p,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ + luaC_barrierback(L,obj2gco(p),obj2gco(o)); } + size_t luaC_separateudata (lua_State *L, int all); void luaC_callGCTM (lua_State *L); void luaC_freeall (lua_State *L); diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c index cd4e75f820..7c14d001c3 100644 --- a/src/lib/lauxlib.c +++ b/src/lib/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.123 2004/08/30 18:35:14 roberto Exp $ +** $Id: lauxlib.c,v 1.124 2004/09/03 13:17:14 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -632,6 +632,7 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; + (void)osize; if (nsize == 0) { free(ptr); return NULL; diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index f734f35838..82a8f509cc 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.156 2004/08/30 18:35:14 roberto Exp $ +** $Id: lbaselib.c,v 1.158 2004/09/15 20:39:42 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -273,25 +273,25 @@ static int luaB_loadfile (lua_State *L) { } -struct Aux_load { - int func; - int res; -}; - - +/* +** Reader for generic `load' function: `lua_load' uses the +** stack for internal stuff, so the reader cannot change the +** stack top. Instead, it keeps its resulting string in a +** reserved slot inside the stack. +*/ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { - struct Aux_load *al = (struct Aux_load *)ud; - luaL_unref(L, al->res, LUA_REGISTRYINDEX); - lua_getref(L, al->func); - lua_call(L, 0, 1); + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { *size = 0; return NULL; } else if (lua_isstring(L, -1)) { - const char *res = lua_tostring(L, -1); - *size = lua_strlen(L, -1); - al->res = luaL_ref(L, LUA_REGISTRYINDEX); + const char *res; + lua_replace(L, 3); /* save string in a reserved stack slot */ + res = lua_tostring(L, 3); + *size = lua_strlen(L, 3); return res; } else luaL_error(L, "reader function must return a string"); @@ -300,16 +300,11 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { static int luaB_load (lua_State *L) { - struct Aux_load al; int status; const char *cname = luaL_optstring(L, 2, "=(load)"); luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 1); - al.func = luaL_ref(L, LUA_REGISTRYINDEX); - al.res = LUA_REFNIL; - status = lua_load(L, generic_reader, &al, cname); - luaL_unref(L, al.func, LUA_REGISTRYINDEX); - luaL_unref(L, al.res, LUA_REGISTRYINDEX); + lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ + status = lua_load(L, generic_reader, NULL, cname); return load_aux(L, status); } @@ -528,9 +523,13 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); + if (lua_threadstatus(co) == 0 && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); + return -1; /* error flag */ + } lua_xmove(L, co, narg); status = lua_resume(co, narg); - if (status == 0) { + if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres)) luaL_error(L, "too many results to resume"); @@ -604,22 +603,44 @@ static int luaB_costatus (lua_State *L) { luaL_argcheck(L, co, 1, "coroutine expected"); if (L == co) lua_pushliteral(L, "running"); else { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) == 0 && lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); + switch (lua_threadstatus(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case 0: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occured */ + lua_pushliteral(L, "dead"); + break; + } } return 1; } +static int luaB_cocurrent (lua_State *L) { + if (lua_pushthread(L)) + return 0; /* main thread is not a coroutine */ + else + return 1; +} + + static const luaL_reg co_funcs[] = { {"create", luaB_cocreate}, {"wrap", luaB_cowrap}, {"resume", luaB_coresume}, {"yield", luaB_yield}, {"status", luaB_costatus}, + {"current", luaB_cocurrent}, {NULL, NULL} }; diff --git a/src/llimits.h b/src/llimits.h index ea0caf7bd1..95a51a0b90 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.59 2004/06/23 15:57:29 roberto Exp $ +** $Id: llimits.h,v 1.60 2004/09/10 17:30:46 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -63,9 +63,7 @@ typedef LUSER_ALIGNMENT_T L_Umaxalign; typedef LUA_UACNUMBER l_uacNumber; -#ifndef check_exp -#define check_exp(c,e) (e) -#endif +#define check_exp(c,e) (lua_assert(c), (e)) #ifndef UNUSED diff --git a/src/lstate.c b/src/lstate.c index e0a439b1da..9f55f997d4 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.12 2004/08/30 13:44:44 roberto Exp $ +** $Id: lstate.c,v 2.14 2004/09/15 20:39:42 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -62,7 +62,7 @@ static void stack_init (lua_State *L1, lua_State *L) { L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; L1->size_ci = BASIC_CI_SIZE; - L1->end_ci = L1->base_ci + L1->size_ci; + L1->end_ci = L1->base_ci + L1->size_ci - 1; } @@ -114,7 +114,7 @@ static void preinit_state (lua_State *L, global_State *g) { L->openupval = NULL; L->size_ci = 0; L->nCcalls = 0; - L->isSuspended = 0; + L->status = 0; L->base_ci = L->ci = NULL; L->errfunc = 0; setnilvalue(gt(L)); diff --git a/src/lstate.h b/src/lstate.h index 0a178fefc6..d7583d279b 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.7 2004/08/30 13:44:44 roberto Exp $ +** $Id: lstate.h,v 2.8 2004/09/15 20:39:42 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -111,7 +111,7 @@ struct lua_State { unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; - lu_byte isSuspended; + lu_byte status; int basehookcount; int hookcount; lua_Hook hook; diff --git a/src/lua/README b/src/lua/README index 1bd07af6e7..525f6c1544 100644 --- a/src/lua/README +++ b/src/lua/README @@ -8,13 +8,19 @@ Usage: lua [options] [script [args]]. Available options are: -i enter interactive mode after executing `script' -l name load and run library `name' -v show version information + -w catch use of undefined global variables -- stop handling options This interpreter is suitable for using Lua as a stand-alone language; it loads all standard libraries. For a minimal interpreter, see ../../etc/min.c. If your application simply exports new functions to Lua (which is common), -then you can use this interpreter (almost) unmodified, as follows: +then you can use this interpreter unmodified by putting your functions into +a library and loading it dynamically (if you have built support for dynamic +libraries). + +If you need to add your library statically, then you can use this interpreter +almost unmodified, as follows: * First, define a function void myinit (lua_State *L) @@ -22,11 +28,14 @@ then you can use this interpreter (almost) unmodified, as follows: are needed by your application, typically exporting your functions to Lua. (Of course, you can use any name instead of "myinit".) -* Then, #define lua_userinit(L) to be "openstdlibs(L)+myinit(L)". - Here, openstdlibs is a function in lua.c that opens all standard libraries. - If you don't need them, just don't call openstdlibs and open any standard - libraries that you do need in myinit. +* Then, #define lua_userinit(L) in luaconf.h to call luaopen_stdlibs and + possibly luaopen_stdlibs, which opens all standard libraries. If you don't + need them, just don't call openstdlibs and open any standard libraries that + you do need in myinit. + +* Alternatively, write your own luaopen_stdlibs; the linker will use your + version (if you ask politely). -* Finally, remember to link your C code when building lua. +Just remember to link your C code when building lua! -For other customizations, see ../../etc/config.c. +For other customizations, see ../../include/luaconf.h . diff --git a/src/lvm.c b/src/lvm.c index 05af9df156..94f98147e4 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.13 2004/08/12 14:19:51 roberto Exp $ +** $Id: lvm.c,v 2.14 2004/09/15 20:39:42 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -398,7 +398,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); /***/ - if (L->isSuspended) { /* did hook yield? */ + if (L->status == LUA_YIELD) { /* did hook yield? */ L->ci->savedpc = pc - 1; return NULL; } From 226f7859b5392b6680b7e703f9cc7f7f101fd365 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 7 Dec 2004 12:00:00 +0000 Subject: [PATCH 20/97] Lua 5.1-work3 --- INSTALL | 2 +- MANIFEST | 227 +++++++++++++------------- Makefile | 27 +-- README | 5 +- config | 6 +- etc/all.c | 1 - etc/lua.hpp | 8 + etc/min.c | 1 + include/lauxlib.h | 22 ++- include/lua.h | 46 +++--- include/luaconf.h | 110 +++++++++---- src/lapi.c | 94 ++++++----- src/lcode.c | 77 ++++++--- src/lcode.h | 3 +- src/ldebug.c | 23 ++- src/ldo.c | 12 +- src/ldump.c | 9 +- src/lfunc.c | 8 +- src/lgc.c | 50 +++--- src/lib/lauxlib.c | 78 +++++++-- src/lib/lbaselib.c | 76 ++------- src/lib/ldblib.c | 9 +- src/lib/loadlib.c | 397 ++++++++++++++++++++++++++++++++++++--------- src/lib/loslib.c | 8 +- src/lib/lstrlib.c | 50 +++--- src/llex.c | 76 +++++---- src/llex.h | 10 +- src/llimits.h | 23 +-- src/lmem.c | 25 +-- src/lmem.h | 38 +++-- src/lobject.c | 23 ++- src/lobject.h | 22 ++- src/lopcodes.c | 11 +- src/lopcodes.h | 18 +- src/lparser.c | 35 ++-- src/lstate.c | 10 +- src/lstate.h | 4 +- src/lstring.c | 13 +- src/lstring.h | 7 +- src/ltable.c | 85 +++++----- src/ltable.h | 5 +- src/lua/lua.c | 8 +- src/luac/print.c | 13 +- src/lundump.c | 21 ++- src/lundump.h | 12 +- src/lvm.c | 37 ++--- 46 files changed, 1107 insertions(+), 738 deletions(-) create mode 100644 etc/lua.hpp diff --git a/INSTALL b/INSTALL index 9d4893012c..228be50f59 100644 --- a/INSTALL +++ b/INSTALL @@ -32,7 +32,7 @@ This is Lua 5.1 (work). * If you have problems (and solutions!) ------------------------------------- - If "make" fails, please let us know (lua@tecgraf.puc-rio.br). + If "make" fails, please let us know. If you make changes to "config" or to the Makefiles, please send them to us. * Shared libraries diff --git a/MANIFEST b/MANIFEST index 7c81b9342d..494d432851 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,114 +1,115 @@ -MANIFEST contents of Lua 5.1 (work2) distribution on Mon Sep 20 21:28:06 BRT 2004 -lua-5.1-work2 -lua-5.1-work2/COPYRIGHT -lua-5.1-work2/HISTORY -lua-5.1-work2/INSTALL -lua-5.1-work2/MANIFEST -lua-5.1-work2/Makefile -lua-5.1-work2/README -lua-5.1-work2/bin -lua-5.1-work2/build -lua-5.1-work2/config -lua-5.1-work2/etc -lua-5.1-work2/etc/Makefile -lua-5.1-work2/etc/README -lua-5.1-work2/etc/all.c -lua-5.1-work2/etc/lua.ico -lua-5.1-work2/etc/min.c -lua-5.1-work2/etc/noparser.c -lua-5.1-work2/etc/saconfig.c -lua-5.1-work2/include -lua-5.1-work2/include/Makefile -lua-5.1-work2/include/lauxlib.h -lua-5.1-work2/include/lua.h -lua-5.1-work2/include/luaconf.h -lua-5.1-work2/include/lualib.h -lua-5.1-work2/lib -lua-5.1-work2/src -lua-5.1-work2/src/Makefile -lua-5.1-work2/src/README -lua-5.1-work2/src/lapi.c -lua-5.1-work2/src/lapi.h -lua-5.1-work2/src/lcode.c -lua-5.1-work2/src/lcode.h -lua-5.1-work2/src/ldebug.c -lua-5.1-work2/src/ldebug.h -lua-5.1-work2/src/ldo.c -lua-5.1-work2/src/ldo.h -lua-5.1-work2/src/ldump.c -lua-5.1-work2/src/lfunc.c -lua-5.1-work2/src/lfunc.h -lua-5.1-work2/src/lgc.c -lua-5.1-work2/src/lgc.h -lua-5.1-work2/src/lib -lua-5.1-work2/src/lib/Makefile -lua-5.1-work2/src/lib/README -lua-5.1-work2/src/lib/lauxlib.c -lua-5.1-work2/src/lib/lbaselib.c -lua-5.1-work2/src/lib/ldblib.c -lua-5.1-work2/src/lib/linit.c -lua-5.1-work2/src/lib/liolib.c -lua-5.1-work2/src/lib/lmathlib.c -lua-5.1-work2/src/lib/loadlib.c -lua-5.1-work2/src/lib/loslib.c -lua-5.1-work2/src/lib/lstrlib.c -lua-5.1-work2/src/lib/ltablib.c -lua-5.1-work2/src/llex.c -lua-5.1-work2/src/llex.h -lua-5.1-work2/src/llimits.h -lua-5.1-work2/src/lmem.c -lua-5.1-work2/src/lmem.h -lua-5.1-work2/src/lobject.c -lua-5.1-work2/src/lobject.h -lua-5.1-work2/src/lopcodes.c -lua-5.1-work2/src/lopcodes.h -lua-5.1-work2/src/lparser.c -lua-5.1-work2/src/lparser.h -lua-5.1-work2/src/lstate.c -lua-5.1-work2/src/lstate.h -lua-5.1-work2/src/lstring.c -lua-5.1-work2/src/lstring.h -lua-5.1-work2/src/ltable.c -lua-5.1-work2/src/ltable.h -lua-5.1-work2/src/ltm.c -lua-5.1-work2/src/ltm.h -lua-5.1-work2/src/lua -lua-5.1-work2/src/lua/Makefile -lua-5.1-work2/src/lua/README -lua-5.1-work2/src/lua/lua.c -lua-5.1-work2/src/luac -lua-5.1-work2/src/luac/Makefile -lua-5.1-work2/src/luac/README -lua-5.1-work2/src/luac/luac.c -lua-5.1-work2/src/luac/print.c -lua-5.1-work2/src/lundump.c -lua-5.1-work2/src/lundump.h -lua-5.1-work2/src/lvm.c -lua-5.1-work2/src/lvm.h -lua-5.1-work2/src/lzio.c -lua-5.1-work2/src/lzio.h -lua-5.1-work2/test -lua-5.1-work2/test/README -lua-5.1-work2/test/bisect.lua -lua-5.1-work2/test/cf.lua -lua-5.1-work2/test/echo.lua -lua-5.1-work2/test/env.lua -lua-5.1-work2/test/factorial.lua -lua-5.1-work2/test/fib.lua -lua-5.1-work2/test/fibfor.lua -lua-5.1-work2/test/globals.lua -lua-5.1-work2/test/hello.lua -lua-5.1-work2/test/life.lua -lua-5.1-work2/test/lua -lua-5.1-work2/test/luac -lua-5.1-work2/test/luac.lua -lua-5.1-work2/test/printf.lua -lua-5.1-work2/test/readonly.lua -lua-5.1-work2/test/sieve.lua -lua-5.1-work2/test/sort.lua -lua-5.1-work2/test/table.lua -lua-5.1-work2/test/trace-calls.lua -lua-5.1-work2/test/trace-globals.lua -lua-5.1-work2/test/undefined.lua -lua-5.1-work2/test/xd.lua +MANIFEST contents of Lua 5.1 (work3) distribution on Mon Dec 6 23:00:22 BRST 2004 +lua-5.1-work3 +lua-5.1-work3/COPYRIGHT +lua-5.1-work3/HISTORY +lua-5.1-work3/INSTALL +lua-5.1-work3/MANIFEST +lua-5.1-work3/Makefile +lua-5.1-work3/README +lua-5.1-work3/bin +lua-5.1-work3/build +lua-5.1-work3/config +lua-5.1-work3/etc +lua-5.1-work3/etc/Makefile +lua-5.1-work3/etc/README +lua-5.1-work3/etc/all.c +lua-5.1-work3/etc/lua.hpp +lua-5.1-work3/etc/lua.ico +lua-5.1-work3/etc/min.c +lua-5.1-work3/etc/noparser.c +lua-5.1-work3/etc/saconfig.c +lua-5.1-work3/include +lua-5.1-work3/include/Makefile +lua-5.1-work3/include/lauxlib.h +lua-5.1-work3/include/lua.h +lua-5.1-work3/include/luaconf.h +lua-5.1-work3/include/lualib.h +lua-5.1-work3/lib +lua-5.1-work3/src +lua-5.1-work3/src/Makefile +lua-5.1-work3/src/README +lua-5.1-work3/src/lapi.c +lua-5.1-work3/src/lapi.h +lua-5.1-work3/src/lcode.c +lua-5.1-work3/src/lcode.h +lua-5.1-work3/src/ldebug.c +lua-5.1-work3/src/ldebug.h +lua-5.1-work3/src/ldo.c +lua-5.1-work3/src/ldo.h +lua-5.1-work3/src/ldump.c +lua-5.1-work3/src/lfunc.c +lua-5.1-work3/src/lfunc.h +lua-5.1-work3/src/lgc.c +lua-5.1-work3/src/lgc.h +lua-5.1-work3/src/lib +lua-5.1-work3/src/lib/Makefile +lua-5.1-work3/src/lib/README +lua-5.1-work3/src/lib/lauxlib.c +lua-5.1-work3/src/lib/lbaselib.c +lua-5.1-work3/src/lib/ldblib.c +lua-5.1-work3/src/lib/linit.c +lua-5.1-work3/src/lib/liolib.c +lua-5.1-work3/src/lib/lmathlib.c +lua-5.1-work3/src/lib/loadlib.c +lua-5.1-work3/src/lib/loslib.c +lua-5.1-work3/src/lib/lstrlib.c +lua-5.1-work3/src/lib/ltablib.c +lua-5.1-work3/src/llex.c +lua-5.1-work3/src/llex.h +lua-5.1-work3/src/llimits.h +lua-5.1-work3/src/lmem.c +lua-5.1-work3/src/lmem.h +lua-5.1-work3/src/lobject.c +lua-5.1-work3/src/lobject.h +lua-5.1-work3/src/lopcodes.c +lua-5.1-work3/src/lopcodes.h +lua-5.1-work3/src/lparser.c +lua-5.1-work3/src/lparser.h +lua-5.1-work3/src/lstate.c +lua-5.1-work3/src/lstate.h +lua-5.1-work3/src/lstring.c +lua-5.1-work3/src/lstring.h +lua-5.1-work3/src/ltable.c +lua-5.1-work3/src/ltable.h +lua-5.1-work3/src/ltm.c +lua-5.1-work3/src/ltm.h +lua-5.1-work3/src/lua +lua-5.1-work3/src/lua/Makefile +lua-5.1-work3/src/lua/README +lua-5.1-work3/src/lua/lua.c +lua-5.1-work3/src/luac +lua-5.1-work3/src/luac/Makefile +lua-5.1-work3/src/luac/README +lua-5.1-work3/src/luac/luac.c +lua-5.1-work3/src/luac/print.c +lua-5.1-work3/src/lundump.c +lua-5.1-work3/src/lundump.h +lua-5.1-work3/src/lvm.c +lua-5.1-work3/src/lvm.h +lua-5.1-work3/src/lzio.c +lua-5.1-work3/src/lzio.h +lua-5.1-work3/test +lua-5.1-work3/test/README +lua-5.1-work3/test/bisect.lua +lua-5.1-work3/test/cf.lua +lua-5.1-work3/test/echo.lua +lua-5.1-work3/test/env.lua +lua-5.1-work3/test/factorial.lua +lua-5.1-work3/test/fib.lua +lua-5.1-work3/test/fibfor.lua +lua-5.1-work3/test/globals.lua +lua-5.1-work3/test/hello.lua +lua-5.1-work3/test/life.lua +lua-5.1-work3/test/lua +lua-5.1-work3/test/luac +lua-5.1-work3/test/luac.lua +lua-5.1-work3/test/printf.lua +lua-5.1-work3/test/readonly.lua +lua-5.1-work3/test/sieve.lua +lua-5.1-work3/test/sort.lua +lua-5.1-work3/test/table.lua +lua-5.1-work3/test/trace-calls.lua +lua-5.1-work3/test/trace-globals.lua +lua-5.1-work3/test/undefined.lua +lua-5.1-work3/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index 1939243574..d6e04bd81a 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,6 @@ all clean co klean: cd src/luac; $(MAKE) $@ cd src/lua; $(MAKE) $@ -clean klean: soclean - # in case they were not created during unpacking all: bin lib @@ -38,27 +36,6 @@ install: all strip $(INSTALL_DATA) lib/*.a $(INSTALL_LIB) $(INSTALL_DATA) doc/*.1 $(INSTALL_MAN) -# shared libraries (for Linux) -so: - ld -o lib/liblua.so.$V -shared src/*.o - ld -o lib/liblualib.so.$V -shared src/lib/*.o - cd lib; ln -fs liblua.so.$V liblua.so; ln -fs liblualib.so.$V liblualib.so - -# binaries using shared libraries -sobin: - rm -f bin/lua* - cd src/lua; $(MAKE) - cd src/luac; $(MAKE) - -# install shared libraries -soinstall: - $(INSTALL_EXEC) lib/*.so.* $(INSTALL_LIB) - cd $(INSTALL_LIB); ln -fs liblua.so.$V liblua.so; ln -fs liblualib.so.$V liblualib.so - -# clean shared libraries -soclean: - rm -f lib/*.so* bin/lua* - # echo config parameters echo: @echo "" @@ -98,7 +75,7 @@ lecho: @make echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' @echo "-- EOF" -# (end of Makefile) - newer: @find . -newer MANIFEST -type f + +# (end of Makefile) diff --git a/README b/README index 8f4aa49ac2..7c5b0b7649 100644 --- a/README +++ b/README @@ -29,9 +29,10 @@ See HISTORY for a summary of changes since the last released version. * Contacting the authors ---------------------- - Send your comments, questions, and bug reports to lua@tecgraf.puc-rio.br. + Send your comments, questions, and bug reports to + lua-team AT tecgraf.puc-rio.br. For more information about the authors, see http://www.lua.org/authors.html . - For reporting bugs, try also the mailing list: lua-l@tecgraf.puc-rio.br. + For reporting bugs, try also the mailing list: lua@bazar2.conectiva.com.br . For more information about this list, including instructions on how to subscribe and access the archives, see http://www.lua.org/lua-l.html . diff --git a/config b/config index fe39c134f4..75ae76f115 100644 --- a/config +++ b/config @@ -21,15 +21,15 @@ USERCONF= # interface (e.g., Linux, Solaris, IRIX, BSD, AIX, HPUX, and probably others), # uncomment the next two lines. Also read the next paragraph. # -#LOADLIB= -DUSE_DLOPEN=1 -#DLLIB= -ldl +LOADLIB= -DUSE_DLOPEN=1 +DLLIB= -ldl # # In Linux with gcc, you should also uncomment the next definition for # MYLDFLAGS, which passes -E (= -export-dynamic) to the linker. This option # allows dynamic libraries to link back to the `lua' program, so that they do # not need the Lua libraries. (Other systems may have an equivalent facility.) # -#MYLDFLAGS= -Wl,-E +MYLDFLAGS= -Wl,-E # # On Windows systems. support for dynamic loading is enabled by default. # To disable this support, uncomment the next line. diff --git a/etc/all.c b/etc/all.c index fc4b045a89..720be1b255 100644 --- a/etc/all.c +++ b/etc/all.c @@ -33,7 +33,6 @@ #include "linit.c" #include "lmathlib.c" #include "loadlib.c" -#define pushresult pushresult2 #include "loslib.c" #include "lstrlib.c" #include "ltablib.c" diff --git a/etc/lua.hpp b/etc/lua.hpp new file mode 100644 index 0000000000..273ec44ca3 --- /dev/null +++ b/etc/lua.hpp @@ -0,0 +1,8 @@ +// lua.hpp +// Lua header files for C++ + +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} diff --git a/etc/min.c b/etc/min.c index dfcc805a27..b1200c05c0 100644 --- a/etc/min.c +++ b/etc/min.c @@ -43,5 +43,6 @@ int main(void) lua_register(L,"print",print); if (lua_load(L,getF,stdin,"=stdin") || lua_pcall(L,0,0,0)) fprintf(stderr,"%s\n",lua_tostring(L,-1)); + lua_close(L); return 0; } diff --git a/include/lauxlib.h b/include/lauxlib.h index 22afc245b9..b47663ced7 100644 --- a/include/lauxlib.h +++ b/include/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.70 2004/07/09 18:23:17 roberto Exp $ +** $Id: lauxlib.h,v 1.73 2004/10/18 12:51:44 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -70,6 +70,12 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, LUALIB_API lua_State *(luaL_newstate) (void); +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r); +LUALIB_API const char *luaL_getfield (lua_State *L, int idx, const char *fname); +LUALIB_API const char *luaL_setfield (lua_State *L, int idx, const char *fname); + + /* ** =============================================================== @@ -78,15 +84,15 @@ LUALIB_API lua_State *(luaL_newstate) (void); */ #define luaL_argcheck(L, cond,numarg,extramsg) \ - ((void)((cond) || luaL_argerror(L, numarg,extramsg))) + ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) -#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, n)) -#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, n,d)) -#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, n)) -#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, n,d)) +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) -#define luaL_typename(L,i) lua_typename(L,lua_type(L,(i))) +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) /* ** {====================================================== @@ -131,7 +137,7 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B); #define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) -#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, ref) +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) #endif diff --git a/include/lua.h b/include/lua.h index ac5435e723..aa4401c720 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.193 2004/09/15 20:39:42 roberto Exp $ +** $Id: lua.h,v 1.196 2004/12/06 17:53:42 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -17,7 +17,7 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (work2)" +#define LUA_VERSION "Lua 5.1 (work3)" #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -81,6 +81,10 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); #define LUA_TTHREAD 8 +/* first index for arrays */ +#define LUA_FIRSTINDEX 1 + + /* minimum Lua stack available to a C function */ #define LUA_MINSTACK 20 @@ -216,11 +220,13 @@ LUA_API int lua_threadstatus (lua_State *L); ** garbage-collection function and options */ -#define LUA_GCSTOP 0 -#define LUA_GCRESTART 1 -#define LUA_GCCOLLECT 2 -#define LUA_GCCOUNT 3 -#define LUA_GCSTEP 4 +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCSTEP 4 +#define LUA_GCSETSTEPMUL 5 +#define LUA_GCSETINCMODE 6 LUA_API int lua_gc (lua_State *L, int what, int data); @@ -251,26 +257,26 @@ LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud); #define lua_newtable(L) lua_createtable(L, 0, 0) -#define lua_register(L,n,f) (lua_pushcfunction(L,f), lua_setglobal(L,n)) +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) -#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) -#define lua_strlen(L,i) lua_objsize(L,i) +#define lua_strlen(L,i) lua_objsize(L, (i)) -#define lua_isfunction(L,n) (lua_type(L,n) == LUA_TFUNCTION) -#define lua_istable(L,n) (lua_type(L,n) == LUA_TTABLE) -#define lua_islightuserdata(L,n) (lua_type(L,n) == LUA_TLIGHTUSERDATA) -#define lua_isnil(L,n) (lua_type(L,n) == LUA_TNIL) -#define lua_isboolean(L,n) (lua_type(L,n) == LUA_TBOOLEAN) -#define lua_isthread(L,n) (lua_type(L,n) == LUA_TTHREAD) -#define lua_isnone(L,n) (lua_type(L,n) == LUA_TNONE) -#define lua_isnoneornil(L, n) (lua_type(L,n) <= 0) +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) #define lua_pushliteral(L, s) \ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) -#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, s) -#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s) +#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) diff --git a/include/luaconf.h b/include/luaconf.h index 7ef4cedfb9..f00bbd0577 100644 --- a/include/luaconf.h +++ b/include/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.12 2004/09/10 17:30:46 roberto Exp $ +** $Id: luaconf.h,v 1.20 2004/12/06 17:53:42 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -31,7 +31,11 @@ */ /* default path */ -#define LUA_PATH_DEFAULT "?;?.lua" +#define LUA_PATH_DEFAULT \ + "./?.lua;/usr/local/share/lua/5.0/?.lua;/usr/local/share/lua/5.0/?/init.lua" +#define LUA_CPATH_DEFAULT \ + "./?.so;/usr/local/lib/lua/5.0/?.so;/usr/local/lib/lua/5.0/lib?.so" + /* type of numbers in Lua */ @@ -42,8 +46,11 @@ #define LUA_NUMBER_FMT "%.14g" -/* type for integer functions */ -#define LUA_INTEGER long +/* +** type for integer functions +** on most machines, `ptrdiff_t' gives a reasonable size for integers +*/ +#define LUA_INTEGER ptrdiff_t /* mark for all API functions */ @@ -56,9 +63,6 @@ #define LUAL_BUFFERSIZE BUFSIZ -/* first index for arrays */ -#define LUA_FIRSTINDEX 1 - /* assertions in Lua (mainly for internal debugging) */ #define lua_assert(c) ((void)0) @@ -123,19 +127,45 @@ #ifdef LUA_CORE /* LUA-C API assertions */ -#define api_check(L, o) lua_assert(o) +#define api_check(L,o) lua_assert(o) -/* an unsigned integer with at least 32 bits */ -#define LUA_UINT32 unsigned long +/* number of bits in an `int' */ +/* avoid overflows in comparison */ +#if INT_MAX-20 < 32760 +#define LUA_BITSINT 16 +#elif INT_MAX > 2147483640L +/* `int' has at least 32 bits */ +#define LUA_BITSINT 32 +#else +#error "you must define LUA_BITSINT with number of bits in an integer" +#endif + -/* a signed integer with at least 32 bits */ +/* +** L_UINT32: unsigned integer with at least 32 bits +** L_INT32: signed integer with at least 32 bits +** LU_MEM: an unsigned integer big enough to count the total memory used by Lua +** L_MEM: a signed integer big enough to count the total memory used by Lua +*/ +#if LUA_BITSINT >= 32 +#define LUA_UINT32 unsigned int +#define LUA_INT32 int +#define LUA_MAXINT32 INT_MAX +#define LU_MEM size_t +#define L_MEM ptrdiff_t +#else +/* 16-bit ints */ +#define LUA_UINT32 unsigned long #define LUA_INT32 long #define LUA_MAXINT32 LONG_MAX +#define LU_MEM LUA_UINT32 +#define L_MEM ptrdiff_t +#endif /* maximum depth for calls (unsigned short) */ -#define LUA_MAXCALLS 4096 +#define LUA_MAXCALLS 10000 /* ** maximum depth for C calls (unsigned short): Not too big, or may @@ -160,7 +190,7 @@ /* maximum number of upvalues per function */ -#define MAXUPVALUES 32 /* = 199900L) /* on machines compliant with C99, you can try `lrint' */ #include #define lua_number2int(i,d) ((i)=lrint(d)) @@ -179,7 +209,7 @@ #endif /* function to convert a lua_Number to lua_Integer (with any rounding method) */ -#define lua_number2integer(i,n) lua_number2int(i,n) +#define lua_number2integer(i,n) lua_number2int((i), (n)) /* function to convert a lua_Number to a string */ @@ -195,17 +225,6 @@ #define LUA_UACNUMBER double -/* number of bits in an `int' */ -/* avoid overflows in comparison */ -#if INT_MAX-20 < 32760 -#define LUA_BITSINT 16 -#elif INT_MAX > 2147483640L -/* machine has at least 32 bits */ -#define LUA_BITSINT 32 -#else -#error "you must define LUA_BITSINT with number of bits in an integer" -#endif - /* type to ensure maximum alignment */ #define LUSER_ALIGNMENT_T union { double u; void *s; long l; } @@ -215,14 +234,14 @@ #ifndef __cplusplus /* default handling with long jumps */ #include -#define L_THROW(c) longjmp((c)->b, 1) -#define L_TRY(c,a) if (setjmp((c)->b) == 0) { a } +#define L_THROW(L,c) longjmp((c)->b, 1) +#define L_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define l_jmpbuf jmp_buf #else /* C++ exceptions */ -#define L_THROW(c) throw(c) -#define L_TRY(c,a) try { a } catch(...) \ +#define L_THROW(L,c) throw(c) +#define L_TRY(L,c,a) try { a } catch(...) \ { if ((c)->status == 0) (c)->status = -1; } #define l_jmpbuf int /* dummy variable */ #endif @@ -251,9 +270,12 @@ /* allows user-specific initialization on new threads */ -#define lua_userstateopen(l) /* empty */ +#define lua_userstateopen(L) /* empty */ +/* initial GC parameters */ +#define STEPMUL 4 + #endif /* }====================================================== */ @@ -272,8 +294,19 @@ /* `assert' options */ -/* environment variable that holds the search path for packages */ +/* environment variables that hold the search path for packages */ #define LUA_PATH "LUA_PATH" +#define LUA_CPATH "LUA_CPATH" + +/* prefix for open functions in C libraries */ +#if defined(__APPLE__) && defined(__MACH__) +#define LUA_POF "_luaopen_" +#else +#define LUA_POF "luaopen_" +#endif + +/* directory separator (for submodules) */ +#define LUA_DIRSEP "/" /* separator of templates in a path */ #define LUA_PATH_SEP ';' @@ -288,7 +321,7 @@ /* ** by default, gcc does not get `tmpname' -*/ +*/ #ifdef __GNUC__ #define USE_TMPNAME 0 #else @@ -296,6 +329,17 @@ #endif +/* +** Configuration for loadlib +*/ +#if defined(__linux) || defined(sun) || defined(sgi) || defined(BSD) +#define USE_DLOPEN +#elif defined(_WIN32) +#define USE_DLL +#elif defined(__APPLE__) && defined(__MACH__) +#define USE_DYLD +#endif + #endif diff --git a/src/lapi.c b/src/lapi.c index ce32f3b083..c2c752e5ec 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.19 2004/09/15 20:39:42 roberto Exp $ +** $Id: lapi.c,v 2.22 2004/12/06 17:53:42 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -45,7 +45,7 @@ const char lua_ident[] = -static TValue *luaA_index (lua_State *L, int idx) { +static TValue *index2adr (lua_State *L, int idx) { if (idx > 0) { TValue *o = L->base + (idx - 1); api_check(L, idx <= L->ci->top - L->base); @@ -160,7 +160,7 @@ LUA_API void lua_settop (lua_State *L, int idx) { LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); - p = luaA_index(L, idx); + p = index2adr(L, idx); api_checkvalidindex(L, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; @@ -172,7 +172,7 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); - p = luaA_index(L, idx); + p = index2adr(L, idx); api_checkvalidindex(L, p); for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); setobjs2s(L, p, L->top); @@ -184,7 +184,7 @@ LUA_API void lua_replace (lua_State *L, int idx) { StkId o; lua_lock(L); api_checknelems(L, 1); - o = luaA_index(L, idx); + o = index2adr(L, idx); api_checkvalidindex(L, o); setobj(L, o, L->top - 1); if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ @@ -196,7 +196,7 @@ LUA_API void lua_replace (lua_State *L, int idx) { LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); - setobj2s(L, L->top, luaA_index(L, idx)); + setobj2s(L, L->top, index2adr(L, idx)); api_incr_top(L); lua_unlock(L); } @@ -209,7 +209,7 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); return (o == &luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -221,14 +221,14 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { TValue n; - const TValue *o = luaA_index(L, idx); + const TValue *o = index2adr(L, idx); return tonumber(o, &n); } @@ -240,14 +240,14 @@ LUA_API int lua_isstring (lua_State *L, int idx) { LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TValue *o = luaA_index(L, idx); + const TValue *o = index2adr(L, idx); return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = luaA_index(L, index1); - StkId o2 = luaA_index(L, index2); + StkId o1 = index2adr(L, index1); + StkId o2 = index2adr(L, index2); return (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 : luaO_rawequalObj(o1, o2); } @@ -257,8 +257,8 @@ LUA_API int lua_equal (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_index(L, index1); - o2 = luaA_index(L, index2); + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 : equalobj(L, o1, o2); lua_unlock(L); @@ -270,8 +270,8 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = luaA_index(L, index1); - o2 = luaA_index(L, index2); + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 : luaV_lessthan(L, o1, o2); lua_unlock(L); @@ -282,7 +282,7 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { TValue n; - const TValue *o = luaA_index(L, idx); + const TValue *o = index2adr(L, idx); if (tonumber(o, &n)) return nvalue(o); else @@ -292,7 +292,7 @@ LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { TValue n; - const TValue *o = luaA_index(L, idx); + const TValue *o = index2adr(L, idx); if (tonumber(o, &n)) { lua_Integer res; lua_number2integer(res, nvalue(o)); @@ -304,13 +304,13 @@ LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { LUA_API int lua_toboolean (lua_State *L, int idx) { - const TValue *o = luaA_index(L, idx); + const TValue *o = index2adr(L, idx); return !l_isfalse(o); } LUA_API const char *lua_tostring (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); if (ttisstring(o)) return svalue(o); else { @@ -325,7 +325,7 @@ LUA_API const char *lua_tostring (lua_State *L, int idx) { LUA_API size_t lua_objsize (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); if (ttisstring(o)) return tsvalue(o)->len; else if (ttisuserdata(o)) @@ -341,13 +341,13 @@ LUA_API size_t lua_objsize (lua_State *L, int idx) { LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); @@ -357,13 +357,13 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) { LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = luaA_index(L, idx); + StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); @@ -498,7 +498,7 @@ LUA_API int lua_pushthread (lua_State *L) { LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_checkvalidindex(L, t); luaV_gettable(L, t, L->top - 1, L->top - 1, NULL); lua_unlock(L); @@ -509,7 +509,7 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; TValue key; lua_lock(L); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); luaV_gettable(L, t, &key, L->top, NULL); @@ -521,7 +521,7 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { LUA_API void lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_check(L, ttistable(t)); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); @@ -531,7 +531,7 @@ LUA_API void lua_rawget (lua_State *L, int idx) { LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); - o = luaA_index(L, idx); + o = index2adr(L, idx); api_check(L, ttistable(o)); setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); @@ -553,7 +553,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { Table *mt = NULL; int res; lua_lock(L); - obj = luaA_index(L, objindex); + obj = index2adr(L, objindex); switch (ttype(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; @@ -577,7 +577,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); - o = luaA_index(L, idx); + o = index2adr(L, idx); api_checkvalidindex(L, o); setobj2s(L, L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); api_incr_top(L); @@ -594,7 +594,7 @@ LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1, NULL); L->top -= 2; /* pop index and value */ @@ -607,7 +607,7 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { TValue key; lua_lock(L); api_checknelems(L, 1); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); luaV_settable(L, t, &key, L->top - 1, NULL); @@ -620,7 +620,7 @@ LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_check(L, ttistable(t)); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); luaC_barriert(L, hvalue(t), L->top-1); @@ -633,7 +633,7 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); api_checknelems(L, 1); - o = luaA_index(L, idx); + o = index2adr(L, idx); api_check(L, ttistable(o)); setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); luaC_barriert(L, hvalue(o), L->top-1); @@ -648,7 +648,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { int res = 1; lua_lock(L); api_checknelems(L, 1); - obj = luaA_index(L, objindex); + obj = index2adr(L, objindex); api_checkvalidindex(L, obj); if (ttisnil(L->top - 1)) mt = NULL; @@ -685,7 +685,7 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { int res = 0; lua_lock(L); api_checknelems(L, 1); - o = luaA_index(L, idx); + o = index2adr(L, idx); api_checkvalidindex(L, o); api_check(L, ttistable(L->top - 1)); if (isLfunction(o)) { @@ -751,7 +751,7 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { if (errfunc == 0) func = 0; else { - StkId o = luaA_index(L, errfunc); + StkId o = index2adr(L, errfunc); api_checkvalidindex(L, o); func = savestack(L, o); } @@ -842,7 +842,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g = G(L); switch (what) { case LUA_GCSTOP: { - g->GCthreshold = MAXLMEM; + g->GCthreshold = MAX_LUMEM; break; } case LUA_GCRESTART: { @@ -867,6 +867,16 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { luaC_step(L); break; } + case LUA_GCSETSTEPMUL: { + res = g->stepmul; + g->stepmul = data; + break; + } + case LUA_GCSETINCMODE: { + res = g->incgc; + g->incgc = data; + break; + } default: res = -1; /* invalid option */ } lua_unlock(L); @@ -898,7 +908,7 @@ LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); - t = luaA_index(L, idx); + t = index2adr(L, idx); api_check(L, ttistable(t)); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { @@ -970,7 +980,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); - name = aux_upvalue(L, luaA_index(L, funcindex), n, &val); + name = aux_upvalue(L, index2adr(L, funcindex), n, &val); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -985,7 +995,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { TValue *val; StkId fi; lua_lock(L); - fi = luaA_index(L, funcindex); + fi = index2adr(L, funcindex); api_checknelems(L, 1); name = aux_upvalue(L, fi, n, &val); if (name) { diff --git a/src/lcode.c b/src/lcode.c index 54ef058112..f7f1182d57 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.6 2004/08/24 20:09:11 roberto Exp $ +** $Id: lcode.c,v 2.8 2004/12/03 20:35:33 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -53,13 +53,13 @@ int luaK_jump (FuncState *fs) { } -static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) { +static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } -static void luaK_fixjump (FuncState *fs, int pc, int dest) { +static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest-(pc+1); lua_assert(dest != NO_JUMP); @@ -79,7 +79,7 @@ int luaK_getlabel (FuncState *fs) { } -static int luaK_getjump (FuncState *fs, int pc) { +static int getjump (FuncState *fs, int pc) { int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ @@ -102,7 +102,7 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) { ** (or produce an inverted value) */ static int need_value (FuncState *fs, int list, int cond) { - for (; list != NO_JUMP; list = luaK_getjump(fs, list)) { + for (; list != NO_JUMP; list = getjump(fs, list)) { Instruction i = *getjumpcontrol(fs, list); if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1; } @@ -116,25 +116,25 @@ static void patchtestreg (Instruction *i, int reg) { } -static void luaK_patchlistaux (FuncState *fs, int list, +static void patchlistaux (FuncState *fs, int list, int ttarget, int treg, int ftarget, int freg, int dtarget) { while (list != NO_JUMP) { - int next = luaK_getjump(fs, list); + int next = getjump(fs, list); Instruction *i = getjumpcontrol(fs, list); if (GET_OPCODE(*i) != OP_TEST) { lua_assert(dtarget != NO_JUMP); - luaK_fixjump(fs, list, dtarget); /* jump to default target */ + fixjump(fs, list, dtarget); /* jump to default target */ } else { if (GETARG_C(*i)) { lua_assert(ttarget != NO_JUMP); patchtestreg(i, treg); - luaK_fixjump(fs, list, ttarget); + fixjump(fs, list, ttarget); } else { lua_assert(ftarget != NO_JUMP); patchtestreg(i, freg); - luaK_fixjump(fs, list, ftarget); + fixjump(fs, list, ftarget); } } list = next; @@ -142,8 +142,8 @@ static void luaK_patchlistaux (FuncState *fs, int list, } -static void luaK_dischargejpc (FuncState *fs) { - luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); +static void dischargejpc (FuncState *fs) { + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } @@ -153,7 +153,7 @@ void luaK_patchlist (FuncState *fs, int list, int target) { luaK_patchtohere(fs, list); else { lua_assert(target < fs->pc); - luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); + patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); } } @@ -171,9 +171,9 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { else { int list = *l1; int next; - while ((next = luaK_getjump(fs, list)) != NO_JUMP) /* find last element */ + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ list = next; - luaK_fixjump(fs, list, l2); + fixjump(fs, list, l2); } } @@ -243,7 +243,14 @@ int luaK_numberK (FuncState *fs, lua_Number r) { } -static int nil_constant (FuncState *fs) { +static int boolK (FuncState *fs, int b) { + TValue o; + setbvalue(&o, b); + return addk(fs, &o, &o); +} + + +static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ @@ -358,7 +365,7 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) { } -static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) { +static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */ @@ -375,8 +382,8 @@ static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) { luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); - luaK_patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f); - luaK_patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t); + patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t); } e->f = e->t = NO_JUMP; e->info = reg; @@ -388,7 +395,7 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); luaK_reserveregs(fs, 1); - luaK_exp2reg(fs, e, fs->freereg - 1); + exp2reg(fs, e, fs->freereg - 1); } @@ -397,7 +404,7 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) { if (!hasjumps(e)) return e->info; /* exp is already in a register */ if (e->info >= fs->nactvar) { /* reg. is not a local? */ - luaK_exp2reg(fs, e, e->info); /* put value on it */ + exp2reg(fs, e, e->info); /* put value on it */ return e->info; } } @@ -417,9 +424,11 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { + case VTRUE: + case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ - e->info = nil_constant(fs); + e->info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); e->k = VK; return RKASK(e->info); } @@ -441,7 +450,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); - luaK_exp2reg(fs, ex, var->info); + exp2reg(fs, ex, var->info); return; } case VUPVAL: { @@ -493,13 +502,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ - return luaK_condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond); + return condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); - return luaK_condjump(fs, OP_TEST, NO_REG, e->info, cond); + return condjump(fs, OP_TEST, NO_REG, e->info, cond); } @@ -651,7 +660,7 @@ static void codebinop (FuncState *fs, expdesc *res, BinOpr op, temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ } else if (op == OPR_NE) cond = 0; - res->info = luaK_condjump(fs, ops[op - OPR_NE], cond, o1, o2); + res->info = condjump(fs, ops[op - OPR_NE], cond, o1, o2); res->k = VJMP; } } @@ -708,7 +717,7 @@ void luaK_fixline (FuncState *fs, int line) { int luaK_code (FuncState *fs, Instruction i, int line) { Proto *f = fs->f; - luaK_dischargejpc(fs); /* `pc' will change */ + dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "code size overflow"); @@ -735,3 +744,17 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); } + +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0); + if (c <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, b, c); + else { + luaK_codeABC(fs, OP_SETLIST, base, b, 0); + luaK_code(fs, cast(Instruction, c), fs->ls->lastline); + } + fs->freereg = base + 1; /* free registers with list values */ +} + diff --git a/src/lcode.h b/src/lcode.h index b854d5cdf2..532b3478f8 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.39 2004/05/31 18:51:50 roberto Exp $ +** $Id: lcode.h,v 1.40 2004/10/04 19:01:53 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -72,6 +72,7 @@ int luaK_getlabel (FuncState *fs); void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); #endif diff --git a/src/ldebug.c b/src/ldebug.c index 139e4cdb62..17727d37ab 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.8 2004/09/01 13:47:31 roberto Exp $ +** $Id: ldebug.c,v 2.11 2004/12/03 20:35:33 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -261,11 +261,11 @@ int luaG_checkopenop (Instruction i) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: - case OP_RETURN: { + case OP_RETURN: + case OP_SETLIST: { check(GETARG_B(i) == 0); return 1; } - case OP_SETLISTO: return 1; default: return 0; /* invalid instruction after an open call */ } } @@ -284,7 +284,7 @@ static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { } -static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { +static Instruction symbexec (const Proto *pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ @@ -315,6 +315,11 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { if (getBMode(op) == OpArgR) { int dest = pc+1+b; check(0 <= dest && dest < pt->sizecode); + if (dest > 0) { + /* cannot jump to a setlist count */ + const Instruction d = pt->code[dest-1]; + check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); + } } break; } @@ -356,7 +361,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_TFORLOOP: { - checkreg(pt, a+5); /* space for control variables */ + check(c >= 1); /* at least one result (control variable) */ + checkreg(pt, a+3+c); /* space for results */ if (reg >= a+3) last = pc; /* affect all regs above its call base */ break; } @@ -392,7 +398,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_SETLIST: { - checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); + if (b > 0) checkreg(pt, a + b); + if (c == 0) pc++; break; } case OP_CLOSURE: { @@ -427,7 +434,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { int luaG_checkcode (const Proto *pt) { - return (luaG_symbexec(pt, pt->sizecode, NO_REG) != 0); + return (symbexec(pt, pt->sizecode, NO_REG) != 0); } @@ -447,7 +454,7 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { *name = luaF_getlocalname(p, stackpos+1, pc); if (*name) /* is a local? */ return "local"; - i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */ + i = symbexec(p, pc, stackpos); /* try symbolic execution */ lua_assert(pc != -1); switch (GET_OPCODE(i)) { case OP_GETGLOBAL: { diff --git a/src/ldo.c b/src/ldo.c index ad9cbc3d29..d75a7063c4 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.10 2004/09/15 20:39:42 roberto Exp $ +** $Id: ldo.c,v 2.13 2004/12/03 20:35:33 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -70,7 +70,7 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; - L_THROW(L->errorJmp); + L_THROW(L, L->errorJmp); } else { if (G(L)->panic) G(L)->panic(L); @@ -84,7 +84,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { lj.status = 0; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; - L_TRY(&lj, + L_TRY(L, &lj, (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ @@ -147,7 +147,7 @@ void luaD_growstack (lua_State *L, int n) { } -static CallInfo *luaD_growCI (lua_State *L) { +static CallInfo *growCI (lua_State *L) { if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */ luaD_throw(L, LUA_ERRERR); else { @@ -238,7 +238,7 @@ static StkId tryfuncTM (lua_State *L, StkId func) { #define inc_ci(L) \ - ((L->ci == L->end_ci) ? luaD_growCI(L) : \ + ((L->ci == L->end_ci) ? growCI(L) : \ (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) @@ -391,7 +391,6 @@ static int resume_error (lua_State *L, const char *msg) { LUA_API int lua_resume (lua_State *L, int nargs) { int status; - lu_byte old_allowhooks; lua_lock(L); lua_assert(L->errfunc == 0 && L->nCcalls == 0); if (L->status != LUA_YIELD) { @@ -400,7 +399,6 @@ LUA_API int lua_resume (lua_State *L, int nargs) { else if (L->ci != L->base_ci) return resume_error(L, "cannot resume non-suspended coroutine"); } - old_allowhooks = L->allowhook; status = luaD_rawrunprotected(L, resume, &nargs); if (status != 0) { /* error? */ L->status = status; /* mark thread as `dead' */ diff --git a/src/ldump.c b/src/ldump.c index bd0becb91e..967596a157 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.8 2004/09/01 21:22:34 lhf Exp $ +** $Id: ldump.c,v 1.9 2004/11/25 09:31:41 lhf Exp $ ** save pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -113,14 +113,17 @@ static void DumpConstants(const Proto* f, DumpState* D) DumpByte(ttype(o),D); switch (ttype(o)) { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpByte(bvalue(o),D); + break; case LUA_TNUMBER: DumpNumber(nvalue(o),D); break; case LUA_TSTRING: DumpString(rawtsvalue(o),D); break; - case LUA_TNIL: - break; default: lua_assert(0); /* cannot happen */ break; diff --git a/src/lfunc.c b/src/lfunc.c index 7d4fbf2015..af431cc3c1 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.4 2004/04/30 20:13:38 roberto Exp $ +** $Id: lfunc.c,v 2.5 2004/11/24 19:20:21 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -75,7 +75,7 @@ void luaF_close (lua_State *L, StkId level) { lua_assert(!isblack(o)); L->openupval = uv->next; /* remove from `open' list */ if (isdead(g, o)) - luaM_freelem(L, uv); /* free upvalue */ + luaM_free(L, uv); /* free upvalue */ else { setobj(L, &uv->value, uv->v); uv->v = &uv->value; /* now current value lives here */ @@ -117,14 +117,14 @@ void luaF_freeproto (lua_State *L, Proto *f) { luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); - luaM_freelem(L, f); + luaM_free(L, f); } void luaF_freeclosure (lua_State *L, Closure *c) { int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : sizeLclosure(c->l.nupvalues); - luaM_free(L, c, size); + luaM_freemem(L, c, size); } diff --git a/src/lgc.c b/src/lgc.c index b3661fd7a1..87a3b53444 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.12 2004/09/15 20:38:15 roberto Exp $ +** $Id: lgc.c,v 2.18 2004/12/06 17:53:42 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -24,7 +24,6 @@ #define GCSTEPSIZE 1000 -#define STEPMUL 2 #define GCSWEEPMAX 10 #define GCSWEEPCOST 30 #define GCFINALIZECOST 100 @@ -65,7 +64,7 @@ static void removeentry (Node *n) { setnilvalue(gval(n)); /* remove corresponding value ... */ if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ + setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ } @@ -139,7 +138,7 @@ size_t luaC_separateudata (lua_State *L, int all) { p = &curr->gch.next; } else { /* must call its gc method */ - deadmem += sizeudata(gco2u(curr)->len); + deadmem += sizeudata(gco2u(curr)); markfinalized(gco2u(curr)); *p = curr->gch.next; curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ @@ -184,6 +183,7 @@ static int traversetable (global_State *g, Table *h) { i = sizenode(h); while (i--) { Node *n = gnode(h, i); + lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); if (ttisnil(gval(n))) removeentry(n); /* remove empty entries */ else { @@ -367,7 +367,7 @@ static void cleartable (GCObject *l) { while (i--) { Node *n = gnode(h, i); if (!ttisnil(gval(n)) && /* non-empty entry? */ - (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) + (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) removeentry(n); /* remove entry from table */ } l = h->gclist; @@ -379,7 +379,7 @@ static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; - case LUA_TUPVAL: luaM_freelem(L, gco2uv(o)); break; + case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); @@ -388,11 +388,11 @@ static void freeobj (lua_State *L, GCObject *o) { } case LUA_TSTRING: { G(L)->strt.nuse--; - luaM_free(L, o, sizestring(gco2ts(o)->len)); + luaM_freemem(L, o, sizestring(gco2ts(o))); break; } case LUA_TUSERDATA: { - luaM_free(L, o, sizeudata(gco2u(o)->len)); + luaM_freemem(L, o, sizeudata(gco2u(o))); break; } default: lua_assert(0); @@ -529,6 +529,7 @@ static void remarkupvals (global_State *g) { static void atomic (lua_State *L) { global_State *g = G(L); + size_t udsize; /* total size of userdata to be finalized */ int aux; /* remark objects cautch by write barrier */ propagateall(g); @@ -544,7 +545,7 @@ static void atomic (lua_State *L) { g->gray = g->grayagain; g->grayagain = NULL; propagateall(g); - luaC_separateudata(L, 0); /* separate userdata to be preserved */ + udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ marktmu(g); /* mark `preserved' userdata */ propagateall(g); /* remark, to propagate `preserveness' */ cleartable(g->weak); /* remove collected objects from weak tables */ @@ -554,10 +555,10 @@ static void atomic (lua_State *L) { g->sweepgc = &g->rootgc; g->gcstate = GCSsweepstring; aux = g->gcgenerational; - g->gcgenerational = (g->estimate <= 4*g->prevestimate/2); + g->gcgenerational = g->incgc && (g->estimate/2 <= g->prevestimate); if (!aux) /* last collection was full? */ g->prevestimate = g->estimate; /* keep estimate of last full collection */ - g->estimate = g->totalbytes; /* first estimate */ + g->estimate = g->totalbytes - udsize; /* first estimate */ } @@ -586,6 +587,7 @@ static l_mem singlestep (lua_State *L) { sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ g->gcstate = GCSsweep; /* end sweep-string phase */ + lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPCOST; } @@ -596,12 +598,15 @@ static l_mem singlestep (lua_State *L) { checkSizes(L); g->gcstate = GCSfinalize; /* end sweep phase */ } + lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPMAX*GCSWEEPCOST; } case GCSfinalize: { if (g->tmudata) { + g->GCthreshold += GCFINALIZECOST; /* avoid GC steps inside method */ GCTM(L); + g->GCthreshold -= GCFINALIZECOST; /* correct threshold */ return GCFINALIZECOST; } else { @@ -616,23 +621,18 @@ static l_mem singlestep (lua_State *L) { void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL; -/*printf("step(%c): ", g->gcgenerational?'g':' ');*/ + l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * g->stepmul; do { - /*printf("%c", "_pswf"[g->gcstate]);*/ lim -= singlestep(L); if (g->gcstate == GCSpause) break; - } while (lim > 0); -/*printf("\n");*/ - if (g->gcstate != GCSpause) + } while (lim > 0 || !g->incgc); + if (g->incgc) g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/STEPMUL; */ else { -/*printf("---\n");*/ lua_assert(g->totalbytes >= g->estimate); + lua_assert(g->gcstate == GCSpause); g->GCthreshold = 2*g->estimate; - if (g->GCthreshold < g->totalbytes + GCSTEPSIZE) - g->GCthreshold = g->totalbytes + GCSTEPSIZE; } } @@ -657,20 +657,19 @@ void luaC_fullgc (lua_State *L) { } markroot(L); lua_assert(!g->gcgenerational); - while (g->gcstate != GCSfinalize) { + while (g->gcstate != GCSpause) { singlestep(L); g->gcgenerational = 0; /* keep it in this mode */ } - lua_assert(g->estimate == g->totalbytes); g->GCthreshold = 2*g->estimate; - luaC_callGCTM(L); /* call finalizers */ } void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcgenerational || g->gcstate != GCSfinalize); + lua_assert(g->gcgenerational || + (g->gcstate != GCSfinalize && g->gcstate != GCSpause)); lua_assert(ttype(&o->gch) != LUA_TTABLE); /* must keep invariant? */ if (g->gcstate == GCSpropagate || g->gcgenerational) @@ -683,7 +682,8 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcgenerational || g->gcstate != GCSfinalize); + lua_assert(g->gcgenerational || + (g->gcstate != GCSfinalize && g->gcstate != GCSpause)); black2gray(o); /* make table gray (again) */ gco2h(o)->gclist = g->grayagain; g->grayagain = o; diff --git a/src/lib/lauxlib.c b/src/lib/lauxlib.c index 7c14d001c3..615be8f2e5 100644 --- a/src/lib/lauxlib.c +++ b/src/lib/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.124 2004/09/03 13:17:14 roberto Exp $ +** $Id: lauxlib.c,v 1.126 2004/09/29 21:03:14 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -239,16 +239,22 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, const luaL_reg *l, int nup) { if (libname) { /* check whether lib already exists */ - lua_getglobal(L, libname); - if (lua_isnil(L, -1)) { /* no? */ - lua_pop(L, 1); + luaL_getfield(L, LUA_GLOBALSINDEX, libname); + if (lua_isnil(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ lua_newtable(L); /* create it */ if (lua_getmetatable(L, LUA_GLOBALSINDEX)) lua_setmetatable(L, -2); /* share metatable with global table */ - lua_pushvalue(L, -1); /* register it with given name */ - lua_setglobal(L, libname); + lua_pushvalue(L, -1); + luaL_setfield(L, LUA_GLOBALSINDEX, libname); } + else if (!lua_istable(L, -1)) + luaL_error(L, "name conflict for library `%s'", libname); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_pushvalue(L, -2); + lua_setfield(L, -2, libname); /* _LOADED[modname] = new table */ + lua_pop(L, 1); /* remove _LOADED table */ lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { @@ -352,8 +358,8 @@ static const char *pushnexttemplate (lua_State *L, const char *path) { } -static const char *luaL_gsub (lua_State *L, const char *s, - const char *p, const char *r) { +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { const char *wild; int l = strlen(p); luaL_Buffer b; @@ -381,16 +387,68 @@ LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, } fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); lua_remove(L, -2); /* remove path template */ - f = fopen(fname, "r"); /* try to read it */ + f = fopen(fname, "r"); /* try to open it */ if (f) { + int err; + getc(f); /* try to read file */ + err = ferror(f); fclose(f); - return fname; + if (err == 0) /* open and read sucessful? */ + return fname; /* return that file name */ } lua_pop(L, 1); /* remove file name */ } } +LUALIB_API const char *luaL_getfield (lua_State *L, int idx, + const char *fname) { + const char *e; + lua_pushvalue(L, idx); + while ((e = strchr(fname, '.')) != NULL) { + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + if (!lua_istable(L, -1)) return fname; + } + lua_pushstring(L, fname); + lua_rawget(L, -2); /* get last field */ + lua_remove(L, -2); /* remove previous table */ + return NULL; +} + + +LUALIB_API const char *luaL_setfield (lua_State *L, int idx, + const char *fname) { + const char *e; + lua_pushvalue(L, idx); + while ((e = strchr(fname, '.')) != NULL) { + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_newtable(L); /* create a new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + if (!lua_istable(L, -1)) { + lua_pop(L, 2); /* remove table and value */ + return fname; + } + } + lua_pushstring(L, fname); + lua_pushvalue(L, -3); /* move value to the top */ + lua_rawset(L, -3); /* set last field */ + lua_pop(L, 2); /* remove value and table */ + return NULL; +} + + + /* ** {====================================================== ** Generic Buffer manipulation diff --git a/src/lib/lbaselib.c b/src/lib/lbaselib.c index 82a8f509cc..8c6280972d 100644 --- a/src/lib/lbaselib.c +++ b/src/lib/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.158 2004/09/15 20:39:42 roberto Exp $ +** $Id: lbaselib.c,v 1.161 2004/12/06 17:53:42 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -181,10 +181,10 @@ static int luaB_gcinfo (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { - static const char *const opts[] = {"stop", "restart", "collect", "count", - "step", NULL}; - static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, - LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP}; + static const char *const opts[] = {"stop", "restart", "collect", + "count", "step", "setstepmul", "setincmode", NULL}; + static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETSTEPMUL, LUA_GCSETINCMODE}; int o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); int ex = luaL_optint(L, 2, 0); luaL_argcheck(L, o >= 0, 1, "invalid option"); @@ -440,50 +440,6 @@ static int luaB_newproxy (lua_State *L) { } -/* -** {====================================================== -** `require' function -** ======================================================= -*/ - - -static const char *getpath (lua_State *L) { - /* try first `LUA_PATH' for compatibility */ - lua_getfield(L, LUA_GLOBALSINDEX, "LUA_PATH"); - if (!lua_isstring(L, -1)) { - lua_pop(L, 1); - lua_getfield(L, LUA_GLOBALSINDEX, "_PATH"); - } - if (!lua_isstring(L, -1)) - luaL_error(L, "global _PATH must be a string"); - return lua_tostring(L, -1); -} - - -static int luaB_require (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - const char *fname; - lua_getfield(L, lua_upvalueindex(1), name); - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded; return its result */ - /* else must load it; first mark it as loaded */ - lua_pushboolean(L, 1); - lua_setfield(L, lua_upvalueindex(1), name); /* _LOADED[name] = true */ - fname = luaL_searchpath(L, name, getpath(L)); - if (fname == NULL || luaL_loadfile(L, fname) != 0) - return luaL_error(L, "error loading package `%s' (%s)", name, - lua_tostring(L, -1)); - lua_pushvalue(L, 1); /* pass name as argument to module */ - lua_call(L, 1, 1); /* run loaded module */ - if (!lua_isnil(L, -1)) /* nil return? */ - lua_setfield(L, lua_upvalueindex(1), name); - lua_getfield(L, lua_upvalueindex(1), name); /* return _LOADED[name] */ - return 1; -} - -/* }====================================================== */ - - static const luaL_reg base_funcs[] = { {"error", luaB_error}, {"getmetatable", luaB_getmetatable}, @@ -656,11 +612,10 @@ static void auxopen (lua_State *L, const char *name, static void base_open (lua_State *L) { - const char *path; lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, LUA_GLOBALSINDEX, "_VERSION"); /* set global _VERSION */ + lua_setglobal(L, "_VERSION"); /* set global _VERSION */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */ auxopen(L, "ipairs", luaB_ipairs, ipairsaux); auxopen(L, "pairs", luaB_pairs, luaB_next); @@ -671,21 +626,16 @@ static void base_open (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_setfield(L, LUA_GLOBALSINDEX, "newproxy"); /* set global `newproxy' */ - /* `require' needs a table to keep loaded chunks */ + lua_setglobal(L, "newproxy"); /* set global `newproxy' */ + /* create register._LOADED to track loaded modules */ + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, "_LOADED"); + /* create register._PRELOAD to allow pre-loaded modules */ lua_newtable(L); - lua_pushvalue(L, -1); - lua_setglobal(L, "_LOADED"); - lua_pushcclosure(L, luaB_require, 1); - lua_setfield(L, LUA_GLOBALSINDEX, "require"); + lua_setfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); /* set global _G */ lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setfield(L, LUA_GLOBALSINDEX, "_G"); - /* set global _PATH */ - path = getenv(LUA_PATH); - if (path == NULL) path = LUA_PATH_DEFAULT; - lua_pushstring(L, path); - lua_setfield(L, LUA_GLOBALSINDEX, "_PATH"); + lua_setglobal(L, "_G"); } diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c index 4ec5f3933d..36d647aaa9 100644 --- a/src/lib/ldblib.c +++ b/src/lib/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.87 2004/08/13 18:02:36 roberto Exp $ +** $Id: ldblib.c,v 1.89 2004/11/17 12:02:41 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -261,7 +261,7 @@ static int debug (lua_State *L) { if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; - if (luaL_loadbuffer(L, buffer, strlen(buffer), "=debug command") || + if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) { fputs(lua_tostring(L, -1), stderr); fputs("\n", stderr); @@ -275,14 +275,15 @@ static int debug (lua_State *L) { #define LEVELS2 10 /* size of the second part of the stack */ static int errorfb (lua_State *L) { - int level = 1; /* skip level 0 (it's this function) */ + int level = 0; int firstpart = 1; /* still before eventual `...' */ int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; + if (L == L1) level++; /* skip level 0 (it's this function) */ if (lua_gettop(L) == arg) lua_pushliteral(L, ""); - else if (!lua_isstring(L, arg+1)) return 1; /* no string message */ + else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ else lua_pushliteral(L, "\n"); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { diff --git a/src/lib/loadlib.c b/src/lib/loadlib.c index 8b98a2bf72..63bc0bcc1e 100644 --- a/src/lib/loadlib.c +++ b/src/lib/loadlib.c @@ -1,31 +1,35 @@ /* -** $Id: loadlib.c,v 1.6 2004/04/30 20:13:38 roberto Exp $ +** $Id: loadlib.c,v 1.11 2004/11/19 15:52:12 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h * -* This Lua library exports a single function, called loadlib, which is -* called from Lua as loadlib(lib,init), where lib is the full name of the -* library to be loaded (including the complete path) and init is the name -* of a function to be called after the library is loaded. Typically, this -* function will register other functions, thus making the complete library -* available to Lua. The init function is *not* automatically called by -* loadlib. Instead, loadlib returns the init function as a Lua function -* that the client can call when it thinks is appropriate. In the case of -* errors, loadlib returns nil and two strings describing the error. -* The first string is supplied by the operating system; it should be -* informative and useful for error messages. The second string is "open", -* "init", or "absent" to identify the error and is meant to be used for -* making decisions without having to look into the first string (whose -* format is system-dependent). -* -* This module contains an implementation of loadlib for Unix systems that -* have dlfcn, an implementation for Windows, and a stub for other systems. -* See the list at the end of this file for some links to available -* implementations of dlfcn and interfaces to other native dynamic loaders -* on top of which loadlib could be implemented. -* +* This Lua library exports a single function, called loadlib, which +* is called from Lua as loadlib(lib,init), where lib is the full +* name of the library to be loaded (including the complete path) and +* init is the name of a function to be called after the library is +* loaded. Typically, this function will register other functions, thus +* making the complete library available to Lua. The init function is +* *not* automatically called by loadlib. Instead, loadlib returns the +* init function as a Lua function that the client can call when it +* thinks is appropriate. In the case of errors, loadlib returns nil and +* two strings describing the error. The first string is supplied by +* the operating system; it should be informative and useful for error +* messages. The second string is "open", "init", or "absent" to identify +* the error and is meant to be used for making decisions without having +* to look into the first string (whose format is system-dependent). +* This module contains an implementation of loadlib for Unix systems +* that have dlfcn, an implementation for Darwin (Mac OS X), an +* implementation for Windows, and a stub for other systems. See +* the list at the end of this file for some links to available +* implementations of dlfcn and interfaces to other native dynamic +* loaders on top of which loadlib could be implemented. */ + +#include +#include + + #define loadlib_c #define LUA_LIB @@ -34,11 +38,14 @@ #include "lualib.h" -#undef LOADLIB +#define ERR_OPEN 1 +#define ERR_FUNCTION 2 + + +static void registerlib (lua_State *L, const void *lib); -#ifdef USE_DLOPEN -#define LOADLIB +#if defined(USE_DLOPEN) /* * This is an implementation of loadlib based on the dlfcn interface. * The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, @@ -48,53 +55,41 @@ #include -static int loadlib(lua_State *L) +#define freelib dlclose + +static int loadlib(lua_State *L, const char *path, const char *init) { - const char *path=luaL_checkstring(L,1); - const char *init=luaL_checkstring(L,2); void *lib=dlopen(path,RTLD_NOW); if (lib!=NULL) { lua_CFunction f=(lua_CFunction) dlsym(lib,init); if (f!=NULL) { - lua_pushlightuserdata(L,lib); - lua_pushcclosure(L,f,1); - return 1; + registerlib(L, lib); + lua_pushcfunction(L,f); + return 0; } } - /* else return appropriate error messages */ - lua_pushnil(L); + /* else return appropriate error message */ lua_pushstring(L,dlerror()); - lua_pushstring(L,(lib!=NULL) ? "init" : "open"); - if (lib!=NULL) dlclose(lib); - return 3; + if (lib!=NULL) { + dlclose(lib); + return ERR_FUNCTION; /* error loading function */ + } + else return ERR_OPEN; /* error loading library */ } -#endif - - - -/* -** In Windows, default is to use dll; otherwise, default is not to use dll -*/ -#ifndef USE_DLL -#ifdef _WIN32 -#define USE_DLL 1 -#else -#define USE_DLL 0 -#endif -#endif -#if USE_DLL -#define LOADLIB +#elif defined(USE_DLL) /* * This is an implementation of loadlib for Windows using native functions. */ #include +#define freelib(lib) FreeLibrary((HINSTANCE)lib) + static void pusherror(lua_State *L) { int error=GetLastError(); @@ -106,61 +101,310 @@ static void pusherror(lua_State *L) lua_pushfstring(L,"system error %d\n",error); } -static int loadlib(lua_State *L) +static int loadlib(lua_State *L, const char *path, const char *init) { - const char *path=luaL_checkstring(L,1); - const char *init=luaL_checkstring(L,2); HINSTANCE lib=LoadLibrary(path); if (lib!=NULL) { lua_CFunction f=(lua_CFunction) GetProcAddress(lib,init); if (f!=NULL) { - lua_pushlightuserdata(L,lib); - lua_pushcclosure(L,f,1); + registerlib(L, lib); + lua_pushcfunction(L,f); return 1; } } - lua_pushnil(L); pusherror(L); - lua_pushstring(L,(lib!=NULL) ? "init" : "open"); - if (lib!=NULL) FreeLibrary(lib); - return 3; + if (lib!=NULL) { + FreeLibrary(lib); + return ERR_OPEN; + } + else return ERR_FUNCTION; } -#endif +/* Native Mac OS X / Darwin Implementation */ +#elif defined(USE_DYLD) + +#include + + +/* Mach cannot unload images (?) */ +#define freelib(lib) ((void)lib) + +static void pusherror (lua_State *L) +{ + const char *err_str; + const char *err_file; + NSLinkEditErrors err; + int err_num; + NSLinkEditError(&err, &err_num, &err_file, &err_str); + lua_pushstring(L, err_str); +} + +static int loadlib (lua_State *L, const char *path, const char *init) { + const struct mach_header *lib; + /* this would be a rare case, but prevents crashing if it happens */ + if(!_dyld_present()) { + lua_pushstring(L,"dyld not present."); + return ERR_OPEN; + } + lib = NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); + if(lib != NULL) { + NSSymbol init_sym = NSLookupSymbolInImage(lib, init, + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | + NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); + if(init_sym != NULL) { + lua_CFunction f = (lua_CFunction)NSAddressOfSymbol(init_sym); + registerlib(L, lib); + lua_pushcfunction(L,f); + return 0; + } + } + /* else an error ocurred */ + pusherror(L); + /* Can't unload image */ + return (lib != NULL) ? ERR_FUNCTION : ERR_OPEN; +} + -#ifndef LOADLIB -/* Fallback for other systems */ -/* -** Those systems support dlopen, so they should have defined USE_DLOPEN. -** The default (no)implementation gives them a special error message. -*/ -#if defined(linux) || defined(sun) || defined(sgi) || defined(BSD) || defined(_WIN32) -#define LOADLIB "`loadlib' not installed (check your Lua configuration)" #else -#define LOADLIB "`loadlib' not supported" -#endif +/* Fallback for other systems */ + +#define freelib(lib) ((void)lib) static int loadlib(lua_State *L) { + registerlib(L, NULL); /* to avoid warnings */ lua_pushnil(L); - lua_pushliteral(L,LOADLIB); + lua_pushliteral(L,"`loadlib' not supported"); lua_pushliteral(L,"absent"); return 3; } + #endif -LUALIB_API int luaopen_loadlib (lua_State *L) + +/* +** common code for all implementations: put a library into the registry +** so that, when Lua closes its state, the library's __gc metamethod +** will be called to unload the library. +*/ +static void registerlib (lua_State *L, const void *lib) +{ + const void **plib = (const void **)lua_newuserdata(L, sizeof(const void *)); + *plib = lib; + luaL_getmetatable(L, "_LOADLIB"); + lua_setmetatable(L, -2); + lua_pushboolean(L, 1); + lua_settable(L, LUA_REGISTRYINDEX); /* registry[lib] = true */ +} + +/* +** __gc tag method: calls library's `freelib' function with the lib +** handle +*/ +static int gctm (lua_State *L) { - lua_register(L,"loadlib",loadlib); + void *lib = *(void **)luaL_checkudata(L, 1, "_LOADLIB"); + freelib(lib); return 0; } + +static int loadlib1 (lua_State *L) { + const char *path=luaL_checkstring(L,1); + const char *init=luaL_checkstring(L,2); + int res = loadlib(L,path,init); + if (res == 0) /* no error? */ + return 1; /* function is at stack top */ + else { /* error */ + lua_pushnil(L); + lua_insert(L,-2); /* insert nil before error message */ + lua_pushstring(L, (res==ERR_OPEN)?"open":"init"); + return 3; + } +} + + + +/* +** {====================================================== +** `require' and `module' functions +** ======================================================= +*/ + + +static const char *loadLua (lua_State *L, const char *fname, const char *name) { + const char *path; + /* try first `LUA_PATH' for compatibility */ + lua_getglobal(L, "LUA_PATH"); + path = lua_tostring(L, -1); + if (!path) { + lua_pop(L, 1); + luaL_getfield(L, LUA_GLOBALSINDEX, "package.path"); + path = lua_tostring(L, -1); + } + if (path == NULL) + luaL_error(L, "`package.path' must be a string"); + fname = luaL_searchpath(L, fname, path); + if (fname == NULL) return path; /* library not found in this path */ + if (luaL_loadfile(L, fname) != 0) + luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); + return NULL; /* library loaded successfully */ +} + + +static const char *loadC (lua_State *L, const char *fname, const char *name) { + const char *path; + const char *funcname; + luaL_getfield(L, LUA_GLOBALSINDEX, "package.cpath"); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, "global _CPATH must be a string"); + fname = luaL_searchpath(L, fname, path); + if (fname == NULL) return path; /* library not found in this path */ + funcname = luaL_gsub(L, name, ".", ""); + funcname = lua_pushfstring(L, "%s%s", LUA_POF, funcname); + if (loadlib(L, fname, funcname) != 0) + luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); + return NULL; /* library loaded successfully */ +} + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, 2, name); + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded; return its result */ + /* else must load it; first mark it as loaded */ + lua_pushboolean(L, 1); + lua_setfield(L, 2, name); /* _LOADED[name] = true */ + /* check whether it is preloaded */ + lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) { /* no preload function for that module? */ + const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); + const char *cpath = loadC(L, fname, name); /* try a C module */ + if (cpath) { /* not found? */ + const char *path = loadLua(L, fname, name); /* try a Lua module */ + if (path) { /* yet not found? */ + lua_pushnil(L); + lua_setfield(L, 2, name); /* unmark _LOADED[name] */ + return luaL_error(L, "package `%s' not found\n" + " cpath: %s\n path: %s", + name, cpath, path); + } + } + } + lua_pushvalue(L, 1); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* update _LOADED[name] with returned value */ + lua_getfield(L, 2, name); /* return _LOADED[name] */ + return 1; +} + + +static void setfenv (lua_State *L) { + lua_Debug ar; + lua_getstack(L, 1, &ar); + lua_getinfo(L, "f", &ar); + lua_pushvalue(L, -2); + lua_setfenv(L, -2); +} + + +static int ll_module (lua_State *L) { + const char *modname = luaL_checkstring(L, 1); + const char *dot; + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + /* try to find given table */ + luaL_getfield(L, LUA_GLOBALSINDEX, modname); + if (lua_isnil(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + lua_newtable(L); /* create it */ + /* register it with given name */ + lua_pushvalue(L, -1); + luaL_setfield(L, LUA_GLOBALSINDEX, modname); + } + else if (!lua_istable(L, -1)) + return luaL_error(L, "name conflict for module `%s'", modname); + /* check whether table already has a _NAME field */ + lua_getfield(L, -1, "_NAME"); + if (!lua_isnil(L, -1)) /* is table an initialized module? */ + lua_pop(L, 1); + else { /* no; initialize it */ + lua_pop(L, 1); + lua_newtable(L); /* create new metatable */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + lua_setmetatable(L, -2); + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); + } + lua_pushvalue(L, -1); + lua_setfield(L, 2, modname); /* _LOADED[modname] = new table */ + setfenv(L); + return 0; +} + + +/* }====================================================== */ + + +static const luaL_reg ll_funcs[] = { + {"loadlib", loadlib1}, + {"require", ll_require}, + {"module", ll_module}, + {NULL, NULL} +}; + + + +LUALIB_API int luaopen_loadlib (lua_State *L) { + const char *path; + /* create new type _LOADLIB */ + luaL_newmetatable(L, "_LOADLIB"); + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); + /* create `package' table */ + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "package"); + /* set field `path' */ + path = getenv(LUA_PATH); + if (path == NULL) path = LUA_PATH_DEFAULT; + lua_pushstring(L, path); + lua_setfield(L, -2, "path"); + /* set field `cpath' */ + path = getenv(LUA_CPATH); + if (path == NULL) path = LUA_CPATH_DEFAULT; + lua_pushstring(L, path); + lua_setfield(L, -2, "cpath"); + /* set field `loaded' */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_setfield(L, -2, "loaded"); + /* set field `preload' */ + lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); + lua_setfield(L, -2, "preload"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + luaL_openlib(L, NULL, ll_funcs, 0); /* open lib into global table */ + return 1; +} + /* * Here are some links to available implementations of dlfcn and * interfaces to other native dynamic loaders on top of which loadlib @@ -179,9 +423,6 @@ LUALIB_API int luaopen_loadlib (lua_State *L) * Macintosh, Windows * http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html * -* Mac OS X/Darwin -* http://www.opendarwin.org/projects/dlcompat/ -* * GLIB has wrapper code for BeOS, OS2, Unix and Windows * http://cvs.gnome.org/lxr/source/glib/gmodule/ * diff --git a/src/lib/loslib.c b/src/lib/loslib.c index c5726cfe77..4f1d2d03a3 100644 --- a/src/lib/loslib.c +++ b/src/lib/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.2 2004/08/05 19:30:37 roberto Exp $ +** $Id: loslib.c,v 1.3 2004/10/08 18:57:16 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -20,7 +20,7 @@ #include "lualib.h" -static int pushresult (lua_State *L, int i, const char *filename) { +static int os_pushresult (lua_State *L, int i, const char *filename) { if (i) { lua_pushboolean(L, 1); return 1; @@ -45,14 +45,14 @@ static int io_execute (lua_State *L) { static int io_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); - return pushresult(L, remove(filename) == 0, filename); + return os_pushresult(L, remove(filename) == 0, filename); } static int io_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); - return pushresult(L, rename(fromname, toname) == 0, fromname); + return os_pushresult(L, rename(fromname, toname) == 0, fromname); } diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c index 7fa205c074..a9c002fb10 100644 --- a/src/lib/lstrlib.c +++ b/src/lib/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.106 2004/08/09 13:30:33 roberto Exp $ +** $Id: lstrlib.c,v 1.109 2004/12/01 15:46:06 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -24,8 +24,6 @@ #define uchar(c) ((unsigned char)(c)) -typedef lua_Integer sint32; /* a signed version for size_t */ - static int str_len (lua_State *L) { size_t l; @@ -35,19 +33,19 @@ static int str_len (lua_State *L) { } -static sint32 posrelat (sint32 pos, size_t len) { +static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { /* relative string position: negative means back from end */ - return (pos>=0) ? pos : (sint32)len+pos+1; + return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 start = posrelat(luaL_checkinteger(L, 2), l); - sint32 end = posrelat(luaL_optinteger(L, 3, -1), l); + ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); + ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; - if (end > (sint32)l) end = (sint32)l; + if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; if (start <= end) lua_pushlstring(L, s+start-1, end-start+1); else lua_pushliteral(L, ""); @@ -107,8 +105,8 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - sint32 posi = posrelat(luaL_optinteger(L, 2, 1), l); - sint32 pose = posrelat(luaL_optinteger(L, 3, posi), l); + ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi <= 0) posi = 1; if ((size_t)pose > l) pose = l; @@ -173,7 +171,7 @@ typedef struct MatchState { int level; /* total number of captures (finished or unfinished) */ struct { const char *init; - sint32 len; + ptrdiff_t len; } capture[MAX_CAPTURES]; } MatchState; @@ -198,7 +196,7 @@ static int capture_to_close (MatchState *ms) { } -static const char *luaI_classend (MatchState *ms, const char *p) { +static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case ESC: { if (*p == '\0') @@ -250,7 +248,7 @@ static int matchbracketclass (int c, const char *p, const char *ec) { while (++p < ec) { if (*p == ESC) { p++; - if (match_class(c, *p)) + if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { @@ -264,10 +262,10 @@ static int matchbracketclass (int c, const char *p, const char *ec) { } -static int luaI_singlematch (int c, const char *p, const char *ep) { +static int singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': return 1; /* matches any char */ - case ESC: return match_class(c, *(p+1)); + case ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } @@ -299,8 +297,8 @@ static const char *matchbalance (MatchState *ms, const char *s, static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { - sint32 i = 0; /* counts maximum expand for item */ - while ((s+i)src_end && luaI_singlematch(uchar(*(s+i)), p, ep)) + ptrdiff_t i = 0; /* counts maximum expand for item */ + while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { @@ -318,7 +316,7 @@ static const char *min_expand (MatchState *ms, const char *s, const char *res = match(ms, s, ep+1); if (res != NULL) return res; - else if (ssrc_end && luaI_singlematch(uchar(*s), p, ep)) + else if (ssrc_end && singlematch(uchar(*s), p, ep)) s++; /* try with one more repetition */ else return NULL; } @@ -385,7 +383,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { p += 2; if (*p != '[') luaL_error(ms->L, "missing `[' after `%%f' in pattern"); - ep = luaI_classend(ms, p); /* points to what is next */ + ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s-1); if (matchbracketclass(uchar(previous), p, ep-1) || !matchbracketclass(uchar(*s), p, ep-1)) return NULL; @@ -393,7 +391,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { } default: { if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, *(p+1)); + s = match_capture(ms, s, uchar(*(p+1))); if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } @@ -410,8 +408,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) { else goto dflt; } default: dflt: { /* it is a pattern item */ - const char *ep = luaI_classend(ms, p); /* points to what is next */ - int m = ssrc_end && luaI_singlematch(uchar(*s), p, ep); + const char *ep = classend(ms, p); /* points to what is next */ + int m = ssrc_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; @@ -490,9 +488,9 @@ static int str_find (lua_State *L) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); - sint32 init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; + ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; if (init < 0) init = 0; - else if ((size_t)(init) > l1) init = (sint32)l1; + else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; if (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ /* do a plain search */ @@ -642,7 +640,7 @@ static int str_gsub (lua_State *L) { #define MAX_FORMAT 20 -static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { +static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); luaL_putchar(b, '"'); @@ -726,7 +724,7 @@ static int str_format (lua_State *L) { break; } case 'q': { - luaI_addquoted(L, &b, arg); + addquoted(L, &b, arg); continue; /* skip the `addsize' at the end */ } case 's': { diff --git a/src/llex.c b/src/llex.c index c5e491e5bd..3940b95574 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.3 2004/04/30 20:13:38 roberto Exp $ +** $Id: llex.c,v 2.9 2004/12/03 20:54:12 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -26,34 +26,45 @@ #define next(ls) (ls->current = zgetc(ls->z)) -#define save(ls,c) { \ - Mbuffer *b = ls->buff; \ - if (b->n + 1 > b->buffsize) \ - luaZ_resizebuffer(ls->L, b, ((b->buffsize*2) + LUA_MINBUFFER)); \ - b->buffer[b->n++] = cast(char, c); } - #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ -static const char *const token2string [] = { +const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", "*name", + "return", "then", "true", "until", "while", "..", "...", "==", ">=", "<=", "~=", - "*number", "*string", "" + "", "", "", "", + NULL }; +#define save_and_next(ls) (save(ls, ls->current), next(ls)) + + +static void save (LexState *ls, int c) { + Mbuffer *b = ls->buff; + if (b->n + 1 > b->buffsize) { + size_t newsize; + if (b->buffsize >= MAX_SIZET/2) + luaX_lexerror(ls, "lexical element too long", 0); + newsize = b->buffsize * 2; + luaZ_resizebuffer(ls->L, b, newsize); + } + b->buffer[b->n++] = cast(char, c); +} + + void luaX_init (lua_State *L) { int i; for (i=0; itsv.reserved = cast(lu_byte, i+1); /* reserved word */ } } @@ -64,12 +75,12 @@ void luaX_init (lua_State *L) { const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { - lua_assert(token == (unsigned char)token); + lua_assert(token == cast(unsigned char, token)); return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : luaO_pushfstring(ls->L, "%c", token); } else - return token2string[token-FIRST_RESERVED]; + return luaX_tokens[token-FIRST_RESERVED]; } @@ -130,6 +141,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->linenumber = 1; ls->lastline = 1; ls->source = source; + luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ next(ls); /* read first char */ } @@ -143,12 +155,6 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { -static void save_and_next (LexState *ls) { - save(ls, ls->current); - next(ls); -} - - /* LUA_NUMBER */ static void read_numeral (LexState *ls, SemInfo *seminfo) { @@ -181,12 +187,12 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { } -static int skip_ast (LexState *ls) { +static int skip_sep (LexState *ls) { int count = 0; int s = ls->current; lua_assert(s == '[' || s == ']'); save_and_next(ls); - while (ls->current == '*') { + while (ls->current == '=') { save_and_next(ls); count++; } @@ -194,7 +200,7 @@ static int skip_ast (LexState *ls) { } -static void read_long_string (LexState *ls, SemInfo *seminfo, int ast) { +static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { int cont = 0; save_and_next(ls); /* skip 2nd `[' */ if (currIsNewline(ls)) /* string starts with a newline? */ @@ -206,13 +212,13 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int ast) { "unfinished long comment", TK_EOS); break; /* to avoid warnings */ case '[': - if (skip_ast(ls) == ast) { + if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `[' */ cont++; } continue; case ']': - if (skip_ast(ls) == ast) { + if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `]' */ if (cont-- == 0) goto endloop; } @@ -229,8 +235,8 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int ast) { } } endloop: if (seminfo) - seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + ast), - luaZ_bufflen(ls->buff) - 2*(2 + ast)); + seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), + luaZ_bufflen(ls->buff) - 2*(2 + sep)); } @@ -305,10 +311,10 @@ int luaX_lex (LexState *ls, SemInfo *seminfo) { /* else is a comment */ next(ls); if (ls->current == '[') { - int ast = skip_ast(ls); - luaZ_resetbuffer(ls->buff); /* `skip_ast' may dirty the buffer */ - if (ast >= 0) { - read_long_string(ls, NULL, ast); /* long comment */ + int sep = skip_sep(ls); + luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ + if (sep >= 0) { + read_long_string(ls, NULL, sep); /* long comment */ luaZ_resetbuffer(ls->buff); continue; } @@ -319,12 +325,12 @@ int luaX_lex (LexState *ls, SemInfo *seminfo) { continue; } case '[': { - int ast = skip_ast(ls); - if (ast >= 0) { - read_long_string(ls, seminfo, ast); + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); return TK_STRING; } - else if (ast == -1) return '['; + else if (sep == -1) return '['; else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { diff --git a/src/llex.h b/src/llex.h index 6cfc3fdde8..a16bba8dcf 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.50 2004/03/12 19:53:56 roberto Exp $ +** $Id: llex.h,v 1.52 2004/12/03 20:54:12 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -28,14 +28,18 @@ enum RESERVED { TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ - TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, - TK_STRING, TK_EOS + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, + TK_NAME, TK_STRING, TK_EOS }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) +/* array with token `names' */ +extern const char *const luaX_tokens []; + + typedef union { lua_Number r; TString *ts; diff --git a/src/llimits.h b/src/llimits.h index 95a51a0b90..6be658f022 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.60 2004/09/10 17:30:46 roberto Exp $ +** $Id: llimits.h,v 1.61 2004/11/24 18:55:56 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -18,22 +18,9 @@ typedef LUA_UINT32 lu_int32; -typedef LUA_INT32 l_int32; +typedef LU_MEM lu_mem; - -/* -** an unsigned integer big enough to count the total memory used by Lua; -** it should be at least as large as `size_t' -*/ -typedef lu_int32 lu_mem; - - -/* -** a signed integer big enough to count the total memory used by Lua; -** it should be at least as large as `size_t' -*/ -typedef l_int32 l_mem; -#define MAXLMEM LUA_MAXINT32 +typedef L_MEM l_mem; @@ -43,6 +30,8 @@ typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) + #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ @@ -51,7 +40,7 @@ typedef unsigned char lu_byte; ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ -#define IntPoint(p) ((unsigned int)(p)) +#define IntPoint(p) ((unsigned int)(lu_mem)(p)) diff --git a/src/lmem.c b/src/lmem.c index c1802ff992..632990fcaa 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.65 2004/08/30 13:44:44 roberto Exp $ +** $Id: lmem.c,v 1.67 2004/12/01 15:46:18 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -43,36 +43,39 @@ #define MINSIZEARRAY 4 -void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, - int limit, const char *errormsg) { +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, + int limit, const char *errormsg) { void *newblock; int newsize; if (*size >= limit/2) { /* cannot double it? */ - if (*size >= limit - MINSIZEARRAY) /* try something smaller... */ + if (*size >= limit) /* cannot grow even a little? */ luaG_runerror(L, errormsg); - newsize = limit; /* still have at least MINSIZEARRAY free places */ + newsize = limit; /* still have at least one free place */ } else { newsize = (*size)*2; if (newsize < MINSIZEARRAY) newsize = MINSIZEARRAY; /* minimum size */ } - newblock = luaM_realloc(L, block, - cast(lu_mem, *size)*cast(lu_mem, size_elems), - cast(lu_mem, newsize)*cast(lu_mem, size_elems)); + newblock = luaM_reallocv(L, block, *size, newsize, size_elems); *size = newsize; /* update only when everything else is OK */ return newblock; } +void *luaM_toobig (lua_State *L) { + luaG_runerror(L, "memory allocation error: block too big"); + return NULL; /* to avoid warnings */ +} + + + /* ** generic allocation routine. */ -void *luaM_realloc (lua_State *L, void *block, lu_mem osize, lu_mem nsize) { +void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { global_State *g = G(L); lua_assert((osize == 0) == (block == NULL)); - if (nsize >= MAX_SIZET) - luaG_runerror(L, "memory allocation error: block too big"); block = (*g->realloc)(g->ud, block, osize, nsize); if (block == NULL && nsize > 0) luaD_throw(L, LUA_ERRMEM); diff --git a/src/lmem.h b/src/lmem.h index 1bb4fde0b2..13a1658b80 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.26 2002/05/01 20:40:42 roberto Exp $ +** $Id: lmem.h,v 1.29 2004/12/01 15:46:18 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -16,28 +16,34 @@ #define MEMERRMSG "not enough memory" -void *luaM_realloc (lua_State *L, void *oldblock, lu_mem oldsize, lu_mem size); +void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); -void *luaM_growaux (lua_State *L, void *block, int *size, int size_elem, - int limit, const char *errormsg); +void *luaM_toobig (lua_State *L); -#define luaM_free(L, b, s) luaM_realloc(L, (b), (s), 0) -#define luaM_freelem(L, b) luaM_realloc(L, (b), sizeof(*(b)), 0) -#define luaM_freearray(L, b, n, t) luaM_realloc(L, (b), \ - cast(lu_mem, n)*cast(lu_mem, sizeof(t)), 0) +#define luaM_reallocv(L,b,on,n,e) \ + ((cast(unsigned int, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ + luaM_toobig(L)) -#define luaM_malloc(L, t) luaM_realloc(L, NULL, 0, (t)) -#define luaM_new(L, t) cast(t *, luaM_malloc(L, sizeof(t))) -#define luaM_newvector(L, n,t) cast(t *, luaM_malloc(L, \ - cast(lu_mem, n)*cast(lu_mem, sizeof(t)))) + +void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, + int limit, const char *errormsg); + +#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) +#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) +#define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t)) + +#define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t)) +#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) +#define luaM_newvector(L,n,t) \ + cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) #define luaM_growvector(L,v,nelems,size,t,limit,e) \ - if (((nelems)+1) > (size)) \ - ((v)=cast(t *, luaM_growaux(L,v,&(size),sizeof(t),limit,e))) + if ((nelems)+1 > (size)) \ + ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) #define luaM_reallocvector(L, v,oldn,n,t) \ - ((v)=cast(t *, luaM_realloc(L, v,cast(lu_mem, oldn)*cast(lu_mem, sizeof(t)), \ - cast(lu_mem, n)*cast(lu_mem, sizeof(t))))) + ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) #endif diff --git a/src/lobject.c b/src/lobject.c index 1e24bb5df6..154a0faf3c 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.4 2004/07/09 16:01:38 roberto Exp $ +** $Id: lobject.c,v 2.7 2004/11/24 19:16:03 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -23,7 +23,7 @@ -const TValue luaO_nilobject = {LUA_TNIL, {NULL}}; +const TValue luaO_nilobject = {{NULL}, LUA_TNIL}; /* @@ -31,12 +31,21 @@ const TValue luaO_nilobject = {LUA_TNIL, {NULL}}; ** (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm) */ int luaO_int2fb (unsigned int x) { - int m = 0; /* mantissa */ - while (x >= (1<<3)) { + int e = 0; /* expoent */ + while (x >= 16) { x = (x+1) >> 1; - m++; + e++; } - return (m << 3) | cast(int, x); + if (x < 8) return x; + else return ((e+1) << 3) | (cast(int, x) - 8); +} + + +/* converts back */ +int luaO_fb2int (int x) { + int e = (x >> 3) & 31; + if (e == 0) return x; + else return ((x & 7)+8) << (e - 1); } @@ -80,7 +89,7 @@ int luaO_str2d (const char *s, lua_Number *result) { char *endptr; lua_Number res = lua_str2number(s, &endptr); if (endptr == s) return 0; /* no conversion */ - while (isspace((unsigned char)(*endptr))) endptr++; + while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ *result = res; return 1; diff --git a/src/lobject.h b/src/lobject.h index 4b6a684b73..56c0fe8ac1 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.5 2004/05/31 18:51:50 roberto Exp $ +** $Id: lobject.h,v 2.8 2004/12/04 18:10:22 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -25,6 +25,7 @@ */ #define LUA_TPROTO (NUM_TAGS+1) #define LUA_TUPVAL (NUM_TAGS+2) +#define LUA_TDEADKEY (NUM_TAGS+3) /* @@ -64,9 +65,11 @@ typedef union { /* ** Tagged Values */ + +#define TValuefields Value value; int tt + typedef struct lua_TValue { - int tt; - Value value; + TValuefields; } TValue; @@ -158,7 +161,7 @@ typedef struct lua_TValue { #define setobj(L,obj1,obj2) \ { const TValue *o2=(obj2); TValue *o1=(obj1); \ - o1->tt=o2->tt; o1->value = o2->value; \ + o1->value = o2->value; o1->tt=o2->tt; \ checkliveness(G(L),o1); } @@ -308,10 +311,15 @@ typedef union Closure { ** Tables */ +typedef struct TKey { + TValuefields; + struct Node *next; /* for chaining */ +} TKey; + + typedef struct Node { - TValue i_key; TValue i_val; - struct Node *next; /* for chaining */ + TKey i_key; } Node; @@ -345,7 +353,7 @@ extern const TValue luaO_nilobject; int luaO_log2 (unsigned int x); int luaO_int2fb (unsigned int x); -#define fb2int(x) (((x) & 7) << ((x) >> 3)) +int luaO_fb2int (int x); int luaO_rawequalObj (const TValue *t1, const TValue *t2); int luaO_str2d (const char *s, lua_Number *result); diff --git a/src/lopcodes.c b/src/lopcodes.c index 87ec8939c1..24cd31d5ab 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.28 2004/07/16 13:15:32 roberto Exp $ +** $Id: lopcodes.c,v 1.30 2004/12/02 12:59:10 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -15,7 +15,7 @@ /* ORDER OP */ -const char *const luaP_opnames[NUM_OPCODES] = { +const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADBOOL", @@ -49,10 +49,10 @@ const char *const luaP_opnames[NUM_OPCODES] = { "TFORLOOP", "TFORPREP", "SETLIST", - "SETLISTO", "CLOSE", "CLOSURE", - "VARARG" + "VARARG", + NULL }; @@ -92,8 +92,7 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_TFORPREP */ - ,opmode(0, 0, OpArgU, OpArgN, iABx) /* OP_SETLIST */ - ,opmode(0, 0, OpArgU, OpArgN, iABx) /* OP_SETLISTO */ + ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ diff --git a/src/lopcodes.h b/src/lopcodes.h index d3429a597b..dfbcaffe1e 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.111 2004/08/04 20:18:13 roberto Exp $ +** $Id: lopcodes.h,v 1.114 2004/12/02 12:59:10 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -198,8 +198,7 @@ OP_TFORLOOP,/* A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); OP_TFORPREP,/* A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next; pc+=sBx */ -OP_SETLIST,/* A Bx R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1 */ -OP_SETLISTO,/* A Bx */ +OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ @@ -219,11 +218,15 @@ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and - set top (like in OP_CALL). + set top (like in OP_CALL with C == 0). (*) In OP_RETURN, if (B == 0) then return up to `top' - (*) For comparisons, B specifies what conditions the test should accept. + (*) In OP_SETLIST, if (B == 0) then B = `top'; + if (C == 0) then next `instruction' is real C + + (*) For comparisons, A specifies what condition the test should accept + (true or false). (*) All `skips' (pc++) assume that next instruction is a jump ===========================================================================*/ @@ -254,12 +257,11 @@ extern const lu_byte luaP_opmodes[NUM_OPCODES]; #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) -extern const char *const luaP_opnames[NUM_OPCODES]; /* opcode names */ +extern const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ -/* (must be a power of 2) */ -#define LFIELDS_PER_FLUSH 32 +#define LFIELDS_PER_FLUSH 50 #endif diff --git a/src/lparser.c b/src/lparser.c index c0fc1579e3..b40cf7c7b1 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.5 2004/05/31 18:51:50 roberto Exp $ +** $Id: lparser.c,v 2.10 2004/12/03 20:50:25 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -31,7 +31,7 @@ #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) -#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) luaY_errorlimit(fs,l,m) +#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) #define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ luaX_lexerror(ls, "chunk has too many syntax levels", 0) @@ -90,7 +90,7 @@ static void error_expected (LexState *ls, int token) { } -static void luaY_errorlimit (FuncState *fs, int limit, const char *what) { +static void errorlimit (FuncState *fs, int limit, const char *what) { const char *msg = (fs->f->lineDefined == 0) ? luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : luaO_pushfstring(fs->L, "function at line %d has more than %d %s", @@ -133,7 +133,7 @@ static void check_match (LexState *ls, int what, int who, int where) { static TString *str_checkname (LexState *ls) { TString *ts; - check_condition(ls, (ls->t.token == TK_NAME), " expected"); + if (ls->t.token != TK_NAME) error_expected(ls, TK_NAME); ts = ls->t.seminfo.ts; next(ls); return ts; @@ -157,7 +157,7 @@ static void checkname(LexState *ls, expdesc *e) { } -static int luaI_registerlocalvar (LexState *ls, TString *varname) { +static int registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizelocvars; @@ -177,8 +177,7 @@ static int luaI_registerlocalvar (LexState *ls, TString *varname) { static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; luaY_checklimit(fs, fs->nactvar+n+1, MAXVARS, "local variables"); - fs->actvar[fs->nactvar+n] = cast(unsigned short, - luaI_registerlocalvar(ls, name)); + fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); } @@ -413,7 +412,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { /*============================================================*/ -static void luaY_field (LexState *ls, expdesc *v) { +static void field (LexState *ls, expdesc *v) { /* field -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; @@ -424,7 +423,7 @@ static void luaY_field (LexState *ls, expdesc *v) { } -static void luaY_index (LexState *ls, expdesc *v) { +static void yindex (LexState *ls, expdesc *v) { /* index -> '[' expr ']' */ next(ls); /* skip the '[' */ expr(ls, v); @@ -460,7 +459,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { checkname(ls, &key); } else /* ls->t.token == '[' */ - luaY_index(ls, &key); + yindex(ls, &key); check(ls, '='); luaK_exp2RK(fs, &key); expr(ls, &val); @@ -475,9 +474,8 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) { luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { - luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); /* flush */ + luaK_setlist(fs, cc->t->info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ - fs->freereg = cc->t->info + 1; /* free registers */ } } @@ -486,15 +484,14 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); - luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1); + luaK_setlist(fs, cc->t->info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); - luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); + luaK_setlist(fs, cc->t->info, cc->na, cc->tostore); } - fs->freereg = cc->t->info + 1; /* free registers */ } @@ -703,13 +700,13 @@ static void primaryexp (LexState *ls, expdesc *v) { for (;;) { switch (ls->t.token) { case '.': { /* field */ - luaY_field(ls, v); + field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyreg(fs, v); - luaY_index(ls, &key); + yindex(ls, &key); luaK_indexed(fs, v, &key); break; } @@ -1213,10 +1210,10 @@ static int funcname (LexState *ls, expdesc *v) { int needself = 0; singlevar(ls, v, 1); while (ls->t.token == '.') - luaY_field(ls, v); + field(ls, v); if (ls->t.token == ':') { needself = 1; - luaY_field(ls, v); + field(ls, v); } return needself; } diff --git a/src/lstate.c b/src/lstate.c index 9f55f997d4..dfd35be6ec 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.14 2004/09/15 20:39:42 roberto Exp $ +** $Id: lstate.c,v 2.18 2004/12/06 17:53:42 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -79,7 +79,7 @@ static void f_luaopen (lua_State *L, void *ud) { Udata *u; /* head of udata list */ global_State *g = G(L); UNUSED(ud); - u = cast(Udata *, luaM_malloc(L, sizeudata(0))); + u = luaM_new(L, Udata); u->uv.len = 0; u->uv.metatable = NULL; g->firstudata = obj2gco(u); @@ -155,7 +155,7 @@ void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); freestack(L, L1); - luaM_free(L, fromstate(L1), state_size(lua_State)); + luaM_freemem(L, fromstate(L1), state_size(lua_State)); } @@ -191,8 +191,10 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->tmudata = NULL; setnilvalue(gkey(g->dummynode)); setnilvalue(gval(g->dummynode)); - g->dummynode->next = NULL; + gnext(g->dummynode) = NULL; g->totalbytes = sizeof(LG); + g->stepmul = STEPMUL; + g->incgc = 1; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); diff --git a/src/lstate.h b/src/lstate.h index d7583d279b..81fb75a0e1 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.8 2004/09/15 20:39:42 roberto Exp $ +** $Id: lstate.h,v 2.9 2004/12/06 17:53:42 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -85,6 +85,8 @@ typedef struct global_State { lu_mem totalbytes; /* number of bytes currently allocated */ lu_mem estimate; /* an estimate of number of bytes actually in use */ lu_mem prevestimate; /* previous estimate */ + int stepmul; /* relative `speed' of the GC */ + int incgc; /* 0 if GC is done non-incrementally */ lua_CFunction panic; /* to be called in unprotected errors */ TValue _registry; struct lua_State *mainthread; diff --git a/src/lstring.c b/src/lstring.c index 4c34dc9b31..af2c696324 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.3 2004/08/24 20:12:06 roberto Exp $ +** $Id: lstring.c,v 2.5 2004/11/24 19:16:03 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -49,8 +49,11 @@ void luaS_resize (lua_State *L, int newsize) { static TString *newlstr (lua_State *L, const char *str, size_t l, unsigned int h) { - TString *ts = cast(TString *, luaM_malloc(L, sizestring(l))); + TString *ts; stringtable *tb; + if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); ts->tsv.len = l; ts->tsv.hash = h; ts->tsv.marked = luaC_white(G(L)); @@ -75,7 +78,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ - h = h ^ ((h<<5)+(h>>2)+(unsigned char)(str[l1-1])); + h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { @@ -92,7 +95,9 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { Udata *luaS_newudata (lua_State *L, size_t s) { Udata *u; - u = cast(Udata *, luaM_malloc(L, sizeudata(s))); + if (s > MAX_SIZET - sizeof(Udata)) + luaM_toobig(L); + u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); u->uv.marked = luaC_white(G(L)); /* is not finalized */ u->uv.tt = LUA_TUSERDATA; u->uv.len = s; diff --git a/src/lstring.h b/src/lstring.h index 2d6e74a442..4198f57ce6 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.39 2004/08/24 20:12:06 roberto Exp $ +** $Id: lstring.h,v 1.40 2004/11/19 15:52:40 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -13,10 +13,9 @@ #include "lstate.h" -#define sizestring(l) (cast(lu_mem, sizeof(union TString))+ \ - (cast(lu_mem, l)+1)*sizeof(char)) +#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) -#define sizeudata(l) (cast(lu_mem, sizeof(union Udata))+(l)) +#define sizeudata(u) (sizeof(union Udata)+(u)->len) #define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ diff --git a/src/ltable.c b/src/ltable.c index 10008c543c..8bfbf64150 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.5 2004/08/31 17:57:33 roberto Exp $ +** $Id: ltable.c,v 2.12 2004/12/04 18:10:22 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -38,7 +38,7 @@ ** max size of array part is 2^MAXBITS */ #if LUA_BITSINT > 26 -#define MAXBITS 24 +#define MAXBITS 26 #else #define MAXBITS (LUA_BITSINT-2) #endif @@ -107,11 +107,10 @@ Node *luaH_mainposition (const Table *t, const TValue *key) { ** returns the index for `key' if `key' is an appropriate key to live in ** the array part of the table, -1 otherwise. */ -static int arrayindex (const TValue *key, lua_Number lim) { +static int arrayindex (const TValue *key) { if (ttisnumber(key)) { lua_Number n = nvalue(key); int k; - if (n <= 0 || n > lim) return -1; /* out of range? */ lua_number2int(k, n); if (cast(lua_Number, k) == nvalue(key)) return k; @@ -123,28 +122,35 @@ static int arrayindex (const TValue *key, lua_Number lim) { /* ** returns the index of a `key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The -** beginning and end of a traversal are signalled by -1. +** beginning of a traversal is signalled by -1. */ -static int luaH_index (lua_State *L, Table *t, StkId key) { +static int findindex (lua_State *L, Table *t, StkId key) { int i; if (ttisnil(key)) return -1; /* first iteration */ - i = arrayindex(key, t->sizearray); - if (0 <= i) { /* is `key' inside array part? */ + i = arrayindex(key); + if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ - } else { - const TValue *v = luaH_get(t, key); - if (v == &luaO_nilobject) - luaG_runerror(L, "invalid key for `next'"); - i = cast(int, (cast(const lu_byte *, v) - - cast(const lu_byte *, gval(gnode(t, 0)))) / sizeof(Node)); - return i + t->sizearray; /* hash elements are numbered after array ones */ + Node *n = luaH_mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in `next' */ + if (luaO_rawequalObj(key2tval(n), key) || + (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && + gcvalue(gkey(n)) == gcvalue(key))) { + i = n - gnode(t, 0); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return i + t->sizearray; + } + else n = gnext(n); + } while (n); + luaG_runerror(L, "invalid key for `next'"); /* key not found */ + return 0; /* to avoid warnings */ } } int luaH_next (lua_State *L, Table *t, StkId key) { - int i = luaH_index(L, t, key); /* find original element */ + int i = findindex(L, t, key); /* find original element */ for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setnvalue(key, cast(lua_Number, i+1)); @@ -154,7 +160,7 @@ int luaH_next (lua_State *L, Table *t, StkId key) { } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(L, key, gkey(gnode(t, i))); + setobj2s(L, key, key2tval(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); return 1; } @@ -195,7 +201,6 @@ static void numuse (const Table *t, int *narray, int *nhash) { int nums[MAXBITS+1]; int i, lg; int totaluse = 0; - lua_Number sizelimit; /* an upper bound for the array size */ /* count elements in array part */ for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ int ttlg = twoto(lg); /* 2^lg */ @@ -215,14 +220,11 @@ static void numuse (const Table *t, int *narray, int *nhash) { *narray = totaluse; /* all previous uses were in array part */ /* count elements in hash part */ i = sizenode(t); - /* array part cannot be larger than twice the maximum number of elements */ - sizelimit = cast(lua_Number, totaluse + i) * 2; - if (sizelimit >= MAXASIZE) sizelimit = MAXASIZE; while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { - int k = arrayindex(gkey(n), sizelimit); - if (k >= 0) { /* is `key' an appropriate array index? */ + int k = arrayindex(key2tval(n)); + if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ nums[luaO_log2(k-1)+1]++; /* count as such */ (*narray)++; } @@ -251,12 +253,12 @@ static void setnodevector (lua_State *L, Table *t, int lsize) { t->node = G(L)->dummynode; /* use common `dummynode' */ lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */ lua_assert(ttisnil(gval(t->node))); - lua_assert(t->node->next == NULL); /* (`dummynode' must be empty) */ + lua_assert(gnext(t->node) == NULL); /* (`dummynode' must be empty) */ } else { t->node = luaM_newvector(L, size, Node); for (i=0; inode[i].next = NULL; + gnext(&t->node[i]) = NULL; setnilvalue(gkey(gnode(t, i))); setnilvalue(gval(gnode(t, i))); } @@ -280,7 +282,7 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { nold = temp; setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */ setnilvalue(gval(G(L)->dummynode)); - lua_assert(G(L)->dummynode->next == NULL); + lua_assert(gnext(G(L)->dummynode) == NULL); } if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); @@ -301,7 +303,7 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) - setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); + setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } if (oldhsize) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ @@ -341,7 +343,7 @@ void luaH_free (lua_State *L, Table *t) { if (t->lsizenode) luaM_freearray(L, t->node, sizenode(t), Node); luaM_freearray(L, t->array, t->sizearray, TValue); - luaM_freelem(L, t); + luaM_free(L, t); } @@ -357,24 +359,25 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { TValue *val; Node *mp = luaH_mainposition(t, key); if (!ttisnil(gval(mp))) { /* main position is not free? */ - Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */ + /* `mp' of colliding node */ + Node *othern = luaH_mainposition(t, key2tval(mp)); Node *n = t->firstfree; /* get a free place */ if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ - while (othern->next != mp) othern = othern->next; /* find previous */ - othern->next = n; /* redo the chain with `n' in place of `mp' */ + while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ + gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - mp->next = NULL; /* now `mp' is free */ + gnext(mp) = NULL; /* now `mp' is free */ setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ - n->next = mp->next; /* chain new position */ - mp->next = n; + gnext(n) = gnext(mp); /* chain new position */ + gnext(mp) = n; mp = n; } } - setobj2t(L, gkey(mp), key); + gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); for (;;) { /* correct `firstfree' */ @@ -397,7 +400,8 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { ** search function for integers */ const TValue *luaH_getnum (Table *t, int key) { - if (1 <= key && key <= t->sizearray) + /* (1 <= key && key <= t->sizearray) */ + if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; else { lua_Number nk = cast(lua_Number, key); @@ -405,7 +409,7 @@ const TValue *luaH_getnum (Table *t, int key) { do { /* check whether `key' is somewhere in the chain */ if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk) return gval(n); /* that's it */ - else n = n->next; + else n = gnext(n); } while (n); return &luaO_nilobject; } @@ -420,7 +424,7 @@ const TValue *luaH_getstr (Table *t, TString *key) { do { /* check whether `key' is somewhere in the chain */ if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) return gval(n); /* that's it */ - else n = n->next; + else n = gnext(n); } while (n); return &luaO_nilobject; } @@ -443,8 +447,9 @@ const TValue *luaH_get (Table *t, const TValue *key) { default: { Node *n = luaH_mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ - else n = n->next; + if (luaO_rawequalObj(key2tval(n), key)) + return gval(n); /* that's it */ + else n = gnext(n); } while (n); return &luaO_nilobject; } diff --git a/src/ltable.h b/src/ltable.h index d72cf9f52e..cfc8601700 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.2 2004/03/26 14:02:41 roberto Exp $ +** $Id: ltable.h,v 2.3 2004/10/06 18:34:16 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -13,6 +13,9 @@ #define gnode(t,i) (&(t)->node[i]) #define gkey(n) (&(n)->i_key) #define gval(n) (&(n)->i_val) +#define gnext(n) ((n)->i_key.next) + +#define key2tval(n) (cast(const TValue *, gkey(n))) const TValue *luaH_getnum (Table *t, int key); diff --git a/src/lua/lua.c b/src/lua/lua.c index 6fe479b309..6a21a6ae16 100644 --- a/src/lua/lua.c +++ b/src/lua/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.132 2004/08/30 18:35:14 roberto Exp $ +** $Id: lua.c,v 1.133 2004/11/18 19:53:49 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -127,9 +127,9 @@ static int dostring (lua_State *L, const char *s, const char *name) { static int dolibrary (lua_State *L, const char *name) { - lua_getfield(L, LUA_GLOBALSINDEX, "_PATH"); + luaL_getfield(L, LUA_GLOBALSINDEX, "package.path"); if (!lua_isstring(L, -1)) { - l_message(progname, "global _PATH must be a string"); + l_message(progname, "`package.path' must be a string"); return 1; } name = luaL_searchpath(L, name, lua_tostring(L, -1)); @@ -295,7 +295,7 @@ static int handle_argv (lua_State *L, char *argv[], int *interactive) { print_usage(); return 1; } - if (dostring(L, chunk, "=") != 0) + if (dostring(L, chunk, "=(command line)") != 0) return 1; break; } diff --git a/src/luac/print.c b/src/luac/print.c index 0d3f18bfc8..f273ebfccc 100644 --- a/src/luac/print.c +++ b/src/luac/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.48 2004/09/01 21:22:34 lhf Exp $ +** $Id: print.c,v 1.49 2004/11/25 09:31:41 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -33,7 +33,7 @@ static void PrintString(const Proto* f, int n) case '\r': printf("\\r"); break; case '\t': printf("\\t"); break; case '\v': printf("\\v"); break; - default: printf(isprint(*s) ? "%c" : "\\%03d",*s); + default: printf(isprint((unsigned char)*s) ? "%c" : "\\%03d",*s); } } putchar('"'); @@ -44,15 +44,18 @@ static void PrintConstant(const Proto* f, int i) const TValue* o=&f->k[i]; switch (ttype(o)) { + case LUA_TNIL: + printf("nil"); + break; + case LUA_TBOOLEAN: + printf(bvalue(o) ? "true" : "false"); + break; case LUA_TNUMBER: printf(LUA_NUMBER_FMT,nvalue(o)); break; case LUA_TSTRING: PrintString(f,i); break; - case LUA_TNIL: - printf("nil"); - break; default: /* cannot happen */ printf("? type=%d",ttype(o)); break; diff --git a/src/lundump.c b/src/lundump.c index ee09160254..e13a4e482e 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.53 2004/09/01 21:22:34 lhf Exp $ +** $Id: lundump.c,v 1.54 2004/11/25 09:31:41 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -177,15 +177,18 @@ static void LoadConstants (LoadState* S, Proto* f) int t=LoadByte(S); switch (t) { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o,LoadByte(S)); + break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; - case LUA_TNIL: - setnilvalue(o); - break; default: error(S,"bad constant type (%d)",t); break; @@ -243,19 +246,15 @@ static void LoadHeader (LoadState* S) lua_Number x,tx=TEST_NUMBER; LoadSignature(S); version=LoadByte(S); - if (version>VERSION) - error(S,"bad version (read %d.%d; expected at %s %d.%d)", - V(version),"most",V(VERSION)); - if (versionswap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */ TestSize(S,sizeof(int),"int"); TestSize(S,sizeof(size_t),"size_t"); TestSize(S,sizeof(Instruction),"instruction"); TestSize(S,sizeof(lua_Number),"number"); x=LoadNumber(S); - if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */ + if (x!=tx) error(S,"unknown number format"); } diff --git a/src/lundump.h b/src/lundump.h index 4628b81d52..1a7b897bc3 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.33 2004/06/09 21:03:53 lhf Exp $ +** $Id: lundump.h,v 1.34 2004/11/25 09:31:41 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -22,12 +22,10 @@ int luaU_dump (lua_State* L, const Proto* f, lua_Chunkwriter w, void* data, int /* print one chunk; from print.c */ void luaU_print (const Proto* f, int full); -/* definitions for headers of binary files */ -#define VERSION 0x51 /* last format change was in 5.1 */ -#define VERSION0 0x51 /* last major change was in 5.1 */ +/* for header of binary files -- this is Lua 5.1 */ +#define VERSION 0x51 -/* a multiple of PI for testing native format */ -/* multiplying by 1E7 gives non-trivial integer values */ -#define TEST_NUMBER ((lua_Number)3.14159265358979323846E7) +/* for testing native format of lua_Numbers */ +#define TEST_NUMBER ((lua_Number)31415926.0) #endif diff --git a/src/lvm.c b/src/lvm.c index 94f98147e4..1a295d1bdd 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.14 2004/09/15 20:39:42 roberto Exp $ +** $Id: lvm.c,v 2.18 2004/12/03 20:35:33 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -214,7 +214,7 @@ static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, } -static int luaV_strcmp (const TString *ls, const TString *rs) { +static int l_strcmp (const TString *ls, const TString *rs) { const char *l = getstr(ls); size_t ll = ls->tsv.len; const char *r = getstr(rs); @@ -243,21 +243,21 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { else if (ttisnumber(l)) return nvalue(l) < nvalue(r); else if (ttisstring(l)) - return luaV_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; return luaG_ordererror(L, l, r); } -static int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { +static int lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return nvalue(l) <= nvalue(r); else if (ttisstring(l)) - return luaV_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; + return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ @@ -303,15 +303,14 @@ void luaV_concat (lua_State *L, int total, int last) { luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ - lu_mem tl = cast(lu_mem, tsvalue(top-1)->len) + - cast(lu_mem, tsvalue(top-2)->len); + size_t tl = tsvalue(top-1)->len; char *buffer; int i; - while (n < total && tostring(L, top-n-1)) { /* collect total length */ + /* collect total length */ + for (n = 1; n < total && tostring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; - n++; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; @@ -462,7 +461,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } case OP_NEWTABLE: { int b = GETARG_B(i); - b = fb2int(b); + b = luaO_fb2int(b); sethvalue(L, ra, luaH_new(L, b, GETARG_C(i))); L->ci->savedpc = pc; luaC_checkGC(L); /***/ @@ -569,7 +568,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } case OP_LE: { L->ci->savedpc = pc; - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ + if (lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ else dojump(L, pc, GETARG_sBx(*pc) + 1); base = L->base; continue; @@ -710,21 +709,19 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { dojump(L, pc, GETARG_sBx(i)); continue; } - case OP_SETLIST: - case OP_SETLISTO: { - int bc = GETARG_Bx(i); - int n, last; + case OP_SETLIST: { + int n = GETARG_B(i); + int c = GETARG_C(i); + int last; Table *h; runtime_check(L, ttistable(ra)); h = hvalue(ra); - if (GET_OPCODE(i) == OP_SETLIST) - n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; - else { + if (n == 0) { n = L->top - ra - 1; L->top = L->ci->top; } - bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ - last = bc + n + LUA_FIRSTINDEX - 1; + if (c == 0) c = cast(int, *pc++); + last = ((c-1)*LFIELDS_PER_FLUSH) + n + LUA_FIRSTINDEX - 1; if (last > h->sizearray) /* needs more space? */ luaH_resize(L, h, last, h->lsizenode); /* pre-alloc it at once */ for (; n > 0; n--) { From e2493a40ee611d5a718fd2a81fe67e24c04c91a0 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Thu, 30 Dec 2004 12:00:00 +0000 Subject: [PATCH 21/97] Lua 5.1-work4 --- INSTALL | 93 ++++---- MANIFEST | 218 +++++++++-------- Makefile | 98 ++++---- README | 14 +- build | 36 --- config | 136 ----------- doc/contents.html | 123 ++++++++++ doc/logo.gif | Bin 0 -> 4232 bytes doc/lua.1 | 167 +++++++++++++ doc/lua.html | 175 ++++++++++++++ doc/luac.1 | 136 +++++++++++ doc/luac.html | 144 ++++++++++++ doc/readme.html | 31 +++ etc/Makefile | 44 ++-- etc/README | 7 +- etc/lua.hpp | 1 + etc/noparser.c | 17 +- etc/saconfig.c | 30 +-- include/Makefile | 17 -- src/Makefile | 208 ++++++++++------- src/README | 5 - src/lapi.c | 8 +- src/{lib => }/lauxlib.c | 25 +- {include => src}/lauxlib.h | 0 src/{lib => }/lbaselib.c | 20 +- src/{lib => }/ldblib.c | 0 src/ldebug.c | 4 +- src/lgc.c | 10 +- src/lib/Makefile | 27 --- src/lib/README | 8 - src/lib/loadlib.c | 429 ---------------------------------- src/{lib => }/linit.c | 0 src/{lib => }/liolib.c | 0 src/llimits.h | 4 +- src/{lib => }/lmathlib.c | 0 src/loadlib.c | 464 +++++++++++++++++++++++++++++++++++++ src/{lib => }/loslib.c | 0 src/lparser.c | 37 +-- src/lstate.c | 4 +- src/lstate.h | 4 +- src/{lib => }/lstrlib.c | 0 src/{lib => }/ltablib.c | 30 +-- src/{lua => }/lua.c | 0 {include => src}/lua.h | 6 +- src/lua/Makefile | 31 --- src/lua/README | 41 ---- src/{luac => }/luac.c | 0 src/luac/Makefile | 31 --- src/luac/README | 18 -- {include => src}/luaconf.h | 74 ++++-- {include => src}/lualib.h | 0 src/{luac => }/print.c | 0 test/lua | 1 - test/luac | 1 - test/printf.lua | 2 +- test/xd.lua | 6 +- 56 files changed, 1739 insertions(+), 1246 deletions(-) delete mode 100755 build delete mode 100644 config create mode 100644 doc/contents.html create mode 100644 doc/logo.gif create mode 100644 doc/lua.1 create mode 100644 doc/lua.html create mode 100644 doc/luac.1 create mode 100644 doc/luac.html create mode 100644 doc/readme.html delete mode 100644 include/Makefile delete mode 100644 src/README rename src/{lib => }/lauxlib.c (97%) rename {include => src}/lauxlib.h (100%) rename src/{lib => }/lbaselib.c (96%) rename src/{lib => }/ldblib.c (100%) delete mode 100644 src/lib/Makefile delete mode 100644 src/lib/README delete mode 100644 src/lib/loadlib.c rename src/{lib => }/linit.c (100%) rename src/{lib => }/liolib.c (100%) rename src/{lib => }/lmathlib.c (100%) create mode 100644 src/loadlib.c rename src/{lib => }/loslib.c (100%) rename src/{lib => }/lstrlib.c (100%) rename src/{lib => }/ltablib.c (92%) rename src/{lua => }/lua.c (100%) rename {include => src}/lua.h (98%) delete mode 100644 src/lua/Makefile delete mode 100644 src/lua/README rename src/{luac => }/luac.c (100%) delete mode 100644 src/luac/Makefile delete mode 100644 src/luac/README rename {include => src}/luaconf.h (85%) rename {include => src}/lualib.h (100%) rename src/{luac => }/print.c (100%) delete mode 120000 test/lua delete mode 120000 test/luac diff --git a/INSTALL b/INSTALL index 228be50f59..3c2c69d096 100644 --- a/INSTALL +++ b/INSTALL @@ -2,82 +2,69 @@ This is Lua 5.1 (work). * Installation ------------ - Building Lua on a Unix system should be very easy: + Building Lua on a Unix system should be very easy: simply doing "make" + should work. This will build Lua in the src directory. - 1. Read "config" and edit it to suit your platform and needs. - We strongly recommend that you enable support for dynamic loading, - if your platform allows it. - 2. Do the same for include/luaconf.h. - 3. Do "make". - 4. If you want to install Lua in an "official" place in your system, - then do "make install". The official place and the way to install - files are defined in "config". You may have to be root to do this. + If you want to install Lua in an official place in your system, then + do "make install". The official place and the way to install files are + defined in Makefile. You must have the right permissions to install files. - See below for instructions for Windows and other systems. - -* What you get - ------------ - If "make" succeeds, you get: - * an interpreter in ./bin/lua and a compiler in ./bin/luac; - * libraries in ./lib; - * include files in ./include. - These are the only directories you need for development. + If you want to install Lua locally, then do "make local". This will + create directories bin, include, lib, man and install Lua there as + follows: - There are man pages for lua and luac, in both nroff and html; a reference - manual in html in ./doc, some sample code in ./test, and some useful stuff - in ./etc. You don't need these directories for development. + bin: lua luac + include: lua.h luaconf.h lualib.h lauxlib.h + lib: liblua.a liblualib.a + man/man1: lua.1 luac.1 - See also the README files in the various subdirectories. - A convenient starting point is ./doc/readme.html. - -* If you have problems (and solutions!) - ------------------------------------- - If "make" fails, please let us know. - If you make changes to "config" or to the Makefiles, please send them to us. + These are the only directories you need for development. -* Shared libraries - ---------------- - If you are running Linux, do "make so" after "make" succeeds. - This will create shared libraries in ./lib. - To install those shared libraries in an official place, do "make soinstall". + There are man pages for lua and luac, in both nroff and html, and a + reference manual in html in ./doc, some sample code in ./test, and some + useful stuff in ./etc. You don't need these directories for development. - If you want the interpreter and the compiler to use shared libraries, - then do "make sobin" too. You may want to do this before "make install". + See below for instructions for Windows and other systems. - If you only want the shared libraries, you may want to add -fPIC to MYCFLAGS - in "config". Also, you may need to run "ldconfig" as root. +* Customization + ------------- + Three things can be customized by editing a file: + - Where and how to install Lua -- edit Makefile. + - How to build Lua -- edit src/Makefile. + - Lua features -- edit src/luaconf.h. - You may need to include ./lib in the LD_LIBRARY_PATH environment variable - to link programs that use the shared libraries if you don't put them in the - official places with "make install". (You may need to use the full path.) - Note also that by default these official places live under /usr/local but - /usr/local/lib may not be a place that is checked for shared libraries. - In Linux, the places checked are in /etc/ld.so.conf. Try also "man ld.so". + You don't actually need to edit the Makefiles because you may set the + relevant variables when invoking make. - Building shared libraries on other systems is similar but details differ; - you may need to fix a few details in the top-level Makefile. + On the other hand, if you need to select some Lua features, you'll need + to edit src/luaconf.h. The edited file will be the one installed, and + will be used by any Lua clients that you build, to ensure consistency. * Installation on Windows and other systems ----------------------------------------- - The instructions for building Lua on other systems depend on the particular - compiler you are using. The simplest way is to create a folder with all .c - and .h files, and then create projects for the core library, the standard - library, the interpreter, and the compiler, as follows: + The instructions for building Lua on other systems depend on the compiler + you use. You'll need to create projects (or whatever your compiler uses) + for building the core library, the standard library, the interpreter, and + the compiler, as follows: core lib: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c - ltablib.c lstrlib.c loadlib.c + ltablib.c lstrlib.c loadlib.c linit.c interpreter: core lib, standard lib, lua.c compiler: core lib, lauxlib.c luac.c print.c - Of course, to use Lua as a library, you'll have to know how to create - and use libraries with your compiler. + If all you want is to build the Lua interpreter, you may put all .c files + in a single project, except for luac.c and print.c. + + To use Lua as a library in your own programs, you'll need to know how to + create and use libraries with your compiler. - Also, read "config" to see what can be customized at compilation time. + As mentioned above, you may edit luaconf.h to select some features before + building Lua. (end of INSTALL) diff --git a/MANIFEST b/MANIFEST index 494d432851..38ca97dfb8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,115 +1,105 @@ -MANIFEST contents of Lua 5.1 (work3) distribution on Mon Dec 6 23:00:22 BRST 2004 -lua-5.1-work3 -lua-5.1-work3/COPYRIGHT -lua-5.1-work3/HISTORY -lua-5.1-work3/INSTALL -lua-5.1-work3/MANIFEST -lua-5.1-work3/Makefile -lua-5.1-work3/README -lua-5.1-work3/bin -lua-5.1-work3/build -lua-5.1-work3/config -lua-5.1-work3/etc -lua-5.1-work3/etc/Makefile -lua-5.1-work3/etc/README -lua-5.1-work3/etc/all.c -lua-5.1-work3/etc/lua.hpp -lua-5.1-work3/etc/lua.ico -lua-5.1-work3/etc/min.c -lua-5.1-work3/etc/noparser.c -lua-5.1-work3/etc/saconfig.c -lua-5.1-work3/include -lua-5.1-work3/include/Makefile -lua-5.1-work3/include/lauxlib.h -lua-5.1-work3/include/lua.h -lua-5.1-work3/include/luaconf.h -lua-5.1-work3/include/lualib.h -lua-5.1-work3/lib -lua-5.1-work3/src -lua-5.1-work3/src/Makefile -lua-5.1-work3/src/README -lua-5.1-work3/src/lapi.c -lua-5.1-work3/src/lapi.h -lua-5.1-work3/src/lcode.c -lua-5.1-work3/src/lcode.h -lua-5.1-work3/src/ldebug.c -lua-5.1-work3/src/ldebug.h -lua-5.1-work3/src/ldo.c -lua-5.1-work3/src/ldo.h -lua-5.1-work3/src/ldump.c -lua-5.1-work3/src/lfunc.c -lua-5.1-work3/src/lfunc.h -lua-5.1-work3/src/lgc.c -lua-5.1-work3/src/lgc.h -lua-5.1-work3/src/lib -lua-5.1-work3/src/lib/Makefile -lua-5.1-work3/src/lib/README -lua-5.1-work3/src/lib/lauxlib.c -lua-5.1-work3/src/lib/lbaselib.c -lua-5.1-work3/src/lib/ldblib.c -lua-5.1-work3/src/lib/linit.c -lua-5.1-work3/src/lib/liolib.c -lua-5.1-work3/src/lib/lmathlib.c -lua-5.1-work3/src/lib/loadlib.c -lua-5.1-work3/src/lib/loslib.c -lua-5.1-work3/src/lib/lstrlib.c -lua-5.1-work3/src/lib/ltablib.c -lua-5.1-work3/src/llex.c -lua-5.1-work3/src/llex.h -lua-5.1-work3/src/llimits.h -lua-5.1-work3/src/lmem.c -lua-5.1-work3/src/lmem.h -lua-5.1-work3/src/lobject.c -lua-5.1-work3/src/lobject.h -lua-5.1-work3/src/lopcodes.c -lua-5.1-work3/src/lopcodes.h -lua-5.1-work3/src/lparser.c -lua-5.1-work3/src/lparser.h -lua-5.1-work3/src/lstate.c -lua-5.1-work3/src/lstate.h -lua-5.1-work3/src/lstring.c -lua-5.1-work3/src/lstring.h -lua-5.1-work3/src/ltable.c -lua-5.1-work3/src/ltable.h -lua-5.1-work3/src/ltm.c -lua-5.1-work3/src/ltm.h -lua-5.1-work3/src/lua -lua-5.1-work3/src/lua/Makefile -lua-5.1-work3/src/lua/README -lua-5.1-work3/src/lua/lua.c -lua-5.1-work3/src/luac -lua-5.1-work3/src/luac/Makefile -lua-5.1-work3/src/luac/README -lua-5.1-work3/src/luac/luac.c -lua-5.1-work3/src/luac/print.c -lua-5.1-work3/src/lundump.c -lua-5.1-work3/src/lundump.h -lua-5.1-work3/src/lvm.c -lua-5.1-work3/src/lvm.h -lua-5.1-work3/src/lzio.c -lua-5.1-work3/src/lzio.h -lua-5.1-work3/test -lua-5.1-work3/test/README -lua-5.1-work3/test/bisect.lua -lua-5.1-work3/test/cf.lua -lua-5.1-work3/test/echo.lua -lua-5.1-work3/test/env.lua -lua-5.1-work3/test/factorial.lua -lua-5.1-work3/test/fib.lua -lua-5.1-work3/test/fibfor.lua -lua-5.1-work3/test/globals.lua -lua-5.1-work3/test/hello.lua -lua-5.1-work3/test/life.lua -lua-5.1-work3/test/lua -lua-5.1-work3/test/luac -lua-5.1-work3/test/luac.lua -lua-5.1-work3/test/printf.lua -lua-5.1-work3/test/readonly.lua -lua-5.1-work3/test/sieve.lua -lua-5.1-work3/test/sort.lua -lua-5.1-work3/test/table.lua -lua-5.1-work3/test/trace-calls.lua -lua-5.1-work3/test/trace-globals.lua -lua-5.1-work3/test/undefined.lua -lua-5.1-work3/test/xd.lua +MANIFEST contents of Lua 5.1 (work4) distribution on Thu Dec 30 12:00:49 BRST 2004 +lua-5.1-work4 +lua-5.1-work4/COPYRIGHT +lua-5.1-work4/HISTORY +lua-5.1-work4/INSTALL +lua-5.1-work4/MANIFEST +lua-5.1-work4/Makefile +lua-5.1-work4/README +lua-5.1-work4/doc +lua-5.1-work4/doc/contents.html +lua-5.1-work4/doc/logo.gif +lua-5.1-work4/doc/lua.1 +lua-5.1-work4/doc/lua.html +lua-5.1-work4/doc/luac.1 +lua-5.1-work4/doc/luac.html +lua-5.1-work4/doc/readme.html +lua-5.1-work4/etc +lua-5.1-work4/etc/Makefile +lua-5.1-work4/etc/README +lua-5.1-work4/etc/all.c +lua-5.1-work4/etc/lua.hpp +lua-5.1-work4/etc/lua.ico +lua-5.1-work4/etc/min.c +lua-5.1-work4/etc/noparser.c +lua-5.1-work4/etc/saconfig.c +lua-5.1-work4/src +lua-5.1-work4/src/Makefile +lua-5.1-work4/src/lapi.c +lua-5.1-work4/src/lapi.h +lua-5.1-work4/src/lauxlib.c +lua-5.1-work4/src/lauxlib.h +lua-5.1-work4/src/lbaselib.c +lua-5.1-work4/src/lcode.c +lua-5.1-work4/src/lcode.h +lua-5.1-work4/src/ldblib.c +lua-5.1-work4/src/ldebug.c +lua-5.1-work4/src/ldebug.h +lua-5.1-work4/src/ldo.c +lua-5.1-work4/src/ldo.h +lua-5.1-work4/src/ldump.c +lua-5.1-work4/src/lfunc.c +lua-5.1-work4/src/lfunc.h +lua-5.1-work4/src/lgc.c +lua-5.1-work4/src/lgc.h +lua-5.1-work4/src/linit.c +lua-5.1-work4/src/liolib.c +lua-5.1-work4/src/llex.c +lua-5.1-work4/src/llex.h +lua-5.1-work4/src/llimits.h +lua-5.1-work4/src/lmathlib.c +lua-5.1-work4/src/lmem.c +lua-5.1-work4/src/lmem.h +lua-5.1-work4/src/loadlib.c +lua-5.1-work4/src/lobject.c +lua-5.1-work4/src/lobject.h +lua-5.1-work4/src/lopcodes.c +lua-5.1-work4/src/lopcodes.h +lua-5.1-work4/src/loslib.c +lua-5.1-work4/src/lparser.c +lua-5.1-work4/src/lparser.h +lua-5.1-work4/src/lstate.c +lua-5.1-work4/src/lstate.h +lua-5.1-work4/src/lstring.c +lua-5.1-work4/src/lstring.h +lua-5.1-work4/src/lstrlib.c +lua-5.1-work4/src/ltable.c +lua-5.1-work4/src/ltable.h +lua-5.1-work4/src/ltablib.c +lua-5.1-work4/src/ltm.c +lua-5.1-work4/src/ltm.h +lua-5.1-work4/src/lua.c +lua-5.1-work4/src/lua.h +lua-5.1-work4/src/luac.c +lua-5.1-work4/src/luaconf.h +lua-5.1-work4/src/lualib.h +lua-5.1-work4/src/lundump.c +lua-5.1-work4/src/lundump.h +lua-5.1-work4/src/lvm.c +lua-5.1-work4/src/lvm.h +lua-5.1-work4/src/lzio.c +lua-5.1-work4/src/lzio.h +lua-5.1-work4/src/print.c +lua-5.1-work4/test +lua-5.1-work4/test/README +lua-5.1-work4/test/bisect.lua +lua-5.1-work4/test/cf.lua +lua-5.1-work4/test/echo.lua +lua-5.1-work4/test/env.lua +lua-5.1-work4/test/factorial.lua +lua-5.1-work4/test/fib.lua +lua-5.1-work4/test/fibfor.lua +lua-5.1-work4/test/globals.lua +lua-5.1-work4/test/hello.lua +lua-5.1-work4/test/life.lua +lua-5.1-work4/test/luac.lua +lua-5.1-work4/test/printf.lua +lua-5.1-work4/test/readonly.lua +lua-5.1-work4/test/sieve.lua +lua-5.1-work4/test/sort.lua +lua-5.1-work4/test/table.lua +lua-5.1-work4/test/trace-calls.lua +lua-5.1-work4/test/trace-globals.lua +lua-5.1-work4/test/undefined.lua +lua-5.1-work4/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index d6e04bd81a..62bb7e49ed 100644 --- a/Makefile +++ b/Makefile @@ -1,62 +1,61 @@ -# makefile for Lua hierarchy +# makefile for installing Lua # see INSTALL for installation instructions -# see config for customization instructions +# see src/Makefile and src/luaconf.h for further customization -LUA= . +# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= -include $(LUA)/config +# Where to install. The installation starts in the src directory, so take +# care if INSTALL_TOP is not an absolute path. +# +INSTALL_TOP= /usr/local +INSTALL_BIN= $(INSTALL_TOP)/bin +INSTALL_INC= $(INSTALL_TOP)/include +INSTALL_LIB= $(INSTALL_TOP)/lib +INSTALL_MAN= $(INSTALL_TOP)/man/man1 -# primary targets ("co" and "klean" are used for making the distribution) -all clean co klean: - cd include; $(MAKE) $@ - cd src; $(MAKE) $@ - cd src/lib; $(MAKE) $@ - cd src/luac; $(MAKE) $@ - cd src/lua; $(MAKE) $@ +# How to install. You may prefer "install" instead of "cp" if you have it. +# To remove debug information from binaries, use "install -s" in INSTALL_EXEC. +# +INSTALL_EXEC= cp +INSTALL_DATA= cp +#INSTALL_EXEC= install -m 0755 +#INSTALL_DATA= install -m 0644 + +# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= + +V= 5.1 -# in case they were not created during unpacking -all: bin lib +TO_BIN= lua luac +TO_INC= lua.h luaconf.h lualib.h lauxlib.h +TO_LIB= liblua.a liblualib.a +TO_MAN= lua.1 luac.1 -bin lib: - mkdir -p $@ +all clean: + cd src; $(MAKE) $@ -# simple test to see Lua working test: all - bin/lua test/hello.lua + src/lua test/hello.lua -# remove debug information from binaries -strip: - $(STRIP) bin/* +install: all + cd src; mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) + cd src; $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) + cd src; $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) + cd src; $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) + cd doc; $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) -# official installation -install: all strip - mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) - $(INSTALL_EXEC) bin/* $(INSTALL_BIN) - $(INSTALL_DATA) include/*.h $(INSTALL_INC) - $(INSTALL_DATA) lib/*.a $(INSTALL_LIB) - $(INSTALL_DATA) doc/*.1 $(INSTALL_MAN) +local: + $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -up" INSTALL_DATA="cp -up" # echo config parameters echo: @echo "" - @echo "These are the parameters currently set in $(LUA)/config to build Lua $V:" + @echo "These are the parameters currently set in src/Makefile to build Lua $V:" + @echo "" + @cd src; $(MAKE) -s echo + @echo "" + @echo "These are the parameters currently set in Makefile to install Lua $V:" @echo "" - @echo "LOADLIB = $(LOADLIB)" - @echo "DLLIB = $(DLLIB)" - @echo "NUMBER = $(NUMBER)" - @echo "POPEN = $(POPEN)" - @echo "TMPNAM = $(TMPNAM)" - @echo "DEGREES = $(DEGREES)" - @echo "USERCONF = $(USERCONF)" - @echo "CC = $(CC)" - @echo "WARN = $(WARN)" - @echo "MYCFLAGS = $(MYCFLAGS)" - @echo "MYLDFLAGS = $(MYLDFLAGS)" - @echo "EXTRA_LIBS = $(EXTRA_LIBS)" - @echo "AR = $(AR)" - @echo "RANLIB = $(RANLIB)" - @echo "STRIP = $(STRIP)" - @echo "INSTALL_ROOT = $(INSTALL_ROOT)" + @echo "INSTALL_TOP = $(INSTALL_TOP)" @echo "INSTALL_BIN = $(INSTALL_BIN)" @echo "INSTALL_INC = $(INSTALL_INC)" @echo "INSTALL_LIB = $(INSTALL_LIB)" @@ -64,17 +63,18 @@ echo: @echo "INSTALL_EXEC = $(INSTALL_EXEC)" @echo "INSTALL_DATA = $(INSTALL_DATA)" @echo "" - @echo "Edit $(LUA)/config if needed to suit your platform and then run make." + @echo "See also src/luaconf.h ." @echo "" -# turn config into Lua code +# echo config parameters as Lua code # uncomment the last sed expression if you want nil instead of empty strings lecho: - @echo "-- $(LUA)/config for Lua $V" - @echo "VERSION = '$(V)'" - @make echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' + @echo "-- installation parameters for Lua $V" + @echo "VERSION = '$V'" + @$(MAKE) echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' @echo "-- EOF" +# show what has changed since we unpacked newer: @find . -newer MANIFEST -type f diff --git a/README b/README index 7c5b0b7649..1efe91ffaf 100644 --- a/README +++ b/README @@ -17,9 +17,7 @@ See HISTORY for a summary of changes since the last released version. ------------ Lua is freely available for both academic and commercial purposes. See COPYRIGHT and http://www.lua.org/license.html for details. - Lua can be downloaded from its official site http://www.lua.org/ and - several other sites aroung the world. For a complete list of mirror sites, - see http://www.lua.org/mirrors.html . + Lua can be downloaded at http://www.lua.org/download.html . * Installation ------------ @@ -27,19 +25,11 @@ See HISTORY for a summary of changes since the last released version. platforms that have an ANSI C compiler. Under Unix, simply typing "make" should work. See INSTALL for detailed instructions. -* Contacting the authors - ---------------------- - Send your comments, questions, and bug reports to - lua-team AT tecgraf.puc-rio.br. - For more information about the authors, see http://www.lua.org/authors.html . - For reporting bugs, try also the mailing list: lua@bazar2.conectiva.com.br . - For more information about this list, including instructions on how to - subscribe and access the archives, see http://www.lua.org/lua-l.html . - * Origin ------ Lua is developed at Tecgraf, the Computer Graphics Technology Group of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). Tecgraf is a laboratory of the Department of Computer Science. + For more information about the authors, see http://www.lua.org/authors.html . (end of README) diff --git a/build b/build deleted file mode 100755 index a0e3fb3f0b..0000000000 --- a/build +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# If you don't want to use make, run this script to build Lua. -# Read config and include/luaconf.h to see what can be customized. - - -# Easiest way to build bin/lua: -# cc -O2 -o bin/lua -Iinclude -Isrc src/*.c src/lib/*.c src/lua/*.c -lm -ldl -# bin/lua test/hello.lua - - -# Easiest way to build Lua libraries and executables: -echo -n 'building core library... ' -cd src -cc -O2 -c -I../include *.c -ar rc ../lib/liblua.a *.o -rm -f *.o - -echo -n 'standard library... ' -cd lib -cc -O2 -c -I../../include *.c -ar rc ../../lib/liblualib.a *.o -rm -f *.o - -echo -n 'lua... ' -cd ../lua -cc -O2 -o ../../bin/lua -I../../include *.c ../../lib/*.a -lm -ldl - -echo -n 'luac... ' -cd ../luac -cc -O2 -o ../../bin/luac -I../../include -I.. *.c ../../lib/*.a - -echo 'done' - -cd ../.. -bin/lua test/hello.lua diff --git a/config b/config deleted file mode 100644 index 75ae76f115..0000000000 --- a/config +++ /dev/null @@ -1,136 +0,0 @@ -# configuration file for making Lua 5.1 (work) -# see INSTALL for installation instructions - -# These are default values. Skip this section and see the explanations below. - -LOADLIB= -DLLIB= -USERCONF= - -# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= - -# ------------------------------------------------------------- dynamic loading - -# Support for dynamically loading C libraries for Lua is a very important -# feature, which we strongly recommend be enabled. By default, this support is -# enabled on Windows systems (see below) but disabled on other systems because -# it relies on system-dependent code that is not part of ANSI C. For more -# information on dynamic loading, read the comments in src/lib/loadlib.c . -# -# To enable support for dynamic loading on Unix systems that support the dlfcn -# interface (e.g., Linux, Solaris, IRIX, BSD, AIX, HPUX, and probably others), -# uncomment the next two lines. Also read the next paragraph. -# -LOADLIB= -DUSE_DLOPEN=1 -DLLIB= -ldl -# -# In Linux with gcc, you should also uncomment the next definition for -# MYLDFLAGS, which passes -E (= -export-dynamic) to the linker. This option -# allows dynamic libraries to link back to the `lua' program, so that they do -# not need the Lua libraries. (Other systems may have an equivalent facility.) -# -MYLDFLAGS= -Wl,-E -# -# On Windows systems. support for dynamic loading is enabled by default. -# To disable this support, uncomment the next line. -# -#LOADLIB= -DUSE_DLL=0 - -# --------------------------------------------------------------- Lua libraries - -# See include/luaconf.h. - -# ------------------------------------------------------------------ Lua core - -# See include/luaconf.h. - -# ------------------------------------------------------------- Lua interpreter - -# The stand-alone Lua interpreter needs the math functions, which are usually -# in libm.a (-lm). If your C library already includes the math functions, -# or if you are using a modified interpreter that does not need them, -# then comment the following line or add the appropriates libraries. -# -EXTRA_LIBS= -lm - -# If you want to customize the stand-alone Lua interpreter, uncomment and -# edit the following two lines; also edit etc/saconfig.c to suit your needs. -# -DUSE_READLINE adds line editing and history to the interpreter. You need -# to add -lreadline (and perhaps also -lhistory and -ltermcap) to EXTRA_LIBS. -# -#USERCONF=-DLUA_USERCONFIG='"$(LUA)/etc/saconfig.c"' -DUSE_READLINE -#EXTRA_LIBS= -lm $(DLLIB) -lreadline # -lhistory -ltermcap -lcurses -lncurses - -# ------------------------------------------------------------------ C compiler - -# You need an ANSI C compiler. gcc is a popular one. We do not use -ansi in -# WARN because it disables POSIX features used in the libraries. -# -CC= gcc -WARN= -Wall - -# ------------------------------------------------------------------ C options - -# Write here any options you may need for your C compiler. -# If you are using gcc, -O3 will get you a faster but larger code. You can -# also add -fomit-frame-pointer to get even faster code at the cost of losing -# debug information. If you only want the shared libraries, you may want to -# add -fPIC to MYCFLAGS. -# -MYCFLAGS= -O2 -#MYCFLAGS= -O3 -fomit-frame-pointer # -fPIC - -# Write here any options you may need for your C linker. -#MYLDFLAGS= - -# ------------------------------------------------------------------ librarian - -# This should work on all Unix systems. -# -AR= ar rcu - -# If your system doesn't have (or need) ranlib, use RANLIB=true. -# On some systems, "ar s" does what ranlib would do. -# -RANLIB= ranlib -#RANLIB= ar s -#RANLIB= true - -# ------------------------------------------------------------------ stripper - -# This should work on all Unix systems, but you may want to add options. -# -STRIP= strip - -# ------------------------------------------------------------------ install - -# Locations for "make install". You may need to be root do "make install". -# -INSTALL_ROOT= /usr/local -INSTALL_BIN= $(INSTALL_ROOT)/bin -INSTALL_INC= $(INSTALL_ROOT)/include -INSTALL_LIB= $(INSTALL_ROOT)/lib -INSTALL_MAN= $(INSTALL_ROOT)/man/man1 - -# You may prefer to use "install" instead of "cp" if you have it. -# If you use "install", you may also want to change the permissions after -m. -# -INSTALL_EXEC= cp -INSTALL_DATA= cp -#INSTALL_EXEC= install -m 0755 -#INSTALL_DATA= install -m 0644 - -# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= - -V= 5.1 - -BIN= $(LUA)/bin -INC= $(LUA)/include -LIB= $(LUA)/lib - -INCS= -I$(INC) $(EXTRA_INCS) -DEFS= $(EXTRA_DEFS) - -CFLAGS= $(MYCFLAGS) $(WARN) $(INCS) $(DEFS) - -# (end of config) diff --git a/doc/contents.html b/doc/contents.html new file mode 100644 index 0000000000..06bd6fb4c7 --- /dev/null +++ b/doc/contents.html @@ -0,0 +1,123 @@ + + +Lua: 5.0 reference manual - contents + + + + +


        +

        +Lua +Reference manual for Lua 5.0 +

        + +Lua 5.0 Reference Manual +[ +top +| +ps +| +pdf +] +

        + + +Copyright +© 2003 Tecgraf, PUC-Rio. All rights reserved. +


        + + + +
        + +Last update: +Wed May 7 18:34:34 EST 2003 + + + + diff --git a/doc/logo.gif b/doc/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..2f5e4ac2e742fbb7675e739879211553758aea9c GIT binary patch literal 4232 zcmeH``9G8i;K!fm@ywWE@XWZzZ5SF?A>^uN#>^O6HI%DVL*tw8h1>$H%uPC0$QQ=txe!o}PX)Ev+jn>*nFZ-TC=<^76WcLZL(=DJm)| zEiIKwrInSHXU?3duCC_u@5try#>U2`rlw1mF15F}U%!66tE;QKyIUmcDJ<+QF77*W zFJd#&)VAl)kJ6K zi<>tmZ{3>g>+2gB7#JQNe(>OdLh;A=`1q42PbMZNCMPF*dXxhLZw3aYhlZwyhu@Bj z%#4n{d-Q1b$&i4QMce4L#8^!oMdw{PDnm4D66&3*dxX=-YIX6DQL_g`jbzkd4k zZDCoLf=%jL&vIeE zO=XcZ9fxt`f}-DQ^%H*PHMUs(JN%UWkI|Y8h9#6~I$Cw@{RqzO4&P-x;jHCPJ6Ks2 zoU%foi)nXd_sdkiuJa@@5J4RrreKfWSnz5>eMa5yTP=)16uu)TIdx~Fhho))6jZl) z($*i>QrIX4u}u3>m{WSn_ehkUGQ& zs})aUlTH1Cj1g3ZE3=MPXsSniEwJ{e6C3N#HjD=B4`8rWIsz!a7ecYpec?WuH+y?Wsm18^$cS4WmHhH3_=r zh*ILlm*X1dB^E5($KVl&zT524%l}vpHg%;Y+LezV_&TAJCmH`idhuj-n$4FZ)UE|jXLayXa-&O3Q z?Iyo!x*$5hD_HfFnDfGYj-RD|eIb7I?%>Y_kf%}Nbd`BXb4l1(Pc+}zoUR|9%_!7f zum2T;wbx&pohtI+&@~wm3nH9xLbOYkg*`phY~TK5iC#3tZNXo9s`cahx+8j2)rh5C zQgZh6D7Ekgib|hpdhxYf{r!PTJc z!vsYG@{hA}l5kL)g)0N_)(nC<*L0qdUi*3fD5<0sn58>zklX@6Tyv3*X^}m=Cqc40 zQ6GfjG@kd1mFIm`qaubWunm_?P>WUZ`9|f_z%gGHi{n|uu(N8!L=aw5(qAcDj$-QK zu;D#j6e42OXTQD>)i zlvM$LX`$n9EEjxM$_QDF&a z7cme_rat}aXmiN&7`6Q98}dh4Z@8L_uAb#nK&GQiZOOUnA9kAEVb-csuN1AWL=sXt z{z9GCN%%l0N9QvJM;tl1nf?rrhT{*sE%4WqR?{0~aIrfCcCPxf4eh_*jjQ=`$p53Y z@_|Rsx2i}|3dNFetMQQ5y8agTK-E0D&7;@3-LUxfvZ7 z7~!p@&mFe^oca2^F|CBt+4Ly?^ViUVSAhAH>JH1GN{^TQb3QnM*x0ZiZgDyNI@_c3 z@{}(WH4*e3T~}n_^0}da4ElIxAf9B!IaL7z9X0Icvj@cIkE*~W--17&WN`Ea5)Gn> z#gpfRb#44;jVTOS{FuaZgd(-ZD848=fQzgST2MxR>wSLc1P=2HDvByz$B$IsNCC6L zCM?nK*OHj6JA9gz4|b<~2%RqelN^1Y)jIqnRs!mDKV^BQTfo@hOtz7*Ug}Ee^cbsj zNNlumRgAmt`1$b5MO;&X#5-EP<}AaY;52ihIpem&MTea$?3!DrwbYa?V`NjEfWF3z zUq5JY8Ch;L{kx&J<1K&Fe_Vn;8gk{%c;n?nA2(%(f%DCRHko3uT~VI7RE^JWEqaCq z)i|%nfj(*4|V*XhY3W%M# z*yn6SN4eUOHFxAD7B&9E_PO`G5bqgs^@J{9bk>&;PlUAiqo`j3rjQDgD!}mqLUtb` zCB}ZD@m@s#pf7bV4jreOC*JVfHZ|hyHkX!rauVdd_I9FL45d{gWH!DNYu;i(|8wVx z!)eLY6YXxZ2{Coae0xuTnxo1ACb5wtED?VJAz&@114$Ao6uG9YSy*!K;m5_mj=0^j zw%?b%AOs}ql@$TGC-!^^*_#RT5+y_kTzQG9?LPPZNAtt6cJ%d2$q(I)ws21*?xF%p zN+NeGnWRQ<5w70Rc(bl|S0Xr&5@WrmdurS|IgPB|EyuZO#=tf!35)G!HJ`E1jh^lH zTBu~rL#DhQO*XAWtBt}JHH$lc>3%r0yD|maW_(W=B_J+y164F>O4dO|@&@N3Z3p=B zmVl{|^Z&#atHY|9n&la)SBo}=3AFIF=_~LDJk6MTlA73CXtX+4bnn+c!}N}IPa5pp zwyqbqIkN|I3j_3vD6$zlu{Ps(N-J|*qzEt<$5Soh;s^AuKv_ z-Tz+O1_~6*9CJh4r}`}mbUtjbf#fX58RIIkP6&@*y9kI|5fK*_eZ%jv3U$5*x<>D_ za2M(TV8?XY+9xy>0En#Te<6X4$0&dbyd(go$~eq4u(u)EA2msyF<5ssLZ zDP|I}=~Bi_q)whWv=Ri~L1TYaNrR;5cMB@s78HF1{w&r(6GJ;_2@bD?#1p&P4n_?n0#9Vx~$qjMX=Lk?*!@aKo8m&$iPO7S{g3sFUwr`*<53(68xx7?z`2xf# zGSicy_zI(PJ|%qc2VxT+6bOE--a{k&aq7$<<= zFt)C<@|TPs`+eycPGoGL1Wn9|Ed&a2JyAmjnkm3DQBECX&`bt~odH9cUPq4M{#$-q?G3!)qO-it*&YHw+j-O* zYy78V*`4Q=kQ@^Yz*b6Tal4(Me7BGeS^;phWAW8+L^5A(=D)t?k!rLIwVAKtq=f7h z&^n&VX1-T$ScvN~639QLZ^d@niMaS{C-Q)8oHHBhwD*r~-1Ze#Q)GFOFptW32a-uF z;M@ux%i%a25NwIgXt*=GHX$3~aZfwovGL!}sf?j9TsVo^cn(%&a<--0mIXYqGe>c PWz_J}_#7St0k8iB@FZjZ literal 0 HcmV?d00001 diff --git a/doc/lua.1 b/doc/lua.1 new file mode 100644 index 0000000000..c9bba7d700 --- /dev/null +++ b/doc/lua.1 @@ -0,0 +1,167 @@ +.\" lua.man,v 1.8 2003/04/02 00:05:20 lhf Exp +.TH LUA 1 "2003/04/02 00:05:20" +.SH NAME +lua \- Lua interpreter +.SH SYNOPSIS +.B lua +[ +.I options +] +[ +.I script +[ +.I args +] +] +.SH DESCRIPTION +.B lua +is the stand-alone Lua interpreter. +It loads and executes Lua programs, +either in textual source form or +in precompiled binary form. +(Precompiled binaries are output by +.BR luac , +the Lua compiler.) +.B lua +can be used as a batch interpreter and also interactively. +.LP +The given +.I options +(see below) +are executed and then +the Lua program in file +.I script +is loaded and executed. +The given +.I args +are available to +.I script +as strings in a global table named +.BR arg . +If these arguments contain spaces or other characters special to the shell, +then they should be quoted +(but note that the quotes will be removed by the shell). +The arguments in +.B arg +start at 0, +which contains the string +.RI ` script '. +The index of the last argument is stored in +.BR "arg.n" . +The arguments given in the command line before +.IR script , +including the name of the interpreter, +are available in negative indices in +.BR arg . +.LP +At the very start, +before even handling the command line, +.B lua +executes the contents of the environment variable +.BR LUA_INIT , +if it is defined. +If the value of +.B LUA_INIT +is of the form +.RI `@ filename ', +then +.I filename +is executed. +Otherwise, the string is assumed to be a Lua statement and is executed. +.LP +Options start with +.B \- +and are described below. +You can use +.B "\--" +to signal the end of options. +.LP +If no arguments are given, +then +.B "\-v \-i" +is assumed when the standard input is a terminal; +otherwise, +.B "\-" +is assumed. +.LP +In interactive mode, +.B lua +prompts the user, +reads lines from the standard input, +and executes them as they are read. +If a line does not contain a complete statement, +then a secondary prompt is displayed and +lines are read until a complete statement is formed or +a syntax error is found. +So, one way to interrupt the reading of an incomplete statement is +to force a syntax error: +adding a +.B `;' +in the middle of a statement is a sure way of forcing a syntax error +(except inside multiline strings and comments; these must be closed explicitly). +If a line starts with +.BR `=' , +then +.B lua +displays the values of all the expressions in the remainder of the +line. The expressions must be separated by commas. +The primary prompt is the value of the global variable +.BR _PROMPT , +if this value is a string; +otherwise, the default prompt is used. +Similarly, the secondary prompt is the value of the global variable +.BR _PROMPT2 . +So, +to change the prompts, +set the corresponding variable to a string of your choice. +You can do that after calling the interpreter +or on the command line with +.BR "_PROMPT" "=\'lua: \'" , +for example. +(Note the need for quotes, because the string contains a space.) +The default prompts are ``> '' and ``>> ''. +.SH OPTIONS +.TP +.B \- +load and execute the standard input as a file, +that is, +not interactively, +even when the standard input is a terminal. +.TP +.BI \-e " stat" +execute statement +.IR stat . +You need to quote +.I stat +if it contains spaces, quotes, +or other characters special to the shell. +.TP +.B \-i +enter interactive mode after +.I script +is executed. +.TP +.BI \-l " file" +call +.BI require( file ) +before executing +.IR script. +Typically used to load libraries +(hence the letter +.IR l ). +.TP +.B \-v +show version information. +.SH "SEE ALSO" +.BR luac (1) +.br +http://www.lua.org/ +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +R. Ierusalimschy, +L. H. de Figueiredo, +and +W. Celes +(lua@tecgraf.puc-rio.br) +.\" EOF diff --git a/doc/lua.html b/doc/lua.html new file mode 100644 index 0000000000..073d4b525a --- /dev/null +++ b/doc/lua.html @@ -0,0 +1,175 @@ + + + +LUA man page + + + + +

        NAME

        +lua - Lua interpreter +

        SYNOPSIS

        +lua +[ +options +] +[ +script +[ +args +] +] +

        DESCRIPTION

        +lua +is the stand-alone Lua interpreter. +It loads and executes Lua programs, +either in textual source form or +in precompiled binary form. +(Precompiled binaries are output by +luac, +the Lua compiler.) +lua +can be used as a batch interpreter and also interactively. +

        +The given +options +(see below) +are executed and then +the Lua program in file +script +is loaded and executed. +The given +args +are available to +script +as strings in a global table named +arg. +If these arguments contain spaces or other characters special to the shell, +then they should be quoted +(but note that the quotes will be removed by the shell). +The arguments in +arg +start at 0, +which contains the string +`script'. +The index of the last argument is stored in +"arg.n". +The arguments given in the command line before +script, +including the name of the interpreter, +are available in negative indices in +arg. +

        +At the very start, +before even handling the command line, +lua +executes the contents of the environment variable +LUA_INIT, +if it is defined. +If the value of +LUA_INIT +is of the form +`@filename', +then +filename +is executed. +Otherwise, the string is assumed to be a Lua statement and is executed. +

        +Options start with +- +and are described below. +You can use +"--" +to signal the end of options. +

        +If no arguments are given, +then +"-v -i" +is assumed when the standard input is a terminal; +otherwise, +"-" +is assumed. +

        +In interactive mode, +lua +prompts the user, +reads lines from the standard input, +and executes them as they are read. +If a line does not contain a complete statement, +then a secondary prompt is displayed and +lines are read until a complete statement is formed or +a syntax error is found. +So, one way to interrupt the reading of an incomplete statement is +to force a syntax error: +adding a +`;' +in the middle of a statement is a sure way of forcing a syntax error +(except inside multiline strings and comments; these must be closed explicitly). +If a line starts with +`=', +then +lua +displays the values of all the expressions in the remainder of the +line. The expressions must be separated by commas. +The primary prompt is the value of the global variable +_PROMPT, +if this value is a string; +otherwise, the default prompt is used. +Similarly, the secondary prompt is the value of the global variable +_PROMPT2. +So, +to change the prompts, +set the corresponding variable to a string of your choice. +You can do that after calling the interpreter +or on the command line with +"_PROMPT" "=\'lua: \'", +for example. +(Note the need for quotes, because the string contains a space.) +The default prompts are ``> '' and ``>> ''. +

        OPTIONS

        +

        +- +load and execute the standard input as a file, +that is, +not interactively, +even when the standard input is a terminal. +

        +-e "stat" +execute statement +stat. +You need to quote +stat +if it contains spaces, quotes, +or other characters special to the shell. +

        +-i +enter interactive mode after +script +is executed. +

        +-l "file" +call +require( file) +before executing +script. +Typically used to load libraries +(hence the letter +l). +

        +-v +show version information. +

        SEE ALSO

        +luac(1) +
        +http://www.lua.org/ +

        DIAGNOSTICS

        +Error messages should be self explanatory. +

        AUTHORS

        +R. Ierusalimschy, +L. H. de Figueiredo, +and +W. Celes +(lua AT tecgraf.puc-rio.br) + + + diff --git a/doc/luac.1 b/doc/luac.1 new file mode 100644 index 0000000000..c6523060f8 --- /dev/null +++ b/doc/luac.1 @@ -0,0 +1,136 @@ +.\" luac.man,v 1.25 2002/12/13 11:45:12 lhf Exp +.TH LUAC 1 "2002/12/13 11:45:12" +.SH NAME +luac \- Lua compiler +.SH SYNOPSIS +.B luac +[ +.I options +] [ +.I filenames +] +.SH DESCRIPTION +.B luac +is the Lua compiler. +It translates programs written in the Lua programming language +into binary files that can be latter loaded and executed. +.LP +The main advantages of precompiling chunks are: +faster loading, +protecting source code from user changes, +and +off-line syntax checking. +.LP +Pre-compiling does not imply faster execution +because in Lua chunks are always compiled into bytecodes before being executed. +.B luac +simply allows those bytecodes to be saved in a file for later execution. +.LP +.B luac +produces a single output file containing the bytecodes +for all source files given. +By default, +the output file is named +.BR luac.out , +but you can change this with the +.B \-o +option. +.LP +The binary files created by +.B luac +are portable to all architectures with the same word size. +This means that +binary files created on a 32-bit platform (such as Intel) +can be read without change in another 32-bit platform (such as Sparc), +even if the byte order (``endianness'') is different. +On the other hand, +binary files created on a 16-bit platform cannot be read in a 32-bit platform, +nor vice-versa. +.LP +In the command line, +you can mix +text files containing Lua source and +binary files containing precompiled chunks. +This is useful to combine several precompiled chunks, +even from different (but compatible) platforms, +into a single precompiled chunk. +.LP +You can use +.B "\-" +to indicate the standard input as a source file +and +.B "\--" +to signal the end of options +(that is, +all remaining arguments will be treated as files even if they start with +.BR "\-" ). +.LP +The internal format of the binary files produced by +.B luac +is likely to change when a new version of Lua is released. +So, +save the source files of all Lua programs that you precompile. +.LP +.SH OPTIONS +Options must be separate. +.TP +.B \-l +produce a listing of the compiled bytecode for Lua's virtual machine. +Listing bytecodes is useful to learn about Lua's virtual machine. +If no files are given, then +.B luac +loads +.B luac.out +and lists its contents. +.TP +.BI \-o " file" +output to +.IR file , +instead of the default +.BR luac.out . +The output file may be a source file because +all files are loaded before the output file is written. +Be careful not to overwrite precious files. +.TP +.B \-p +load files but do not generate any output file. +Used mainly for syntax checking and for testing precompiled chunks: +corrupted files will probably generate errors when loaded. +Lua always performs a thorough integrity test on precompiled chunks. +Bytecode that passes this test is completely safe, +in the sense that it will not break the interpreter. +However, +there is no guarantee that such code does anything sensible. +(None can be given, because the halting problem is unsolvable.) +If no files are given, then +.B luac +loads +.B luac.out +and tests its contents. +No messages are displayed if the file passes the integrity test. +.TP +.B \-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running these chunks, +then the error messages may not contain the full information they usually do +(line numbers and names of locals are lost). +.TP +.B \-v +show version information. +.SH FILES +.TP 15 +.B luac.out +default output file +.SH "SEE ALSO" +.BR lua (1) +.br +http://www.lua.org/ +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +L. H. de Figueiredo, +R. Ierusalimschy and +W. Celes +(lua@tecgraf.puc-rio.br) +.\" EOF diff --git a/doc/luac.html b/doc/luac.html new file mode 100644 index 0000000000..3a71622e0b --- /dev/null +++ b/doc/luac.html @@ -0,0 +1,144 @@ + + + +LUAC man page + + + + +

        NAME

        +luac - Lua compiler +

        SYNOPSIS

        +luac +[ +options +] [ +filenames +] +

        DESCRIPTION

        +luac +is the Lua compiler. +It translates programs written in the Lua programming language +into binary files that can be latter loaded and executed. +

        +The main advantages of precompiling chunks are: +faster loading, +protecting source code from user changes, +and +off-line syntax checking. +

        +Pre-compiling does not imply faster execution +because in Lua chunks are always compiled into bytecodes before being executed. +luac +simply allows those bytecodes to be saved in a file for later execution. +

        +luac +produces a single output file containing the bytecodes +for all source files given. +By default, +the output file is named +luac.out, +but you can change this with the +-o +option. +

        +The binary files created by +luac +are portable to all architectures with the same word size. +This means that +binary files created on a 32-bit platform (such as Intel) +can be read without change in another 32-bit platform (such as Sparc), +even if the byte order (``endianness'') is different. +On the other hand, +binary files created on a 16-bit platform cannot be read in a 32-bit platform, +nor vice-versa. +

        +In the command line, +you can mix +text files containing Lua source and +binary files containing precompiled chunks. +This is useful to combine several precompiled chunks, +even from different (but compatible) platforms, +into a single precompiled chunk. +

        +You can use +"-" +to indicate the standard input as a source file +and +"--" +to signal the end of options +(that is, +all remaining arguments will be treated as files even if they start with +"-"). +

        +The internal format of the binary files produced by +luac +is likely to change when a new version of Lua is released. +So, +save the source files of all Lua programs that you precompile. +

        +

        OPTIONS

        +Options must be separate. +

        +-l +produce a listing of the compiled bytecode for Lua's virtual machine. +Listing bytecodes is useful to learn about Lua's virtual machine. +If no files are given, then +luac +loads +luac.out +and lists its contents. +

        +-o "file" +output to +file, +instead of the default +luac.out. +The output file may be a source file because +all files are loaded before the output file is written. +Be careful not to overwrite precious files. +

        +-p +load files but do not generate any output file. +Used mainly for syntax checking and for testing precompiled chunks: +corrupted files will probably generate errors when loaded. +Lua always performs a thorough integrity test on precompiled chunks. +Bytecode that passes this test is completely safe, +in the sense that it will not break the interpreter. +However, +there is no guarantee that such code does anything sensible. +(None can be given, because the halting problem is unsolvable.) +If no files are given, then +luac +loads +luac.out +and tests its contents. +No messages are displayed if the file passes the integrity test. +

        +-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running these chunks, +then the error messages may not contain the full information they usually do +(line numbers and names of locals are lost). +

        +-v +show version information. +

        FILES

        +

        +luac.out +default output file +

        SEE ALSO

        +lua(1) +
        +http://www.lua.org/ +

        DIAGNOSTICS

        +Error messages should be self explanatory. +

        AUTHORS

        +L. H. de Figueiredo, +R. Ierusalimschy and +W. Celes +(lua AT tecgraf.puc-rio.br) + + + diff --git a/doc/readme.html b/doc/readme.html new file mode 100644 index 0000000000..2eab92029a --- /dev/null +++ b/doc/readme.html @@ -0,0 +1,31 @@ + + +Lua documentation + + + + +
        +

        +Lua +Documentation +

        + + + +
        + +Last update: +Wed Dec 22 13:55:42 BRST 2004 + + + + diff --git a/etc/Makefile b/etc/Makefile index 805df1d21d..51bbb40714 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,32 +1,36 @@ # makefile for Lua etc -LUA= .. - -include $(LUA)/config - -ALL= min noparser luab 1 +TOP= .. +LIB= $(TOP)/src +INC= $(TOP)/src +BIN= $(TOP)/src +SRC= $(TOP)/src +TST= $(TOP)/test + +CC= gcc +CFLAGS= -O2 -Wall $(MYCFLAGS) +MYCFLAGS= -ansi -I$(INC) +MYLDFLAGS= -Wl,-E +MYLIBS= -lm -ldl +RM= rm -f + +ALL= min noparser.o 1 all: @echo 'choose a target:' $(ALL) -min: min.c $(LIBLUA) +min: min.c $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib -noparser: noparser.c - $(CC) $(CFLAGS) -I$(LUA)/src -o $@.o -c $@.c - -luab: noparser - $(CC) -o $@ noparser.o $(LUA)/src/lua/lua.o -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) - $(BIN)/luac $(LUA)/test/hello.lua - $@ luac.out - -$@ -e'a=1' +noparser: noparser.o + $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua -llualib $(MYLIBS) + $(BIN)/luac $(TST)/hello.lua + -./a.out luac.out + -./a.out -e'a=1' 1: - $(CC) $(CFLAGS) -I../src -I../src/lib -I../src/lua all.c $(EXTRA_LIBS) $(DLLIB) - ./a.out $(LUA)/test/hello.lua - -flat: - cd ..; mkdir flat; mv include/*.h src/*.[ch] src/*/*.[ch] flat + $(CC) $(CFLAGS) all.c $(MYLIBS) + ./a.out $(TST)/hello.lua clean: - rm -f $(ALL) a.out core *.o luac.out + $(RM) $(ALL) a.out core core.* *.o luac.out diff --git a/etc/README b/etc/README index 01df94c42d..77b6f19a9e 100644 --- a/etc/README +++ b/etc/README @@ -5,6 +5,10 @@ all.c Full Lua interpreter in a single file. Do "make 1". +lua.hpp + Lua header files for C++. + This keeps the C interface to Lua. But Lua also compiles as clean C++. + lua.ico A Lua icon for Windows (and web sites, as favicon.ico). Drawn by hand by Markus Gritsch . @@ -15,8 +19,7 @@ min.c noparser.c Linking with noparser.o avoids loading the parsing modules in lualib.a. - Do "make luab" to build a sample Lua intepreter that does not parse - Lua programs, only loads precompiled programs. + Do "make noparser" to see a demo. saconfig.c Configuration for Lua interpreter. diff --git a/etc/lua.hpp b/etc/lua.hpp index 273ec44ca3..ec417f5946 100644 --- a/etc/lua.hpp +++ b/etc/lua.hpp @@ -1,5 +1,6 @@ // lua.hpp // Lua header files for C++ +// <> not supplied automatically because Lua also compiles as C++ extern "C" { #include "lua.h" diff --git a/etc/noparser.c b/etc/noparser.c index dc58faffa7..9396ad6025 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -4,9 +4,12 @@ * You'll only be able to load binary files and strings, precompiled with luac. * (Of course, you'll have to build luac with the original parsing modules!) * -* To use this module, simply compile it ("make noparser" does that) and -* list its object file before the Lua libraries. The linker should then not -* load the parsing modules. To try it, do "make luab". +* To use this module, simply compile it ("make noparser" does that) and list +* its object file before the Lua libraries. The linker should then not load +* the parsing modules. To try it, do "make luab". +* +* If you also want to avoid the dump module (ldump.o), define NODUMP. +* #define NODUMP */ #define LUA_CORE @@ -22,22 +25,18 @@ void luaX_init (lua_State *L) { Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { UNUSED(z); UNUSED(buff); - lua_pushstring(L,"parser not loaded"); + lua_pushliteral(L,"parser not loaded"); lua_error(L); return NULL; } -/* -* If you also want to avoid the dump module, ldump.o, enable the code below. -*/ -#define NODUMP #ifdef NODUMP #include "lundump.h" int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip) { return 0; - lua_pushstring(L,"dumper not loaded"); + lua_pushliteral(L,"dumper not loaded"); lua_error(L); } #endif diff --git a/etc/saconfig.c b/etc/saconfig.c index 6c07cce102..676b38e110 100644 --- a/etc/saconfig.c +++ b/etc/saconfig.c @@ -6,39 +6,17 @@ * *** Line editing and history: * #define USE_READLINE to use the GNU readline library. +* Add "-lreadline -ltermcap" to MYLIBS. * * To use another library for this, use the code below as a start. * Make sure you #define lua_readline and lua_saveline accordingly. +* * If you do not #define lua_readline, you'll get a version based on fgets * that uses a static buffer of size MAXINPUT. -* -* -*** Static Lua libraries to be loaded at startup: -* #define lua_userinit(L) to a Lua function that loads libraries; typically -* #define lua_userinit(L) openstdlibs(L);myinit(L) -* or -* #define lua_userinit(L) myinit(L) -* -* Another way is to add the prototypes of the init functions here and -* #define LUA_EXTRALIBS accordingly. For example, -* #define LUA_EXTRALIBS {"mylib","luaopen_mylib"}, -* Note the ending comma! -* -* -*** Prompts: -* The stand-alone Lua interpreter uses two prompts: PROMPT and PROMPT2. -* PROMPT is the primary prompt, shown when the intepreter is ready to receive -* a new statement. PROMPT2 is the secondary prompt, shown while a statement -* is being entered but is still incomplete. -* -* -*** Program name: -* Error messages usually show argv[0] as a program name. In systems that do -* not give a valid string as argv[0], error messages show PROGNAME instead. -* -* */ +#define USE_READLINE + #ifdef USE_READLINE /* * This section implements of lua_readline and lua_saveline for lua.c using diff --git a/include/Makefile b/include/Makefile deleted file mode 100644 index 687cf383de..0000000000 --- a/include/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# makefile for Lua distribution (includes) - -LUA= .. - -include $(LUA)/config - -SRCS= lua.h lualib.h lauxlib.h luaconf.h - -all: - -clean: - -co: - co -q -f -M $(SRCS) - -klean: clean - rm -f $(SRCS) diff --git a/src/Makefile b/src/Makefile index 7812b9188f..cf7ff181d0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,83 +1,135 @@ -# makefile for Lua core library - -LUA= .. - -include $(LUA)/config - -OBJS= \ - lapi.o \ - lcode.o \ - ldebug.o \ - ldo.o \ - ldump.o \ - lfunc.o \ - lgc.o \ - llex.o \ - lmem.o \ - lobject.o \ - lopcodes.o \ - lparser.o \ - lstate.o \ - lstring.o \ - ltable.o \ - ltm.o \ - lundump.o \ - lvm.o \ - lzio.o - -SRCS= \ - lapi.c \ - lcode.c \ - ldebug.c \ - ldo.c \ - ldump.c \ - lfunc.c \ - lgc.c \ - llex.c \ - lmem.c \ - lobject.c \ - lopcodes.c \ - lparser.c \ - lstate.c \ - lstring.c \ - ltable.c \ - ltm.c \ - lundump.c \ - lvm.c \ - lzio.c \ - lapi.h \ - lcode.h \ - ldebug.h \ - ldo.h \ - lfunc.h \ - lgc.h \ - llex.h \ - llimits.h \ - lmem.h \ - lobject.h \ - lopcodes.h \ - lparser.h \ - lstate.h \ - lstring.h \ - ltable.h \ - ltm.h \ - lundump.h \ - lvm.h \ - lzio.h - -T= $(LIB)/liblua.a - -all: $T - -$T: $(OBJS) - $(AR) $@ $(OBJS) +# makefile for building Lua +# see INSTALL for installation instructions +# see ../Makefile and luaconf.h for further customization + +# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= + +CC= gcc +CFLAGS= -O2 -Wall $(MYCFLAGS) +MYCFLAGS= +MYLDFLAGS= -Wl,-E # enable dynamic loading in Linux +MYLIBS= -lm -ldl # enable dynamic loading in Linux +AR= ar rcu +RANLIB= ranlib +RM= rm -f + +# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= + +CORE_T= liblua.a +CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ + lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ + lundump.o lvm.o lzio.o + +LIB_T= liblualib.a +LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ + lstrlib.o loadlib.o linit.o + +LUA_T= lua +LUA_O= lua.o + +LUAC_T= luac +LUAC_O= luac.o print.o lauxlib.o + +ALL_T= $(CORE_T) $(LIB_T) $(LUA_T) $(LUAC_T) +ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) +ALL_A= $(CORE_T) $(LIB_T) + +all: $(ALL_T) + +o: $(ALL_O) + +a: $(ALL_A) + +$(CORE_T): $(CORE_O) + $(AR) $@ $? $(RANLIB) $@ +$(LIB_T): $(LIB_O) + $(AR) $@ $? + $(RANLIB) $@ + +$(LUA_T): $(LUA_O) $(CORE_T) $(LIB_T) + $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) -L. -llua -llualib $(MYLIBS) + +$(LUAC_T): $(LUAC_O) $(CORE_T) + $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) -L. -llua + clean: - rm -f $(OBJS) $T + $(RM) $(ALL_T) $(ALL_O) + +depend: + @$(CC) $(CFLAGS) -MM *.c + +echo: + @echo "CC = $(CC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "MYCFLAGS = $(MYCFLAGS)" + @echo "MYLDFLAGS = $(MYLDFLAGS)" + @echo "MYLIBS = $(MYLIBS)" + @echo "AR = $(AR)" + @echo "RANLIB = $(RANLIB)" + @echo "RM = $(RM)" + +# DO NOT DELETE -co: - co -q -f -M $(SRCS) +lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ + lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ + lundump.h lvm.h +lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h +lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h +lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ + lzio.h lmem.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h \ + ldo.h lgc.h +ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h +ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ + llex.h lzio.h lmem.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h \ + ltm.h ldo.h lfunc.h lstring.h lgc.h lvm.h +ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h ltable.h \ + lstring.h lundump.h lvm.h +ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lopcodes.h lstate.h \ + ltm.h lzio.h lmem.h lundump.h +lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ + lstate.h ltm.h lzio.h +lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h +linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h +liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h +llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ + lzio.h lmem.h llex.h lparser.h ltable.h lstring.h lgc.h +lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h +lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h +loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h +lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ + ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h +lopcodes.o: lopcodes.c lua.h luaconf.h lobject.h llimits.h lopcodes.h +loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h +lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ + lzio.h lmem.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h \ + ldo.h lfunc.h lstring.h lgc.h +lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h +lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ + ltm.h lzio.h lstring.h lgc.h +lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h +ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h +ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h +ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ + lmem.h lstring.h lgc.h ltable.h +lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h +luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ + lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ + lundump.h +lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lopcodes.h lstring.h lgc.h \ + lundump.h +lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h +lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ + lzio.h +print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ + ltm.h lzio.h lmem.h lopcodes.h lundump.h -klean: clean - rm -f $(SRCS) +# (end of Makefile) diff --git a/src/README b/src/README deleted file mode 100644 index 915f30b411..0000000000 --- a/src/README +++ /dev/null @@ -1,5 +0,0 @@ -This is the Lua core. - -The standard Lua library are in lib/. -The standalone interpreter is in lua/. -The standalone compiler is in luac/. diff --git a/src/lapi.c b/src/lapi.c index c2c752e5ec..e2dd11d182 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.22 2004/12/06 17:53:42 roberto Exp $ +** $Id: lapi.c,v 2.23 2004/12/13 12:15:11 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -867,9 +867,9 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { luaC_step(L); break; } - case LUA_GCSETSTEPMUL: { - res = g->stepmul; - g->stepmul = data; + case LUA_GCSETPACE: { + res = g->gcpace; + g->gcpace = data; break; } case LUA_GCSETINCMODE: { diff --git a/src/lib/lauxlib.c b/src/lauxlib.c similarity index 97% rename from src/lib/lauxlib.c rename to src/lauxlib.c index 615be8f2e5..5bbe918b8f 100644 --- a/src/lib/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.126 2004/09/29 21:03:14 roberto Exp $ +** $Id: lauxlib.c,v 1.127 2004/12/20 13:47:29 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -375,9 +375,19 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, } +static int readable (const char *fname) { + int err; + FILE *f = fopen(fname, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + getc(f); /* try to read it */ + err = ferror(f); + fclose(f); + return (err == 0); +} + + LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, const char *path) { - FILE *f; const char *p = path; for (;;) { const char *fname; @@ -387,15 +397,8 @@ LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, } fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); lua_remove(L, -2); /* remove path template */ - f = fopen(fname, "r"); /* try to open it */ - if (f) { - int err; - getc(f); /* try to read file */ - err = ferror(f); - fclose(f); - if (err == 0) /* open and read sucessful? */ - return fname; /* return that file name */ - } + if (readable(fname)) /* does file exist and is readable? */ + return fname; /* return that file name */ lua_pop(L, 1); /* remove file name */ } } diff --git a/include/lauxlib.h b/src/lauxlib.h similarity index 100% rename from include/lauxlib.h rename to src/lauxlib.h diff --git a/src/lib/lbaselib.c b/src/lbaselib.c similarity index 96% rename from src/lib/lbaselib.c rename to src/lbaselib.c index 8c6280972d..3b034bbc03 100644 --- a/src/lib/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.161 2004/12/06 17:53:42 roberto Exp $ +** $Id: lbaselib.c,v 1.163 2004/12/13 12:15:11 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -182,9 +182,9 @@ static int luaB_gcinfo (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setstepmul", "setincmode", NULL}; + "count", "step", "setpace", "setincmode", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETSTEPMUL, LUA_GCSETINCMODE}; + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPACE, LUA_GCSETINCMODE}; int o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); int ex = luaL_optint(L, 2, 0); luaL_argcheck(L, o >= 0, 1, "invalid option"); @@ -396,18 +396,8 @@ static int luaB_tostring (lua_State *L) { case LUA_TNIL: lua_pushliteral(L, "nil"); break; - case LUA_TTABLE: - lua_pushfstring(L, "table: %p", lua_topointer(L, 1)); - break; - case LUA_TFUNCTION: - lua_pushfstring(L, "function: %p", lua_topointer(L, 1)); - break; - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - lua_pushfstring(L, "userdata: %p", lua_topointer(L, 1)); - break; - case LUA_TTHREAD: - lua_pushfstring(L, "thread: %p", lua_topointer(L, 1)); + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); break; } return 1; diff --git a/src/lib/ldblib.c b/src/ldblib.c similarity index 100% rename from src/lib/ldblib.c rename to src/ldblib.c diff --git a/src/ldebug.c b/src/ldebug.c index 17727d37ab..0456669f17 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.11 2004/12/03 20:35:33 roberto Exp $ +** $Id: ldebug.c,v 2.12 2004/12/20 15:50:00 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -477,7 +477,7 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { } case OP_GETUPVAL: { int u = GETARG_B(i); /* upvalue index */ - *name = getstr(p->upvalues[u]); + *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; return "upvalue"; } case OP_SELF: { diff --git a/src/lgc.c b/src/lgc.c index 87a3b53444..9259bff0bf 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.18 2004/12/06 17:53:42 roberto Exp $ +** $Id: lgc.c,v 2.19 2004/12/13 12:15:11 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -27,6 +27,7 @@ #define GCSWEEPMAX 10 #define GCSWEEPCOST 30 #define GCFINALIZECOST 100 +#define GCSTEPMUL 8 #define FIXEDMASK bitmask(FIXEDBIT) @@ -621,18 +622,17 @@ static l_mem singlestep (lua_State *L) { void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * g->stepmul; + l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * GCSTEPMUL; do { lim -= singlestep(L); if (g->gcstate == GCSpause) break; } while (lim > 0 || !g->incgc); - if (g->incgc) + if (g->gcstate != GCSpause) g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/STEPMUL; */ else { lua_assert(g->totalbytes >= g->estimate); - lua_assert(g->gcstate == GCSpause); - g->GCthreshold = 2*g->estimate; + g->GCthreshold = g->estimate + ((g->estimate/GCDIV) * g->gcpace); } } diff --git a/src/lib/Makefile b/src/lib/Makefile deleted file mode 100644 index 74f652157c..0000000000 --- a/src/lib/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# makefile for Lua standard library - -LUA= ../.. - -include $(LUA)/config - -EXTRA_DEFS= $(POPEN) $(TMPNAM) $(DEGREES) $(LOADLIB) - -OBJS= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o lstrlib.o loadlib.o linit.o -SRCS= lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c lstrlib.c loadlib.c linit.c - -T= $(LIB)/liblualib.a - -all: $T - -$T: $(OBJS) - $(AR) $@ $(OBJS) - $(RANLIB) $@ - -clean: - rm -f $(OBJS) $T - -co: - co -q -f -M $(SRCS) - -klean: clean - rm -f $(SRCS) diff --git a/src/lib/README b/src/lib/README deleted file mode 100644 index c5600b8eca..0000000000 --- a/src/lib/README +++ /dev/null @@ -1,8 +0,0 @@ -This is the standard Lua library. - -The code of the standard library can be read as an example of how to export -C functions to Lua. The easiest library to read is lmathlib.c. - -The library is implemented entirely on top of the official Lua API as declared -in lua.h, using lauxlib.c, which contains several useful functions for writing -libraries. We encourage developers to use lauxlib.c in their own libraries. diff --git a/src/lib/loadlib.c b/src/lib/loadlib.c deleted file mode 100644 index 63bc0bcc1e..0000000000 --- a/src/lib/loadlib.c +++ /dev/null @@ -1,429 +0,0 @@ -/* -** $Id: loadlib.c,v 1.11 2004/11/19 15:52:12 roberto Exp $ -** Dynamic library loader for Lua -** See Copyright Notice in lua.h -* -* This Lua library exports a single function, called loadlib, which -* is called from Lua as loadlib(lib,init), where lib is the full -* name of the library to be loaded (including the complete path) and -* init is the name of a function to be called after the library is -* loaded. Typically, this function will register other functions, thus -* making the complete library available to Lua. The init function is -* *not* automatically called by loadlib. Instead, loadlib returns the -* init function as a Lua function that the client can call when it -* thinks is appropriate. In the case of errors, loadlib returns nil and -* two strings describing the error. The first string is supplied by -* the operating system; it should be informative and useful for error -* messages. The second string is "open", "init", or "absent" to identify -* the error and is meant to be used for making decisions without having -* to look into the first string (whose format is system-dependent). -* This module contains an implementation of loadlib for Unix systems -* that have dlfcn, an implementation for Darwin (Mac OS X), an -* implementation for Windows, and a stub for other systems. See -* the list at the end of this file for some links to available -* implementations of dlfcn and interfaces to other native dynamic -* loaders on top of which loadlib could be implemented. -*/ - - -#include -#include - - -#define loadlib_c -#define LUA_LIB - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - - -#define ERR_OPEN 1 -#define ERR_FUNCTION 2 - - -static void registerlib (lua_State *L, const void *lib); - - -#if defined(USE_DLOPEN) -/* -* This is an implementation of loadlib based on the dlfcn interface. -* The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, -* NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least -* as an emulation layer on top of native functions. -*/ - -#include - -#define freelib dlclose - -static int loadlib(lua_State *L, const char *path, const char *init) -{ - void *lib=dlopen(path,RTLD_NOW); - if (lib!=NULL) - { - lua_CFunction f=(lua_CFunction) dlsym(lib,init); - if (f!=NULL) - { - registerlib(L, lib); - lua_pushcfunction(L,f); - return 0; - } - } - /* else return appropriate error message */ - lua_pushstring(L,dlerror()); - if (lib!=NULL) { - dlclose(lib); - return ERR_FUNCTION; /* error loading function */ - } - else return ERR_OPEN; /* error loading library */ -} - - - -#elif defined(USE_DLL) -/* -* This is an implementation of loadlib for Windows using native functions. -*/ - -#include - -#define freelib(lib) FreeLibrary((HINSTANCE)lib) - -static void pusherror(lua_State *L) -{ - int error=GetLastError(); - char buffer[128]; - if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - 0, error, 0, buffer, sizeof(buffer), 0)) - lua_pushstring(L,buffer); - else - lua_pushfstring(L,"system error %d\n",error); -} - -static int loadlib(lua_State *L, const char *path, const char *init) -{ - HINSTANCE lib=LoadLibrary(path); - if (lib!=NULL) - { - lua_CFunction f=(lua_CFunction) GetProcAddress(lib,init); - if (f!=NULL) - { - registerlib(L, lib); - lua_pushcfunction(L,f); - return 1; - } - } - pusherror(L); - if (lib!=NULL) { - FreeLibrary(lib); - return ERR_OPEN; - } - else return ERR_FUNCTION; -} - - - -/* Native Mac OS X / Darwin Implementation */ -#elif defined(USE_DYLD) - -#include - - -/* Mach cannot unload images (?) */ -#define freelib(lib) ((void)lib) - -static void pusherror (lua_State *L) -{ - const char *err_str; - const char *err_file; - NSLinkEditErrors err; - int err_num; - NSLinkEditError(&err, &err_num, &err_file, &err_str); - lua_pushstring(L, err_str); -} - -static int loadlib (lua_State *L, const char *path, const char *init) { - const struct mach_header *lib; - /* this would be a rare case, but prevents crashing if it happens */ - if(!_dyld_present()) { - lua_pushstring(L,"dyld not present."); - return ERR_OPEN; - } - lib = NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); - if(lib != NULL) { - NSSymbol init_sym = NSLookupSymbolInImage(lib, init, - NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | - NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); - if(init_sym != NULL) { - lua_CFunction f = (lua_CFunction)NSAddressOfSymbol(init_sym); - registerlib(L, lib); - lua_pushcfunction(L,f); - return 0; - } - } - /* else an error ocurred */ - pusherror(L); - /* Can't unload image */ - return (lib != NULL) ? ERR_FUNCTION : ERR_OPEN; -} - - - -#else -/* Fallback for other systems */ - - -#define freelib(lib) ((void)lib) - -static int loadlib(lua_State *L) -{ - registerlib(L, NULL); /* to avoid warnings */ - lua_pushnil(L); - lua_pushliteral(L,"`loadlib' not supported"); - lua_pushliteral(L,"absent"); - return 3; -} - -#endif - - -/* -** common code for all implementations: put a library into the registry -** so that, when Lua closes its state, the library's __gc metamethod -** will be called to unload the library. -*/ -static void registerlib (lua_State *L, const void *lib) -{ - const void **plib = (const void **)lua_newuserdata(L, sizeof(const void *)); - *plib = lib; - luaL_getmetatable(L, "_LOADLIB"); - lua_setmetatable(L, -2); - lua_pushboolean(L, 1); - lua_settable(L, LUA_REGISTRYINDEX); /* registry[lib] = true */ -} - -/* -** __gc tag method: calls library's `freelib' function with the lib -** handle -*/ -static int gctm (lua_State *L) -{ - void *lib = *(void **)luaL_checkudata(L, 1, "_LOADLIB"); - freelib(lib); - return 0; -} - - -static int loadlib1 (lua_State *L) { - const char *path=luaL_checkstring(L,1); - const char *init=luaL_checkstring(L,2); - int res = loadlib(L,path,init); - if (res == 0) /* no error? */ - return 1; /* function is at stack top */ - else { /* error */ - lua_pushnil(L); - lua_insert(L,-2); /* insert nil before error message */ - lua_pushstring(L, (res==ERR_OPEN)?"open":"init"); - return 3; - } -} - - - -/* -** {====================================================== -** `require' and `module' functions -** ======================================================= -*/ - - -static const char *loadLua (lua_State *L, const char *fname, const char *name) { - const char *path; - /* try first `LUA_PATH' for compatibility */ - lua_getglobal(L, "LUA_PATH"); - path = lua_tostring(L, -1); - if (!path) { - lua_pop(L, 1); - luaL_getfield(L, LUA_GLOBALSINDEX, "package.path"); - path = lua_tostring(L, -1); - } - if (path == NULL) - luaL_error(L, "`package.path' must be a string"); - fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return path; /* library not found in this path */ - if (luaL_loadfile(L, fname) != 0) - luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); - return NULL; /* library loaded successfully */ -} - - -static const char *loadC (lua_State *L, const char *fname, const char *name) { - const char *path; - const char *funcname; - luaL_getfield(L, LUA_GLOBALSINDEX, "package.cpath"); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, "global _CPATH must be a string"); - fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return path; /* library not found in this path */ - funcname = luaL_gsub(L, name, ".", ""); - funcname = lua_pushfstring(L, "%s%s", LUA_POF, funcname); - if (loadlib(L, fname, funcname) != 0) - luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); - return NULL; /* library loaded successfully */ -} - - -static int ll_require (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - lua_settop(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, 2, name); - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded; return its result */ - /* else must load it; first mark it as loaded */ - lua_pushboolean(L, 1); - lua_setfield(L, 2, name); /* _LOADED[name] = true */ - /* check whether it is preloaded */ - lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); - lua_getfield(L, -1, name); - if (lua_isnil(L, -1)) { /* no preload function for that module? */ - const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); - const char *cpath = loadC(L, fname, name); /* try a C module */ - if (cpath) { /* not found? */ - const char *path = loadLua(L, fname, name); /* try a Lua module */ - if (path) { /* yet not found? */ - lua_pushnil(L); - lua_setfield(L, 2, name); /* unmark _LOADED[name] */ - return luaL_error(L, "package `%s' not found\n" - " cpath: %s\n path: %s", - name, cpath, path); - } - } - } - lua_pushvalue(L, 1); /* pass name as argument to module */ - lua_call(L, 1, 1); /* run loaded module */ - if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* update _LOADED[name] with returned value */ - lua_getfield(L, 2, name); /* return _LOADED[name] */ - return 1; -} - - -static void setfenv (lua_State *L) { - lua_Debug ar; - lua_getstack(L, 1, &ar); - lua_getinfo(L, "f", &ar); - lua_pushvalue(L, -2); - lua_setfenv(L, -2); -} - - -static int ll_module (lua_State *L) { - const char *modname = luaL_checkstring(L, 1); - const char *dot; - lua_settop(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - /* try to find given table */ - luaL_getfield(L, LUA_GLOBALSINDEX, modname); - if (lua_isnil(L, -1)) { /* not found? */ - lua_pop(L, 1); /* remove previous result */ - lua_newtable(L); /* create it */ - /* register it with given name */ - lua_pushvalue(L, -1); - luaL_setfield(L, LUA_GLOBALSINDEX, modname); - } - else if (!lua_istable(L, -1)) - return luaL_error(L, "name conflict for module `%s'", modname); - /* check whether table already has a _NAME field */ - lua_getfield(L, -1, "_NAME"); - if (!lua_isnil(L, -1)) /* is table an initialized module? */ - lua_pop(L, 1); - else { /* no; initialize it */ - lua_pop(L, 1); - lua_newtable(L); /* create new metatable */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setfield(L, -2, "__index"); /* mt.__index = _G */ - lua_setmetatable(L, -2); - lua_pushstring(L, modname); - lua_setfield(L, -2, "_NAME"); - dot = strrchr(modname, '.'); /* look for last dot in module name */ - if (dot == NULL) dot = modname; - else dot++; - /* set _PACKAGE as package name (full module name minus last part) */ - lua_pushlstring(L, modname, dot - modname); - lua_setfield(L, -2, "_PACKAGE"); - } - lua_pushvalue(L, -1); - lua_setfield(L, 2, modname); /* _LOADED[modname] = new table */ - setfenv(L); - return 0; -} - - -/* }====================================================== */ - - -static const luaL_reg ll_funcs[] = { - {"loadlib", loadlib1}, - {"require", ll_require}, - {"module", ll_module}, - {NULL, NULL} -}; - - - -LUALIB_API int luaopen_loadlib (lua_State *L) { - const char *path; - /* create new type _LOADLIB */ - luaL_newmetatable(L, "_LOADLIB"); - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); - /* create `package' table */ - lua_newtable(L); - lua_pushvalue(L, -1); - lua_setglobal(L, "package"); - /* set field `path' */ - path = getenv(LUA_PATH); - if (path == NULL) path = LUA_PATH_DEFAULT; - lua_pushstring(L, path); - lua_setfield(L, -2, "path"); - /* set field `cpath' */ - path = getenv(LUA_CPATH); - if (path == NULL) path = LUA_CPATH_DEFAULT; - lua_pushstring(L, path); - lua_setfield(L, -2, "cpath"); - /* set field `loaded' */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_setfield(L, -2, "loaded"); - /* set field `preload' */ - lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); - lua_setfield(L, -2, "preload"); - lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_openlib(L, NULL, ll_funcs, 0); /* open lib into global table */ - return 1; -} - -/* -* Here are some links to available implementations of dlfcn and -* interfaces to other native dynamic loaders on top of which loadlib -* could be implemented. Please send contributions and corrections to us. -* -* AIX -* Starting with AIX 4.2, dlfcn is included in the base OS. -* There is also an emulation package available. -* http://www.faqs.org/faqs/aix-faq/part4/section-21.html -* -* HPUX -* HPUX 11 has dlfcn. For HPUX 10 use shl_*. -* http://www.geda.seul.org/mailinglist/geda-dev37/msg00094.html -* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html -* -* Macintosh, Windows -* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html -* -* GLIB has wrapper code for BeOS, OS2, Unix and Windows -* http://cvs.gnome.org/lxr/source/glib/gmodule/ -* -*/ diff --git a/src/lib/linit.c b/src/linit.c similarity index 100% rename from src/lib/linit.c rename to src/linit.c diff --git a/src/lib/liolib.c b/src/liolib.c similarity index 100% rename from src/lib/liolib.c rename to src/liolib.c diff --git a/src/llimits.h b/src/llimits.h index 6be658f022..c3d5d532b8 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.61 2004/11/24 18:55:56 roberto Exp $ +** $Id: llimits.h,v 1.62 2004/12/13 12:15:11 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -73,6 +73,8 @@ typedef LUA_UACNUMBER l_uacNumber; typedef lu_int32 Instruction; +/* divisor for GC pace */ +#define GCDIV 8 /* maximum stack for a Lua function */ #define MAXSTACK 250 diff --git a/src/lib/lmathlib.c b/src/lmathlib.c similarity index 100% rename from src/lib/lmathlib.c rename to src/lmathlib.c diff --git a/src/loadlib.c b/src/loadlib.c new file mode 100644 index 0000000000..4adcbdc077 --- /dev/null +++ b/src/loadlib.c @@ -0,0 +1,464 @@ +/* +** $Id: loadlib.c,v 1.15 2004/12/29 18:56:34 roberto Exp $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +* +* This module contains an implementation of loadlib for Unix systems +* that have dlfcn, an implementation for Darwin (Mac OS X), an +* implementation for Windows, and a stub for other systems. +*/ + + +#include +#include + + +#define loadlib_c +#define LUA_LIB + +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" + + +#define LIBPREFIX "LOADLIB: " + +#define POF LUA_POF +#define LIB_FAIL "open" + + +static void ll_unloadlib (void *lib); +static void *ll_load (lua_State *L, const char *path); +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); + + + +#if defined(USE_DLOPEN) +/* +** {======================================================================== +** This is an implementation of loadlib based on the dlfcn interface. +** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, +** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least +** as an emulation layer on top of native functions. +** ========================================================================= +*/ + +#include + +static void ll_unloadlib (void *lib) { + dlclose(lib); +} + + +static void *ll_load (lua_State *L, const char *path) { + void *lib = dlopen(path, RTLD_NOW); + if (lib == NULL) lua_pushstring(L, dlerror()); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)dlsym(lib, sym); + if (f == NULL) lua_pushstring(L, dlerror()); + return f; +} + +/* }====================================================== */ + + + +#elif defined(USE_DLL) +/* +** {====================================================================== +** This is an implementation of loadlib for Windows using native functions. +** ======================================================================= +*/ + +#include + + +static void pusherror (lua_State *L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, buffer, sizeof(buffer), NULL)) + lua_pushstring(L,buffer); + else + lua_pushfstring(L, "system error %d\n", error); +} + +static void ll_unloadlib (void *lib) { + FreeLibrary((HINSTANCE)lib); +} + + +static void *ll_load (lua_State *L, const char *path) { + HINSTANCE lib = LoadLibrary(path); + if (lib == NULL) pusherror(L); + return lib; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); + if (f == NULL) pusherror(L); + return f; +} + +/* }====================================================== */ + + + +#elif defined(USE_DYLD) +/* +** {====================================================================== +** Native Mac OS X / Darwin Implementation +** ======================================================================= +*/ + +#include + + +#undef POF +#define POF "_" LUA_POF + + +static void pusherror (lua_State *L) { + const char *err_str; + const char *err_file; + NSLinkEditErrors err; + int err_num; + NSLinkEditError(&err, &err_num, &err_file, &err_str); + lua_pushstring(L, err_str); +} + + +static const char *errorfromcode (NSObjectFileImageReturnCode ret) { + switch (ret) { + case NSObjectFileImageInappropriateFile: + return "file is not a bundle"; + case NSObjectFileImageArch: + return "library is for wrong CPU type"; + case NSObjectFileImageFormat: + return "bad format"; + case NSObjectFileImageAccess: + return "cannot access file"; + case NSObjectFileImageFailure: + default: + return "unable to load library"; + } +} + + +static void ll_unloadlib (void *lib) { + NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); +} + + +static void *ll_load (lua_State *L, const char *path) { + NSObjectFileImage img; + NSObjectFileImageReturnCode ret; + /* this would be a rare case, but prevents crashing if it happens */ + if(!_dyld_present()) { + lua_pushliteral(L, "dyld not present"); + return NULL; + } + ret = NSCreateObjectFileImageFromFile(path, &img); + if (ret == NSObjectFileImageSuccess) { + NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | + NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSDestroyObjectFileImage(img); + if (mod == NULL) pusherror(L); + return mod; + } + lua_pushstring(L, errorfromcode(ret)); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); + if (nss == NULL) { + lua_pushfstring(L, "symbol `%s' not found", sym); + return NULL; + } + return (lua_CFunction)NSAddressOfSymbol(nss); +} + +/* }====================================================== */ + + + +#else +/* +** {====================================================== +** Fallback for other systems +** ======================================================= +*/ + +#undef LIB_FAIL +#define LIB_FAIL "absent" + + +static void ll_unloadlib (void *lib) { + (void)lib; /* to avoid warnings */ +} + + +static void *ll_load (lua_State *L, const char *path) { + (void)path; /* to avoid warnings */ + lua_pushliteral(L,"`loadlib' not supported"); + return NULL; +} + + +static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { + (void)lib; (void)sym; /* to avoid warnings */ + lua_pushliteral(L,"`loadlib' not supported"); + return NULL; +} + +/* }====================================================== */ +#endif + + + +static void **ll_register (lua_State *L, const char *path) { + void **plib; + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ + if (!lua_isnil(L, -1)) /* is there an entry? */ + plib = (void **)lua_touserdata(L, -1); + else { /* no entry yet; create one */ + lua_pop(L, 1); + plib = (void **)lua_newuserdata(L, sizeof(const void *)); + *plib = NULL; + luaL_getmetatable(L, "_LOADLIB"); + lua_setmetatable(L, -2); + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + return plib; +} + + +/* +** __gc tag method: calls library's `ll_unloadlib' function with the lib +** handle +*/ +static int gctm (lua_State *L) { + void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); + if (lib) { + if (*lib) ll_unloadlib(*lib); + *lib = NULL; /* mark library as closed */ + } + return 0; +} + + +static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { + const char *reason; + void **reg = ll_register(L, path); + if (*reg == NULL) *reg = ll_load(L, path); + if (*reg == NULL) + reason = LIB_FAIL; + else { + lua_CFunction f = ll_sym(L, *reg, sym); + if (f) { + lua_pushcfunction(L, f); + return 1; /* return function */ + } + reason = "init"; + } + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, reason); + return 3; /* return nil, ll_error, reason */ +} + + +static int ll_loadlib (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + const char *init = luaL_checkstring(L, 2); + return ll_loadfunc(L, path, init); +} + + + +/* +** {====================================================== +** `require' and `module' functions +** ======================================================= +*/ + + +static const char *loadLua (lua_State *L, const char *fname, const char *name) { + const char *path; + /* try first `LUA_PATH' for compatibility */ + lua_getglobal(L, "LUA_PATH"); + path = lua_tostring(L, -1); + if (!path) { + lua_pop(L, 1); + luaL_getfield(L, LUA_GLOBALSINDEX, "package.path"); + path = lua_tostring(L, -1); + } + if (path == NULL) + luaL_error(L, "`package.path' must be a string"); + fname = luaL_searchpath(L, fname, path); + if (fname == NULL) return path; /* library not found in this path */ + if (luaL_loadfile(L, fname) != 0) + luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); + return NULL; /* library loaded successfully */ +} + + +static const char *loadC (lua_State *L, const char *fname, const char *name) { + const char *path; + const char *funcname; + luaL_getfield(L, LUA_GLOBALSINDEX, "package.cpath"); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, "`package.cpath' must be a string"); + fname = luaL_searchpath(L, fname, path); + if (fname == NULL) return path; /* library not found in this path */ + funcname = luaL_gsub(L, name, ".", LUA_OFSEP); + funcname = lua_pushfstring(L, "%s%s", POF, funcname); + if (ll_loadfunc(L, fname, funcname) != 1) + luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -2)); + return NULL; /* library loaded successfully */ +} + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, 2, name); + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded; return its result */ + /* else must load it; first mark it as loaded */ + lua_pushboolean(L, 1); + lua_setfield(L, 2, name); /* _LOADED[name] = true */ + /* check whether it is preloaded */ + lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) { /* no preload function for that module? */ + const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); + const char *cpath = loadC(L, fname, name); /* try a C module */ + if (cpath) { /* not found? */ + const char *path = loadLua(L, fname, name); /* try a Lua module */ + if (path) { /* yet not found? */ + lua_pushnil(L); + lua_setfield(L, 2, name); /* unmark _LOADED[name] */ + return luaL_error(L, "package `%s' not found\n" + " cpath: %s\n path: %s", + name, cpath, path); + } + } + } + lua_pushvalue(L, 1); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* update _LOADED[name] with returned value */ + lua_getfield(L, 2, name); /* return _LOADED[name] */ + return 1; +} + + +static void setfenv (lua_State *L) { + lua_Debug ar; + lua_getstack(L, 1, &ar); + lua_getinfo(L, "f", &ar); + lua_pushvalue(L, -2); + lua_setfenv(L, -2); +} + + +static int ll_module (lua_State *L) { + const char *modname = luaL_checkstring(L, 1); + const char *dot; + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + /* try to find given table */ + luaL_getfield(L, LUA_GLOBALSINDEX, modname); + if (lua_isnil(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + lua_newtable(L); /* create it */ + /* register it with given name */ + lua_pushvalue(L, -1); + luaL_setfield(L, LUA_GLOBALSINDEX, modname); + } + else if (!lua_istable(L, -1)) + return luaL_error(L, "name conflict for module `%s'", modname); + /* check whether table already has a _NAME field */ + lua_getfield(L, -1, "_NAME"); + if (!lua_isnil(L, -1)) /* is table an initialized module? */ + lua_pop(L, 1); + else { /* no; initialize it */ + lua_pop(L, 1); + lua_newtable(L); /* create new metatable */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + lua_setmetatable(L, -2); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); + } + lua_pushvalue(L, -1); + lua_setfield(L, 2, modname); /* _LOADED[modname] = new table */ + setfenv(L); + return 0; +} + + +/* }====================================================== */ + + +static const luaL_reg ll_funcs[] = { + {"loadlib", ll_loadlib}, + {"require", ll_require}, + {"module", ll_module}, + {NULL, NULL} +}; + + + +LUALIB_API int luaopen_loadlib (lua_State *L) { + const char *path; + /* create new type _LOADLIB */ + luaL_newmetatable(L, "_LOADLIB"); + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); + /* create `package' table */ + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "package"); + /* set field `path' */ + path = getenv(LUA_PATH); + if (path == NULL) path = LUA_PATH_DEFAULT; + lua_pushstring(L, path); + lua_setfield(L, -2, "path"); + /* set field `cpath' */ + path = getenv(LUA_CPATH); + if (path == NULL) path = LUA_CPATH_DEFAULT; + lua_pushstring(L, path); + lua_setfield(L, -2, "cpath"); + /* set field `loaded' */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_setfield(L, -2, "loaded"); + /* set field `preload' */ + lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); + lua_setfield(L, -2, "preload"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + luaL_openlib(L, NULL, ll_funcs, 0); /* open lib into global table */ + return 1; +} + diff --git a/src/lib/loslib.c b/src/loslib.c similarity index 100% rename from src/lib/loslib.c rename to src/loslib.c diff --git a/src/lparser.c b/src/lparser.c index b40cf7c7b1..b6b3c0a0e5 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.10 2004/12/03 20:50:25 roberto Exp $ +** $Id: lparser.c,v 2.11 2004/12/07 18:31:16 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -109,10 +109,15 @@ static int testnext (LexState *ls, int c) { static void check (LexState *ls, int c) { - if (!testnext(ls, c)) + if (ls->t.token != c) error_expected(ls, c); } +static void checknext (LexState *ls, int c) { + check(ls, c); + next(ls); +} + #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } @@ -133,7 +138,7 @@ static void check_match (LexState *ls, int what, int who, int where) { static TString *str_checkname (LexState *ls) { TString *ts; - if (ls->t.token != TK_NAME) error_expected(ls, TK_NAME); + check(ls, TK_NAME); ts = ls->t.seminfo.ts; next(ls); return ts; @@ -396,7 +401,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { funcstate.f->is_vararg = NEWSTYLEVARARG; next(&lexstate); /* read first token */ chunk(&lexstate); - check_condition(&lexstate, (lexstate.t.token == TK_EOS), " expected"); + check(&lexstate, TK_EOS); close_func(&lexstate); lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); @@ -428,7 +433,7 @@ static void yindex (LexState *ls, expdesc *v) { next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); - check(ls, ']'); + checknext(ls, ']'); } @@ -460,7 +465,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { } else /* ls->t.token == '[' */ yindex(ls, &key); - check(ls, '='); + checknext(ls, '='); luaK_exp2RK(fs, &key); expr(ls, &val); luaK_codeABC(fs, OP_SETTABLE, cc->t->info, luaK_exp2RK(fs, &key), @@ -514,7 +519,7 @@ static void constructor (LexState *ls, expdesc *t) { init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ - check(ls, '{'); + checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); testnext(ls, ';'); /* compatibility only */ @@ -584,13 +589,13 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { FuncState new_fs; open_func(ls, &new_fs); new_fs.f->lineDefined = line; - check(ls, '('); + checknext(ls, '('); if (needself) { new_localvarliteral(ls, "self", 0); adjustlocalvars(ls, 1); } parlist(ls); - check(ls, ')'); + checknext(ls, ')'); chunk(ls); check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); @@ -944,7 +949,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { } else { /* assignment -> `=' explist1 */ int nexps; - check(ls, '='); + checknext(ls, '='); nexps = explist1(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); @@ -1011,7 +1016,7 @@ static void whilestat (LexState *ls, int line) { codeexp[i] = fs->f->code[expinit + i]; fs->pc = expinit; /* remove `exp' code */ enterblock(fs, &bl, 1); - check(ls, TK_DO); + checknext(ls, TK_DO); blockinit = luaK_getlabel(fs); block(ls); luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ @@ -1059,7 +1064,7 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ - check(ls, TK_DO); + checknext(ls, TK_DO); prep = luaK_codeAsBx(fs, (isnum ? OP_FORPREP : OP_TFORPREP), base, NO_JUMP); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); @@ -1082,9 +1087,9 @@ static void fornum (LexState *ls, TString *varname, int line) { new_localvarliteral(ls, "(for limit)", 1); new_localvarliteral(ls, "(for step)", 2); new_localvar(ls, varname, 3); - check(ls, '='); + checknext(ls, '='); exp1(ls); /* initial value */ - check(ls, ','); + checknext(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ @@ -1111,7 +1116,7 @@ static void forlist (LexState *ls, TString *indexname) { new_localvar(ls, indexname, nvars++); while (testnext(ls, ',')) new_localvar(ls, str_checkname(ls), nvars++); - check(ls, TK_IN); + checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 3, explist1(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ @@ -1142,7 +1147,7 @@ static int test_then_block (LexState *ls) { int flist; next(ls); /* skip IF or ELSEIF */ flist = cond(ls); - check(ls, TK_THEN); + checknext(ls, TK_THEN); block(ls); /* `then' part */ return flist; } diff --git a/src/lstate.c b/src/lstate.c index dfd35be6ec..bd238c5862 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.18 2004/12/06 17:53:42 roberto Exp $ +** $Id: lstate.c,v 2.19 2004/12/13 12:15:11 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -193,7 +193,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { setnilvalue(gval(g->dummynode)); gnext(g->dummynode) = NULL; g->totalbytes = sizeof(LG); - g->stepmul = STEPMUL; + g->gcpace = GCDIV; g->incgc = 1; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ diff --git a/src/lstate.h b/src/lstate.h index 81fb75a0e1..4f29190abd 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.9 2004/12/06 17:53:42 roberto Exp $ +** $Id: lstate.h,v 2.10 2004/12/13 12:15:11 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -85,7 +85,7 @@ typedef struct global_State { lu_mem totalbytes; /* number of bytes currently allocated */ lu_mem estimate; /* an estimate of number of bytes actually in use */ lu_mem prevestimate; /* previous estimate */ - int stepmul; /* relative `speed' of the GC */ + int gcpace; /* relative `speed' of the GC */ int incgc; /* 0 if GC is done non-incrementally */ lua_CFunction panic; /* to be called in unprotected errors */ TValue _registry; diff --git a/src/lib/lstrlib.c b/src/lstrlib.c similarity index 100% rename from src/lib/lstrlib.c rename to src/lstrlib.c diff --git a/src/lib/ltablib.c b/src/ltablib.c similarity index 92% rename from src/lib/ltablib.c rename to src/ltablib.c index ab953c6101..792bf3134c 100644 --- a/src/lib/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.26 2004/06/15 13:37:21 roberto Exp $ +** $Id: ltablib.c,v 1.27 2004/12/07 18:28:47 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -19,7 +19,7 @@ #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) -static int luaB_foreachi (lua_State *L) { +static int foreachi (lua_State *L) { int i; int n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); @@ -36,7 +36,7 @@ static int luaB_foreachi (lua_State *L) { } -static int luaB_foreach (lua_State *L) { +static int foreach (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TFUNCTION); lua_pushnil(L); /* first key */ @@ -54,13 +54,13 @@ static int luaB_foreach (lua_State *L) { } -static int luaB_getn (lua_State *L) { +static int getn (lua_State *L) { lua_pushinteger(L, aux_getn(L, 1)); return 1; } -static int luaB_setn (lua_State *L) { +static int setn (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_setn(L, 1, luaL_checkint(L, 2)); lua_pushvalue(L, 1); @@ -68,7 +68,7 @@ static int luaB_setn (lua_State *L) { } -static int luaB_tinsert (lua_State *L) { +static int tinsert (lua_State *L) { int v = lua_gettop(L); /* number of arguments */ int e = aux_getn(L, 1) + LUA_FIRSTINDEX; /* first empty element */ int pos; /* where to insert new element */ @@ -90,7 +90,7 @@ static int luaB_tinsert (lua_State *L) { } -static int luaB_tremove (lua_State *L) { +static int tremove (lua_State *L) { int e = aux_getn(L, 1) + LUA_FIRSTINDEX - 1; int pos = luaL_optint(L, 2, e); if (e < LUA_FIRSTINDEX) return 0; /* table is `empty' */ @@ -220,7 +220,7 @@ static void auxsort (lua_State *L, int l, int u) { } /* repeat the routine for the larger one */ } -static int luaB_sort (lua_State *L) { +static int sort (lua_State *L) { int n = aux_getn(L, 1); luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ @@ -235,13 +235,13 @@ static int luaB_sort (lua_State *L) { static const luaL_reg tab_funcs[] = { {"concat", str_concat}, - {"foreach", luaB_foreach}, - {"foreachi", luaB_foreachi}, - {"getn", luaB_getn}, - {"setn", luaB_setn}, - {"sort", luaB_sort}, - {"insert", luaB_tinsert}, - {"remove", luaB_tremove}, + {"foreach", foreach}, + {"foreachi", foreachi}, + {"getn", getn}, + {"setn", setn}, + {"sort", sort}, + {"insert", tinsert}, + {"remove", tremove}, {NULL, NULL} }; diff --git a/src/lua/lua.c b/src/lua.c similarity index 100% rename from src/lua/lua.c rename to src/lua.c diff --git a/include/lua.h b/src/lua.h similarity index 98% rename from include/lua.h rename to src/lua.h index aa4401c720..25fc84055a 100644 --- a/include/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.196 2004/12/06 17:53:42 roberto Exp $ +** $Id: lua.h,v 1.197 2004/12/13 12:15:11 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -17,7 +17,7 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (work3)" +#define LUA_VERSION "Lua 5.1 (work4)" #define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -225,7 +225,7 @@ LUA_API int lua_threadstatus (lua_State *L); #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 #define LUA_GCSTEP 4 -#define LUA_GCSETSTEPMUL 5 +#define LUA_GCSETPACE 5 #define LUA_GCSETINCMODE 6 LUA_API int lua_gc (lua_State *L, int what, int data); diff --git a/src/lua/Makefile b/src/lua/Makefile deleted file mode 100644 index aa52832f26..0000000000 --- a/src/lua/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# makefile for Lua interpreter - -LUA= ../.. - -include $(LUA)/config - -EXTRA_DEFS= $(USERCONF) -OBJS= lua.o -SRCS= lua.c - -T= $(BIN)/lua - -all: $T - -$T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a - $(CC) -o $@ $(MYLDFLAGS) $(OBJS) -L$(LIB) -llua -llualib $(EXTRA_LIBS) $(DLLIB) - -$(LIB)/liblua.a: - cd ..; $(MAKE) - -$(LIB)/liblualib.a: - cd ../lib; $(MAKE) - -clean: - rm -f $(OBJS) $T - -co: - co -q -f -M $(SRCS) - -klean: clean - rm -f $(SRCS) diff --git a/src/lua/README b/src/lua/README deleted file mode 100644 index 525f6c1544..0000000000 --- a/src/lua/README +++ /dev/null @@ -1,41 +0,0 @@ -This is lua, the stand-alone Lua interpreter. -It can be used as a batch interpreter and also interactively. -There are man pages for it in both nroff and html in ../../doc. - -Usage: lua [options] [script [args]]. Available options are: - - execute stdin as a file - -e stat execute string `stat' - -i enter interactive mode after executing `script' - -l name load and run library `name' - -v show version information - -w catch use of undefined global variables - -- stop handling options - -This interpreter is suitable for using Lua as a stand-alone language; it loads -all standard libraries. For a minimal interpreter, see ../../etc/min.c. - -If your application simply exports new functions to Lua (which is common), -then you can use this interpreter unmodified by putting your functions into -a library and loading it dynamically (if you have built support for dynamic -libraries). - -If you need to add your library statically, then you can use this interpreter -almost unmodified, as follows: - -* First, define a function - void myinit (lua_State *L) - in your own code. In this function, you should do whatever initializations - are needed by your application, typically exporting your functions to Lua. - (Of course, you can use any name instead of "myinit".) - -* Then, #define lua_userinit(L) in luaconf.h to call luaopen_stdlibs and - possibly luaopen_stdlibs, which opens all standard libraries. If you don't - need them, just don't call openstdlibs and open any standard libraries that - you do need in myinit. - -* Alternatively, write your own luaopen_stdlibs; the linker will use your - version (if you ask politely). - -Just remember to link your C code when building lua! - -For other customizations, see ../../include/luaconf.h . diff --git a/src/luac/luac.c b/src/luac.c similarity index 100% rename from src/luac/luac.c rename to src/luac.c diff --git a/src/luac/Makefile b/src/luac/Makefile deleted file mode 100644 index 509577bb6f..0000000000 --- a/src/luac/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# makefile for Lua compiler - -LUA= ../.. - -include $(LUA)/config - -INCS= -I$(INC) -I.. $(EXTRA_INCS) -OBJS= luac.o print.o -SRCS= luac.c print.c - -T= $(BIN)/luac - -all: $T - -$T: $(OBJS) $(LIB)/liblua.a ../lib/lauxlib.o - $(CC) -o $@ $(MYLDFLAGS) $(OBJS) ../lib/lauxlib.o -L$(LIB) -llua $(EXTRA_LIBS) - -$(LIB)/liblua.a: - cd ..; $(MAKE) - -../lib/lauxlib.o: - cd ../lib; $(MAKE) lauxlib.o - -clean: - rm -f $(OBJS) $T - -co: - co -q -f -M $(SRCS) - -klean: clean - rm -f $(SRCS) diff --git a/src/luac/README b/src/luac/README deleted file mode 100644 index 00dd1cd479..0000000000 --- a/src/luac/README +++ /dev/null @@ -1,18 +0,0 @@ -This is luac, the Lua compiler. -There are man pages for it in both nroff and html in ../../doc. - -luac translates Lua programs into binary files that can be loaded later. -The main advantages of pre-compiling chunks are: faster loading, protecting -source code from user changes, and off-line syntax error detection. -luac can also be used to learn about the Lua virtual machine. - -Usage: luac [options] [filenames]. Available options are: - - process stdin - -l list - -o name output to file `name' (default is "luac.out") - -p parse only - -s strip debug information - -v show version information - -- stop handling options - -luac is also an example of how to use the internals of Lua (politely). diff --git a/include/luaconf.h b/src/luaconf.h similarity index 85% rename from include/luaconf.h rename to src/luaconf.h index f00bbd0577..7ea477e23a 100644 --- a/include/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.20 2004/12/06 17:53:42 roberto Exp $ +** $Id: luaconf.h,v 1.22 2004/12/27 15:58:15 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -31,10 +31,22 @@ */ /* default path */ -#define LUA_PATH_DEFAULT \ - "./?.lua;/usr/local/share/lua/5.0/?.lua;/usr/local/share/lua/5.0/?/init.lua" -#define LUA_CPATH_DEFAULT \ - "./?.so;/usr/local/lib/lua/5.0/?.so;/usr/local/lib/lua/5.0/lib?.so" +#if defined(_WIN32) +#define LUA_ROOT "C:\\Program Files\\Lua51" +#define LUA_LDIR LUA_ROOT "\\lua" +#define LUA_CDIR LUA_ROOT "\\dll" +#define LUA_PATH_DEFAULT \ + "?.lua;" LUA_LDIR "\\?.lua;" LUA_LDIR "\\?\\init.lua" +#define LUA_CPATH_DEFAULT "?.dll;" LUA_CDIR "\\?.dll" + +#else +#define LUA_ROOT "/usr/local" +#define LUA_LDIR LUA_ROOT "/share/lua/5.1" +#define LUA_CDIR LUA_ROOT "/lib/lua/5.1" +#define LUA_PATH_DEFAULT \ + "./?.lua;" LUA_LDIR "/?.lua;" LUA_LDIR "/?/init.lua" +#define LUA_CPATH_DEFAULT "./?.so;" LUA_CDIR "/?.so" +#endif @@ -57,10 +69,10 @@ #define LUA_API extern /* mark for auxlib functions */ -#define LUALIB_API extern +#define LUALIB_API extern /* buffer size used by lauxlib buffer system */ -#define LUAL_BUFFERSIZE BUFSIZ +#define LUAL_BUFFERSIZE BUFSIZ /* assertions in Lua (mainly for internal debugging) */ @@ -82,6 +94,10 @@ #ifdef _POSIX_C_SOURCE #include #define stdin_is_tty() isatty(0) +#elif defined(_WIN32) +#include +#include +#define stdin_is_tty() _isatty(_fileno(stdin)) #else #define stdin_is_tty() 1 /* assume stdin is a tty */ #endif @@ -200,14 +216,31 @@ /* function to convert a lua_Number to int (with any rounding method) */ #if defined(__GNUC__) && defined(__i386) #define lua_number2int(i,d) __asm__ ("fistpl %0":"=m"(i):"t"(d):"st") + +#elif defined(_WIN32) && defined(_M_IX86) +#include +#pragma warning(disable: 4514) +__inline int l_lrint (double flt) +{ int i; + _asm { + fld flt + fistp i + }; + return i; +} +#define lua_number2int(i,d) ((i)=l_lrint((d))) + #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199900L) /* on machines compliant with C99, you can try `lrint' */ #include #define lua_number2int(i,d) ((i)=lrint(d)) + #else #define lua_number2int(i,d) ((i)=(int)(d)) + #endif + /* function to convert a lua_Number to lua_Integer (with any rounding method) */ #define lua_number2integer(i,n) lua_number2int((i), (n)) @@ -258,8 +291,8 @@ ** or when reading immutable fields from global objects ** (such as string values and udata values). */ -#define lua_lock(L) ((void) 0) -#define lua_unlock(L) ((void) 0) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) /* ** this macro allows a thread switch in appropriate places in the Lua @@ -273,9 +306,6 @@ #define lua_userstateopen(L) /* empty */ -/* initial GC parameters */ -#define STEPMUL 4 - #endif /* }====================================================== */ @@ -299,14 +329,17 @@ #define LUA_CPATH "LUA_CPATH" /* prefix for open functions in C libraries */ -#if defined(__APPLE__) && defined(__MACH__) -#define LUA_POF "_luaopen_" -#else #define LUA_POF "luaopen_" -#endif + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "" /* directory separator (for submodules) */ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else #define LUA_DIRSEP "/" +#endif /* separator of templates in a path */ #define LUA_PATH_SEP ';' @@ -332,12 +365,12 @@ /* ** Configuration for loadlib */ -#if defined(__linux) || defined(sun) || defined(sgi) || defined(BSD) -#define USE_DLOPEN -#elif defined(_WIN32) +#if defined(_WIN32) #define USE_DLL #elif defined(__APPLE__) && defined(__MACH__) #define USE_DYLD +#elif defined(__linux) || defined(sun) || defined(sgi) || defined(BSD) +#define USE_DLOPEN #endif @@ -350,7 +383,4 @@ /* Local configuration */ -#undef USE_TMPNAME -#define USE_TMPNAME 1 - #endif diff --git a/include/lualib.h b/src/lualib.h similarity index 100% rename from include/lualib.h rename to src/lualib.h diff --git a/src/luac/print.c b/src/print.c similarity index 100% rename from src/luac/print.c rename to src/print.c diff --git a/test/lua b/test/lua deleted file mode 120000 index 3b0b1a28e1..0000000000 --- a/test/lua +++ /dev/null @@ -1 +0,0 @@ -../bin/lua \ No newline at end of file diff --git a/test/luac b/test/luac deleted file mode 120000 index 694bc0dc9e..0000000000 --- a/test/luac +++ /dev/null @@ -1 +0,0 @@ -../bin/luac \ No newline at end of file diff --git a/test/printf.lua b/test/printf.lua index 66dfda65d5..58c63ff518 100644 --- a/test/printf.lua +++ b/test/printf.lua @@ -1,7 +1,7 @@ -- an implementation of printf function printf(...) - io.write(string.format(unpack(arg))) + io.write(string.format(...)) end printf("Hello %s from %s on %s\n",os.getenv"USER" or "there",_VERSION,os.date()) diff --git a/test/xd.lua b/test/xd.lua index 32331dc116..ebc3effc06 100644 --- a/test/xd.lua +++ b/test/xd.lua @@ -2,12 +2,12 @@ -- usage: lua xd.lua < file local offset=0 - -while 1 do +while true do local s=io.read(16) if s==nil then return end io.write(string.format("%08X ",offset)) - string.gsub(s,"(.)",function (c) io.write(string.format("%02X ",string.byte(c))) end) + string.gsub(s,"(.)", + function (c) io.write(string.format("%02X ",string.byte(c))) end) io.write(string.rep(" ",3*(16-string.len(s)))) io.write(" ",string.gsub(s,"%c","."),"\n") offset=offset+16 From e6ddfd3b09c0a3727afc773029c323a3defe50fa Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 4 Mar 2005 12:00:00 +0000 Subject: [PATCH 22/97] Lua 5.1-work5 --- COPYRIGHT | 2 +- HISTORY | 19 +++++ MANIFEST | 208 +++++++++++++++++++++++----------------------- Makefile | 2 +- src/Makefile | 19 +++-- src/lapi.c | 89 ++++++++++++++------ src/lauxlib.c | 7 +- src/lauxlib.h | 89 ++++++++++---------- src/lbaselib.c | 29 +++---- src/lcode.c | 4 +- src/ldblib.c | 51 ++++++++++-- src/ldo.c | 4 +- src/lfunc.c | 53 +++++++++--- src/lfunc.h | 7 +- src/lgc.c | 198 ++++++++++++++++++++------------------------ src/lgc.h | 23 +++-- src/linit.c | 4 +- src/liolib.c | 34 ++++---- src/llimits.h | 4 +- src/lmathlib.c | 4 +- src/lmem.c | 32 +++++-- src/loadlib.c | 82 ++++++++++++------ src/lobject.c | 4 +- src/lobject.h | 19 +++-- src/loslib.c | 8 +- src/lparser.c | 4 +- src/lstate.c | 43 ++++------ src/lstate.h | 19 ++--- src/lstring.c | 11 +-- src/lstring.h | 6 +- src/ltable.c | 221 ++++++++++++++++++++++++++++--------------------- src/ltable.h | 6 +- src/lua.c | 20 ++++- src/lua.h | 156 +++++++++++++++++----------------- src/luaconf.h | 79 ++++++++++-------- src/lualib.h | 20 ++--- src/lvm.c | 75 +++++++++-------- 37 files changed, 938 insertions(+), 717 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 16321abf6b..ba49873370 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 2003-2004 Tecgraf, PUC-Rio. +Copyright (C) 1994-2005 Tecgraf, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/HISTORY b/HISTORY index dd29bc7c8f..3be1eb553d 100644 --- a/HISTORY +++ b/HISTORY @@ -1,5 +1,24 @@ This is Lua 5.1 (work). +* Changes from version 5.0 to 5.1 + ------------------------------- + Language: + + new module system. + + new semantics for control variables of fors. + + new semantics for setn/getn. + + new syntax/semantics for varargs. + + new long strings. + API: + + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + + user supplies memory allocator (lua_open becomes lua_newstate). + Implementation: + + incremental garbage collection. + + debug works over other threads. + + better handling of end-of-line in the lexer. + + fully reentrant parser (new Lua function `load') + + better support for 64-bit machines (special thanks to Mike Pall). + + native loadlib support for Mac OS X (thanks to Matthew Cox). + * Changes from version 4.0 to 5.0 ------------------------------- Language: diff --git a/MANIFEST b/MANIFEST index 38ca97dfb8..01a2a7e7c7 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,105 +1,105 @@ -MANIFEST contents of Lua 5.1 (work4) distribution on Thu Dec 30 12:00:49 BRST 2004 -lua-5.1-work4 -lua-5.1-work4/COPYRIGHT -lua-5.1-work4/HISTORY -lua-5.1-work4/INSTALL -lua-5.1-work4/MANIFEST -lua-5.1-work4/Makefile -lua-5.1-work4/README -lua-5.1-work4/doc -lua-5.1-work4/doc/contents.html -lua-5.1-work4/doc/logo.gif -lua-5.1-work4/doc/lua.1 -lua-5.1-work4/doc/lua.html -lua-5.1-work4/doc/luac.1 -lua-5.1-work4/doc/luac.html -lua-5.1-work4/doc/readme.html -lua-5.1-work4/etc -lua-5.1-work4/etc/Makefile -lua-5.1-work4/etc/README -lua-5.1-work4/etc/all.c -lua-5.1-work4/etc/lua.hpp -lua-5.1-work4/etc/lua.ico -lua-5.1-work4/etc/min.c -lua-5.1-work4/etc/noparser.c -lua-5.1-work4/etc/saconfig.c -lua-5.1-work4/src -lua-5.1-work4/src/Makefile -lua-5.1-work4/src/lapi.c -lua-5.1-work4/src/lapi.h -lua-5.1-work4/src/lauxlib.c -lua-5.1-work4/src/lauxlib.h -lua-5.1-work4/src/lbaselib.c -lua-5.1-work4/src/lcode.c -lua-5.1-work4/src/lcode.h -lua-5.1-work4/src/ldblib.c -lua-5.1-work4/src/ldebug.c -lua-5.1-work4/src/ldebug.h -lua-5.1-work4/src/ldo.c -lua-5.1-work4/src/ldo.h -lua-5.1-work4/src/ldump.c -lua-5.1-work4/src/lfunc.c -lua-5.1-work4/src/lfunc.h -lua-5.1-work4/src/lgc.c -lua-5.1-work4/src/lgc.h -lua-5.1-work4/src/linit.c -lua-5.1-work4/src/liolib.c -lua-5.1-work4/src/llex.c -lua-5.1-work4/src/llex.h -lua-5.1-work4/src/llimits.h -lua-5.1-work4/src/lmathlib.c -lua-5.1-work4/src/lmem.c -lua-5.1-work4/src/lmem.h -lua-5.1-work4/src/loadlib.c -lua-5.1-work4/src/lobject.c -lua-5.1-work4/src/lobject.h -lua-5.1-work4/src/lopcodes.c -lua-5.1-work4/src/lopcodes.h -lua-5.1-work4/src/loslib.c -lua-5.1-work4/src/lparser.c -lua-5.1-work4/src/lparser.h -lua-5.1-work4/src/lstate.c -lua-5.1-work4/src/lstate.h -lua-5.1-work4/src/lstring.c -lua-5.1-work4/src/lstring.h -lua-5.1-work4/src/lstrlib.c -lua-5.1-work4/src/ltable.c -lua-5.1-work4/src/ltable.h -lua-5.1-work4/src/ltablib.c -lua-5.1-work4/src/ltm.c -lua-5.1-work4/src/ltm.h -lua-5.1-work4/src/lua.c -lua-5.1-work4/src/lua.h -lua-5.1-work4/src/luac.c -lua-5.1-work4/src/luaconf.h -lua-5.1-work4/src/lualib.h -lua-5.1-work4/src/lundump.c -lua-5.1-work4/src/lundump.h -lua-5.1-work4/src/lvm.c -lua-5.1-work4/src/lvm.h -lua-5.1-work4/src/lzio.c -lua-5.1-work4/src/lzio.h -lua-5.1-work4/src/print.c -lua-5.1-work4/test -lua-5.1-work4/test/README -lua-5.1-work4/test/bisect.lua -lua-5.1-work4/test/cf.lua -lua-5.1-work4/test/echo.lua -lua-5.1-work4/test/env.lua -lua-5.1-work4/test/factorial.lua -lua-5.1-work4/test/fib.lua -lua-5.1-work4/test/fibfor.lua -lua-5.1-work4/test/globals.lua -lua-5.1-work4/test/hello.lua -lua-5.1-work4/test/life.lua -lua-5.1-work4/test/luac.lua -lua-5.1-work4/test/printf.lua -lua-5.1-work4/test/readonly.lua -lua-5.1-work4/test/sieve.lua -lua-5.1-work4/test/sort.lua -lua-5.1-work4/test/table.lua -lua-5.1-work4/test/trace-calls.lua -lua-5.1-work4/test/trace-globals.lua -lua-5.1-work4/test/undefined.lua -lua-5.1-work4/test/xd.lua +MANIFEST contents of Lua 5.1 (work5) distribution on Fri Mar 4 13:32:55 BRST 2005 +lua-5.1-work5 +lua-5.1-work5/COPYRIGHT +lua-5.1-work5/HISTORY +lua-5.1-work5/INSTALL +lua-5.1-work5/MANIFEST +lua-5.1-work5/Makefile +lua-5.1-work5/README +lua-5.1-work5/doc +lua-5.1-work5/doc/contents.html +lua-5.1-work5/doc/logo.gif +lua-5.1-work5/doc/lua.1 +lua-5.1-work5/doc/lua.html +lua-5.1-work5/doc/luac.1 +lua-5.1-work5/doc/luac.html +lua-5.1-work5/doc/readme.html +lua-5.1-work5/etc +lua-5.1-work5/etc/Makefile +lua-5.1-work5/etc/README +lua-5.1-work5/etc/all.c +lua-5.1-work5/etc/lua.hpp +lua-5.1-work5/etc/lua.ico +lua-5.1-work5/etc/min.c +lua-5.1-work5/etc/noparser.c +lua-5.1-work5/etc/saconfig.c +lua-5.1-work5/src +lua-5.1-work5/src/Makefile +lua-5.1-work5/src/lapi.c +lua-5.1-work5/src/lapi.h +lua-5.1-work5/src/lauxlib.c +lua-5.1-work5/src/lauxlib.h +lua-5.1-work5/src/lbaselib.c +lua-5.1-work5/src/lcode.c +lua-5.1-work5/src/lcode.h +lua-5.1-work5/src/ldblib.c +lua-5.1-work5/src/ldebug.c +lua-5.1-work5/src/ldebug.h +lua-5.1-work5/src/ldo.c +lua-5.1-work5/src/ldo.h +lua-5.1-work5/src/ldump.c +lua-5.1-work5/src/lfunc.c +lua-5.1-work5/src/lfunc.h +lua-5.1-work5/src/lgc.c +lua-5.1-work5/src/lgc.h +lua-5.1-work5/src/linit.c +lua-5.1-work5/src/liolib.c +lua-5.1-work5/src/llex.c +lua-5.1-work5/src/llex.h +lua-5.1-work5/src/llimits.h +lua-5.1-work5/src/lmathlib.c +lua-5.1-work5/src/lmem.c +lua-5.1-work5/src/lmem.h +lua-5.1-work5/src/loadlib.c +lua-5.1-work5/src/lobject.c +lua-5.1-work5/src/lobject.h +lua-5.1-work5/src/lopcodes.c +lua-5.1-work5/src/lopcodes.h +lua-5.1-work5/src/loslib.c +lua-5.1-work5/src/lparser.c +lua-5.1-work5/src/lparser.h +lua-5.1-work5/src/lstate.c +lua-5.1-work5/src/lstate.h +lua-5.1-work5/src/lstring.c +lua-5.1-work5/src/lstring.h +lua-5.1-work5/src/lstrlib.c +lua-5.1-work5/src/ltable.c +lua-5.1-work5/src/ltable.h +lua-5.1-work5/src/ltablib.c +lua-5.1-work5/src/ltm.c +lua-5.1-work5/src/ltm.h +lua-5.1-work5/src/lua.c +lua-5.1-work5/src/lua.h +lua-5.1-work5/src/luac.c +lua-5.1-work5/src/luaconf.h +lua-5.1-work5/src/lualib.h +lua-5.1-work5/src/lundump.c +lua-5.1-work5/src/lundump.h +lua-5.1-work5/src/lvm.c +lua-5.1-work5/src/lvm.h +lua-5.1-work5/src/lzio.c +lua-5.1-work5/src/lzio.h +lua-5.1-work5/src/print.c +lua-5.1-work5/test +lua-5.1-work5/test/README +lua-5.1-work5/test/bisect.lua +lua-5.1-work5/test/cf.lua +lua-5.1-work5/test/echo.lua +lua-5.1-work5/test/env.lua +lua-5.1-work5/test/factorial.lua +lua-5.1-work5/test/fib.lua +lua-5.1-work5/test/fibfor.lua +lua-5.1-work5/test/globals.lua +lua-5.1-work5/test/hello.lua +lua-5.1-work5/test/life.lua +lua-5.1-work5/test/luac.lua +lua-5.1-work5/test/printf.lua +lua-5.1-work5/test/readonly.lua +lua-5.1-work5/test/sieve.lua +lua-5.1-work5/test/sort.lua +lua-5.1-work5/test/table.lua +lua-5.1-work5/test/trace-calls.lua +lua-5.1-work5/test/trace-globals.lua +lua-5.1-work5/test/undefined.lua +lua-5.1-work5/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index 62bb7e49ed..d01b51a95c 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ install: all cd doc; $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) local: - $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -up" INSTALL_DATA="cp -up" + $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -p" INSTALL_DATA="cp -p" # echo config parameters echo: diff --git a/src/Makefile b/src/Makefile index cf7ff181d0..9ec6d349b3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,13 +6,15 @@ CC= gcc CFLAGS= -O2 -Wall $(MYCFLAGS) -MYCFLAGS= -MYLDFLAGS= -Wl,-E # enable dynamic loading in Linux -MYLIBS= -lm -ldl # enable dynamic loading in Linux AR= ar rcu RANLIB= ranlib RM= rm -f +MYCFLAGS= +MYLDFLAGS= +MYLIBS= -lm +DL= -ldl -Wl,-E # enable dynamic loading in Linux + # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= CORE_T= liblua.a @@ -49,10 +51,10 @@ $(LIB_T): $(LIB_O) $(RANLIB) $@ $(LUA_T): $(LUA_O) $(CORE_T) $(LIB_T) - $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) -L. -llua -llualib $(MYLIBS) + $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) -L. -llua -llualib $(MYLIBS) $(DL) $(LUAC_T): $(LUAC_O) $(CORE_T) - $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) -L. -llua + $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) -L. -llua $(MYLIBS) clean: $(RM) $(ALL_T) $(ALL_O) @@ -63,12 +65,13 @@ depend: echo: @echo "CC = $(CC)" @echo "CFLAGS = $(CFLAGS)" - @echo "MYCFLAGS = $(MYCFLAGS)" - @echo "MYLDFLAGS = $(MYLDFLAGS)" - @echo "MYLIBS = $(MYLIBS)" @echo "AR = $(AR)" @echo "RANLIB = $(RANLIB)" @echo "RM = $(RM)" + @echo "MYCFLAGS = $(MYCFLAGS)" + @echo "MYLDFLAGS = $(MYLDFLAGS)" + @echo "MYLIBS = $(MYLIBS)" + @echo "DL = $(DL)" # DO NOT DELETE diff --git a/src/lapi.c b/src/lapi.c index e2dd11d182..9b4b5b3301 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.23 2004/12/13 12:15:11 roberto Exp $ +** $Id: lapi.c,v 2.28 2005/02/23 17:30:22 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -58,6 +58,11 @@ static TValue *index2adr (lua_State *L, int idx) { } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); + case LUA_ENVIRONINDEX: { + Closure *func = curr_func(L); + sethvalue(L, &L->env, func->c.env); + return &L->env; + } case LUA_GLOBALSINDEX: return gt(L); default: { Closure *func = curr_func(L); @@ -70,6 +75,16 @@ static TValue *index2adr (lua_State *L, int idx) { } +static Table *getcurrenv (lua_State *L) { + if (L->ci == L->base_ci) /* no enclosing function? */ + return hvalue(gt(L)); /* use global table as environment */ + else { + Closure *func = curr_func(L); + return func->c.env; + } +} + + void luaA_pushobject (lua_State *L, const TValue *o) { setobj2s(L, L->top, o); incr_top(L); @@ -186,9 +201,17 @@ LUA_API void lua_replace (lua_State *L, int idx) { api_checknelems(L, 1); o = index2adr(L, idx); api_checkvalidindex(L, o); - setobj(L, o, L->top - 1); - if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ - luaC_barrier(L, curr_func(L), L->top - 1); + if (idx == LUA_ENVIRONINDEX) { + Closure *func = curr_func(L); + api_check(L, ttistable(L->top - 1)); + func->c.env = hvalue(L->top - 1); + luaC_barrier(L, func, L->top - 1); + } + else { + setobj(L, o, L->top - 1); + if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), L->top - 1); + } L->top--; lua_unlock(L); } @@ -452,7 +475,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { lua_lock(L); luaC_checkGC(L); api_checknelems(L, n); - cl = luaF_newCclosure(L, n); + cl = luaF_newCclosure(L, n, getcurrenv(L)); cl->c.f = fn; L->top -= n; while (n--) @@ -542,7 +565,7 @@ LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { lua_lock(L); luaC_checkGC(L); - sethvalue(L, L->top, luaH_new(L, narray, luaO_log2(nrec) + 1)); + sethvalue(L, L->top, luaH_new(L, narray, nrec)); api_incr_top(L); lua_unlock(L); } @@ -579,7 +602,17 @@ LUA_API void lua_getfenv (lua_State *L, int idx) { lua_lock(L); o = index2adr(L, idx); api_checkvalidindex(L, o); - setobj2s(L, L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); + switch (ttype(o)) { + case LUA_TFUNCTION: + sethvalue(L, L->top, clvalue(o)->c.env); + break; + case LUA_TUSERDATA: + sethvalue(L, L->top, uvalue(o)->env); + break; + default: + setnilvalue(L->top); + break; + } api_incr_top(L); lua_unlock(L); } @@ -682,17 +715,24 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { LUA_API int lua_setfenv (lua_State *L, int idx) { StkId o; - int res = 0; + int res = 1; lua_lock(L); api_checknelems(L, 1); o = index2adr(L, idx); api_checkvalidindex(L, o); api_check(L, ttistable(L->top - 1)); - if (isLfunction(o)) { - res = 1; - clvalue(o)->l.g = *(L->top - 1); - luaC_objbarrier(L, clvalue(o), hvalue(L->top - 1)); + switch (ttype(o)) { + case LUA_TFUNCTION: + clvalue(o)->c.env = hvalue(L->top - 1); + break; + case LUA_TUSERDATA: + uvalue(o)->env = hvalue(L->top - 1); + break; + default: + res = 0; + break; } + luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); L->top--; lua_unlock(L); return res; @@ -776,7 +816,7 @@ struct CCallS { /* data to `f_Ccall' */ static void f_Ccall (lua_State *L, void *ud) { struct CCallS *c = cast(struct CCallS *, ud); Closure *cl; - cl = luaF_newCclosure(L, 0); + cl = luaF_newCclosure(L, 0, getcurrenv(L)); cl->c.f = c->func; setclvalue(L, L->top, cl); /* push function */ incr_top(L); @@ -826,7 +866,7 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { } -LUA_API int lua_threadstatus (lua_State *L) { +LUA_API int lua_status (lua_State *L) { return L->status; } @@ -872,9 +912,9 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->gcpace = data; break; } - case LUA_GCSETINCMODE: { - res = g->incgc; - g->incgc = data; + case LUA_GCSETSTEPMUL: { + res = g->gcstepmul; + g->gcstepmul = data; break; } default: res = -1; /* invalid option */ @@ -890,11 +930,6 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { */ -LUA_API const char *lua_version (void) { - return LUA_VERSION; -} - - LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); @@ -940,7 +975,7 @@ LUA_API void lua_concat (lua_State *L, int n) { LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { *ud = G(L)->ud; - return G(L)->realloc; + return G(L)->frealloc; } @@ -948,7 +983,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); - u = luaS_newudata(L, size); + u = luaS_newudata(L, size, getcurrenv(L)); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); @@ -958,7 +993,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { -static const char *aux_upvalue (lua_State *L, StkId fi, int n, TValue **val) { +static const char *aux_upvalue (StkId fi, int n, TValue **val) { Closure *f; if (!ttisfunction(fi)) return NULL; f = clvalue(fi); @@ -980,7 +1015,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); - name = aux_upvalue(L, index2adr(L, funcindex), n, &val); + name = aux_upvalue(index2adr(L, funcindex), n, &val); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -997,7 +1032,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { lua_lock(L); fi = index2adr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(L, fi, n, &val); + name = aux_upvalue(fi, n, &val); if (name) { L->top--; setobj(L, val, L->top); diff --git a/src/lauxlib.c b/src/lauxlib.c index 5bbe918b8f..ac53db396c 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.127 2004/12/20 13:47:29 roberto Exp $ +** $Id: lauxlib.c,v 1.129 2005/02/23 17:30:22 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -350,8 +350,8 @@ LUALIB_API int luaL_getn (lua_State *L, int t) { static const char *pushnexttemplate (lua_State *L, const char *path) { const char *l; if (*path == '\0') return NULL; /* no more templates */ - if (*path == LUA_PATH_SEP) path++; /* skip separator */ - l = strchr(path, LUA_PATH_SEP); /* find next separator */ + if (*path == LUA_PATHSEP) path++; /* skip separator */ + l = strchr(path, LUA_PATHSEP); /* find next separator */ if (l == NULL) l = path+strlen(path); lua_pushlstring(L, path, l - path); /* template */ return l; @@ -704,6 +704,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { static int panic (lua_State *L) { + (void)L; /* to avoid warnings */ fprintf(stderr, "PANIC: unprotected error during Lua-API call\n"); return 0; } diff --git a/src/lauxlib.h b/src/lauxlib.h index b47663ced7..82585cf41e 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.73 2004/10/18 12:51:44 roberto Exp $ +** $Id: lauxlib.h,v 1.74 2005/01/10 17:31:50 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -25,55 +25,58 @@ typedef struct luaL_reg { } luaL_reg; -LUALIB_API void luaL_openlib (lua_State *L, const char *libname, - const luaL_reg *l, int nup); -LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *e); -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *e); -LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname); -LUALIB_API int luaL_argerror (lua_State *L, int numarg, const char *extramsg); -LUALIB_API const char *luaL_checklstring (lua_State *L, int numArg, size_t *l); -LUALIB_API const char *luaL_optlstring (lua_State *L, int numArg, - const char *def, size_t *l); -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int numArg); -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number def); +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_reg *l, int nup); +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); +LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int numArg); -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int nArg, - lua_Integer def); +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, + lua_Integer def); -LUALIB_API void luaL_checkstack (lua_State *L, int sz, const char *msg); -LUALIB_API void luaL_checktype (lua_State *L, int narg, int t); -LUALIB_API void luaL_checkany (lua_State *L, int narg); +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int narg); -LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname); -LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname); -LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname); +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void (luaL_getmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); -LUALIB_API void luaL_where (lua_State *L, int lvl); -LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...); +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); -LUALIB_API int luaL_findstring (const char *st, const char *const lst[]); +LUALIB_API int (luaL_findstring) (const char *st, const char *const lst[]); -LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, - const char *path); +LUALIB_API const char *(luaL_searchpath) (lua_State *L, const char *name, + const char *path); -LUALIB_API int luaL_ref (lua_State *L, int t); -LUALIB_API void luaL_unref (lua_State *L, int t, int ref); +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); -LUALIB_API int luaL_getn (lua_State *L, int t); -LUALIB_API void luaL_setn (lua_State *L, int t, int n); +LUALIB_API int (luaL_getn) (lua_State *L, int t); +LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); -LUALIB_API int luaL_loadfile (lua_State *L, const char *filename); -LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, - const char *name); +LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); +LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, + const char *name); LUALIB_API lua_State *(luaL_newstate) (void); -LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, - const char *r); -LUALIB_API const char *luaL_getfield (lua_State *L, int idx, const char *fname); -LUALIB_API const char *luaL_setfield (lua_State *L, int idx, const char *fname); +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, + const char *r); +LUALIB_API const char *(luaL_getfield) (lua_State *L, int idx, + const char *fname); +LUALIB_API const char *(luaL_setfield) (lua_State *L, int idx, + const char *fname); @@ -115,12 +118,12 @@ typedef struct luaL_Buffer { #define luaL_addsize(B,n) ((B)->p += (n)) -LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B); -LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B); -LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l); -LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s); -LUALIB_API void luaL_addvalue (luaL_Buffer *B); -LUALIB_API void luaL_pushresult (luaL_Buffer *B); +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); /* }====================================================== */ diff --git a/src/lbaselib.c b/src/lbaselib.c index 3b034bbc03..9e1573cb9e 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.163 2004/12/13 12:15:11 roberto Exp $ +** $Id: lbaselib.c,v 1.169 2005/02/28 17:24:41 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -131,7 +131,10 @@ static void getfunc (lua_State *L) { static int luaB_getfenv (lua_State *L) { getfunc(L); - lua_getfenv(L, -1); + if (lua_iscfunction(L, -1)) /* is a C function? */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the global env. */ + else + lua_getfenv(L, -1); return 1; } @@ -144,8 +147,8 @@ static int luaB_setfenv (lua_State *L) { lua_replace(L, LUA_GLOBALSINDEX); return 0; } - else if (lua_setfenv(L, -2) == 0) - luaL_error(L, "`setfenv' cannot change environment of given function"); + else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) + luaL_error(L, "`setfenv' cannot change environment of given object"); return 1; } @@ -182,11 +185,11 @@ static int luaB_gcinfo (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpace", "setincmode", NULL}; + "count", "step", "setpace", "setstepmul", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPACE, LUA_GCSETINCMODE}; + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPACE, LUA_GCSETSTEPMUL}; int o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); - int ex = luaL_optint(L, 2, 0); + int ex = luaL_optinteger(L, 2, 0); luaL_argcheck(L, o >= 0, 1, "invalid option"); lua_pushinteger(L, lua_gc(L, optsnum[o], ex)); return 1; @@ -280,6 +283,7 @@ static int luaB_loadfile (lua_State *L) { ** reserved slot inside the stack. */ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { + (void)ud; /* to avoid warnings */ luaL_checkstack(L, 2, "too many nested functions"); lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ @@ -469,7 +473,7 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); - if (lua_threadstatus(co) == 0 && lua_gettop(co) == 0) { + if (lua_status(co) == 0 && lua_gettop(co) == 0) { lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } @@ -549,7 +553,7 @@ static int luaB_costatus (lua_State *L) { luaL_argcheck(L, co, 1, "coroutine expected"); if (L == co) lua_pushliteral(L, "running"); else { - switch (lua_threadstatus(co)) { + switch (lua_status(co)) { case LUA_YIELD: lua_pushliteral(L, "suspended"); break; @@ -572,7 +576,7 @@ static int luaB_costatus (lua_State *L) { } -static int luaB_cocurrent (lua_State *L) { +static int luaB_corunning (lua_State *L) { if (lua_pushthread(L)) return 0; /* main thread is not a coroutine */ else @@ -586,7 +590,7 @@ static const luaL_reg co_funcs[] = { {"resume", luaB_coresume}, {"yield", luaB_yield}, {"status", luaB_costatus}, - {"current", luaB_cocurrent}, + {"running", luaB_corunning}, {NULL, NULL} }; @@ -620,9 +624,6 @@ static void base_open (lua_State *L) { /* create register._LOADED to track loaded modules */ lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "_LOADED"); - /* create register._PRELOAD to allow pre-loaded modules */ - lua_newtable(L); - lua_setfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); /* set global _G */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setglobal(L, "_G"); diff --git a/src/lcode.c b/src/lcode.c index f7f1182d57..b40bc5a194 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.8 2004/12/03 20:35:33 roberto Exp $ +** $Id: lcode.c,v 2.9 2005/01/10 18:17:39 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -606,7 +606,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { if (op == OPR_MINUS) { luaK_exp2val(fs, e); if (e->k == VK && ttisnumber(&fs->f->k[e->info])) - e->info = luaK_numberK(fs, -nvalue(&fs->f->k[e->info])); + e->info = luaK_numberK(fs, num_unm(nvalue(&fs->f->k[e->info]))); else { luaK_exp2anyreg(fs, e); freeexp(fs, e); diff --git a/src/ldblib.c b/src/ldblib.c index 36d647aaa9..7f8bde1f58 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.89 2004/11/17 12:02:41 roberto Exp $ +** $Id: ldblib.c,v 1.93 2005/02/18 12:40:02 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -19,6 +19,40 @@ +static int getmetatable (lua_State *L) { + luaL_checkany(L, 1); + if (!lua_getmetatable(L, 1)) { + lua_pushnil(L); /* no metatable */ + } + return 1; +} + + +static int setmetatable (lua_State *L) { + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_pushboolean(L, lua_setmetatable(L, 1)); + return 1; +} + + +static int getfenv (lua_State *L) { + lua_getfenv(L, 1); + return 1; +} + + +static int setfenv (lua_State *L) { + luaL_checktype(L, 2, LUA_TTABLE); + lua_settop(L, 2); + if (lua_setfenv(L, 1) == 0) + luaL_error(L, "`setfenv' cannot change environment of given object"); + return 1; +} + + static void settabss (lua_State *L, const char *i, const char *v) { lua_pushstring(L, v); lua_setfield(L, -2, i); @@ -275,12 +309,17 @@ static int debug (lua_State *L) { #define LEVELS2 10 /* size of the second part of the stack */ static int errorfb (lua_State *L) { - int level = 0; + int level; int firstpart = 1; /* still before eventual `...' */ int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (L == L1) level++; /* skip level 0 (it's this function) */ + if (lua_isnumber(L, arg+2)) { + level = lua_tointeger(L, arg+2); + lua_pop(L, 1); + } + else + level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ if (lua_gettop(L) == arg) lua_pushliteral(L, ""); else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ @@ -323,6 +362,10 @@ static int errorfb (lua_State *L) { static const luaL_reg dblib[] = { + {"getmetatable", getmetatable}, + {"setmetatable", setmetatable}, + {"getfenv", getfenv}, + {"setfenv", setfenv}, {"getlocal", getlocal}, {"getinfo", getinfo}, {"gethook", gethook}, @@ -338,8 +381,6 @@ static const luaL_reg dblib[] = { LUALIB_API int luaopen_debug (lua_State *L) { luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); - lua_pushcfunction(L, errorfb); - lua_setglobal(L, "_TRACEBACK"); return 1; } diff --git a/src/ldo.c b/src/ldo.c index d75a7063c4..da46d39d47 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.13 2004/12/03 20:35:33 roberto Exp $ +** $Id: ldo.c,v 2.14 2005/02/18 12:40:02 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -474,7 +474,7 @@ static void f_parser (lua_State *L, void *ud) { luaC_checkGC(L); tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, &p->buff, p->name); - cl = luaF_newLclosure(L, tf->nups, gt(L)); + cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); cl->l.p = tf; for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ cl->l.upvals[i] = luaF_newupval(L); diff --git a/src/lfunc.c b/src/lfunc.c index af431cc3c1..1c95e78193 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.5 2004/11/24 19:20:21 roberto Exp $ +** $Id: lfunc.c,v 2.9 2005/02/18 12:40:02 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -20,20 +20,21 @@ -Closure *luaF_newCclosure (lua_State *L, int nelems) { +Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; + c->c.env = e; c->c.nupvalues = cast(lu_byte, nelems); return c; } -Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e) { +Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->l.isC = 0; - c->l.g = *e; + c->l.env = e; c->l.nupvalues = cast(lu_byte, nelems); while (nelems--) c->l.upvals[nelems] = NULL; return c; @@ -43,42 +44,72 @@ Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e) { UpVal *luaF_newupval (lua_State *L) { UpVal *uv = luaM_new(L, UpVal); luaC_link(L, obj2gco(uv), LUA_TUPVAL); - uv->v = &uv->value; + uv->v = &uv->u.value; setnilvalue(uv->v); return uv; } UpVal *luaF_findupval (lua_State *L, StkId level) { + global_State *g = G(L); GCObject **pp = &L->openupval; UpVal *p; UpVal *uv; while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { - if (p->v == level) return p; + lua_assert(p->v != &p->u.value); + if (p->v == level) { /* found a corresponding upvalue? */ + if (isdead(g, obj2gco(p))) /* is it dead? */ + changewhite(obj2gco(p)); /* ressurect it */ + return p; + } pp = &p->next; } uv = luaM_new(L, UpVal); /* not found: create a new one */ uv->tt = LUA_TUPVAL; - uv->marked = luaC_white(G(L)); + uv->marked = luaC_white(g); uv->v = level; /* current value lives in the stack */ uv->next = *pp; /* chain it in the proper position */ *pp = obj2gco(uv); + uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ + uv->u.l.next = g->uvhead.u.l.next; + uv->u.l.next->u.l.prev = uv; + g->uvhead.u.l.next = uv; + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); return uv; } +static void unlinkupval (UpVal *uv) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ + uv->u.l.prev->u.l.next = uv->u.l.next; +} + + +void luaF_freeupval (lua_State *L, UpVal *uv) { + if (uv->v != &uv->u.value) /* is it open? */ + unlinkupval(uv); /* remove from open list */ + luaM_free(L, uv); /* free upvalue */ +} + + void luaF_close (lua_State *L, StkId level) { UpVal *uv; global_State *g = G(L); while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { GCObject *o = obj2gco(uv); - lua_assert(!isblack(o)); + lua_assert(!isblack(o) && uv->v != &uv->u.value); L->openupval = uv->next; /* remove from `open' list */ if (isdead(g, o)) - luaM_free(L, uv); /* free upvalue */ + luaF_freeupval(L, uv); /* free upvalue */ else { - setobj(L, &uv->value, uv->v); - uv->v = &uv->value; /* now current value lives here */ + unlinkupval(uv); + setobj(L, &uv->u.value, uv->v); + if (isgray(o)) { + gray2black(o); /* closed upvalues are never gray */ + luaC_barrier(L, uv, &uv->u.value); + } + uv->v = &uv->u.value; /* now current value lives here */ luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ } } diff --git a/src/lfunc.h b/src/lfunc.h index 044376017d..93f7b88851 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: lfunc.h,v 2.3 2005/02/18 12:40:02 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -19,13 +19,14 @@ Proto *luaF_newproto (lua_State *L); -Closure *luaF_newCclosure (lua_State *L, int nelems); -Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e); +Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); +Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); UpVal *luaF_newupval (lua_State *L); UpVal *luaF_findupval (lua_State *L, StkId level); void luaF_close (lua_State *L, StkId level); void luaF_freeproto (lua_State *L, Proto *f); void luaF_freeclosure (lua_State *L, Closure *c); +void luaF_freeupval (lua_State *L, UpVal *uv); const char *luaF_getlocalname (const Proto *func, int local_number, int pc); diff --git a/src/lgc.c b/src/lgc.c index 9259bff0bf..dd7a6850a7 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.19 2004/12/13 12:15:11 roberto Exp $ +** $Id: lgc.c,v 2.27 2005/02/23 17:30:22 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -23,30 +23,26 @@ #include "ltm.h" -#define GCSTEPSIZE 1000 -#define GCSWEEPMAX 10 -#define GCSWEEPCOST 30 +#define GCSTEPSIZE 1024u +#define GCSWEEPMAX 40 +#define GCSWEEPCOST 10 #define GCFINALIZECOST 100 -#define GCSTEPMUL 8 -#define FIXEDMASK bitmask(FIXEDBIT) - #define maskmarks \ - cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) + cast(lu_byte, ~(bitmask(BLACKBIT)|WHITEBITS)) #define makewhite(g,x) \ - ((x)->gch.marked = ((x)->gch.marked & maskmarks) | g->currentwhite) + ((x)->gch.marked = ((x)->gch.marked & maskmarks) | luaC_white(g)) #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) -#define gray2black(x) setbit((x)->gch.marked, BLACKBIT) #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) -#define markfinalized(u) setbit((u)->marked, FINALIZEDBIT) +#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) #define KEYWEAK bitmask(KEYWEAKBIT) @@ -61,9 +57,11 @@ reallymarkobject(g, obj2gco(t)); } +#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpace) + static void removeentry (Node *n) { - setnilvalue(gval(n)); /* remove corresponding value ... */ + lua_assert(ttisnil(gval(n))); if (iscollectable(gkey(n))) setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ } @@ -80,14 +78,14 @@ static void reallymarkobject (global_State *g, GCObject *o) { Table *mt = gco2u(o)->metatable; gray2black(o); /* udata are never gray */ if (mt) markobject(g, mt); + markobject(g, gco2u(o)->env); return; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); - if (uv->v == &uv->value) { /* closed? */ - markvalue(g, uv->v); - gray2black(o); - } + markvalue(g, uv->v); + if (uv->v == &uv->u.value) /* closed? */ + gray2black(o); /* open upvalues are never black */ return; } case LUA_TFUNCTION: { @@ -116,22 +114,24 @@ static void reallymarkobject (global_State *g, GCObject *o) { static void marktmu (global_State *g) { - GCObject *u; - for (u = g->tmudata; u; u = u->gch.next) { - makewhite(g, u); /* may be marked, if left from previous GC */ - reallymarkobject(g, u); + GCObject *u = g->tmudata; + if (u) { + do { + u = u->gch.next; + makewhite(g, u); /* may be marked, if left from previous GC */ + reallymarkobject(g, u); + } while (u != g->tmudata); } } /* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L, int all) { + global_State *g = G(L); size_t deadmem = 0; - GCObject **p = &G(L)->firstudata; + GCObject **p = &g->mainthread->next; GCObject *curr; - GCObject *collected = NULL; /* to collect udata with gc event */ - GCObject **lastcollected = &collected; - while ((curr = *p)->gch.tt == LUA_TUSERDATA) { + while ((curr = *p) != NULL) { if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { @@ -142,15 +142,16 @@ size_t luaC_separateudata (lua_State *L, int all) { deadmem += sizeudata(gco2u(curr)); markfinalized(gco2u(curr)); *p = curr->gch.next; - curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ - *lastcollected = curr; - lastcollected = &curr->gch.next; + /* link `curr' at the end of `tmudata' list */ + if (g->tmudata == NULL) /* list is empty? */ + g->tmudata = curr->gch.next = curr; /* creates a circular list */ + else { + curr->gch.next = g->tmudata->gch.next; + g->tmudata->gch.next = curr; + g->tmudata = curr; + } } } - lua_assert(curr == obj2gco(G(L)->mainthread)); - /* insert collected udata with gc event into `tmudata' list */ - *lastcollected = G(L)->tmudata; - G(L)->tmudata = collected; return deadmem; } @@ -162,7 +163,6 @@ static int traversetable (global_State *g, Table *h) { const TValue *mode; if (h->metatable) markobject(g, h->metatable); - lua_assert(h->lsizenode || h->node == g->dummynode); mode = gfasttm(g, h->metatable, TM_MODE); if (mode && ttisstring(mode)) { /* is there a weak mode? */ weakkey = (strchr(svalue(mode), 'k') != NULL); @@ -223,6 +223,7 @@ static void traverseproto (global_State *g, Proto *f) { static void traverseclosure (global_State *g, Closure *cl) { + markobject(g, cl->c.env); if (cl->c.isC) { int i; for (i=0; ic.nupvalues; i++) /* mark its upvalues */ @@ -231,7 +232,6 @@ static void traverseclosure (global_State *g, Closure *cl) { else { int i; lua_assert(cl->l.nupvalues == cl->l.p->nups); - markobject(g, hvalue(&cl->l.g)); markobject(g, cl->l.p); for (i=0; il.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); @@ -368,8 +368,10 @@ static void cleartable (GCObject *l) { while (i--) { Node *n = gnode(h, i); if (!ttisnil(gval(n)) && /* non-empty entry? */ - (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) + (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { + setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* remove entry from table */ + } } l = h->gclist; } @@ -380,7 +382,7 @@ static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; - case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break; + case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); @@ -402,26 +404,23 @@ static void freeobj (lua_State *L, GCObject *o) { -#define sweepwholelist(L,p) sweeplist(L,p,LUA_MAXINT32) +#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) -static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) { +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { GCObject *curr; global_State *g = G(L); - int whitebit = otherwhite(g); - int deadmask = whitebit | FIXEDMASK; - int generational = g->gcgenerational; + int deadmask = otherwhite(g); while ((curr = *p) != NULL && count-- > 0) { - if ((curr->gch.marked ^ whitebit) & deadmask) { + if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ + sweepwholelist(L, &gco2th(curr)->openupval); + if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); - if (!generational || isdead(g, curr)) - makewhite(g, curr); - if (curr->gch.tt == LUA_TTHREAD) - sweepwholelist(L, &gco2th(curr)->openupval); + makewhite(g, curr); /* make it white (for next cycle) */ p = &curr->gch.next; } - else { - lua_assert(isdead(g, curr)); + else { /* must erase `curr' */ + lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); *p = curr->gch.next; if (curr == g->rootgc) /* is the first element of the list? */ g->rootgc = curr->gch.next; /* adjust first */ @@ -432,21 +431,10 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) { } - -static void freelist (lua_State *L, GCObject **p) { - while (*p) { - GCObject *curr = *p; - *p = (*p)->gch.next; - if (curr != obj2gco(L)) - freeobj(L, curr); - } -} - - static void checkSizes (lua_State *L) { global_State *g = G(L); /* check size of string hash */ - if (g->strt.nuse < cast(lu_int32, G(L)->strt.size/4) && + if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && g->strt.size > MINSTRTABSIZE*2) luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ @@ -459,22 +447,29 @@ static void checkSizes (lua_State *L) { static void GCTM (lua_State *L) { global_State *g = G(L); - GCObject *o = g->tmudata; + GCObject *o = g->tmudata->gch.next; /* get first element */ Udata *udata = rawgco2u(o); const TValue *tm; - g->tmudata = udata->uv.next; /* remove udata from `tmudata' */ - udata->uv.next = g->firstudata->uv.next; /* return it to `root' list */ - g->firstudata->uv.next = o; + /* remove udata from `tmudata' */ + if (o == g->tmudata) /* last element? */ + g->tmudata = NULL; + else + g->tmudata->gch.next = udata->uv.next; + udata->uv.next = g->mainthread->next; /* return it to `root' list */ + g->mainthread->next = o; makewhite(g, o); tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { lu_byte oldah = L->allowhook; + lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ + g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0); L->allowhook = oldah; /* restore hooks */ + g->GCthreshold = oldt; /* restore threshold */ } } @@ -491,9 +486,10 @@ void luaC_callGCTM (lua_State *L) { void luaC_freeall (lua_State *L) { global_State *g = G(L); int i; - freelist(L, &g->rootgc); + g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ + sweepwholelist(L, &g->rootgc); for (i = 0; i < g->strt.size; i++) /* free all string lists */ - freelist(L, &G(L)->strt.hash[i]); + sweepwholelist(L, &g->strt.hash[i]); } @@ -512,18 +508,11 @@ static void markroot (lua_State *L) { static void remarkupvals (global_State *g) { - GCObject *o; - for (o = obj2gco(g->mainthread); o; o = o->gch.next) { - lua_assert(!isblack(o)); - if (iswhite(o)) { - GCObject *curr; - for (curr = gco2th(o)->openupval; curr != NULL; curr = curr->gch.next) { - if (isgray(curr)) { - UpVal *uv = gco2uv(curr); - markvalue(g, uv->v); - } - } - } + UpVal *uv; + for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (isgray(obj2gco(uv))) + markvalue(g, uv->v); } } @@ -531,7 +520,6 @@ static void remarkupvals (global_State *g) { static void atomic (lua_State *L) { global_State *g = G(L); size_t udsize; /* total size of userdata to be finalized */ - int aux; /* remark objects cautch by write barrier */ propagateall(g); /* remark occasional upvalues of (maybe) dead threads */ @@ -555,10 +543,6 @@ static void atomic (lua_State *L) { g->sweepstrgc = 0; g->sweepgc = &g->rootgc; g->gcstate = GCSsweepstring; - aux = g->gcgenerational; - g->gcgenerational = g->incgc && (g->estimate/2 <= g->prevestimate); - if (!aux) /* last collection was full? */ - g->prevestimate = g->estimate; /* keep estimate of last full collection */ g->estimate = g->totalbytes - udsize; /* first estimate */ } @@ -568,11 +552,7 @@ static l_mem singlestep (lua_State *L) { /*lua_checkmemory(L);*/ switch (g->gcstate) { case GCSpause: { - /* start a new collection */ - if (g->gcgenerational) - atomic(L); - else - markroot(L); + markroot(L); /* start a new collection */ return 0; } case GCSpropagate: { @@ -605,13 +585,12 @@ static l_mem singlestep (lua_State *L) { } case GCSfinalize: { if (g->tmudata) { - g->GCthreshold += GCFINALIZECOST; /* avoid GC steps inside method */ GCTM(L); - g->GCthreshold -= GCFINALIZECOST; /* correct threshold */ return GCFINALIZECOST; } else { g->gcstate = GCSpause; /* end collection */ + g->gcdept = 0; return 0; } } @@ -622,25 +601,33 @@ static l_mem singlestep (lua_State *L) { void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * GCSTEPMUL; + l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; + if (lim == 0) + lim = (MAX_LUMEM-1)/2; /* no limit */ + g->gcdept += g->totalbytes - g->GCthreshold; do { lim -= singlestep(L); if (g->gcstate == GCSpause) break; - } while (lim > 0 || !g->incgc); - if (g->gcstate != GCSpause) - g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/STEPMUL; */ + } while (lim > 0); + if (g->gcstate != GCSpause) { + if (g->gcdept < GCSTEPSIZE) + g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ + else { + g->gcdept -= GCSTEPSIZE; + g->GCthreshold = g->totalbytes; + } + } else { lua_assert(g->totalbytes >= g->estimate); - g->GCthreshold = g->estimate + ((g->estimate/GCDIV) * g->gcpace); + setthreshold(g); } } void luaC_fullgc (lua_State *L) { global_State *g = G(L); - if (g->gcstate <= GCSpropagate || g->gcgenerational) { - g->gcgenerational = 0; + if (g->gcstate <= GCSpropagate) { /* reset sweep marks to sweep all elements (returning them to white) */ g->sweepstrgc = 0; g->sweepgc = &g->rootgc; @@ -650,40 +637,37 @@ void luaC_fullgc (lua_State *L) { g->weak = NULL; g->gcstate = GCSsweepstring; } + lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); /* finish any pending sweep phase */ while (g->gcstate != GCSfinalize) { lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); singlestep(L); } markroot(L); - lua_assert(!g->gcgenerational); while (g->gcstate != GCSpause) { singlestep(L); - g->gcgenerational = 0; /* keep it in this mode */ } - g->GCthreshold = 2*g->estimate; + setthreshold(g); } void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcgenerational || - (g->gcstate != GCSfinalize && g->gcstate != GCSpause)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); lua_assert(ttype(&o->gch) != LUA_TTABLE); /* must keep invariant? */ - if (g->gcstate == GCSpropagate || g->gcgenerational) + if (g->gcstate == GCSpropagate) reallymarkobject(g, v); /* restore invariant */ else /* don't mind */ makewhite(g, o); /* mark as white just to avoid other barriers */ } -void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) { +void luaC_barrierback (lua_State *L, GCObject *o) { global_State *g = G(L); - lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcgenerational || - (g->gcstate != GCSfinalize && g->gcstate != GCSpause)); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); black2gray(o); /* make table gray (again) */ gco2h(o)->gclist = g->grayagain; g->grayagain = o; @@ -705,7 +689,7 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ g->rootgc = o; if (isgray(o)) { - if (g->gcstate == GCSpropagate || g->gcgenerational) { + if (g->gcstate == GCSpropagate) { gray2black(o); /* closed upvalues need barrier */ luaC_barrier(L, uv, uv->v); } diff --git a/src/lgc.h b/src/lgc.h index 81f6da5f81..43d4009a43 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.9 2004/09/15 20:38:15 roberto Exp $ +** $Id: lgc.h,v 2.12 2005/02/23 17:30:22 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -29,7 +29,7 @@ #define testbits(x,m) ((x) & (m)) #define bitmask(b) (1<<(b)) #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) -#define setbit(x,b) setbits(x, bitmask(b)) +#define l_setbit(x,b) setbits(x, bitmask(b)) #define resetbit(x,b) resetbits(x, bitmask(b)) #define testbit(x,b) testbits(x, bitmask(b)) #define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) @@ -47,8 +47,10 @@ ** bit 3 - for tables: has weak keys ** bit 4 - for tables: has weak values ** bit 5 - object is fixed (should not be collected) +** bit 6 - object is "super" fixed (only the main thread) */ + #define WHITE0BIT 0 #define WHITE1BIT 1 #define BLACKBIT 2 @@ -56,20 +58,23 @@ #define KEYWEAKBIT 3 #define VALUEWEAKBIT 4 #define FIXEDBIT 5 +#define SFIXEDBIT 6 +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) #define isgray(x) (!isblack(x) && !iswhite(x)) -#define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) -#define isdead(g,v) ((v)->gch.marked & otherwhite(g)) +#define otherwhite(g) (g->currentwhite ^ WHITEBITS) +#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) -#define changewhite(x) ((x)->gch.marked ^= bit2mask(WHITE0BIT, WHITE1BIT)) +#define changewhite(x) ((x)->gch.marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) -#define luaC_white(g) cast(lu_byte, (g)->currentwhite) +#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) #define luaC_checkGC(L) { if (G(L)->totalbytes >= G(L)->GCthreshold) \ @@ -80,7 +85,7 @@ luaC_barrierf(L,obj2gco(p),gcvalue(v)); } #define luaC_barriert(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ - luaC_barrierback(L,obj2gco(p),gcvalue(v)); } + luaC_barrierback(L,obj2gco(p)); } #define luaC_objbarrier(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ @@ -88,7 +93,7 @@ #define luaC_objbarriert(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ - luaC_barrierback(L,obj2gco(p),obj2gco(o)); } + luaC_barrierback(L,obj2gco(p)); } size_t luaC_separateudata (lua_State *L, int all); void luaC_callGCTM (lua_State *L); @@ -98,7 +103,7 @@ void luaC_fullgc (lua_State *L); void luaC_link (lua_State *L, GCObject *o, lu_byte tt); void luaC_linkupval (lua_State *L, UpVal *uv); void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); -void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v); +void luaC_barrierback (lua_State *L, GCObject *o); #endif diff --git a/src/linit.c b/src/linit.c index 0d5f9cd48a..24f70edbc7 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.8 2004/07/09 15:47:48 roberto Exp $ +** $Id: linit.c,v 1.9 2005/02/18 12:40:02 roberto Exp $ ** Initialization of libraries for lua.c ** See Copyright Notice in lua.h */ @@ -32,6 +32,8 @@ LUALIB_API int luaopen_stdlibs (lua_State *L) { for (; lib->func; lib++) { lib->func(L); /* open library */ lua_settop(L, 0); /* discard any results */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_replace(L, LUA_ENVIRONINDEX); /* restore environment */ } return 0; } diff --git a/src/liolib.c b/src/liolib.c index ca9b80258b..854ba3bae6 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.57 2004/08/13 19:52:13 roberto Exp $ +** $Id: liolib.c,v 2.58 2005/02/18 12:40:02 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -105,8 +105,8 @@ static int aux_close (lua_State *L) { static int io_close (lua_State *L) { - if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) - lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); + if (lua_isnone(L, 1)) + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); return pushresult(L, aux_close(L), NULL); } @@ -147,7 +147,7 @@ static int io_tmpfile (lua_State *L) { static FILE *getiofile (lua_State *L, int findex) { FILE *f; - lua_rawgeti(L, lua_upvalueindex(1), findex); + lua_rawgeti(L, LUA_ENVIRONINDEX, findex); lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); f = *(FILE **)lua_touserdata(L, -1); if (f == NULL) @@ -170,10 +170,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) { lua_pushvalue(L, 1); } lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); - lua_rawseti(L, lua_upvalueindex(1), f); + lua_rawseti(L, LUA_ENVIRONINDEX, f); } /* return current value */ - lua_rawgeti(L, lua_upvalueindex(1), f); + lua_rawgeti(L, LUA_ENVIRONINDEX, f); return 1; } @@ -192,10 +192,9 @@ static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int idx, int close) { - lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); lua_pushvalue(L, idx); lua_pushboolean(L, close); /* close/not close file when finished */ - lua_pushcclosure(L, io_readline, 3); + lua_pushcclosure(L, io_readline, 2); } @@ -209,7 +208,7 @@ static int f_lines (lua_State *L) { static int io_lines (lua_State *L) { if (lua_isnoneornil(L, 1)) { /* no arguments? */ /* will iterate over default input */ - lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); return f_lines(L); } else { @@ -349,7 +348,7 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { - FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2)); + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); int sucess; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); @@ -358,9 +357,9 @@ static int io_readline (lua_State *L) { luaL_error(L, "%s", strerror(errno)); if (sucess) return 1; else { /* EOF */ - if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(2)); + lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ } return 0; @@ -489,12 +488,13 @@ LUALIB_API int luaopen_io (lua_State *L) { createmeta(L); createupval(L); lua_pushvalue(L, -1); - luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); + lua_replace(L, LUA_ENVIRONINDEX); + luaL_openlib(L, LUA_IOLIBNAME, iolib, 0); /* put predefined file handles into `io' table */ - lua_rawgeti(L, -2, IO_INPUT); /* get current input from metatable */ - lua_setfield(L, -2, "stdin"); /* io.stdin = metatable[IO_INPUT] */ - lua_rawgeti(L, -2, IO_OUTPUT); /* get current output from metatable */ - lua_setfield(L, -2, "stdout"); /* io.stdout = metatable[IO_OUTPUT] */ + lua_rawgeti(L, -2, IO_INPUT); /* get current input from upval */ + lua_setfield(L, -2, "stdin"); /* io.stdin = upval[IO_INPUT] */ + lua_rawgeti(L, -2, IO_OUTPUT); /* get current output from upval */ + lua_setfield(L, -2, "stdout"); /* io.stdout = upval[IO_OUTPUT] */ *newfile(L) = stderr; lua_setfield(L, -2, "stderr"); /* io.stderr = newfile(stderr) */ return 1; diff --git a/src/llimits.h b/src/llimits.h index c3d5d532b8..5b11e82069 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.62 2004/12/13 12:15:11 roberto Exp $ +** $Id: llimits.h,v 1.63 2005/01/14 14:19:42 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -73,8 +73,6 @@ typedef LUA_UACNUMBER l_uacNumber; typedef lu_int32 Instruction; -/* divisor for GC pace */ -#define GCDIV 8 /* maximum stack for a Lua function */ #define MAXSTACK 250 diff --git a/src/lmathlib.c b/src/lmathlib.c index fcd2eefb98..add8897097 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.61 2004/05/10 18:11:32 roberto Exp $ +** $Id: lmathlib.c,v 1.62 2005/01/07 20:00:33 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -225,8 +225,6 @@ LUALIB_API int luaopen_math (lua_State *L) { luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); - lua_pushcfunction(L, math_pow); - lua_setglobal(L, "__pow"); return 1; } diff --git a/src/lmem.c b/src/lmem.c index 632990fcaa..dd9096552a 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.67 2004/12/01 15:46:18 roberto Exp $ +** $Id: lmem.c,v 1.69 2005/02/23 17:30:22 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -22,19 +22,19 @@ /* ** About the realloc function: -** void * realloc (void *ud, void *ptr, size_t osize, size_t nsize); +** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); ** (`osize' is the old size, `nsize' is the new size) ** ** Lua ensures that (ptr == NULL) iff (osize == 0). ** -** * realloc(ud, NULL, 0, x) creates a new block of size `x' +** * frealloc(ud, NULL, 0, x) creates a new block of size `x' ** -** * realloc(ud, p, x, 0) frees the block `p' -** (in this specific case, realloc must return NULL). -** particularly, realloc(ud, NULL, 0, 0) does nothing +** * frealloc(ud, p, x, 0) frees the block `p' +** (in this specific case, frealloc must return NULL). +** particularly, frealloc(ud, NULL, 0, 0) does nothing ** (which is equivalent to free(NULL) in ANSI C) ** -** realloc returns NULL if it cannot create or reallocate the area +** frealloc returns NULL if it cannot create or reallocate the area ** (any reallocation to an equal or smaller size cannot fail!) */ @@ -76,11 +76,27 @@ void *luaM_toobig (lua_State *L) { void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { global_State *g = G(L); lua_assert((osize == 0) == (block == NULL)); - block = (*g->realloc)(g->ud, block, osize, nsize); + block = (*g->frealloc)(g->ud, block, osize, nsize); if (block == NULL && nsize > 0) luaD_throw(L, LUA_ERRMEM); lua_assert((nsize == 0) == (block == NULL)); g->totalbytes = (g->totalbytes - osize) + nsize; +#if 0 + { /* auxiliar patch to monitor garbage collection */ + static unsigned long total = 0; /* our "time" */ + static lu_mem last = 0; /* last totalmem that generated an output */ + static FILE *f = NULL; /* output file */ + if (nsize <= osize) total += 1; /* "time" always grow */ + else total += (nsize - osize); + if ((int)g->totalbytes - (int)last > 1000 || + (int)g->totalbytes - (int)last < -1000) { + last = g->totalbytes; + if (f == NULL) f = fopen("trace", "w"); + fprintf(f, "%lu %u %u %u %d\n", total, g->totalbytes, g->GCthreshold, + g->estimate, g->gcstate); + } + } +#endif return block; } diff --git a/src/loadlib.c b/src/loadlib.c index 4adcbdc077..957310b6ad 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.15 2004/12/29 18:56:34 roberto Exp $ +** $Id: loadlib.c,v 1.18 2005/02/28 15:58:48 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h * @@ -293,45 +293,60 @@ static int ll_loadlib (lua_State *L) { */ -static const char *loadLua (lua_State *L, const char *fname, const char *name) { +static int loader_Lua (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); const char *path; /* try first `LUA_PATH' for compatibility */ - lua_getglobal(L, "LUA_PATH"); + lua_pushstring(L, "LUA_PATH"); + lua_rawget(L, LUA_GLOBALSINDEX); path = lua_tostring(L, -1); if (!path) { lua_pop(L, 1); - luaL_getfield(L, LUA_GLOBALSINDEX, "package.path"); + lua_getfield(L, LUA_ENVIRONINDEX, "path"); path = lua_tostring(L, -1); } if (path == NULL) luaL_error(L, "`package.path' must be a string"); fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return path; /* library not found in this path */ + if (fname == NULL) return 0; /* library not found in this path */ if (luaL_loadfile(L, fname) != 0) luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); - return NULL; /* library loaded successfully */ + return 1; /* library loaded successfully */ } -static const char *loadC (lua_State *L, const char *fname, const char *name) { +static int loader_C (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); const char *path; const char *funcname; - luaL_getfield(L, LUA_GLOBALSINDEX, "package.cpath"); + lua_getfield(L, LUA_ENVIRONINDEX, "cpath"); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, "`package.cpath' must be a string"); fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return path; /* library not found in this path */ + if (fname == NULL) return 0; /* library not found in this path */ funcname = luaL_gsub(L, name, ".", LUA_OFSEP); funcname = lua_pushfstring(L, "%s%s", POF, funcname); if (ll_loadfunc(L, fname, funcname) != 1) luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -2)); - return NULL; /* library loaded successfully */ + return 1; /* library loaded successfully */ +} + + +static int loader_preload (lua_State *L) { + lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + if (!lua_istable(L, -1)) + luaL_error(L, "`package.preload' must be a table"); + lua_getfield(L, -1, luaL_checkstring(L, 1)); + return 1; } static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); + int i; lua_settop(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); @@ -340,22 +355,18 @@ static int ll_require (lua_State *L) { /* else must load it; first mark it as loaded */ lua_pushboolean(L, 1); lua_setfield(L, 2, name); /* _LOADED[name] = true */ - /* check whether it is preloaded */ - lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); - lua_getfield(L, -1, name); - if (lua_isnil(L, -1)) { /* no preload function for that module? */ - const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); - const char *cpath = loadC(L, fname, name); /* try a C module */ - if (cpath) { /* not found? */ - const char *path = loadLua(L, fname, name); /* try a Lua module */ - if (path) { /* yet not found? */ - lua_pushnil(L); - lua_setfield(L, 2, name); /* unmark _LOADED[name] */ - return luaL_error(L, "package `%s' not found\n" - " cpath: %s\n path: %s", - name, cpath, path); - } - } + /* iterate over available loaders */ + lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + if (!lua_istable(L, -1)) + luaL_error(L, "`package.loaders' must be a table"); + for (i=1;; i++) { + lua_rawgeti(L, -1, i); /* get a loader */ + if (lua_isnil(L, -1)) + return luaL_error(L, "package `%s' not found", name); + lua_pushstring(L, name); + lua_call(L, 1, 1); /* call it */ + if (lua_isnil(L, -1)) lua_pop(L, 1); + else break; /* module loaded successfully */ } lua_pushvalue(L, 1); /* pass name as argument to module */ lua_call(L, 1, 1); /* run loaded module */ @@ -430,9 +441,13 @@ static const luaL_reg ll_funcs[] = { }; +static const lua_CFunction loaders[] = + {loader_preload, loader_C, loader_Lua, NULL}; + LUALIB_API int luaopen_loadlib (lua_State *L) { const char *path; + int i; /* create new type _LOADLIB */ luaL_newmetatable(L, "_LOADLIB"); lua_pushcfunction(L, gctm); @@ -441,6 +456,19 @@ LUALIB_API int luaopen_loadlib (lua_State *L) { lua_newtable(L); lua_pushvalue(L, -1); lua_setglobal(L, "package"); + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, "_PACKAGE"); + lua_pushvalue(L, -1); + lua_replace(L, LUA_ENVIRONINDEX); + /* create `loaders' table */ + lua_newtable(L); + /* fill it with pre-defined loaders */ + for (i=0; loaders[i] != NULL; i++) { + lua_pushcfunction(L, loaders[i]); + lua_rawseti(L, -2, i+1); + } + /* put it in field `loaders' */ + lua_setfield(L, -2, "loaders"); /* set field `path' */ path = getenv(LUA_PATH); if (path == NULL) path = LUA_PATH_DEFAULT; @@ -455,7 +483,7 @@ LUALIB_API int luaopen_loadlib (lua_State *L) { lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); /* set field `preload' */ - lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); + lua_newtable(L); lua_setfield(L, -2, "preload"); lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, ll_funcs, 0); /* open lib into global table */ diff --git a/src/lobject.c b/src/lobject.c index 154a0faf3c..f4464474d9 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.7 2004/11/24 19:16:03 roberto Exp $ +** $Id: lobject.c,v 2.8 2005/01/10 18:17:39 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -73,7 +73,7 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { case LUA_TNIL: return 1; case LUA_TNUMBER: - return nvalue(t1) == nvalue(t2); + return num_eq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: diff --git a/src/lobject.h b/src/lobject.h index 56c0fe8ac1..967b46c74f 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.8 2004/12/04 18:10:22 roberto Exp $ +** $Id: lobject.h,v 2.11 2005/02/18 12:40:02 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -218,6 +218,7 @@ typedef union Udata { struct { CommonHeader; struct Table *metatable; + struct Table *env; size_t len; } uv; } Udata; @@ -271,7 +272,13 @@ typedef struct LocVar { typedef struct UpVal { CommonHeader; TValue *v; /* points to stack or to its own value */ - TValue value; /* the value (when closed) */ + union { + TValue value; /* the value (when closed) */ + struct { /* double linked list (when open) */ + struct UpVal *prev; + struct UpVal *next; + } l; + } u; } UpVal; @@ -280,7 +287,8 @@ typedef struct UpVal { */ #define ClosureHeader \ - CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist + CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ + struct Table *env typedef struct CClosure { ClosureHeader; @@ -292,7 +300,6 @@ typedef struct CClosure { typedef struct LClosure { ClosureHeader; struct Proto *p; - TValue g; /* global table for this closure */ UpVal *upvals[1]; } LClosure; @@ -330,7 +337,7 @@ typedef struct Table { struct Table *metatable; TValue *array; /* array part */ Node *node; - Node *firstfree; /* this position is free; all positions after it are full */ + Node *lastfree; /* any free position is before this position */ GCObject *gclist; int sizearray; /* size of `array' array */ } Table; @@ -351,6 +358,8 @@ typedef struct Table { extern const TValue luaO_nilobject; +#define ceillog2(x) (luaO_log2((x)-1) + 1) + int luaO_log2 (unsigned int x); int luaO_int2fb (unsigned int x); int luaO_fb2int (int x); diff --git a/src/loslib.c b/src/loslib.c index 4f1d2d03a3..dad959e2b5 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.3 2004/10/08 18:57:16 roberto Exp $ +** $Id: loslib.c,v 1.4 2005/01/10 19:16:29 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -91,15 +91,13 @@ static int io_clock (lua_State *L) { */ static void setfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); lua_pushinteger(L, value); - lua_rawset(L, -3); + lua_setfield(L, -2, key); } static void setboolfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); lua_pushboolean(L, value); - lua_rawset(L, -3); + lua_setfield(L, -2, key); } static int getboolfield (lua_State *L, const char *key) { diff --git a/src/lparser.c b/src/lparser.c index b6b3c0a0e5..19e048ce3f 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.11 2004/12/07 18:31:16 roberto Exp $ +** $Id: lparser.c,v 2.13 2005/01/05 18:20:51 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -547,7 +547,7 @@ static void constructor (LexState *ls, expdesc *t) { check_match(ls, '}', '{', line); lastlistfield(fs, &cc); SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ - SETARG_C(fs->f->code[pc], luaO_log2(cc.nh)+1); /* set initial table size */ + SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ } /* }====================================================================== */ diff --git a/src/lstate.c b/src/lstate.c index bd238c5862..18dd4f95a7 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.19 2004/12/13 12:15:11 roberto Exp $ +** $Id: lstate.c,v 2.25 2005/02/23 17:30:22 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -76,33 +76,22 @@ static void freestack (lua_State *L, lua_State *L1) { ** open parts that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { - Udata *u; /* head of udata list */ global_State *g = G(L); UNUSED(ud); - u = luaM_new(L, Udata); - u->uv.len = 0; - u->uv.metatable = NULL; - g->firstudata = obj2gco(u); - luaC_link(L, obj2gco(u), LUA_TUSERDATA); - setbit(u->uv.marked, FIXEDBIT); - setbit(L->marked, FIXEDBIT); stack_init(L, L); /* init stack */ - sethvalue(L, gt(L), luaH_new(L, 0, 4)); /* table of globals */ + sethvalue(L, gt(L), luaH_new(L, 0, 20)); /* table of globals */ hvalue(gt(L))->metatable = luaH_new(L, 0, 0); /* globals metatable */ - sethvalue(L, registry(L), luaH_new(L, 4, 4)); /* registry */ + sethvalue(L, registry(L), luaH_new(L, 6, 20)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); luaS_fix(luaS_newliteral(L, MEMERRMSG)); g->GCthreshold = 4*g->totalbytes; - g->prevestimate = g->estimate = g->totalbytes; } static void preinit_state (lua_State *L, global_State *g) { L->l_G = g; - L->tt = LUA_TTHREAD; - L->marked = luaC_white(g); L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; @@ -125,20 +114,19 @@ static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_freeall(L); /* collect all objects */ - lua_assert(g->rootgc == NULL); + lua_assert(g->rootgc == obj2gco(L)); lua_assert(g->strt.nuse == 0); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); luaZ_freebuffer(L, &g->buff); freestack(L, L); lua_assert(g->totalbytes == sizeof(LG)); - (*g->realloc)(g->ud, fromstate(L), state_size(LG), 0); + (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); } lua_State *luaE_newthread (lua_State *L) { lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); - L1->next = L->next; /* link new thread after `L' */ - L->next = obj2gco(L1); + luaC_link(L, obj2gco(L1), LUA_TTHREAD); preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ setobj2n(L, gt(L1), gt(L)); /* share table of globals */ @@ -167,11 +155,16 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { L = tostate(l); g = &((LG *)L)->g; L->next = NULL; - g->currentwhite = bitmask(WHITE0BIT); + L->tt = LUA_TTHREAD; + g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); + L->marked = luaC_white(g); + set2bits(L->marked, FIXEDBIT, SFIXEDBIT); preinit_state(L, g); - g->realloc = f; + g->frealloc = f; g->ud = ud; g->mainthread = L; + g->uvhead.u.l.prev = &g->uvhead; + g->uvhead.u.l.next = &g->uvhead; g->GCthreshold = 0; /* mark it as unfinished state */ g->strt.size = 0; g->strt.nuse = 0; @@ -180,21 +173,17 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { luaZ_initbuffer(L, &g->buff); g->panic = NULL; g->gcstate = GCSpause; - g->gcgenerational = 0; g->rootgc = obj2gco(L); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; - g->firstudata = NULL; g->gray = NULL; g->grayagain = NULL; g->weak = NULL; g->tmudata = NULL; - setnilvalue(gkey(g->dummynode)); - setnilvalue(gval(g->dummynode)); - gnext(g->dummynode) = NULL; g->totalbytes = sizeof(LG); - g->gcpace = GCDIV; - g->incgc = 1; + g->gcpace = 200; /* 200% (wait memory to double before next collection) */ + g->gcstepmul = 200; /* GC runs `twice the speed' of memory allocation */ + g->gcdept = 0; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); diff --git a/src/lstate.h b/src/lstate.h index 4f29190abd..54469172ba 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.10 2004/12/13 12:15:11 roberto Exp $ +** $Id: lstate.h,v 2.16 2005/02/23 17:30:22 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -67,30 +67,28 @@ typedef struct CallInfo { */ typedef struct global_State { stringtable strt; /* hash table for strings */ - lua_Alloc realloc; /* function to reallocate memory */ - void *ud; /* auxiliary data to `realloc' */ + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to `frealloc' */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ - lu_byte gcgenerational; GCObject *rootgc; /* list of all collectable objects */ - GCObject *firstudata; /* udata go to the end of `rootgc' */ GCObject **sweepgc; /* position of sweep in `rootgc' */ int sweepstrgc; /* position of sweep in `strt' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of weak tables (to be cleared) */ - GCObject *tmudata; /* list of userdata to be GC */ + GCObject *tmudata; /* last element of list of userdata to be GC */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; lu_mem totalbytes; /* number of bytes currently allocated */ lu_mem estimate; /* an estimate of number of bytes actually in use */ - lu_mem prevestimate; /* previous estimate */ - int gcpace; /* relative `speed' of the GC */ - int incgc; /* 0 if GC is done non-incrementally */ + lu_mem gcdept; /* how much GC is `behind schedule' */ + int gcpace; /* size of pause between successive GCs */ + int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ TValue _registry; struct lua_State *mainthread; - Node dummynode[1]; /* common node array for all empty tables */ + UpVal uvhead; /* head of double-linked list of all open upvalues */ TString *tmname[TM_N]; /* array with tag-method names */ } global_State; @@ -118,6 +116,7 @@ struct lua_State { int hookcount; lua_Hook hook; TValue _gt; /* table of globals */ + TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ diff --git a/src/lstring.c b/src/lstring.c index af2c696324..897089a4b3 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.5 2004/11/24 19:16:03 roberto Exp $ +** $Id: lstring.c,v 2.7 2005/02/18 12:40:02 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -93,7 +93,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { } -Udata *luaS_newudata (lua_State *L, size_t s) { +Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) luaM_toobig(L); @@ -102,9 +102,10 @@ Udata *luaS_newudata (lua_State *L, size_t s) { u->uv.tt = LUA_TUSERDATA; u->uv.len = s; u->uv.metatable = NULL; - /* chain it on udata list */ - u->uv.next = G(L)->firstudata->uv.next; - G(L)->firstudata->uv.next = obj2gco(u); + u->uv.env = e; + /* chain it on udata list (after main thread) */ + u->uv.next = G(L)->mainthread->next; + G(L)->mainthread->next = obj2gco(u); return u; } diff --git a/src/lstring.h b/src/lstring.h index 4198f57ce6..88f6da8068 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.40 2004/11/19 15:52:40 roberto Exp $ +** $Id: lstring.h,v 1.42 2005/02/23 17:30:22 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -21,10 +21,10 @@ #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s) setbit((s)->tsv.marked, FIXEDBIT) +#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) void luaS_resize (lua_State *L, int newsize); -Udata *luaS_newudata (lua_State *L, size_t s); +Udata *luaS_newudata (lua_State *L, size_t s, Table *e); TString *luaS_newlstr (lua_State *L, const char *str, size_t l); diff --git a/src/ltable.c b/src/ltable.c index 8bfbf64150..d4070dd556 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.12 2004/12/04 18:10:22 roberto Exp $ +** $Id: ltable.c,v 2.15 2005/01/10 18:17:39 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -68,6 +68,13 @@ #define numints cast(int, sizeof(lua_Number)/sizeof(int)) + +const Node luaH_dummynode = { + {{NULL}, LUA_TNIL}, /* value */ + {{NULL}, LUA_TNIL, NULL} /* key */ +}; + + /* ** hash for lua_Numbers */ @@ -112,7 +119,7 @@ static int arrayindex (const TValue *key) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); - if (cast(lua_Number, k) == nvalue(key)) + if (num_eq(cast(lua_Number, k), nvalue(key))) return k; } return -1; /* `key' did not match some condition */ @@ -176,62 +183,77 @@ int luaH_next (lua_State *L, Table *t, StkId key) { */ -static void computesizes (int nums[], int ntotal, int *narray, int *nhash) { +static int computesizes (int nums[], int *narray) { int i; - int a = nums[0]; /* number of elements smaller than 2^i */ - int na = a; /* number of elements to go to array part */ - int n = (na == 0) ? -1 : 0; /* (log of) optimal size for array part */ - for (i = 1; a < *narray && *narray >= twoto(i-1); i++) { + int twotoi; /* 2^i */ + int a = 0; /* number of elements smaller than 2^i */ + int na = 0; /* number of elements to go to array part */ + int n = 0; /* optimal size for array part */ + for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; - if (a >= twoto(i-1)) { /* more than half elements in use? */ - n = i; - na = a; + if (a > twotoi/2) { /* more than half elements present? */ + n = twotoi; /* optimal size (till now) */ + na = a; /* all elements smaller than n will go to array part */ } } + if (a == *narray) break; /* all elements already counted */ + } + *narray = n; + lua_assert(*narray/2 <= na && na <= *narray); + return na; +} + + +static int countint (const TValue *key, int *nums) { + int k = arrayindex(key); + if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ + nums[ceillog2(k)]++; /* count as such */ + return 1; } - lua_assert(na <= *narray && *narray <= ntotal); - *nhash = ntotal - na; - *narray = (n == -1) ? 0 : twoto(n); - lua_assert(na <= *narray && na >= *narray/2); + else + return 0; } -static void numuse (const Table *t, int *narray, int *nhash) { - int nums[MAXBITS+1]; - int i, lg; - int totaluse = 0; - /* count elements in array part */ - for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ - int ttlg = twoto(lg); /* 2^lg */ - if (ttlg > t->sizearray) { - ttlg = t->sizearray; - if (i >= ttlg) break; +static int numusearray (const Table *t, int *nums) { + int lg; + int ttlg; /* 2^lg */ + int ause = 0; /* summation of `nums' */ + int i = 1; /* count to traverse all array keys */ + for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ + int lc = 0; /* counter */ + int lim = ttlg; + if (lim > t->sizearray) { + lim = t->sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ } - nums[lg] = 0; - for (; iarray[i])) { - nums[lg]++; - totaluse++; - } + /* count elements in range (2^(lg-1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(&t->array[i-1])) + lc++; } + nums[lg] += lc; + ause += lc; } - for (; lg<=MAXBITS; lg++) nums[lg] = 0; /* reset other counts */ - *narray = totaluse; /* all previous uses were in array part */ - /* count elements in hash part */ - i = sizenode(t); + return ause; +} + + +static int numusehash (const Table *t, int *nums, int *pnasize) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* summation of `nums' */ + int i = sizenode(t); while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { - int k = arrayindex(key2tval(n)); - if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ - nums[luaO_log2(k-1)+1]++; /* count as such */ - (*narray)++; - } + ause += countint(key2tval(n), nums); totaluse++; } } - computesizes(nums, totaluse, narray, nhash); + *pnasize += ause; + return totaluse; } @@ -244,18 +266,18 @@ static void setarrayvector (lua_State *L, Table *t, int size) { } -static void setnodevector (lua_State *L, Table *t, int lsize) { - int i; - int size = twoto(lsize); - if (lsize > MAXBITS) - luaG_runerror(L, "table overflow"); - if (lsize == 0) { /* no elements to hash part? */ - t->node = G(L)->dummynode; /* use common `dummynode' */ - lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */ - lua_assert(ttisnil(gval(t->node))); - lua_assert(gnext(t->node) == NULL); /* (`dummynode' must be empty) */ +static void setnodevector (lua_State *L, Table *t, int size) { + int lsize; + if (size == 0) { /* no elements to hash part? */ + t->node = cast(Node *, &luaH_dummynode); /* use common `dummynode' */ + lsize = 0; } else { + int i; + lsize = ceillog2(size); + if (lsize > MAXBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); t->node = luaM_newvector(L, size, Node); for (i=0; inode[i]) = NULL; @@ -264,31 +286,19 @@ static void setnodevector (lua_State *L, Table *t, int lsize) { } } t->lsizenode = cast(lu_byte, lsize); - t->firstfree = gnode(t, size-1); /* first free position to be used */ + t->lastfree = gnode(t, size); /* all positions are free */ } -void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { +static void resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; - Node *nold; - Node temp[1]; - if (oldhsize) - nold = t->node; /* save old hash ... */ - else { /* old hash is `dummynode' */ - lua_assert(t->node == G(L)->dummynode); - temp[0] = t->node[0]; /* copy it to `temp' */ - nold = temp; - setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */ - setnilvalue(gval(G(L)->dummynode)); - lua_assert(gnext(G(L)->dummynode) == NULL); - } + Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ setnodevector(L, t, nhsize); - /* re-insert elements */ if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ @@ -299,21 +309,39 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } - /* re-insert elements in hash part */ + /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } - if (oldhsize) + if (nold != &luaH_dummynode) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ } -static void rehash (lua_State *L, Table *t) { - int nasize, nhsize; - numuse(t, &nasize, &nhsize); /* compute new sizes for array and hash parts */ - luaH_resize(L, t, nasize, luaO_log2(nhsize)+1); +void luaH_resizearray (lua_State *L, Table *t, int nasize) { + int nsize = (t->node == &luaH_dummynode) ? 0 : sizenode(t); + resize(L, t, nasize, nsize); +} + + +static void rehash (lua_State *L, Table *t, const TValue *ek) { + int nasize, na; + int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ + int i; + int totaluse; + for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ + nasize = numusearray(t, nums); /* count keys in array part */ + totaluse = nasize; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ + /* count extra key */ + nasize += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + na = computesizes(nums, &nasize); + /* resize the table to new computed sizes */ + resize(L, t, nasize, totaluse - na); } @@ -323,7 +351,7 @@ static void rehash (lua_State *L, Table *t) { */ -Table *luaH_new (lua_State *L, int narray, int lnhash) { +Table *luaH_new (lua_State *L, int narray, int nhash) { Table *t = luaM_new(L, Table); luaC_link(L, obj2gco(t), LUA_TTABLE); t->metatable = NULL; @@ -332,21 +360,30 @@ Table *luaH_new (lua_State *L, int narray, int lnhash) { t->array = NULL; t->sizearray = 0; t->lsizenode = 0; - t->node = NULL; + t->node = cast(Node *, &luaH_dummynode); setarrayvector(L, t, narray); - setnodevector(L, t, lnhash); + setnodevector(L, t, nhash); return t; } void luaH_free (lua_State *L, Table *t) { - if (t->lsizenode) + if (t->node != &luaH_dummynode) luaM_freearray(L, t->node, sizenode(t), Node); luaM_freearray(L, t->array, t->sizearray, TValue); luaM_free(L, t); } +static Node *getfreepos (lua_State *L, Table *t) { + while (t->lastfree-- > t->node) { + if (ttisnil(gkey(t->lastfree))) + return t->lastfree; + } + return NULL; /* could not find a free place */ +} + + /* ** inserts a new key into a hash table; first, check whether key's main @@ -356,12 +393,16 @@ void luaH_free (lua_State *L, Table *t) { ** position), new key goes to an empty position. */ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { - TValue *val; Node *mp = luaH_mainposition(t, key); - if (!ttisnil(gval(mp))) { /* main position is not free? */ - /* `mp' of colliding node */ - Node *othern = luaH_mainposition(t, key2tval(mp)); - Node *n = t->firstfree; /* get a free place */ + if (!ttisnil(gval(mp)) || mp == &luaH_dummynode) { + Node *othern; + Node *n = getfreepos(L, t); /* get a free place */ + if (n == NULL) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + return luaH_set(L, t, key); /* re-insert key into grown table */ + } + lua_assert(n != &luaH_dummynode); + othern = luaH_mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ @@ -380,19 +421,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); - for (;;) { /* correct `firstfree' */ - if (ttisnil(gkey(t->firstfree))) - return gval(mp); /* OK; table still has a free place */ - else if (t->firstfree == t->node) break; /* cannot decrement from here */ - else (t->firstfree)--; - } - /* no more free places; must create one */ - setbvalue(gval(mp), 0); /* avoid new key being removed */ - rehash(L, t); /* grow table */ - val = cast(TValue *, luaH_get(t, key)); /* get new position */ - lua_assert(ttisboolean(val)); - setnilvalue(val); - return val; + return gval(mp); } @@ -407,7 +436,7 @@ const TValue *luaH_getnum (Table *t, int key) { lua_Number nk = cast(lua_Number, key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk) + if (ttisnumber(gkey(n)) && num_eq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); @@ -440,7 +469,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { case LUA_TNUMBER: { int k; lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key)) /* is an integer index? */ + if (num_eq(cast(lua_Number, k), nvalue(key))) /* is an integer index? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } @@ -464,7 +493,7 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && nvalue(key) != nvalue(key)) + else if (ttisnumber(key) && !num_eq(nvalue(key), nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } diff --git a/src/ltable.h b/src/ltable.h index cfc8601700..9700062e30 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.3 2004/10/06 18:34:16 roberto Exp $ +** $Id: ltable.h,v 2.5 2005/01/05 18:20:51 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -18,6 +18,8 @@ #define key2tval(n) (cast(const TValue *, gkey(n))) +extern const Node luaH_dummynode; + const TValue *luaH_getnum (Table *t, int key); TValue *luaH_setnum (lua_State *L, Table *t, int key); const TValue *luaH_getstr (Table *t, TString *key); @@ -25,7 +27,7 @@ TValue *luaH_setstr (lua_State *L, Table *t, TString *key); const TValue *luaH_get (Table *t, const TValue *key); TValue *luaH_set (lua_State *L, Table *t, const TValue *key); Table *luaH_new (lua_State *L, int narray, int lnhash); -void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); +void luaH_resizearray (lua_State *L, Table *t, int nasize); void luaH_free (lua_State *L, Table *t); int luaH_next (lua_State *L, Table *t, StkId key); diff --git a/src/lua.c b/src/lua.c index 6a21a6ae16..1d2fc75715 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.133 2004/11/18 19:53:49 roberto Exp $ +** $Id: lua.c,v 1.135 2005/01/10 17:21:10 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -79,11 +79,23 @@ static int report (lua_State *L, int status) { } +static int traceback (lua_State *L) { + luaL_getfield(L, LUA_GLOBALSINDEX, "debug.traceback"); + if (!lua_isfunction(L, -1)) + lua_pop(L, 1); + else { + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ + } + return 1; +} + + static int docall (lua_State *L, int narg, int clear) { int status; int base = lua_gettop(L) - narg; /* function index */ - lua_pushliteral(L, "_TRACEBACK"); - lua_rawget(L, LUA_GLOBALSINDEX); /* get traceback function */ + lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ signal(SIGINT, laction); status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); @@ -359,7 +371,7 @@ static int pmain (lua_State *L) { int interactive = 1; if (s->argv[0] && s->argv[0][0]) progname = s->argv[0]; globalL = L; - lua_userinit(L); /* open libraries */ + luaopen_stdlibs(L); /* open libraries */ status = handle_luainit(L); if (status == 0) { status = handle_argv(L, s->argv, &interactive); diff --git a/src/lua.h b/src/lua.h index 25fc84055a..1020abd123 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.197 2004/12/13 12:15:11 roberto Exp $ +** $Id: lua.h,v 1.202 2005/02/18 12:40:02 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -17,8 +17,9 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (work4)" -#define LUA_COPYRIGHT "Copyright (C) 1994-2004 Tecgraf, PUC-Rio" +#define LUA_VERSION "Lua 5.1 (work5)" +#define LUA_VERSION_NUM 501 +#define LUA_COPYRIGHT "Copyright (C) 1994-2005 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -33,11 +34,12 @@ ** pseudo-indices */ #define LUA_REGISTRYINDEX (-10000) -#define LUA_GLOBALSINDEX (-10001) +#define LUA_ENVIRONINDEX (-10001) +#define LUA_GLOBALSINDEX (-10002) #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) -/* return codes for `lua_pcall', `lua_resume', and `lua_threadstatus' */ +/* return codes for `lua_pcall', `lua_resume', and `lua_status' */ #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 @@ -109,112 +111,112 @@ typedef LUA_INTEGER lua_Integer; /* ** state manipulation */ -LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud); -LUA_API void lua_close (lua_State *L); -LUA_API lua_State *lua_newthread (lua_State *L); +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); -LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf); +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); /* ** basic stack manipulation */ -LUA_API int lua_gettop (lua_State *L); -LUA_API void lua_settop (lua_State *L, int idx); -LUA_API void lua_pushvalue (lua_State *L, int idx); -LUA_API void lua_remove (lua_State *L, int idx); -LUA_API void lua_insert (lua_State *L, int idx); -LUA_API void lua_replace (lua_State *L, int idx); -LUA_API int lua_checkstack (lua_State *L, int sz); +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_remove) (lua_State *L, int idx); +LUA_API void (lua_insert) (lua_State *L, int idx); +LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API int (lua_checkstack) (lua_State *L, int sz); -LUA_API void lua_xmove (lua_State *from, lua_State *to, int n); +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); /* ** access functions (stack -> C) */ -LUA_API int lua_isnumber (lua_State *L, int idx); -LUA_API int lua_isstring (lua_State *L, int idx); -LUA_API int lua_iscfunction (lua_State *L, int idx); -LUA_API int lua_isuserdata (lua_State *L, int idx); -LUA_API int lua_type (lua_State *L, int idx); -LUA_API const char *lua_typename (lua_State *L, int tp); +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); -LUA_API int lua_equal (lua_State *L, int idx1, int idx2); -LUA_API int lua_rawequal (lua_State *L, int idx1, int idx2); -LUA_API int lua_lessthan (lua_State *L, int idx1, int idx2); +LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); -LUA_API lua_Number lua_tonumber (lua_State *L, int idx); -LUA_API lua_Integer lua_tointeger (lua_State *L, int idx); -LUA_API int lua_toboolean (lua_State *L, int idx); -LUA_API const char *lua_tostring (lua_State *L, int idx); -LUA_API size_t lua_objsize (lua_State *L, int idx); -LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx); -LUA_API void *lua_touserdata (lua_State *L, int idx); -LUA_API lua_State *lua_tothread (lua_State *L, int idx); -LUA_API const void *lua_topointer (lua_State *L, int idx); +LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); +LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tostring) (lua_State *L, int idx); +LUA_API size_t (lua_objsize) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); /* ** push functions (C -> stack) */ -LUA_API void lua_pushnil (lua_State *L); -LUA_API void lua_pushnumber (lua_State *L, lua_Number n); -LUA_API void lua_pushinteger (lua_State *L, lua_Integer n); -LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t l); -LUA_API void lua_pushstring (lua_State *L, const char *s); -LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, - va_list argp); -LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...); -LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); -LUA_API void lua_pushboolean (lua_State *L, int b); -LUA_API void lua_pushlightuserdata (lua_State *L, void *p); -LUA_API int lua_pushthread (lua_State *L); +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API void (lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ -LUA_API void lua_gettable (lua_State *L, int idx); -LUA_API void lua_getfield (lua_State *L, int idx, const char *k); -LUA_API void lua_rawget (lua_State *L, int idx); -LUA_API void lua_rawgeti (lua_State *L, int idx, int n); -LUA_API void lua_createtable (lua_State *L, int narr, int nrec); -LUA_API void *lua_newuserdata (lua_State *L, size_t sz); -LUA_API int lua_getmetatable (lua_State *L, int objindex); -LUA_API void lua_getfenv (lua_State *L, int idx); +LUA_API void (lua_gettable) (lua_State *L, int idx); +LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawget) (lua_State *L, int idx); +LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API void (lua_getfenv) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ -LUA_API void lua_settable (lua_State *L, int idx); -LUA_API void lua_setfield (lua_State *L, int idx, const char *k); -LUA_API void lua_rawset (lua_State *L, int idx); -LUA_API void lua_rawseti (lua_State *L, int idx, int n); -LUA_API int lua_setmetatable (lua_State *L, int objindex); -LUA_API int lua_setfenv (lua_State *L, int idx); +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API int (lua_setfenv) (lua_State *L, int idx); /* ** `load' and `call' functions (load and run Lua code) */ -LUA_API void lua_call (lua_State *L, int nargs, int nresults); -LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc); -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud); -LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *dt, - const char *chunkname); +LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); +LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API int (lua_load) (lua_State *L, lua_Chunkreader reader, void *dt, + const char *chunkname); -LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data); +LUA_API int (lua_dump) (lua_State *L, lua_Chunkwriter writer, void *data); /* ** coroutine functions */ -LUA_API int lua_yield (lua_State *L, int nresults); -LUA_API int lua_resume (lua_State *L, int narg); -LUA_API int lua_threadstatus (lua_State *L); +LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_resume) (lua_State *L, int narg); +LUA_API int (lua_status) (lua_State *L); /* ** garbage-collection function and options @@ -226,24 +228,22 @@ LUA_API int lua_threadstatus (lua_State *L); #define LUA_GCCOUNT 3 #define LUA_GCSTEP 4 #define LUA_GCSETPACE 5 -#define LUA_GCSETINCMODE 6 +#define LUA_GCSETSTEPMUL 6 -LUA_API int lua_gc (lua_State *L, int what, int data); +LUA_API int (lua_gc) (lua_State *L, int what, int data); /* ** miscellaneous functions */ -LUA_API const char *lua_version (void); +LUA_API int (lua_error) (lua_State *L); -LUA_API int lua_error (lua_State *L); +LUA_API int (lua_next) (lua_State *L, int idx); -LUA_API int lua_next (lua_State *L, int idx); +LUA_API void (lua_concat) (lua_State *L, int n); -LUA_API void lua_concat (lua_State *L, int n); - -LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud); +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); diff --git a/src/luaconf.h b/src/luaconf.h index 7ea477e23a..04b8e99089 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.22 2004/12/27 15:58:15 roberto Exp $ +** $Id: luaconf.h,v 1.30 2005/02/28 15:59:11 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -96,7 +96,7 @@ #define stdin_is_tty() isatty(0) #elif defined(_WIN32) #include -#include +#include #define stdin_is_tty() _isatty(_fileno(stdin)) #else #define stdin_is_tty() 1 /* assume stdin is a tty */ @@ -108,16 +108,6 @@ #define PROGNAME "lua" -/* -** this macro allows you to open other libraries when starting the -** stand-alone interpreter -*/ -#define lua_userinit(L) luaopen_stdlibs(L) -/* -** #define lua_userinit(L) { int luaopen_mylibs(lua_State *L); \ -** luaopen_stdlibs(L); luaopen_mylibs(L); } -*/ - /* @@ -217,8 +207,7 @@ #if defined(__GNUC__) && defined(__i386) #define lua_number2int(i,d) __asm__ ("fistpl %0":"=m"(i):"t"(d):"st") -#elif defined(_WIN32) && defined(_M_IX86) -#include +#elif defined(_MSC_VER) && defined(_M_IX86) #pragma warning(disable: 4514) __inline int l_lrint (double flt) { int i; @@ -248,6 +237,8 @@ __inline int l_lrint (double flt) /* function to convert a lua_Number to a string */ #include #define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) +/* maximum size of previous conversion */ +#define MAX_NUMBER2STR 32 /* 16 digits, sign, point and \0 (+ some extra) */ /* function to convert a string to a lua_Number */ #define lua_str2number(s,p) strtod((s), (p)) @@ -258,12 +249,29 @@ __inline int l_lrint (double flt) #define LUA_UACNUMBER double +/* primitive operators for numbers */ +#define num_add(a,b) ((a)+(b)) +#define num_sub(a,b) ((a)-(b)) +#define num_mul(a,b) ((a)*(b)) +#define num_div(a,b) ((a)/(b)) +#define num_unm(a) (-(a)) +#define num_eq(a,b) ((a)==(b)) +#define num_lt(a,b) ((a)<(b)) +#define num_le(a,b) ((a)<=(b)) +#include +#define num_pow(a,b) pow(a,b) + + /* type to ensure maximum alignment */ #define LUSER_ALIGNMENT_T union { double u; void *s; long l; } -/* exception handling */ +/* +** exception handling: by default, Lua handles errors with longjmp/setjmp +** when compiling as C code and with exceptions when compiling as C++ code. +** Change that if you prefer to use longjmp/setjmp even with C++. +*/ #ifndef __cplusplus /* default handling with long jumps */ #include @@ -282,18 +290,20 @@ __inline int l_lrint (double flt) /* -** macros for thread synchronization inside Lua core machine: -** all accesses to the global state and to global objects are synchronized. -** Because threads can read the stack of other threads -** (when running garbage collection), -** a thread must also synchronize any write-access to its own stack. -** Unsynchronized accesses are allowed only when reading its own stack, -** or when reading immutable fields from global objects -** (such as string values and udata values). +** macros for thread synchronization inside Lua core machine: This is +** an attempt to simplify the implementation of a multithreaded version +** of Lua. Do not change that unless you know what you are doing. all +** accesses to the global state and to global objects are synchronized. +** Because threads can read the stack of other threads (when running +** garbage collection), a thread must also synchronize any write-access +** to its own stack. Unsynchronized accesses are allowed only when +** reading its own stack, or when reading immutable fields from global +** objects (such as string values and udata values). */ #define lua_lock(L) ((void) 0) #define lua_unlock(L) ((void) 0) + /* ** this macro allows a thread switch in appropriate places in the Lua ** core @@ -303,7 +313,7 @@ __inline int l_lrint (double flt) /* allows user-specific initialization on new threads */ -#define lua_userstateopen(L) /* empty */ +#define lua_userstateopen(L) ((void)0) #endif @@ -321,9 +331,6 @@ __inline int l_lrint (double flt) #ifdef LUA_LIB - -/* `assert' options */ - /* environment variables that hold the search path for packages */ #define LUA_PATH "LUA_PATH" #define LUA_CPATH "LUA_CPATH" @@ -332,7 +339,7 @@ __inline int l_lrint (double flt) #define LUA_POF "luaopen_" /* separator for open functions in C libraries */ -#define LUA_OFSEP "" +#define LUA_OFSEP "_" /* directory separator (for submodules) */ #if defined(_WIN32) @@ -342,18 +349,20 @@ __inline int l_lrint (double flt) #endif /* separator of templates in a path */ -#define LUA_PATH_SEP ';' +#define LUA_PATHSEP ';' /* wild char in each template */ #define LUA_PATH_MARK "?" -/* maximum number of captures in pattern-matching */ -#define MAX_CAPTURES 32 /* arbitrary limit */ +/* maximum number of captures in pattern-matching (arbitrary limit) */ +#define MAX_CAPTURES 32 /* -** by default, gcc does not get `tmpname' +** by default, gcc does not get `os.tmpname', because it generates a warning +** when using `tmpname'. Change that if you really want (or do not want) +** `os.tmpname' available. */ #ifdef __GNUC__ #define USE_TMPNAME 0 @@ -363,7 +372,11 @@ __inline int l_lrint (double flt) /* -** Configuration for loadlib +** Configuration for loadlib: Lua tries to guess the dynamic-library +** system that your platform uses (either Windows' DLL, Mac's dyld, or +** dlopen). If your system is some kind of Unix, there is a good chance +** that USE_DLOPEN will work for it. You may need to adapt also the +** makefile. */ #if defined(_WIN32) #define USE_DLL diff --git a/src/lualib.h b/src/lualib.h index c8114ed259..a5dde23693 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.32 2004/07/09 15:47:48 roberto Exp $ +** $Id: lualib.h,v 1.33 2005/01/10 16:31:30 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -16,32 +16,32 @@ #define LUA_COLIBNAME "coroutine" -LUALIB_API int luaopen_base (lua_State *L); +LUALIB_API int (luaopen_base) (lua_State *L); #define LUA_TABLIBNAME "table" -LUALIB_API int luaopen_table (lua_State *L); +LUALIB_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" -LUALIB_API int luaopen_io (lua_State *L); +LUALIB_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" -LUALIB_API int luaopen_os (lua_State *L); +LUALIB_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" -LUALIB_API int luaopen_string (lua_State *L); +LUALIB_API int (luaopen_string) (lua_State *L); #define LUA_MATHLIBNAME "math" -LUALIB_API int luaopen_math (lua_State *L); +LUALIB_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" -LUALIB_API int luaopen_debug (lua_State *L); +LUALIB_API int (luaopen_debug) (lua_State *L); -LUALIB_API int luaopen_loadlib (lua_State *L); +LUALIB_API int (luaopen_loadlib) (lua_State *L); /* open all previous libraries */ -LUALIB_API int luaopen_stdlibs (lua_State *L); +LUALIB_API int (luaopen_stdlibs) (lua_State *L); #endif diff --git a/src/lvm.c b/src/lvm.c index 1a295d1bdd..1fd2ae75cb 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.18 2004/12/03 20:35:33 roberto Exp $ +** $Id: lvm.c,v 2.26 2005/02/23 17:30:22 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -47,7 +47,7 @@ int luaV_tostring (lua_State *L, StkId obj) { if (!ttisnumber(obj)) return 0; else { - char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ + char s[MAX_NUMBER2STR]; lua_number2str(s, nvalue(obj)); setsvalue2s(L, obj, luaS_new(L, s)); return 1; @@ -113,7 +113,7 @@ StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); - const TValue *res = luaH_get(h, key); /* do a primitive set */ + const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); @@ -241,7 +241,7 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return nvalue(l) < nvalue(r); + return num_lt(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) @@ -255,7 +255,7 @@ static int lessequal (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return nvalue(l) <= nvalue(r); + return num_le(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ @@ -271,7 +271,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; - case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); + case LUA_TNUMBER: return num_eq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { @@ -335,18 +335,11 @@ static StkId Arith (lua_State *L, StkId ra, const TValue *rb, if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { switch (op) { - case TM_ADD: setnvalue(ra, nvalue(b) + nvalue(c)); break; - case TM_SUB: setnvalue(ra, nvalue(b) - nvalue(c)); break; - case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; - case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; - case TM_POW: { - const TValue *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); - if (!ttisfunction(f)) - luaG_runerror(L, "`__pow' (`^' operator) is not a function"); - prepTMcall(L, f, b, c); - callTMres(L, ra); - break; - } + case TM_ADD: setnvalue(ra, num_add(nvalue(b), nvalue(c))); break; + case TM_SUB: setnvalue(ra, num_sub(nvalue(b), nvalue(c))); break; + case TM_MUL: setnvalue(ra, num_mul(nvalue(b), nvalue(c))); break; + case TM_DIV: setnvalue(ra, num_div(nvalue(b), nvalue(c))); break; + case TM_POW: setnvalue(ra, num_pow(nvalue(b), nvalue(c))); break; default: lua_assert(0); break; } } @@ -435,9 +428,11 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_GETGLOBAL: { + TValue g; TValue *rb = KBx(i); - lua_assert(ttisstring(rb) && ttistable(&cl->g)); - base = luaV_gettable(L, &cl->g, rb, ra, pc); /***/ + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(rb)); + base = luaV_gettable(L, &g, rb, ra, pc); /***/ continue; } case OP_GETTABLE: { @@ -445,8 +440,10 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_SETGLOBAL: { - lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - base = luaV_settable(L, &cl->g, KBx(i), ra, pc); /***/ + TValue g; + sethvalue(L, &g, cl->env); + lua_assert(ttisstring(KBx(i))); + base = luaV_settable(L, &g, KBx(i), ra, pc); /***/ continue; } case OP_SETUPVAL: { @@ -461,8 +458,8 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } case OP_NEWTABLE: { int b = GETARG_B(i); - b = luaO_fb2int(b); - sethvalue(L, ra, luaH_new(L, b, GETARG_C(i))); + int c = GETARG_C(i); + sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); L->ci->savedpc = pc; luaC_checkGC(L); /***/ base = L->base; @@ -478,7 +475,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) + nvalue(rc)); + setnvalue(ra, num_add(nvalue(rb), nvalue(rc))); } else base = Arith(L, ra, rb, rc, TM_ADD, pc); /***/ @@ -488,7 +485,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) - nvalue(rc)); + setnvalue(ra, num_sub(nvalue(rb), nvalue(rc))); } else base = Arith(L, ra, rb, rc, TM_SUB, pc); /***/ @@ -498,7 +495,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) * nvalue(rc)); + setnvalue(ra, num_mul(nvalue(rb), nvalue(rc))); } else base = Arith(L, ra, rb, rc, TM_MUL, pc); /***/ @@ -508,21 +505,27 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) / nvalue(rc)); + setnvalue(ra, num_div(nvalue(rb), nvalue(rc))); } else base = Arith(L, ra, rb, rc, TM_DIV, pc); /***/ continue; } case OP_POW: { - base = Arith(L, ra, RKB(i), RKC(i), TM_POW, pc); /***/ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + if (ttisnumber(rb) && ttisnumber(rc)) { + setnvalue(ra, num_pow(nvalue(rb), nvalue(rc))); + } + else + base = Arith(L, ra, rb, rc, TM_POW, pc); /***/ continue; } case OP_UNM: { const TValue *rb = RB(i); TValue temp; if (tonumber(rb, &temp)) { - setnvalue(ra, -nvalue(rb)); + setnvalue(ra, num_unm(nvalue(rb))); } else { setnilvalue(&temp); @@ -617,9 +620,9 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { int aux; StkId func = ci->func; StkId pfunc = (ci+1)->func; /* previous function index */ + if (L->openupval) luaF_close(L, base); base = ci->base = ci->func + ((ci+1)->base - pfunc); L->base = base; - if (L->openupval) luaF_close(L, base); for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ setobjs2s(L, func+aux, pfunc+aux); ci->top = L->top = func+aux; /* correct top */ @@ -658,9 +661,9 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); - lua_Number idx = nvalue(ra) + step; /* increment index */ + lua_Number idx = num_add(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); - if (step > 0 ? idx <= limit : idx >= limit) { + if (step > 0 ? num_le(idx, limit) : num_le(limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ @@ -678,7 +681,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { luaG_runerror(L, "`for' limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, "`for' step must be a number"); - setnvalue(ra, nvalue(ra) - nvalue(pstep)); + setnvalue(ra, num_sub(nvalue(ra), nvalue(pstep))); dojump(L, pc, GETARG_sBx(i)); continue; } @@ -723,7 +726,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { if (c == 0) c = cast(int, *pc++); last = ((c-1)*LFIELDS_PER_FLUSH) + n + LUA_FIRSTINDEX - 1; if (last > h->sizearray) /* needs more space? */ - luaH_resize(L, h, last, h->lsizenode); /* pre-alloc it at once */ + luaH_resizearray(L, h, last); /* pre-alloc it at once */ for (; n > 0; n--) { TValue *val = ra+n; setobj2t(L, luaH_setnum(L, h, last--), val); @@ -741,7 +744,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { int nup, j; p = cl->p->p[GETARG_Bx(i)]; nup = p->nups; - ncl = luaF_newLclosure(L, nup, &cl->g); + ncl = luaF_newLclosure(L, nup, cl->env); ncl->l.p = p; for (j=0; j Date: Fri, 20 May 2005 12:00:00 +0000 Subject: [PATCH 23/97] Lua 5.1-work6 --- HISTORY | 4 + INSTALL | 25 +- MANIFEST | 207 +++++++------- Makefile | 21 +- etc/Makefile | 4 +- etc/README | 6 +- etc/all.c | 4 +- etc/lua.pc | 24 ++ etc/saconfig.c | 65 ----- src/Makefile | 34 +-- src/lapi.c | 85 +++--- src/lapi.h | 4 +- src/lauxlib.c | 67 ++--- src/lauxlib.h | 8 +- src/lbaselib.c | 33 ++- src/lcode.c | 31 +- src/lcode.h | 66 ++--- src/ldblib.c | 114 ++++---- src/ldebug.c | 115 +++++--- src/ldebug.h | 21 +- src/ldo.c | 40 +-- src/ldo.h | 28 +- src/ldump.c | 5 +- src/lfunc.c | 9 +- src/lfunc.h | 24 +- src/lgc.c | 17 +- src/lgc.h | 20 +- src/linit.c | 14 +- src/liolib.c | 8 +- src/llex.c | 35 ++- src/llex.h | 18 +- src/llimits.h | 14 +- src/lmathlib.c | 31 +- src/lmem.h | 23 +- src/loadlib.c | 74 +++-- src/lobject.c | 10 +- src/lobject.h | 24 +- src/lopcodes.c | 8 +- src/lopcodes.h | 10 +- src/loslib.c | 19 +- src/lparser.c | 64 +++-- src/lparser.h | 11 +- src/lstate.c | 39 ++- src/lstate.h | 12 +- src/lstring.h | 8 +- src/lstrlib.c | 62 ++-- src/ltable.c | 67 ++++- src/ltable.h | 25 +- src/ltablib.c | 39 +-- src/ltm.c | 10 +- src/ltm.h | 13 +- src/lua.c | 137 ++++----- src/lua.h | 56 ++-- src/luac.c | 4 +- src/luaconf.h | 697 +++++++++++++++++++++++++++++++-------------- src/lualib.h | 6 +- src/lundump.c | 5 +- src/lundump.h | 10 +- src/lvm.c | 358 +++++++++++------------ src/lvm.h | 22 +- src/lzio.c | 4 +- src/lzio.h | 23 +- src/print.c | 33 +-- test/README | 1 - test/luac.lua | 4 +- test/undefined.lua | 9 - 66 files changed, 1742 insertions(+), 1346 deletions(-) create mode 100644 etc/lua.pc delete mode 100644 etc/saconfig.c delete mode 100644 test/undefined.lua diff --git a/HISTORY b/HISTORY index 3be1eb553d..bc7c4181be 100644 --- a/HISTORY +++ b/HISTORY @@ -8,6 +8,9 @@ This is Lua 5.1 (work). + new semantics for setn/getn. + new syntax/semantics for varargs. + new long strings. + + new `mod' (`%') operator + + new operation *t (for size of t) + + metatables for all types API: + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + user supplies memory allocator (lua_open becomes lua_newstate). @@ -18,6 +21,7 @@ This is Lua 5.1 (work). + fully reentrant parser (new Lua function `load') + better support for 64-bit machines (special thanks to Mike Pall). + native loadlib support for Mac OS X (thanks to Matthew Cox). + + standard distribution in only one library (lualib.a merged into lua.a) * Changes from version 4.0 to 5.0 ------------------------------- diff --git a/INSTALL b/INSTALL index 3c2c69d096..0ddd37e0cf 100644 --- a/INSTALL +++ b/INSTALL @@ -5,17 +5,20 @@ This is Lua 5.1 (work). Building Lua on a Unix system should be very easy: simply doing "make" should work. This will build Lua in the src directory. + See below for customization instructions. We strongly recommend that + you enable dynamic loading. + If you want to install Lua in an official place in your system, then do "make install". The official place and the way to install files are defined in Makefile. You must have the right permissions to install files. If you want to install Lua locally, then do "make local". This will - create directories bin, include, lib, man and install Lua there as + create directories bin, include, lib, man, and install Lua there as follows: bin: lua luac include: lua.h luaconf.h lualib.h lauxlib.h - lib: liblua.a liblualib.a + lib: liblua.a man/man1: lua.1 luac.1 These are the only directories you need for development. @@ -38,25 +41,23 @@ This is Lua 5.1 (work). On the other hand, if you need to select some Lua features, you'll need to edit src/luaconf.h. The edited file will be the one installed, and - will be used by any Lua clients that you build, to ensure consistency. + it will be used by any Lua clients that you build, to ensure consistency. * Installation on Windows and other systems ----------------------------------------- The instructions for building Lua on other systems depend on the compiler you use. You'll need to create projects (or whatever your compiler uses) - for building the core library, the standard library, the interpreter, and - the compiler, as follows: + for building the library, the interpreter, and the compiler, as follows: - core lib: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c - lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c + library: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c + lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c + lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c + ltablib.c lstrlib.c loadlib.c linit.c - standard lib: lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c - ltablib.c lstrlib.c loadlib.c linit.c - - interpreter: core lib, standard lib, lua.c + interpreter: library, lua.c - compiler: core lib, lauxlib.c luac.c print.c + compiler: library, luac.c print.c If all you want is to build the Lua interpreter, you may put all .c files in a single project, except for luac.c and print.c. diff --git a/MANIFEST b/MANIFEST index 01a2a7e7c7..dbd86863c5 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,105 +1,104 @@ -MANIFEST contents of Lua 5.1 (work5) distribution on Fri Mar 4 13:32:55 BRST 2005 -lua-5.1-work5 -lua-5.1-work5/COPYRIGHT -lua-5.1-work5/HISTORY -lua-5.1-work5/INSTALL -lua-5.1-work5/MANIFEST -lua-5.1-work5/Makefile -lua-5.1-work5/README -lua-5.1-work5/doc -lua-5.1-work5/doc/contents.html -lua-5.1-work5/doc/logo.gif -lua-5.1-work5/doc/lua.1 -lua-5.1-work5/doc/lua.html -lua-5.1-work5/doc/luac.1 -lua-5.1-work5/doc/luac.html -lua-5.1-work5/doc/readme.html -lua-5.1-work5/etc -lua-5.1-work5/etc/Makefile -lua-5.1-work5/etc/README -lua-5.1-work5/etc/all.c -lua-5.1-work5/etc/lua.hpp -lua-5.1-work5/etc/lua.ico -lua-5.1-work5/etc/min.c -lua-5.1-work5/etc/noparser.c -lua-5.1-work5/etc/saconfig.c -lua-5.1-work5/src -lua-5.1-work5/src/Makefile -lua-5.1-work5/src/lapi.c -lua-5.1-work5/src/lapi.h -lua-5.1-work5/src/lauxlib.c -lua-5.1-work5/src/lauxlib.h -lua-5.1-work5/src/lbaselib.c -lua-5.1-work5/src/lcode.c -lua-5.1-work5/src/lcode.h -lua-5.1-work5/src/ldblib.c -lua-5.1-work5/src/ldebug.c -lua-5.1-work5/src/ldebug.h -lua-5.1-work5/src/ldo.c -lua-5.1-work5/src/ldo.h -lua-5.1-work5/src/ldump.c -lua-5.1-work5/src/lfunc.c -lua-5.1-work5/src/lfunc.h -lua-5.1-work5/src/lgc.c -lua-5.1-work5/src/lgc.h -lua-5.1-work5/src/linit.c -lua-5.1-work5/src/liolib.c -lua-5.1-work5/src/llex.c -lua-5.1-work5/src/llex.h -lua-5.1-work5/src/llimits.h -lua-5.1-work5/src/lmathlib.c -lua-5.1-work5/src/lmem.c -lua-5.1-work5/src/lmem.h -lua-5.1-work5/src/loadlib.c -lua-5.1-work5/src/lobject.c -lua-5.1-work5/src/lobject.h -lua-5.1-work5/src/lopcodes.c -lua-5.1-work5/src/lopcodes.h -lua-5.1-work5/src/loslib.c -lua-5.1-work5/src/lparser.c -lua-5.1-work5/src/lparser.h -lua-5.1-work5/src/lstate.c -lua-5.1-work5/src/lstate.h -lua-5.1-work5/src/lstring.c -lua-5.1-work5/src/lstring.h -lua-5.1-work5/src/lstrlib.c -lua-5.1-work5/src/ltable.c -lua-5.1-work5/src/ltable.h -lua-5.1-work5/src/ltablib.c -lua-5.1-work5/src/ltm.c -lua-5.1-work5/src/ltm.h -lua-5.1-work5/src/lua.c -lua-5.1-work5/src/lua.h -lua-5.1-work5/src/luac.c -lua-5.1-work5/src/luaconf.h -lua-5.1-work5/src/lualib.h -lua-5.1-work5/src/lundump.c -lua-5.1-work5/src/lundump.h -lua-5.1-work5/src/lvm.c -lua-5.1-work5/src/lvm.h -lua-5.1-work5/src/lzio.c -lua-5.1-work5/src/lzio.h -lua-5.1-work5/src/print.c -lua-5.1-work5/test -lua-5.1-work5/test/README -lua-5.1-work5/test/bisect.lua -lua-5.1-work5/test/cf.lua -lua-5.1-work5/test/echo.lua -lua-5.1-work5/test/env.lua -lua-5.1-work5/test/factorial.lua -lua-5.1-work5/test/fib.lua -lua-5.1-work5/test/fibfor.lua -lua-5.1-work5/test/globals.lua -lua-5.1-work5/test/hello.lua -lua-5.1-work5/test/life.lua -lua-5.1-work5/test/luac.lua -lua-5.1-work5/test/printf.lua -lua-5.1-work5/test/readonly.lua -lua-5.1-work5/test/sieve.lua -lua-5.1-work5/test/sort.lua -lua-5.1-work5/test/table.lua -lua-5.1-work5/test/trace-calls.lua -lua-5.1-work5/test/trace-globals.lua -lua-5.1-work5/test/undefined.lua -lua-5.1-work5/test/xd.lua +MANIFEST contents of Lua 5.1 (work6) distribution on Wed May 18 10:13:40 BRST 2005 +lua-5.1-work6 +lua-5.1-work6/COPYRIGHT +lua-5.1-work6/HISTORY +lua-5.1-work6/INSTALL +lua-5.1-work6/MANIFEST +lua-5.1-work6/Makefile +lua-5.1-work6/README +lua-5.1-work6/doc +lua-5.1-work6/doc/contents.html +lua-5.1-work6/doc/logo.gif +lua-5.1-work6/doc/lua.1 +lua-5.1-work6/doc/lua.html +lua-5.1-work6/doc/luac.1 +lua-5.1-work6/doc/luac.html +lua-5.1-work6/doc/readme.html +lua-5.1-work6/etc +lua-5.1-work6/etc/Makefile +lua-5.1-work6/etc/README +lua-5.1-work6/etc/all.c +lua-5.1-work6/etc/lua.hpp +lua-5.1-work6/etc/lua.ico +lua-5.1-work6/etc/lua.pc +lua-5.1-work6/etc/min.c +lua-5.1-work6/etc/noparser.c +lua-5.1-work6/src +lua-5.1-work6/src/Makefile +lua-5.1-work6/src/lapi.c +lua-5.1-work6/src/lapi.h +lua-5.1-work6/src/lauxlib.c +lua-5.1-work6/src/lauxlib.h +lua-5.1-work6/src/lbaselib.c +lua-5.1-work6/src/lcode.c +lua-5.1-work6/src/lcode.h +lua-5.1-work6/src/ldblib.c +lua-5.1-work6/src/ldebug.c +lua-5.1-work6/src/ldebug.h +lua-5.1-work6/src/ldo.c +lua-5.1-work6/src/ldo.h +lua-5.1-work6/src/ldump.c +lua-5.1-work6/src/lfunc.c +lua-5.1-work6/src/lfunc.h +lua-5.1-work6/src/lgc.c +lua-5.1-work6/src/lgc.h +lua-5.1-work6/src/linit.c +lua-5.1-work6/src/liolib.c +lua-5.1-work6/src/llex.c +lua-5.1-work6/src/llex.h +lua-5.1-work6/src/llimits.h +lua-5.1-work6/src/lmathlib.c +lua-5.1-work6/src/lmem.c +lua-5.1-work6/src/lmem.h +lua-5.1-work6/src/loadlib.c +lua-5.1-work6/src/lobject.c +lua-5.1-work6/src/lobject.h +lua-5.1-work6/src/lopcodes.c +lua-5.1-work6/src/lopcodes.h +lua-5.1-work6/src/loslib.c +lua-5.1-work6/src/lparser.c +lua-5.1-work6/src/lparser.h +lua-5.1-work6/src/lstate.c +lua-5.1-work6/src/lstate.h +lua-5.1-work6/src/lstring.c +lua-5.1-work6/src/lstring.h +lua-5.1-work6/src/lstrlib.c +lua-5.1-work6/src/ltable.c +lua-5.1-work6/src/ltable.h +lua-5.1-work6/src/ltablib.c +lua-5.1-work6/src/ltm.c +lua-5.1-work6/src/ltm.h +lua-5.1-work6/src/lua.c +lua-5.1-work6/src/lua.h +lua-5.1-work6/src/luac.c +lua-5.1-work6/src/luaconf.h +lua-5.1-work6/src/lualib.h +lua-5.1-work6/src/lundump.c +lua-5.1-work6/src/lundump.h +lua-5.1-work6/src/lvm.c +lua-5.1-work6/src/lvm.h +lua-5.1-work6/src/lzio.c +lua-5.1-work6/src/lzio.h +lua-5.1-work6/src/print.c +lua-5.1-work6/test +lua-5.1-work6/test/README +lua-5.1-work6/test/bisect.lua +lua-5.1-work6/test/cf.lua +lua-5.1-work6/test/echo.lua +lua-5.1-work6/test/env.lua +lua-5.1-work6/test/factorial.lua +lua-5.1-work6/test/fib.lua +lua-5.1-work6/test/fibfor.lua +lua-5.1-work6/test/globals.lua +lua-5.1-work6/test/hello.lua +lua-5.1-work6/test/life.lua +lua-5.1-work6/test/luac.lua +lua-5.1-work6/test/printf.lua +lua-5.1-work6/test/readonly.lua +lua-5.1-work6/test/sieve.lua +lua-5.1-work6/test/sort.lua +lua-5.1-work6/test/table.lua +lua-5.1-work6/test/trace-calls.lua +lua-5.1-work6/test/trace-globals.lua +lua-5.1-work6/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index d01b51a95c..beb36e869d 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,9 @@ # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= -# Where to install. The installation starts in the src directory, so take -# care if INSTALL_TOP is not an absolute path. +# Where to install. The installation starts in the src directory, so take care +# if INSTALL_TOP is not an absolute path. (Man pages are installed from the +# doc directory.) # INSTALL_TOP= /usr/local INSTALL_BIN= $(INSTALL_TOP)/bin @@ -23,13 +24,15 @@ INSTALL_DATA= cp # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= -V= 5.1 - +# What to install. TO_BIN= lua luac TO_INC= lua.h luaconf.h lualib.h lauxlib.h -TO_LIB= liblua.a liblualib.a +TO_LIB= liblua.a TO_MAN= lua.1 luac.1 +# Lua version. Currently used only for messages. +V= 5.1 + all clean: cd src; $(MAKE) $@ @@ -66,6 +69,14 @@ echo: @echo "See also src/luaconf.h ." @echo "" +# echo private config parameters +pecho: + @echo "V = $(V)" + @echo "TO_BIN = $(TO_BIN)" + @echo "TO_INC = $(TO_INC)" + @echo "TO_LIB = $(TO_LIB)" + @echo "TO_MAN = $(TO_MAN)" + # echo config parameters as Lua code # uncomment the last sed expression if you want nil instead of empty strings lecho: diff --git a/etc/Makefile b/etc/Makefile index 51bbb40714..fc3d1468f4 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -20,10 +20,10 @@ all: @echo 'choose a target:' $(ALL) min: min.c - $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua -llualib + $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua $(MYLIBS) noparser: noparser.o - $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua -llualib $(MYLIBS) + $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) $(BIN)/luac $(TST)/hello.lua -./a.out luac.out -./a.out -e'a=1' diff --git a/etc/README b/etc/README index 77b6f19a9e..476267694e 100644 --- a/etc/README +++ b/etc/README @@ -13,6 +13,9 @@ lua.ico A Lua icon for Windows (and web sites, as favicon.ico). Drawn by hand by Markus Gritsch . +lua.pc + pkg-config data for Lua + min.c A minimal Lua interpreter. Good for learning and for starting your own. @@ -20,6 +23,3 @@ min.c noparser.c Linking with noparser.o avoids loading the parsing modules in lualib.a. Do "make noparser" to see a demo. - -saconfig.c - Configuration for Lua interpreter. diff --git a/etc/all.c b/etc/all.c index 720be1b255..dab68fac58 100644 --- a/etc/all.c +++ b/etc/all.c @@ -2,9 +2,7 @@ * all.c -- Lua core, libraries and interpreter in a single file */ -#define LUA_CORE -#define LUA_LIB -#define lua_c +#define luaall_c #include "lapi.c" #include "lcode.c" diff --git a/etc/lua.pc b/etc/lua.pc new file mode 100644 index 0000000000..c476f7e48b --- /dev/null +++ b/etc/lua.pc @@ -0,0 +1,24 @@ +# lua.pc -- pkg-config data for Lua + +# vars from install Makefile +# grep ^INSTALL_...= ../Makefile +INSTALL_TOP= /usr/local +INSTALL_BIN= $(INSTALL_TOP)/bin +INSTALL_INC= $(INSTALL_TOP)/include +INSTALL_LIB= $(INSTALL_TOP)/lib +INSTALL_MAN= $(INSTALL_TOP)/man/man1 +# grep ^V= ../Makefile +V= 5.1 + +prefix=${INSTALL_TOP} +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: Lua +Description: An Extensible Extension Language +Version: ${V} +Requires: +Libs: -L${libdir} -llua -lm +Cflags: -I${includedir} + diff --git a/etc/saconfig.c b/etc/saconfig.c deleted file mode 100644 index 676b38e110..0000000000 --- a/etc/saconfig.c +++ /dev/null @@ -1,65 +0,0 @@ -/* saconfig.c -- configuration for stand-alone Lua interpreter -* -* #define LUA_USERCONFIG to this file -* -* Here are the features that can be customized using #define: -* -*** Line editing and history: -* #define USE_READLINE to use the GNU readline library. -* Add "-lreadline -ltermcap" to MYLIBS. -* -* To use another library for this, use the code below as a start. -* Make sure you #define lua_readline and lua_saveline accordingly. -* -* If you do not #define lua_readline, you'll get a version based on fgets -* that uses a static buffer of size MAXINPUT. -*/ - -#define USE_READLINE - -#ifdef USE_READLINE -/* -* This section implements of lua_readline and lua_saveline for lua.c using -* the GNU readline and history libraries. It should also work with drop-in -* replacements such as editline and libedit (you may have to include -* different headers, though). -* -*/ - -#define lua_readline myreadline -#define lua_saveline mysaveline - -#include -#include -#include - -static int myreadline (lua_State *L, const char *prompt) { - char *s=readline(prompt); - if (s==NULL) - return 0; - else { - lua_pushstring(L,s); - lua_pushliteral(L,"\n"); - lua_concat(L,2); - free(s); - return 1; - } -} - -static void mysaveline (lua_State *L, const char *s) { - const char *p; - for (p=s; isspace(*p); p++) - ; - if (*p!=0) { - size_t n=strlen(s)-1; - if (s[n]!='\n') - add_history(s); - else { - lua_pushlstring(L,s,n); - s=lua_tostring(L,-1); - add_history(s); - lua_remove(L,-1); - } - } -} -#endif diff --git a/src/Makefile b/src/Makefile index 9ec6d349b3..60fd14c83c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,20 +9,21 @@ CFLAGS= -O2 -Wall $(MYCFLAGS) AR= ar rcu RANLIB= ranlib RM= rm -f +LIBS= -lm $(MYLIBS) MYCFLAGS= MYLDFLAGS= -MYLIBS= -lm -DL= -ldl -Wl,-E # enable dynamic loading in Linux +MYLIBS= +# enable dynamic loading and line editing in Linux +# MYCFLAGS= -DLUA_USE_DLOPEN -DLUA_USE_READLINE +# MYLIBS= -Wl,-E -ldl -lreadline -lhistory -lncurses # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= -CORE_T= liblua.a +LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ lundump.o lvm.o lzio.o - -LIB_T= liblualib.a LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ lstrlib.o loadlib.o linit.o @@ -30,11 +31,11 @@ LUA_T= lua LUA_O= lua.o LUAC_T= luac -LUAC_O= luac.o print.o lauxlib.o +LUAC_O= luac.o print.o -ALL_T= $(CORE_T) $(LIB_T) $(LUA_T) $(LUAC_T) ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) -ALL_A= $(CORE_T) $(LIB_T) +ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) +ALL_A= $(LUA_A) all: $(ALL_T) @@ -42,25 +43,21 @@ o: $(ALL_O) a: $(ALL_A) -$(CORE_T): $(CORE_O) - $(AR) $@ $? - $(RANLIB) $@ - -$(LIB_T): $(LIB_O) +$(LUA_A): $(CORE_O) $(LIB_O) $(AR) $@ $? $(RANLIB) $@ -$(LUA_T): $(LUA_O) $(CORE_T) $(LIB_T) - $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) -L. -llua -llualib $(MYLIBS) $(DL) +$(LUA_T): $(LUA_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) -$(LUAC_T): $(LUAC_O) $(CORE_T) - $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) -L. -llua $(MYLIBS) +$(LUAC_T): $(LUAC_O) $(LUA_A) + $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) clean: $(RM) $(ALL_T) $(ALL_O) depend: - @$(CC) $(CFLAGS) -MM *.c + @$(CC) $(CFLAGS) -MM l*.c print.c echo: @echo "CC = $(CC)" @@ -71,7 +68,6 @@ echo: @echo "MYCFLAGS = $(MYCFLAGS)" @echo "MYLDFLAGS = $(MYLDFLAGS)" @echo "MYLIBS = $(MYLIBS)" - @echo "DL = $(DL)" # DO NOT DELETE diff --git a/src/lapi.c b/src/lapi.c index 9b4b5b3301..1fe7916ad6 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,11 +1,12 @@ /* -** $Id: lapi.c,v 2.28 2005/02/23 17:30:22 roberto Exp $ +** $Id: lapi.c,v 2.41 2005/05/17 19:49:15 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include +#include #include #include @@ -87,14 +88,14 @@ static Table *getcurrenv (lua_State *L) { void luaA_pushobject (lua_State *L, const TValue *o) { setobj2s(L, L->top, o); - incr_top(L); + api_incr_top(L); } LUA_API int lua_checkstack (lua_State *L, int size) { int res; lua_lock(L); - if ((L->top - L->base + size) > MAXCSTACK) + if ((L->top - L->base + size) > LUAI_MAXCSTACK) res = 0; /* stack overflow */ else { luaD_checkstack(L, size); @@ -140,7 +141,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { setthvalue(L, L->top, L1); api_incr_top(L); lua_unlock(L); - lua_userstateopen(L1); + luai_userstateopen(L1); return L1; } @@ -318,7 +319,8 @@ LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { const TValue *o = index2adr(L, idx); if (tonumber(o, &n)) { lua_Integer res; - lua_number2integer(res, nvalue(o)); + lua_Number num = nvalue(o); + lua_number2integer(res, num); return res; } else @@ -332,33 +334,37 @@ LUA_API int lua_toboolean (lua_State *L, int idx) { } -LUA_API const char *lua_tostring (lua_State *L, int idx) { +LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2adr(L, idx); - if (ttisstring(o)) - return svalue(o); - else { - const char *s; + if (!ttisstring(o)) { lua_lock(L); /* `luaV_tostring' may create a new string */ - s = (luaV_tostring(L, o) ? svalue(o) : NULL); + if (!luaV_tostring(L, o)) { /* conversion failed? */ + if (len != NULL) *len = 0; + lua_unlock(L); + return NULL; + } luaC_checkGC(L); lua_unlock(L); - return s; } + if (len != NULL) *len = tsvalue(o)->len; + return svalue(o); } LUA_API size_t lua_objsize (lua_State *L, int idx) { StkId o = index2adr(L, idx); - if (ttisstring(o)) - return tsvalue(o)->len; - else if (ttisuserdata(o)) - return uvalue(o)->len; - else { - size_t l; - lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); - lua_unlock(L); - return l; + switch (ttype(o)) { + case LUA_TSTRING: return tsvalue(o)->len; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: return luaH_getn(hvalue(o)); + case LUA_TNUMBER: { + size_t l; + lua_lock(L); /* `luaV_tostring' may create a new string */ + l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); + lua_unlock(L); + return l; + } + default: return 0; } } @@ -523,7 +529,7 @@ LUA_API void lua_gettable (lua_State *L, int idx) { lua_lock(L); t = index2adr(L, idx); api_checkvalidindex(L, t); - luaV_gettable(L, t, L->top - 1, L->top - 1, NULL); + luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } @@ -535,7 +541,7 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_gettable(L, t, &key, L->top, NULL); + luaV_gettable(L, t, &key, L->top); api_incr_top(L); lua_unlock(L); } @@ -584,6 +590,9 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { case LUA_TUSERDATA: mt = uvalue(obj)->metatable; break; + default: + mt = G(L)->mt[ttype(obj)]; + break; } if (mt == NULL) res = 0; @@ -629,7 +638,7 @@ LUA_API void lua_settable (lua_State *L, int idx) { api_checknelems(L, 2); t = index2adr(L, idx); api_checkvalidindex(L, t); - luaV_settable(L, t, L->top - 2, L->top - 1, NULL); + luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); } @@ -643,7 +652,7 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_settable(L, t, &key, L->top - 1, NULL); + luaV_settable(L, t, &key, L->top - 1); L->top--; /* pop value */ lua_unlock(L); } @@ -678,7 +687,6 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { LUA_API int lua_setmetatable (lua_State *L, int objindex) { TValue *obj; Table *mt; - int res = 1; lua_lock(L); api_checknelems(L, 1); obj = index2adr(L, objindex); @@ -703,13 +711,13 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { break; } default: { - res = 0; /* cannot set */ + G(L)->mt[ttype(obj)] = mt; break; } } L->top--; lua_unlock(L); - return res; + return 1; } @@ -819,9 +827,9 @@ static void f_Ccall (lua_State *L, void *ud) { cl = luaF_newCclosure(L, 0, getcurrenv(L)); cl->c.f = c->func; setclvalue(L, L->top, cl); /* push function */ - incr_top(L); + api_incr_top(L); setpvalue(L->top, c->ud); /* push only argument */ - incr_top(L); + api_incr_top(L); luaD_call(L, L->top - 2, 0); } @@ -838,7 +846,7 @@ LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { } -LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, +LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname) { ZIO z; int status; @@ -851,7 +859,7 @@ LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, } -LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { int status; TValue *o; lua_lock(L); @@ -904,12 +912,15 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->GCthreshold = g->totalbytes - a; else g->GCthreshold = 0; - luaC_step(L); + while (g->GCthreshold <= g->totalbytes) + luaC_step(L); + if (g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ break; } - case LUA_GCSETPACE: { - res = g->gcpace; - g->gcpace = data; + case LUA_GCSETPAUSE: { + res = g->gcpause; + g->gcpause = data; break; } case LUA_GCSETSTEPMUL: { diff --git a/src/lapi.h b/src/lapi.h index 0ff8beb641..9d1d435649 100644 --- a/src/lapi.h +++ b/src/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -11,6 +11,6 @@ #include "lobject.h" -void luaA_pushobject (lua_State *L, const TValue *o); +LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); #endif diff --git a/src/lauxlib.c b/src/lauxlib.c index ac53db396c..964f5eb05d 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.129 2005/02/23 17:30:22 roberto Exp $ +** $Id: lauxlib.c,v 1.133 2005/05/17 19:49:15 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -25,12 +25,7 @@ #include "lauxlib.h" -/* number of prereserved references (for internal use) */ -#define RESERVED_REFS 2 - -/* reserved references */ -#define FREELIST_REF 1 /* free list of references */ -#define ARRAYSIZE_REF 2 /* array sizes */ +#define FREELIST_REF 0 /* free list of references */ /* convert a stack index to positive */ @@ -52,11 +47,12 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg); + return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + ar.name, extramsg); } if (ar.name == NULL) ar.name = "?"; - return luaL_error(L, "bad argument #%d to `%s' (%s)", + return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", narg, ar.name, extramsg); } @@ -163,9 +159,8 @@ LUALIB_API void luaL_checkany (lua_State *L, int narg) { LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { - const char *s = lua_tostring(L, narg); + const char *s = lua_tolstring(L, narg, len); if (!s) tag_error(L, narg, LUA_TSTRING); - if (len) *len = lua_strlen(L, narg); return s; } @@ -250,7 +245,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, luaL_setfield(L, LUA_GLOBALSINDEX, libname); } else if (!lua_istable(L, -1)) - luaL_error(L, "name conflict for library `%s'", libname); + luaL_error(L, "name conflict for library " LUA_QS, libname); lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_pushvalue(L, -2); lua_setfield(L, -2, libname); /* _LOADED[modname] = new table */ @@ -275,6 +270,8 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** ======================================================= */ +#ifndef luaL_getn + static int checkint (lua_State *L, int topop) { int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; lua_pop(L, topop); @@ -283,7 +280,7 @@ static int checkint (lua_State *L, int topop) { static void getsizes (lua_State *L) { - lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); + lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); if (lua_isnil(L, -1)) { /* no `size' table? */ lua_pop(L, 1); /* remove nil */ lua_newtable(L); /* create it */ @@ -292,7 +289,7 @@ static void getsizes (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ lua_pushvalue(L, -1); - lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ } } @@ -307,31 +304,6 @@ LUALIB_API void luaL_setn (lua_State *L, int t, int n) { } -/* find an `n' such that t[n] ~= nil and t[n+1] == nil */ -static int countn (lua_State *L, int t) { - int i = LUA_FIRSTINDEX - 1; - int j = 2; - /* find `i' such that i <= n < i*2 (= j) */ - for (;;) { - lua_rawgeti(L, t, j); - if (lua_isnil(L, -1)) break; - lua_pop(L, 1); - i = j; - j = i*2; - } - lua_pop(L, 1); - /* i <= n < j; do a binary search */ - while (i < j-1) { - int m = (i+j)/2; - lua_rawgeti(L, t, m); - if (lua_isnil(L, -1)) j = m; - else i = m; - lua_pop(L, 1); - } - return i - LUA_FIRSTINDEX + 1; -} - - LUALIB_API int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); @@ -341,9 +313,11 @@ LUALIB_API int luaL_getn (lua_State *L, int t) { if ((n = checkint(L, 2)) >= 0) return n; lua_getfield(L, t, "n"); /* else try t.n */ if ((n = checkint(L, 1)) >= 0) return n; - return countn(L, t); + return lua_objsize(L, t); } +#endif + /* }====================================================== */ @@ -392,7 +366,8 @@ LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, for (;;) { const char *fname; if ((p = pushnexttemplate(L, p)) == NULL) { - lua_pushfstring(L, "no readable `%s' in path `%s'", name, path); + lua_pushfstring(L, "no readable " LUA_QS " in path " LUA_QS "", + name, path); return NULL; } fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); @@ -523,9 +498,10 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B) { LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; - size_t vl = lua_strlen(L, -1); + size_t vl; + const char *s = lua_tolstring(L, -1, &vl); if (vl <= bufffree(B)) { /* fit into buffer? */ - memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */ + memcpy(B->p, s, vl); /* put it there */ B->p += vl; lua_pop(L, 1); /* remove from stack */ } @@ -562,11 +538,8 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ - ref = luaL_getn(L, t); - if (ref < RESERVED_REFS) - ref = RESERVED_REFS; /* skip reserved references */ + ref = lua_objsize(L, t); ref++; /* create new reference */ - luaL_setn(L, t, ref); } lua_rawseti(L, t, ref); return ref; diff --git a/src/lauxlib.h b/src/lauxlib.h index 82585cf41e..83c807e90f 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.74 2005/01/10 17:31:50 roberto Exp $ +** $Id: lauxlib.h,v 1.75 2005/03/29 16:20:48 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -15,6 +15,12 @@ #include "lua.h" +#if !LUA_COMPAT_GETN +#define luaL_getn(L,i) lua_objsize(L, i) +#define luaL_setn(L,i,j) ((void)0) /* no op! */ +#endif + + /* extra error code for `luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) diff --git a/src/lbaselib.c b/src/lbaselib.c index 9e1573cb9e..d69d83ff76 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.169 2005/02/28 17:24:41 roberto Exp $ +** $Id: lbaselib.c,v 1.176 2005/05/17 19:49:15 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -39,7 +39,8 @@ static int luaB_print (lua_State *L) { lua_call(L, 1, 1); s = lua_tostring(L, -1); /* get result */ if (s == NULL) - return luaL_error(L, "`tostring' must return a string to `print'"); + return luaL_error(L, LUA_QL("tostring") " must return a string to " + LUA_QL("print")); if (i>1) fputs("\t", stdout); fputs(s, stdout); lua_pop(L, 1); /* pop result */ @@ -148,7 +149,8 @@ static int luaB_setfenv (lua_State *L) { return 0; } else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) - luaL_error(L, "`setfenv' cannot change environment of given object"); + luaL_error(L, + LUA_QL("setfenv") " cannot change environment of given object"); return 1; } @@ -164,6 +166,7 @@ static int luaB_rawequal (lua_State *L) { static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); + lua_settop(L, 2); lua_rawget(L, 1); return 1; } @@ -172,6 +175,7 @@ static int luaB_rawset (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); luaL_checkany(L, 3); + lua_settop(L, 3); lua_rawset(L, 1); return 1; } @@ -185,9 +189,9 @@ static int luaB_gcinfo (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpace", "setstepmul", NULL}; + "count", "step", "setpause", "setstepmul", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPACE, LUA_GCSETSTEPMUL}; + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; int o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); int ex = luaL_optinteger(L, 2, 0); luaL_argcheck(L, o >= 0, 1, "invalid option"); @@ -238,7 +242,7 @@ static int luaB_ipairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ - lua_pushinteger(L, LUA_FIRSTINDEX - 1); /* and initial value */ + lua_pushinteger(L, 0); /* and initial value */ return 3; } @@ -292,11 +296,8 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { return NULL; } else if (lua_isstring(L, -1)) { - const char *res; lua_replace(L, 3); /* save string in a reserved stack slot */ - res = lua_tostring(L, 3); - *size = lua_strlen(L, 3); - return res; + return lua_tolstring(L, 3, size); } else luaL_error(L, "reader function must return a string"); return NULL; /* to avoid warnings */ @@ -330,13 +331,20 @@ static int luaB_assert (lua_State *L) { } +static int luaB_getn (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushinteger(L, lua_objsize(L, 1)); + return 1; +} + + static int luaB_unpack (lua_State *L) { - int i = luaL_optint(L, 2, LUA_FIRSTINDEX); + int i = luaL_optint(L, 2, 1); int e = luaL_optint(L, 3, -1); int n; luaL_checktype(L, 1, LUA_TTABLE); if (e == -1) - e = luaL_getn(L, 1) + LUA_FIRSTINDEX - 1; + e = luaL_getn(L, 1); n = e - i + 1; /* number of elements */ if (n <= 0) return 0; /* empty range */ luaL_checkstack(L, n, "table too big to unpack"); @@ -446,6 +454,7 @@ static const luaL_reg base_funcs[] = { {"tostring", luaB_tostring}, {"type", luaB_type}, {"assert", luaB_assert}, + {"getn", luaB_getn}, {"unpack", luaB_unpack}, {"select", luaB_select}, {"rawequal", luaB_rawequal}, diff --git a/src/lcode.c b/src/lcode.c index b40bc5a194..1e8d80fb21 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.9 2005/01/10 18:17:39 roberto Exp $ +** $Id: lcode.c,v 2.12 2005/03/16 16:59:21 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -603,19 +603,32 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { - if (op == OPR_MINUS) { - luaK_exp2val(fs, e); - if (e->k == VK && ttisnumber(&fs->f->k[e->info])) - e->info = luaK_numberK(fs, num_unm(nvalue(&fs->f->k[e->info]))); - else { + switch (op) { + case OPR_MINUS: { + luaK_exp2val(fs, e); + if (e->k == VK && ttisnumber(&fs->f->k[e->info])) + e->info = luaK_numberK(fs, luai_numunm(nvalue(&fs->f->k[e->info]))); + else { + luaK_exp2anyreg(fs, e); + freeexp(fs, e); + e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0); + e->k = VRELOCABLE; + } + break; + } + case OPR_NOT: { + codenot(fs, e); + break; + } + case OPR_SIZE: { luaK_exp2anyreg(fs, e); freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0); + e->info = luaK_codeABC(fs, OP_SIZ, 0, e->info, 0); e->k = VRELOCABLE; + break; } + default: lua_assert(0); } - else /* op == NOT */ - codenot(fs, e); } diff --git a/src/lcode.h b/src/lcode.h index 532b3478f8..19a3284e01 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.40 2004/10/04 19:01:53 roberto Exp $ +** $Id: lcode.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ ** grep "ORDER OPR" if you change these enums */ typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_POW, + OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE, @@ -34,7 +34,7 @@ typedef enum BinOpr { #define binopistest(op) ((op) >= OPR_NE) -typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_SIZE, OPR_NOUNOPR } UnOpr; #define getcode(fs,e) ((fs)->f->code[(e)->info]) @@ -43,36 +43,36 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) -int luaK_code (FuncState *fs, Instruction i, int line); -int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); -int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); -void luaK_fixline (FuncState *fs, int line); -void luaK_nil (FuncState *fs, int from, int n); -void luaK_reserveregs (FuncState *fs, int n); -void luaK_checkstack (FuncState *fs, int n); -int luaK_stringK (FuncState *fs, TString *s); -int luaK_numberK (FuncState *fs, lua_Number r); -void luaK_dischargevars (FuncState *fs, expdesc *e); -int luaK_exp2anyreg (FuncState *fs, expdesc *e); -void luaK_exp2nextreg (FuncState *fs, expdesc *e); -void luaK_exp2val (FuncState *fs, expdesc *e); -int luaK_exp2RK (FuncState *fs, expdesc *e); -void luaK_self (FuncState *fs, expdesc *e, expdesc *key); -void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); -void luaK_goiftrue (FuncState *fs, expdesc *e); -void luaK_goiffalse (FuncState *fs, expdesc *e); -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); -void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); -void luaK_setoneret (FuncState *fs, expdesc *e); -int luaK_jump (FuncState *fs); -void luaK_patchlist (FuncState *fs, int list, int target); -void luaK_patchtohere (FuncState *fs, int list); -void luaK_concat (FuncState *fs, int *l1, int l2); -int luaK_getlabel (FuncState *fs); -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); -void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); -void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); -void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); +LUAI_FUNC int luaK_code (FuncState *fs, Instruction i, int line); +LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); +LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +LUAI_FUNC void luaK_fixline (FuncState *fs, int line); +LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); +LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); +LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); +LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); +LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); +LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); +LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); +LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); +LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); +LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); +LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); +LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); +LUAI_FUNC int luaK_getlabel (FuncState *fs); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); +LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); +LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); #endif diff --git a/src/ldblib.c b/src/ldblib.c index 7f8bde1f58..6c1a17762d 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.93 2005/02/18 12:40:02 roberto Exp $ +** $Id: ldblib.c,v 1.98 2005/05/17 19:49:15 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -19,7 +19,7 @@ -static int getmetatable (lua_State *L) { +static int db_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); /* no metatable */ @@ -28,7 +28,7 @@ static int getmetatable (lua_State *L) { } -static int setmetatable (lua_State *L) { +static int db_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); @@ -38,17 +38,18 @@ static int setmetatable (lua_State *L) { } -static int getfenv (lua_State *L) { +static int db_getfenv (lua_State *L) { lua_getfenv(L, 1); return 1; } -static int setfenv (lua_State *L) { +static int db_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); if (lua_setfenv(L, 1) == 0) - luaL_error(L, "`setfenv' cannot change environment of given object"); + luaL_error(L, LUA_QL("setfenv") + " cannot change environment of given object"); return 1; } @@ -77,7 +78,18 @@ static lua_State *getthread (lua_State *L, int *arg) { } -static int getinfo (lua_State *L) { +static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { + if (L == L1) { + lua_pushvalue(L, -2); + lua_remove(L, -3); + } + else + lua_xmove(L1, L, 1); + lua_setfield(L, -2, fname); +} + + +static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); @@ -99,38 +111,30 @@ static int getinfo (lua_State *L) { if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); lua_newtable(L); - for (; *options; options++) { - switch (*options) { - case 'S': - settabss(L, "source", ar.source); - settabss(L, "short_src", ar.short_src); - settabsi(L, "linedefined", ar.linedefined); - settabss(L, "what", ar.what); - break; - case 'l': - settabsi(L, "currentline", ar.currentline); - break; - case 'u': - settabsi(L, "nups", ar.nups); - break; - case 'n': - settabss(L, "name", ar.name); - settabss(L, "namewhat", ar.namewhat); - break; - case 'f': - if (L == L1) - lua_pushvalue(L, -2); - else - lua_xmove(L1, L, 1); - lua_setfield(L, -2, "func"); - break; - } + if (strchr(options, 'S')) { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l')) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u')) + settabsi(L, "nups", ar.nups); + if (strchr(options, 'n')) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); } + if (strchr(options, 'L')) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f')) + treatstackoption(L, L1, "func"); return 1; /* return table */ } -static int getlocal (lua_State *L) { +static int db_getlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; @@ -151,7 +155,7 @@ static int getlocal (lua_State *L) { } -static int setlocal (lua_State *L) { +static int db_setlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; @@ -178,12 +182,12 @@ static int auxupvalue (lua_State *L, int get) { } -static int getupvalue (lua_State *L) { +static int db_getupvalue (lua_State *L) { return auxupvalue(L, 1); } -static int setupvalue (lua_State *L) { +static int db_setupvalue (lua_State *L) { luaL_checkany(L, 3); return auxupvalue(L, 0); } @@ -244,7 +248,7 @@ static void gethooktable (lua_State *L) { } -static int sethook (lua_State *L) { +static int db_sethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); if (lua_isnoneornil(L, arg+1)) { @@ -267,7 +271,7 @@ static int sethook (lua_State *L) { } -static int gethook (lua_State *L) { +static int db_gethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); char buff[5]; @@ -288,7 +292,7 @@ static int gethook (lua_State *L) { } -static int debug (lua_State *L) { +static int db_debug (lua_State *L) { for (;;) { char buffer[250]; fputs("lua_debug> ", stderr); @@ -308,7 +312,7 @@ static int debug (lua_State *L) { #define LEVELS1 12 /* size of the first part of the stack */ #define LEVELS2 10 /* size of the second part of the stack */ -static int errorfb (lua_State *L) { +static int db_errorfb (lua_State *L) { int level; int firstpart = 1; /* still before eventual `...' */ int arg; @@ -344,7 +348,7 @@ static int errorfb (lua_State *L) { if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); if (*ar.namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, " in function `%s'", ar.name); + lua_pushfstring(L, " in function " LUA_QS, ar.name); else { if (*ar.what == 'm') /* main? */ lua_pushfstring(L, " in main chunk"); @@ -362,19 +366,19 @@ static int errorfb (lua_State *L) { static const luaL_reg dblib[] = { - {"getmetatable", getmetatable}, - {"setmetatable", setmetatable}, - {"getfenv", getfenv}, - {"setfenv", setfenv}, - {"getlocal", getlocal}, - {"getinfo", getinfo}, - {"gethook", gethook}, - {"getupvalue", getupvalue}, - {"sethook", sethook}, - {"setlocal", setlocal}, - {"setupvalue", setupvalue}, - {"debug", debug}, - {"traceback", errorfb}, + {"getmetatable", db_getmetatable}, + {"setmetatable", db_setmetatable}, + {"getfenv", db_getfenv}, + {"setfenv", db_setfenv}, + {"getlocal", db_getlocal}, + {"getinfo", db_getinfo}, + {"gethook", db_gethook}, + {"getupvalue", db_getupvalue}, + {"sethook", db_sethook}, + {"setlocal", db_setlocal}, + {"setupvalue", db_setupvalue}, + {"debug", db_debug}, + {"traceback", db_errorfb}, {NULL, NULL} }; diff --git a/src/ldebug.c b/src/ldebug.c index 0456669f17..73a604ffb0 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.12 2004/12/20 15:50:00 roberto Exp $ +** $Id: ldebug.c,v 2.20 2005/05/17 19:49:15 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -30,17 +30,19 @@ -static const char *getfuncname (CallInfo *ci, const char **name); +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); -static int currentpc (CallInfo *ci) { +static int currentpc (lua_State *L, CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ + if (ci == L->ci) + ci->savedpc = L->savedpc; return pcRel(ci->savedpc, ci_func(ci)->l.p); } -static int currentline (CallInfo *ci) { - int pc = currentpc(ci); +static int currentline (lua_State *L, CallInfo *ci) { + int pc = currentpc(L, ci); if (pc < 0) return -1; /* only active lua functions have current-line information */ else @@ -88,15 +90,15 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { if (f_isLua(ci)) /* Lua function? */ level -= ci->tailcalls; /* skip lost tail calls */ } - if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ - else if (level < 0) { /* level is of a lost tail call */ + if (level == 0 && ci > L->base_ci) { /* level found? */ status = 1; - ar->i_ci = 0; + ar->i_ci = ci - L->base_ci; } - else { + else if (level < 0) { /* level is of a lost tail call? */ status = 1; - ar->i_ci = ci - L->base_ci; + ar->i_ci = 0; } + else status = 0; /* no such level */ lua_unlock(L); return status; } @@ -116,7 +118,7 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { ci = L->base_ci + ar->i_ci; fp = getluaproto(ci); if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(ci)); + name = luaF_getlocalname(fp, n, currentpc(L, ci)); if (name) luaA_pushobject(L, ci->base+(n-1)); /* push value */ } @@ -135,7 +137,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { fp = getluaproto(ci); L->top--; /* pop new value */ if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(ci)); + name = luaF_getlocalname(fp, n, currentpc(L, ci)); if (!name || name[0] == '(') /* `(' starts private locals */ name = NULL; else @@ -146,8 +148,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { } -static void funcinfo (lua_Debug *ar, StkId func) { - Closure *cl = clvalue(func); +static void funcinfo (lua_Debug *ar, Closure *cl) { if (cl->c.isC) { ar->source = "=[C]"; ar->linedefined = -1; @@ -155,7 +156,8 @@ static void funcinfo (lua_Debug *ar, StkId func) { } else { ar->source = getstr(cl->l.p->source); - ar->linedefined = cl->l.p->lineDefined; + ar->linedefined = cl->l.p->linedefined; + ar->lastlinedefined = cl->l.p->lastlinedefined; ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); @@ -165,17 +167,36 @@ static void funcinfo (lua_Debug *ar, StkId func) { static void info_tailcall (lua_State *L, lua_Debug *ar) { ar->name = ar->namewhat = ""; ar->what = "tail"; - ar->linedefined = ar->currentline = -1; + ar->lastlinedefined = ar->linedefined = ar->currentline = -1; ar->source = "=(tail call)"; luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); ar->nups = 0; - setnilvalue(L->top); +} + + +static void collectvalidlines (lua_State *L, Closure *f) { + if (f == NULL || f->c.isC) { + setnilvalue(L->top); + } + else { + Table *t = luaH_new(L, 0, 0); + int *lineinfo = f->l.p->lineinfo; + int i; + for (i=0; il.p->sizelineinfo; i++) + setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); + sethvalue(L, L->top, t); + } + incr_top(L); } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - StkId f, CallInfo *ci) { + Closure *f, CallInfo *ci) { int status = 1; + if (f == NULL) { + info_tailcall(L, ar); + return status; + } for (; *what; what++) { switch (*what) { case 'S': { @@ -183,25 +204,24 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'l': { - ar->currentline = (ci) ? currentline(ci) : -1; + ar->currentline = (ci) ? currentline(L, ci) : -1; break; } case 'u': { - ar->nups = clvalue(f)->c.nupvalues; + ar->nups = f->c.nupvalues; break; } case 'n': { - ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; + ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; if (ar->namewhat == NULL) { ar->namewhat = ""; /* not found */ ar->name = NULL; } break; } - case 'f': { - setobj2s(L, L->top, f); + case 'L': + case 'f': /* handled by lua_getinfo */ break; - } default: status = 0; /* invalid option */ } } @@ -210,23 +230,30 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { - int status = 1; + int status; + Closure *f = NULL; + CallInfo *ci = NULL; lua_lock(L); if (*what == '>') { - StkId f = L->top - 1; - if (!ttisfunction(f)) - luaG_runerror(L, "value for `lua_getinfo' is not a function"); - status = auxgetinfo(L, what + 1, ar, f, NULL); + StkId func = L->top - 1; + luai_apicheck(L, ttisfunction(func)); + what++; /* skip the '>' */ + f = clvalue(func); L->top--; /* pop function */ } else if (ar->i_ci != 0) { /* no tail call? */ - CallInfo *ci = L->base_ci + ar->i_ci; + ci = L->base_ci + ar->i_ci; lua_assert(ttisfunction(ci->func)); - status = auxgetinfo(L, what, ar, ci->func, ci); + f = clvalue(ci->func); } - else - info_tailcall(L, ar); - if (strchr(what, 'f')) incr_top(L); + status = auxgetinfo(L, what, ar, f, ci); + if (strchr(what, 'f')) { + if (f == NULL) setnilvalue(L->top); + else setclvalue(L, L->top, f); + incr_top(L); + } + if (strchr(what, 'L')) + collectvalidlines(L, f); lua_unlock(L); return status; } @@ -366,7 +393,6 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { if (reg >= a+3) last = pc; /* affect all regs above its call base */ break; } - case OP_TFORPREP: case OP_FORLOOP: case OP_FORPREP: checkreg(pt, a+3); @@ -446,10 +472,11 @@ static const char *kname (Proto *p, int c) { } -static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { +static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, + const char **name) { if (isLua(ci)) { /* a Lua function? */ Proto *p = ci_func(ci)->l.p; - int pc = currentpc(ci); + int pc = currentpc(L, ci); Instruction i; *name = luaF_getlocalname(p, stackpos+1, pc); if (*name) /* is a local? */ @@ -467,7 +494,7 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { int a = GETARG_A(i); int b = GETARG_B(i); /* move from `b' to `a' */ if (b < a) - return getobjname(ci, b, name); /* get name for `b' */ + return getobjname(L, ci, b, name); /* get name for `b' */ break; } case OP_GETTABLE: { @@ -492,15 +519,15 @@ static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { } -static const char *getfuncname (CallInfo *ci, const char **name) { +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { Instruction i; if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) return NULL; /* calling function is not Lua (or is unknown) */ ci--; /* calling function */ - i = ci_func(ci)->l.p->code[currentpc(ci)]; + i = ci_func(ci)->l.p->code[currentpc(L, ci)]; if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_TFORLOOP) - return getobjname(ci, GETARG_A(i), name); + return getobjname(L, ci, GETARG_A(i), name); else return NULL; /* no useful name can be found */ } @@ -519,9 +546,9 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? - getobjname(L->ci, o - L->base, &name) : NULL; + getobjname(L, L->ci, o - L->base, &name) : NULL; if (kind) - luaG_runerror(L, "attempt to %s %s `%s' (a %s value)", + luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); else luaG_runerror(L, "attempt to %s a %s value", op, t); @@ -558,7 +585,7 @@ static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(ci); + int line = currentline(L, ci); luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } diff --git a/src/ldebug.h b/src/ldebug.h index 5d8d2c2ee4..9c76aa10f0 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.2 2004/06/02 19:07:55 roberto Exp $ +** $Id: ldebug.h,v 2.3 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -18,13 +18,16 @@ #define resethookcount(L) (L->hookcount = L->basehookcount) -void luaG_typeerror (lua_State *L, const TValue *o, const char *opname); -void luaG_concaterror (lua_State *L, StkId p1, StkId p2); -void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2); -int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); -void luaG_runerror (lua_State *L, const char *fmt, ...); -void luaG_errormsg (lua_State *L); -int luaG_checkcode (const Proto *pt); -int luaG_checkopenop (Instruction i); +LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2); +LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaG_errormsg (lua_State *L); +LUAI_FUNC int luaG_checkcode (const Proto *pt); +LUAI_FUNC int luaG_checkopenop (Instruction i); #endif diff --git a/src/ldo.c b/src/ldo.c index da46d39d47..09e0a44dc4 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,10 +1,11 @@ /* -** $Id: ldo.c,v 2.14 2005/02/18 12:40:02 roberto Exp $ +** $Id: ldo.c,v 2.23 2005/05/03 19:01:17 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ +#include #include #include @@ -42,7 +43,7 @@ /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; - l_jmpbuf b; + luai_jmpbuf b; volatile int status; /* error code */ }; @@ -70,9 +71,10 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; - L_THROW(L, L->errorJmp); + LUAI_THROW(L, L->errorJmp); } else { + L->status = errcode; if (G(L)->panic) G(L)->panic(L); exit(EXIT_FAILURE); } @@ -84,7 +86,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { lj.status = 0; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; - L_TRY(L, &lj, + LUAI_TRY(L, &lj, (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ @@ -94,10 +96,10 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { static void restore_stack_limit (lua_State *L) { lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); - if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */ + if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ int inuse = (L->ci - L->base_ci); - if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUA_MAXCALLS); + if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUAI_MAXCALLS); } } @@ -114,6 +116,7 @@ static void correctstack (lua_State *L, TValue *oldstack) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; + lua_assert(lua_checkpc(L, ci)); } L->base = L->ci->base; } @@ -133,7 +136,7 @@ void luaD_reallocstack (lua_State *L, int newsize) { void luaD_reallocCI (lua_State *L, int newsize) { CallInfo *oldci = L->base_ci; luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); - L->size_ci = cast(unsigned short, newsize); + L->size_ci = newsize; L->ci = (L->ci - oldci) + L->base_ci; L->end_ci = L->base_ci + L->size_ci - 1; } @@ -148,11 +151,11 @@ void luaD_growstack (lua_State *L, int n) { static CallInfo *growCI (lua_State *L) { - if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */ + if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ luaD_throw(L, LUA_ERRERR); else { luaD_reallocCI(L, 2*L->size_ci); - if (L->size_ci > LUA_MAXCALLS) + if (L->size_ci > LUAI_MAXCALLS) luaG_runerror(L, "stack overflow"); } return ++L->ci; @@ -195,16 +198,18 @@ static StkId adjust_varargs (lua_State *L, int nfixargs, int actual, for (; actual < nfixargs; ++actual) setnilvalue(L->top++); } +#if LUA_COMPAT_VARARG if (style != NEWSTYLEVARARG) { /* compatibility with old-style vararg */ int nvar = actual - nfixargs; /* number of extra arguments */ luaC_checkGC(L); htab = luaH_new(L, nvar, 1); /* create `arg' table */ for (i=0; itop - nvar + i); + setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i); /* store counter in field `n' */ setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast(lua_Number, nvar)); } +#endif /* move fixed parameters to final position */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ @@ -249,6 +254,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); cl = &clvalue(func)->l; + L->ci->savedpc = L->savedpc; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; StkId st, base; @@ -269,7 +275,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { L->base = ci->base = base; ci->top = L->base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); - ci->savedpc = p->code; /* starting point */ + L->savedpc = p->code; /* starting point */ ci->tailcalls = 0; ci->nresults = nresults; for (st = L->top; st < ci->top; st++) @@ -321,6 +327,7 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { res = L->ci->func; /* res == final position of 1st result */ L->ci--; L->base = L->ci->base; /* restore base */ + L->savedpc = L->ci->savedpc; /* restore savedpc */ /* move results to correct place */ while (wanted != 0 && firstResult < L->top) { setobjs2s(L, res++, firstResult++); @@ -339,10 +346,10 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults) { - if (++L->nCcalls >= LUA_MAXCCALLS) { - if (L->nCcalls == LUA_MAXCCALLS) + if (++L->nCcalls >= LUAI_MAXCCALLS) { + if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3))) + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } if (luaD_precall(L, func, nResults) == PCRLUA) { /* is a Lua function? */ @@ -434,7 +441,7 @@ LUA_API int lua_yield (lua_State *L, int nresults) { int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; - unsigned short oldnCcalls = L->nCcalls; + int oldnCcalls = L->nCcalls; ptrdiff_t old_ci = saveci(L, L->ci); lu_byte old_allowhooks = L->allowhook; ptrdiff_t old_errfunc = L->errfunc; @@ -447,6 +454,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, L->nCcalls = oldnCcalls; L->ci = restoreci(L, old_ci); L->base = L->ci->base; + L->savedpc = L->ci->savedpc; L->allowhook = old_allowhooks; restore_stack_limit(L); } diff --git a/src/ldo.h b/src/ldo.h index ff5b652c36..b355b7e8cb 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.3 2004/09/08 14:23:09 roberto Exp $ +** $Id: ldo.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -47,20 +47,20 @@ /* type of protected functions, to be ran by `runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); -void luaD_resetprotection (lua_State *L); -int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); -void luaD_callhook (lua_State *L, int event, int line); -int luaD_precall (lua_State *L, StkId func, int nresults); -void luaD_call (lua_State *L, StkId func, int nResults); -int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t oldtop, ptrdiff_t ef); -void luaD_poscall (lua_State *L, int wanted, StkId firstResult); -void luaD_reallocCI (lua_State *L, int newsize); -void luaD_reallocstack (lua_State *L, int newsize); -void luaD_growstack (lua_State *L, int n); +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); +LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); +LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC void luaD_poscall (lua_State *L, int wanted, StkId firstResult); +LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); +LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); +LUAI_FUNC void luaD_growstack (lua_State *L, int n); -void luaD_throw (lua_State *L, int errcode); -int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); +LUAI_FUNC void luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); #endif + diff --git a/src/ldump.c b/src/ldump.c index 967596a157..0c9f00d182 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.9 2004/11/25 09:31:41 lhf Exp $ +** $Id: ldump.c,v 1.10 2005/05/12 00:26:50 lhf Exp $ ** save pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -136,7 +136,8 @@ static void DumpConstants(const Proto* f, DumpState* D) static void DumpFunction(const Proto* f, const TString* p, DumpState* D) { DumpString((f->source==p) ? NULL : f->source,D); - DumpInt(f->lineDefined,D); + DumpInt(f->linedefined,D); + DumpInt(f->lastlinedefined,D); DumpByte(f->nups,D); DumpByte(f->numparams,D); DumpByte(f->is_vararg,D); diff --git a/src/lfunc.c b/src/lfunc.c index 1c95e78193..c9286d9159 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.9 2005/02/18 12:40:02 roberto Exp $ +** $Id: lfunc.c,v 2.11 2005/05/05 20:47:02 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -105,10 +105,6 @@ void luaF_close (lua_State *L, StkId level) { else { unlinkupval(uv); setobj(L, &uv->u.value, uv->v); - if (isgray(o)) { - gray2black(o); /* closed upvalues are never gray */ - luaC_barrier(L, uv, &uv->u.value); - } uv->v = &uv->u.value; /* now current value lives here */ luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ } @@ -135,7 +131,8 @@ Proto *luaF_newproto (lua_State *L) { f->lineinfo = NULL; f->sizelocvars = 0; f->locvars = NULL; - f->lineDefined = 0; + f->linedefined = 0; + f->lastlinedefined = 0; f->source = NULL; return f; } diff --git a/src/lfunc.h b/src/lfunc.h index 93f7b88851..2e02419bd6 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.3 2005/02/18 12:40:02 roberto Exp $ +** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -18,17 +18,17 @@ cast(int, sizeof(TValue *)*((n)-1))) -Proto *luaF_newproto (lua_State *L); -Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); -Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); -UpVal *luaF_newupval (lua_State *L); -UpVal *luaF_findupval (lua_State *L, StkId level); -void luaF_close (lua_State *L, StkId level); -void luaF_freeproto (lua_State *L, Proto *f); -void luaF_freeclosure (lua_State *L, Closure *c); -void luaF_freeupval (lua_State *L, UpVal *uv); - -const char *luaF_getlocalname (const Proto *func, int local_number, int pc); +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC UpVal *luaF_newupval (lua_State *L); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_close (lua_State *L, StkId level); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); +LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); #endif diff --git a/src/lgc.c b/src/lgc.c index dd7a6850a7..9257d2bcd8 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.27 2005/02/23 17:30:22 roberto Exp $ +** $Id: lgc.c,v 2.32 2005/05/05 15:34:03 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -57,7 +57,7 @@ reallymarkobject(g, obj2gco(t)); } -#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpace) +#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) static void removeentry (Node *n) { @@ -242,7 +242,7 @@ static void traverseclosure (global_State *g, Closure *cl) { static void checkstacksizes (lua_State *L, StkId max) { int ci_used = L->ci - L->base_ci; /* number of `ci' in use */ int s_used = max - L->stack; /* part of stack in use */ - if (L->size_ci > LUA_MAXCALLS) /* handling overflow? */ + if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ return; /* do not touch the stacks */ if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ @@ -493,6 +493,13 @@ void luaC_freeall (lua_State *L) { } +static void markmt (global_State *g) { + int i; + for (i=0; imt[i]) markobject(g, g->mt[i]); +} + + /* mark root set */ static void markroot (lua_State *L) { global_State *g = G(L); @@ -503,6 +510,7 @@ static void markroot (lua_State *L) { /* make global table be traversed before main stack */ markvalue(g, gt(g->mainthread)); markvalue(g, registry(L)); + markmt(g); g->gcstate = GCSpropagate; } @@ -529,6 +537,7 @@ static void atomic (lua_State *L) { g->weak = NULL; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ + markmt(g); /* mark basic metatables (again) */ propagateall(g); /* remark gray again */ g->gray = g->grayagain; @@ -539,7 +548,7 @@ static void atomic (lua_State *L) { propagateall(g); /* remark, to propagate `preserveness' */ cleartable(g->weak); /* remove collected objects from weak tables */ /* flip current white */ - g->currentwhite = otherwhite(g); + g->currentwhite = cast(lu_byte, otherwhite(g)); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; g->gcstate = GCSsweepstring; diff --git a/src/lgc.h b/src/lgc.h index 43d4009a43..4fc4a81e93 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.12 2005/02/23 17:30:22 roberto Exp $ +** $Id: lgc.h,v 2.13 2005/04/25 19:24:10 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -95,15 +95,15 @@ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ luaC_barrierback(L,obj2gco(p)); } -size_t luaC_separateudata (lua_State *L, int all); -void luaC_callGCTM (lua_State *L); -void luaC_freeall (lua_State *L); -void luaC_step (lua_State *L); -void luaC_fullgc (lua_State *L); -void luaC_link (lua_State *L, GCObject *o, lu_byte tt); -void luaC_linkupval (lua_State *L, UpVal *uv); -void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); -void luaC_barrierback (lua_State *L, GCObject *o); +LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); +LUAI_FUNC void luaC_callGCTM (lua_State *L); +LUAI_FUNC void luaC_freeall (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_fullgc (lua_State *L); +LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); +LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback (lua_State *L, GCObject *o); #endif diff --git a/src/linit.c b/src/linit.c index 24f70edbc7..afcd338bec 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.9 2005/02/18 12:40:02 roberto Exp $ +** $Id: linit.c,v 1.11 2005/04/13 17:24:20 roberto Exp $ ** Initialization of libraries for lua.c ** See Copyright Notice in lua.h */ @@ -22,19 +22,17 @@ static const luaL_reg lualibs[] = { {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, - {"", luaopen_loadlib}, + {LUA_LOADLIBNAME, luaopen_loadlib}, {NULL, NULL} }; -LUALIB_API int luaopen_stdlibs (lua_State *L) { +LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_reg *lib = lualibs; for (; lib->func; lib++) { - lib->func(L); /* open library */ - lua_settop(L, 0); /* discard any results */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_replace(L, LUA_ENVIRONINDEX); /* restore environment */ + lua_pushcfunction(L, lib->func); + lua_pushstring(L, lib->name); + lua_call(L, 1, 0); } - return 0; } diff --git a/src/liolib.c b/src/liolib.c index 854ba3bae6..1dba7eff83 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.58 2005/02/18 12:40:02 roberto Exp $ +** $Id: liolib.c,v 2.60 2005/05/16 21:19:00 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -191,9 +191,9 @@ static int io_output (lua_State *L) { static int io_readline (lua_State *L); -static void aux_lines (lua_State *L, int idx, int close) { +static void aux_lines (lua_State *L, int idx, int toclose) { lua_pushvalue(L, idx); - lua_pushboolean(L, close); /* close/not close file when finished */ + lua_pushboolean(L, toclose); /* close/not close file when finished */ lua_pushcclosure(L, io_readline, 2); } @@ -319,8 +319,6 @@ static int g_read (lua_State *L, FILE *f, int first) { read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = 1; /* always success */ break; - case 'w': /* word */ - return luaL_error(L, "obsolete option `*w' to `read'"); default: return luaL_argerror(L, n, "invalid format"); } diff --git a/src/llex.c b/src/llex.c index 3940b95574..b663b43299 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.9 2004/12/03 20:54:12 roberto Exp $ +** $Id: llex.c,v 2.12 2005/05/17 19:49:15 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -102,7 +102,7 @@ void luaX_lexerror (LexState *ls, const char *msg, int token) { luaO_chunkid(buff, getstr(ls->source), MAXSRC); msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); if (token) - luaO_pushfstring(ls->L, "%s near `%s'", msg, txtToken(ls, token)); + luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); } @@ -202,6 +202,7 @@ static int skip_sep (LexState *ls) { static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { int cont = 0; + (void)(cont); /* avoid warnings when `cont' is not used */ save_and_next(ls); /* skip 2nd `[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ @@ -211,27 +212,41 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { luaX_lexerror(ls, (seminfo) ? "unfinished long string" : "unfinished long comment", TK_EOS); break; /* to avoid warnings */ - case '[': +#if defined(LUA_COMPAT_LSTR) + case '[': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `[' */ cont++; +#if LUA_COMPAT_LSTR == 1 + if (sep == 0) + luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); +#endif } - continue; - case ']': + break; + } +#endif + case ']': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `]' */ - if (cont-- == 0) goto endloop; +#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 + cont--; + if (sep == 0 && cont >= 0) break; +#endif + goto endloop; } - continue; + break; + } case '\n': - case '\r': + case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ - continue; - default: + break; + } + default: { if (seminfo) save_and_next(ls); else next(ls); + } } } endloop: if (seminfo) diff --git a/src/llex.h b/src/llex.h index a16bba8dcf..8bff8f43c6 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.52 2004/12/03 20:54:12 roberto Exp $ +** $Id: llex.h,v 1.54 2005/04/25 19:24:10 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -63,17 +63,17 @@ typedef struct LexState { ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ TString *source; /* current source name */ - int nestlevel; /* level of nested non-terminals */ } LexState; -void luaX_init (lua_State *L); -void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source); -TString *luaX_newstring (LexState *LS, const char *str, size_t l); -int luaX_lex (LexState *LS, SemInfo *seminfo); -void luaX_lexerror (LexState *ls, const char *msg, int token); -void luaX_syntaxerror (LexState *ls, const char *s); -const char *luaX_token2str (LexState *ls, int token); +LUAI_FUNC void luaX_init (lua_State *L); +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, + TString *source); +LUAI_FUNC TString *luaX_newstring (LexState *LS, const char *str, size_t l); +LUAI_FUNC int luaX_lex (LexState *LS, SemInfo *seminfo); +LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); +LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); +LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); #endif diff --git a/src/llimits.h b/src/llimits.h index 5b11e82069..7a536a1624 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.63 2005/01/14 14:19:42 roberto Exp $ +** $Id: llimits.h,v 1.65 2005/03/09 16:28:07 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -15,12 +15,14 @@ #include "lua.h" +#define api_check luai_apicheck -typedef LUA_UINT32 lu_int32; -typedef LU_MEM lu_mem; +typedef LUAI_UINT32 lu_int32; -typedef L_MEM l_mem; +typedef LUAI_UMEM lu_mem; + +typedef LUAI_MEM l_mem; @@ -45,11 +47,11 @@ typedef unsigned char lu_byte; /* type to ensure maximum alignment */ -typedef LUSER_ALIGNMENT_T L_Umaxalign; +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; /* result of a `usual argument conversion' over lua_Number */ -typedef LUA_UACNUMBER l_uacNumber; +typedef LUAI_UACNUMBER l_uacNumber; #define check_exp(c,e) (lua_assert(c), (e)) diff --git a/src/lmathlib.c b/src/lmathlib.c index add8897097..bba99b0dc9 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.62 2005/01/07 20:00:33 roberto Exp $ +** $Id: lmathlib.c,v 1.63 2005/03/04 18:57:03 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -33,16 +33,31 @@ static int math_sin (lua_State *L) { return 1; } +static int math_sinh (lua_State *L) { + lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); + return 1; +} + static int math_cos (lua_State *L) { lua_pushnumber(L, cos(luaL_checknumber(L, 1))); return 1; } +static int math_cosh (lua_State *L) { + lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); + return 1; +} + static int math_tan (lua_State *L) { lua_pushnumber(L, tan(luaL_checknumber(L, 1))); return 1; } +static int math_tanh (lua_State *L) { + lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); + return 1; +} + static int math_asin (lua_State *L) { lua_pushnumber(L, asin(luaL_checknumber(L, 1))); return 1; @@ -78,6 +93,14 @@ static int math_mod (lua_State *L) { return 1; } +static int math_modf (lua_State *L) { + double ip; + double fp = modf(luaL_checknumber(L, 1), &ip); + lua_pushnumber(L, ip); + lua_pushnumber(L, fp); + return 2; +} + static int math_sqrt (lua_State *L) { lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); return 1; @@ -192,8 +215,11 @@ static int math_randomseed (lua_State *L) { static const luaL_reg mathlib[] = { {"abs", math_abs}, {"sin", math_sin}, + {"sinh", math_sinh}, {"cos", math_cos}, + {"cosh", math_cosh}, {"tan", math_tan}, + {"tanh", math_tanh}, {"asin", math_asin}, {"acos", math_acos}, {"atan", math_atan}, @@ -201,6 +227,7 @@ static const luaL_reg mathlib[] = { {"ceil", math_ceil}, {"floor", math_floor}, {"mod", math_mod}, + {"modf", math_modf}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, {"sqrt", math_sqrt}, @@ -225,6 +252,8 @@ LUALIB_API int luaopen_math (lua_State *L) { luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); + lua_pushnumber(L, HUGE_VAL); + lua_setfield(L, -2, "huge"); return 1; } diff --git a/src/lmem.h b/src/lmem.h index 13a1658b80..19df1fbb6c 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.29 2004/12/01 15:46:18 roberto Exp $ +** $Id: lmem.h,v 1.31 2005/04/25 19:24:10 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -16,18 +16,10 @@ #define MEMERRMSG "not enough memory" -void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); - -void *luaM_toobig (lua_State *L); - #define luaM_reallocv(L,b,on,n,e) \ - ((cast(unsigned int, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ - luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ - luaM_toobig(L)) - - -void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, - int limit, const char *errormsg); + ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ + luaM_toobig(L)) #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) @@ -46,5 +38,12 @@ void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) +LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void *luaM_toobig (lua_State *L); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, + size_t size_elem, int limit, + const char *errormsg); + #endif diff --git a/src/loadlib.c b/src/loadlib.c index 957310b6ad..1ae9ab57ad 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,11 +1,11 @@ /* -** $Id: loadlib.c,v 1.18 2005/02/28 15:58:48 roberto Exp $ +** $Id: loadlib.c,v 1.28 2005/05/17 19:49:15 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h -* -* This module contains an implementation of loadlib for Unix systems -* that have dlfcn, an implementation for Darwin (Mac OS X), an -* implementation for Windows, and a stub for other systems. +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Darwin (Mac OS X), an +** implementation for Windows, and a stub for other systems. */ @@ -21,6 +21,17 @@ #include "lualib.h" +/* environment variables that hold the search path for packages */ +#define LUA_PATH "LUA_PATH" +#define LUA_CPATH "LUA_CPATH" + +/* prefix for open functions in C libraries */ +#define LUA_POF "luaopen_" + +/* separator for open functions in C libraries */ +#define LUA_OFSEP "_" + + #define LIBPREFIX "LOADLIB: " #define POF LUA_POF @@ -33,7 +44,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); -#if defined(USE_DLOPEN) +#if defined(LUA_DL_DLOPEN) /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. @@ -67,7 +78,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { -#elif defined(USE_DLL) +#elif defined(LUA_DL_DLL) /* ** {====================================================================== ** This is an implementation of loadlib for Windows using native functions. @@ -82,7 +93,7 @@ static void pusherror (lua_State *L) { char buffer[128]; if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buffer, sizeof(buffer), NULL)) - lua_pushstring(L,buffer); + lua_pushstring(L, buffer); else lua_pushfstring(L, "system error %d\n", error); } @@ -109,7 +120,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { -#elif defined(USE_DYLD) +#elif defined(LUA_DL_DYLD) /* ** {====================================================================== ** Native Mac OS X / Darwin Implementation @@ -119,6 +130,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #include +/* Mac appends a `_' before C function names */ #undef POF #define POF "_" LUA_POF @@ -179,7 +191,7 @@ static void *ll_load (lua_State *L, const char *path) { static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); if (nss == NULL) { - lua_pushfstring(L, "symbol `%s' not found", sym); + lua_pushfstring(L, "symbol " LUA_QS " not found", sym); return NULL; } return (lua_CFunction)NSAddressOfSymbol(nss); @@ -200,6 +212,12 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #define LIB_FAIL "absent" +#if defined(__ELF__) || defined(__sun) || defined(sgi) || defined(__hpux) +#define DLMSG LUA_QL("loadlib") " not enabled; check your Lua installation" +#else +#define DLMSG LUA_QL("loadlib") " not supported" +#endif + static void ll_unloadlib (void *lib) { (void)lib; /* to avoid warnings */ } @@ -207,14 +225,14 @@ static void ll_unloadlib (void *lib) { static void *ll_load (lua_State *L, const char *path) { (void)path; /* to avoid warnings */ - lua_pushliteral(L,"`loadlib' not supported"); + lua_pushliteral(L, DLMSG); return NULL; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { (void)lib; (void)sym; /* to avoid warnings */ - lua_pushliteral(L,"`loadlib' not supported"); + lua_pushliteral(L, DLMSG); return NULL; } @@ -296,22 +314,25 @@ static int ll_loadlib (lua_State *L) { static int loader_Lua (lua_State *L) { const char *name = luaL_checkstring(L, 1); const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); - const char *path; + const char *path = NULL; +#if LUA_COMPAT_PATH /* try first `LUA_PATH' for compatibility */ lua_pushstring(L, "LUA_PATH"); lua_rawget(L, LUA_GLOBALSINDEX); path = lua_tostring(L, -1); +#endif if (!path) { lua_pop(L, 1); lua_getfield(L, LUA_ENVIRONINDEX, "path"); path = lua_tostring(L, -1); } if (path == NULL) - luaL_error(L, "`package.path' must be a string"); + luaL_error(L, LUA_QL("package.path") " must be a string"); fname = luaL_searchpath(L, fname, path); if (fname == NULL) return 0; /* library not found in this path */ if (luaL_loadfile(L, fname) != 0) - luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); + luaL_error(L, "error loading package " LUA_QS " (%s)", + name, lua_tostring(L, -1)); return 1; /* library loaded successfully */ } @@ -324,13 +345,14 @@ static int loader_C (lua_State *L) { lua_getfield(L, LUA_ENVIRONINDEX, "cpath"); path = lua_tostring(L, -1); if (path == NULL) - luaL_error(L, "`package.cpath' must be a string"); + luaL_error(L, LUA_QL("package.cpath") " must be a string"); fname = luaL_searchpath(L, fname, path); if (fname == NULL) return 0; /* library not found in this path */ funcname = luaL_gsub(L, name, ".", LUA_OFSEP); funcname = lua_pushfstring(L, "%s%s", POF, funcname); if (ll_loadfunc(L, fname, funcname) != 1) - luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -2)); + luaL_error(L, "error loading package " LUA_QS " (%s)", + name, lua_tostring(L, -2)); return 1; /* library loaded successfully */ } @@ -338,7 +360,7 @@ static int loader_C (lua_State *L) { static int loader_preload (lua_State *L) { lua_getfield(L, LUA_ENVIRONINDEX, "preload"); if (!lua_istable(L, -1)) - luaL_error(L, "`package.preload' must be a table"); + luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, luaL_checkstring(L, 1)); return 1; } @@ -358,11 +380,11 @@ static int ll_require (lua_State *L) { /* iterate over available loaders */ lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); if (!lua_istable(L, -1)) - luaL_error(L, "`package.loaders' must be a table"); + luaL_error(L, LUA_QL("package.loaders") " must be a table"); for (i=1;; i++) { lua_rawgeti(L, -1, i); /* get a loader */ if (lua_isnil(L, -1)) - return luaL_error(L, "package `%s' not found", name); + return luaL_error(L, "package " LUA_QS " not found", name); lua_pushstring(L, name); lua_call(L, 1, 1); /* call it */ if (lua_isnil(L, -1)) lua_pop(L, 1); @@ -401,7 +423,7 @@ static int ll_module (lua_State *L) { luaL_setfield(L, LUA_GLOBALSINDEX, modname); } else if (!lua_istable(L, -1)) - return luaL_error(L, "name conflict for module `%s'", modname); + return luaL_error(L, "name conflict for module " LUA_QS, modname); /* check whether table already has a _NAME field */ lua_getfield(L, -1, "_NAME"); if (!lua_isnil(L, -1)) /* is table an initialized module? */ @@ -434,7 +456,6 @@ static int ll_module (lua_State *L) { static const luaL_reg ll_funcs[] = { - {"loadlib", ll_loadlib}, {"require", ll_require}, {"module", ll_module}, {NULL, NULL} @@ -455,7 +476,7 @@ LUALIB_API int luaopen_loadlib (lua_State *L) { /* create `package' table */ lua_newtable(L); lua_pushvalue(L, -1); - lua_setglobal(L, "package"); + lua_setglobal(L, LUA_LOADLIBNAME); lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, "_PACKAGE"); lua_pushvalue(L, -1); @@ -485,6 +506,13 @@ LUALIB_API int luaopen_loadlib (lua_State *L) { /* set field `preload' */ lua_newtable(L); lua_setfield(L, -2, "preload"); + /* create `loadlib' function */ + lua_pushcfunction(L, ll_loadlib); +#if LUA_COMPAT_LOADLIB + lua_pushvalue(L, -1); + lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); +#endif + lua_setfield(L, -2, "loadlib"); lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, ll_funcs, 0); /* open lib into global table */ return 1; diff --git a/src/lobject.c b/src/lobject.c index f4464474d9..98b083519c 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,11 +1,12 @@ /* -** $Id: lobject.c,v 2.8 2005/01/10 18:17:39 roberto Exp $ +** $Id: lobject.c,v 2.13 2005/05/16 21:19:00 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include #include +#include #include #include @@ -28,7 +29,8 @@ const TValue luaO_nilobject = {{NULL}, LUA_TNIL}; /* ** converts an integer to a "floating point byte", represented as -** (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm) +** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if +** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { int e = 0; /* expoent */ @@ -73,7 +75,7 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { case LUA_TNIL: return 1; case LUA_TNUMBER: - return num_eq(nvalue(t1), nvalue(t2)); + return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: @@ -182,7 +184,7 @@ void luaO_chunkid (char *out, const char *source, int bufflen) { if (*source == '@') { int l; source++; /* skip the `@' */ - bufflen -= sizeof(" `...' "); + bufflen -= sizeof(" '...' "); l = strlen(source); strcpy(out, ""); if (l>bufflen) { diff --git a/src/lobject.h b/src/lobject.h index 967b46c74f..4a77a539df 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.11 2005/02/18 12:40:02 roberto Exp $ +** $Id: lobject.h,v 2.13 2005/05/05 20:47:02 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -244,7 +244,8 @@ typedef struct Proto { int sizelineinfo; int sizep; /* size of `p' */ int sizelocvars; - int lineDefined; + int linedefined; + int lastlinedefined; GCObject *gclist; lu_byte nups; /* number of upvalues */ lu_byte numparams; @@ -360,16 +361,15 @@ extern const TValue luaO_nilobject; #define ceillog2(x) (luaO_log2((x)-1) + 1) -int luaO_log2 (unsigned int x); -int luaO_int2fb (unsigned int x); -int luaO_fb2int (int x); - -int luaO_rawequalObj (const TValue *t1, const TValue *t2); -int luaO_str2d (const char *s, lua_Number *result); - -const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); -const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); -void luaO_chunkid (char *out, const char *source, int len); +LUAI_FUNC int luaO_log2 (unsigned int x); +LUAI_FUNC int luaO_int2fb (unsigned int x); +LUAI_FUNC int luaO_fb2int (int x); +LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); +LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, int len); #endif diff --git a/src/lopcodes.c b/src/lopcodes.c index 24cd31d5ab..46b30ba923 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.30 2004/12/02 12:59:10 roberto Exp $ +** $Id: lopcodes.c,v 1.33 2005/05/04 20:42:28 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -32,9 +32,11 @@ const char *const luaP_opnames[NUM_OPCODES+1] = { "SUB", "MUL", "DIV", + "MOD", "POW", "UNM", "NOT", + "SIZ", "CONCAT", "JMP", "EQ", @@ -47,7 +49,6 @@ const char *const luaP_opnames[NUM_OPCODES+1] = { "FORLOOP", "FORPREP", "TFORLOOP", - "TFORPREP", "SETLIST", "CLOSE", "CLOSURE", @@ -76,9 +77,11 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_SIZ */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ @@ -91,7 +94,6 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ - ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_TFORPREP */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ diff --git a/src/lopcodes.h b/src/lopcodes.h index dfbcaffe1e..77f60c000e 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.114 2004/12/02 12:59:10 roberto Exp $ +** $Id: lopcodes.h,v 1.119 2005/05/04 20:42:28 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -51,9 +51,9 @@ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ /* ** limits for opcode arguments. ** we use (signed) int to manipulate most arguments, -** so they must fit in LUA_BITSINT-1 bits (-1 for sign) +** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) */ -#if SIZE_Bx < LUA_BITSINT-1 +#if SIZE_Bx < LUAI_BITSINT-1 #define MAXARG_Bx ((1<>1) /* `sBx' is signed */ #else @@ -172,9 +172,11 @@ OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ +OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ OP_UNM,/* A B R(A) := -R(B) */ OP_NOT,/* A B R(A) := not R(B) */ +OP_SIZ,/* A B R(A) := size of R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ @@ -195,8 +197,6 @@ OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */ OP_TFORLOOP,/* A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); if R(A+2) ~= nil then pc++ */ -OP_TFORPREP,/* A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next; - pc+=sBx */ OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ diff --git a/src/loslib.c b/src/loslib.c index dad959e2b5..52532143e9 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.4 2005/01/10 19:16:29 roberto Exp $ +** $Id: loslib.c,v 1.9 2005/05/17 19:49:15 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -57,16 +57,13 @@ static int io_rename (lua_State *L) { static int io_tmpname (lua_State *L) { -#if !USE_TMPNAME - luaL_error(L, "`tmpname' not supported"); - return 0; -#else - char buff[L_tmpnam]; - if (tmpnam(buff) != buff) - return luaL_error(L, "unable to generate a unique filename in `tmpname'"); + char buff[LUA_TMPNAMBUFSIZE]; + int err; + lua_tmpnam(buff, err); + if (err) + return luaL_error(L, "unable to generate a unique filename"); lua_pushstring(L, buff); return 1; -#endif } @@ -116,7 +113,7 @@ static int getfield (lua_State *L, const char *key, int d) { res = (int)lua_tointeger(L, -1); else { if (d < 0) - return luaL_error(L, "field `%s' missing in date table", key); + return luaL_error(L, "field " LUA_QS " missing in date table", key); res = d; } lua_pop(L, 1); @@ -154,7 +151,7 @@ static int io_date (lua_State *L) { if (strftime(b, sizeof(b), s, stm)) lua_pushstring(L, b); else - return luaL_error(L, "`date' format too long"); + return luaL_error(L, LUA_QL("date") " format too long"); } return 1; } diff --git a/src/lparser.c b/src/lparser.c index 19e048ce3f..54facfc460 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.13 2005/01/05 18:20:51 roberto Exp $ +** $Id: lparser.c,v 2.27 2005/05/17 19:49:15 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -33,10 +33,6 @@ #define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) -#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ - luaX_lexerror(ls, "chunk has too many syntax levels", 0) -#define leavelevel(ls) ((ls)->nestlevel--) - /* ** nodes for block list (list of active blocks) @@ -86,15 +82,15 @@ static void anchor_token (LexState *ls) { static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token))); + luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); } static void errorlimit (FuncState *fs, int limit, const char *what) { - const char *msg = (fs->f->lineDefined == 0) ? + const char *msg = (fs->f->linedefined == 0) ? luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : luaO_pushfstring(fs->L, "function at line %d has more than %d %s", - fs->f->lineDefined, limit, what); + fs->f->linedefined, limit, what); luaX_lexerror(fs->ls, msg, 0); } @@ -129,7 +125,7 @@ static void check_match (LexState *ls, int what, int who, int where) { error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - "`%s' expected (to close `%s' at line %d)", + LUA_QS " expected (to close " LUA_QS " at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } @@ -167,7 +163,7 @@ static int registerlocalvar (LexState *ls, TString *varname) { Proto *f = fs->f; int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, USHRT_MAX, "too many local variables"); + LocVar, SHRT_MAX, "too many local variables"); while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); @@ -181,7 +177,7 @@ static int registerlocalvar (LexState *ls, TString *varname) { static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; - luaY_checklimit(fs, fs->nactvar+n+1, MAXVARS, "local variables"); + luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); } @@ -213,7 +209,7 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { } } /* new one */ - luaY_checklimit(fs, f->nups + 1, MAXUPVALUES, "upvalues"); + luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, TString *, MAX_INT, ""); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; @@ -295,6 +291,15 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { } +static void enterlevel (LexState *ls) { + if (++ls->L->nCcalls > LUAI_MAXCCALLS) + luaX_lexerror(ls, "chunk has too many syntax levels", 0); +} + + +#define leavelevel(ls) ((ls)->L->nCcalls--) + + static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; @@ -395,7 +400,6 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; - lexstate.nestlevel = 0; luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); funcstate.f->is_vararg = NEWSTYLEVARARG; @@ -405,7 +409,6 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { close_func(&lexstate); lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); - lua_assert(lexstate.nestlevel == 0); lua_assert(lexstate.fs == NULL); return funcstate.f; } @@ -460,11 +463,11 @@ static void recfield (LexState *ls, struct ConsControl *cc) { expdesc key, val; if (ls->t.token == TK_NAME) { luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); - cc->nh++; checkname(ls, &key); } else /* ls->t.token == '[' */ yindex(ls, &key); + cc->nh++; checknext(ls, '='); luaK_exp2RK(fs, &key); expr(ls, &val); @@ -574,7 +577,7 @@ static void parlist (LexState *ls) { f->is_vararg = 1; break; } - default: luaX_syntaxerror(ls, " or `...' expected"); + default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); } } while (!f->is_vararg && testnext(ls, ',')); } @@ -588,7 +591,7 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); - new_fs.f->lineDefined = line; + new_fs.f->linedefined = line; checknext(ls, '('); if (needself) { new_localvarliteral(ls, "self", 0); @@ -597,6 +600,7 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { parlist(ls); checknext(ls, ')'); chunk(ls); + new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); pushclosure(ls, &new_fs, e); @@ -735,8 +739,8 @@ static void primaryexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | constructor | FUNCTION body - | primaryexp */ + /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | + constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r)); @@ -761,7 +765,7 @@ static void simpleexp (LexState *ls, expdesc *v) { case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, - "cannot use `...' outside a vararg function"); + "cannot use " LUA_QL("...") " outside a vararg function"); fs->f->is_vararg = NEWSTYLEVARARG; init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; @@ -788,6 +792,7 @@ static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; + case '*': return OPR_SIZE; default: return OPR_NOUNOPR; } } @@ -799,6 +804,7 @@ static BinOpr getbinopr (int op) { case '-': return OPR_SUB; case '*': return OPR_MULT; case '/': return OPR_DIV; + case '%': return OPR_MOD; case '^': return OPR_POW; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; @@ -818,9 +824,9 @@ static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, /* arithmetic */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ {10, 9}, {5, 4}, /* power and concat (right associative) */ - {3, 3}, {3, 3}, /* equality */ + {3, 3}, {3, 3}, /* equality and inequality */ {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ {2, 2}, {1, 1} /* logical (and/or) */ }; @@ -829,7 +835,7 @@ static const struct { /* -** subexpr -> (simplexep | unop subexpr) { binop subexpr } +** subexpr -> (simpleexp | 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) { @@ -992,7 +998,7 @@ static int cond (LexState *ls) { static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ - Instruction codeexp[MAXEXPWHILE + EXTRAEXP]; + Instruction codeexp[LUAI_MAXEXPWHILE + EXTRAEXP]; int lineexp; int i; int sizeexp; @@ -1010,8 +1016,8 @@ static void whilestat (LexState *ls, int line) { luaK_concat(fs, &v.f, fs->jpc); fs->jpc = NO_JUMP; sizeexp = fs->pc - expinit; /* size of expression code */ - if (sizeexp > MAXEXPWHILE) - luaX_syntaxerror(ls, "`while' condition too complex"); + if (sizeexp > LUAI_MAXEXPWHILE) + luaX_syntaxerror(ls, LUA_QL("while") " condition too complex"); for (i = 0; i < sizeexp; i++) /* save `exp' code */ codeexp[i] = fs->f->code[expinit + i]; fs->pc = expinit; /* remove `exp' code */ @@ -1065,7 +1071,7 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); - prep = luaK_codeAsBx(fs, (isnum ? OP_FORPREP : OP_TFORPREP), base, NO_JUMP); + prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); @@ -1135,7 +1141,7 @@ static void forstat (LexState *ls, int line) { switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; - default: luaX_syntaxerror(ls, "`=' or `in' expected"); + default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); } check_match(ls, TK_END, TK_FOR, line); leaveblock(fs); /* loop scope (`break' jumps to this point) */ @@ -1284,7 +1290,7 @@ static void retstat (LexState *ls) { static void breakstat (LexState *ls) { - /* stat -> BREAK [NAME] */ + /* stat -> BREAK */ FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; int upval = 0; diff --git a/src/lparser.h b/src/lparser.h index 582b48784e..d8542f9c9b 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.51 2004/05/31 18:51:50 roberto Exp $ +** $Id: lparser.h,v 1.55 2005/04/25 19:24:10 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -65,14 +65,15 @@ typedef struct FuncState { int freereg; /* first free register */ int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ - int nlocvars; /* number of elements in `locvars' */ + short nlocvars; /* number of elements in `locvars' */ lu_byte nactvar; /* number of active local variables */ - upvaldesc upvalues[MAXUPVALUES]; /* upvalues */ - unsigned short actvar[MAXVARS]; /* declared-variable stack */ + upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ + unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ } FuncState; -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name); +LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + const char *name); #endif diff --git a/src/lstate.c b/src/lstate.c index 18dd4f95a7..41162dac87 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.25 2005/02/23 17:30:22 roberto Exp $ +** $Id: lstate.c,v 2.31 2005/05/05 15:34:03 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -24,20 +24,9 @@ #include "ltm.h" -/* -** macro to allow the inclusion of user information in Lua state -*/ -#ifndef LUA_USERSTATE -#define EXTRASPACE 0 -#else -union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; -#define EXTRASPACE (sizeof(union UEXTRASPACE)) -#endif - - -#define state_size(x) (sizeof(x) + EXTRASPACE) -#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + EXTRASPACE)) -#define fromstate(l) (cast(lu_byte *, (l)) - EXTRASPACE) +#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) +#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) +#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) /* @@ -51,18 +40,21 @@ typedef struct LG { static void stack_init (lua_State *L1, lua_State *L) { + /* initialize CallInfo array */ + L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); + L1->ci = L1->base_ci; + L1->size_ci = BASIC_CI_SIZE; + L1->end_ci = L1->base_ci + L1->size_ci - 1; + /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; L1->top = L1->stack; L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; - L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); - L1->ci = L1->base_ci; + /* initialize first ci */ L1->ci->func = L1->top; setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; - L1->size_ci = BASIC_CI_SIZE; - L1->end_ci = L1->base_ci + L1->size_ci - 1; } @@ -105,6 +97,7 @@ static void preinit_state (lua_State *L, global_State *g) { L->nCcalls = 0; L->status = 0; L->base_ci = L->ci = NULL; + L->savedpc = NULL; L->errfunc = 0; setnilvalue(gt(L)); } @@ -148,6 +141,7 @@ void luaE_freethread (lua_State *L, lua_State *L1) { LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { + int i; lua_State *L; global_State *g; void *l = (*f)(ud, NULL, 0, state_size(LG)); @@ -181,16 +175,17 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->weak = NULL; g->tmudata = NULL; g->totalbytes = sizeof(LG); - g->gcpace = 200; /* 200% (wait memory to double before next collection) */ - g->gcstepmul = 200; /* GC runs `twice the speed' of memory allocation */ + g->gcpause = LUAI_GCPAUSE; + g->gcstepmul = LUAI_GCMUL; g->gcdept = 0; + for (i=0; imt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); L = NULL; } else - lua_userstateopen(L); + luai_userstateopen(L); return L; } diff --git a/src/lstate.h b/src/lstate.h index 54469172ba..7dafa4d589 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.16 2005/02/23 17:30:22 roberto Exp $ +** $Id: lstate.h,v 2.21 2005/05/05 15:34:03 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -83,12 +83,13 @@ typedef struct global_State { lu_mem totalbytes; /* number of bytes currently allocated */ lu_mem estimate; /* an estimate of number of bytes actually in use */ lu_mem gcdept; /* how much GC is `behind schedule' */ - int gcpace; /* size of pause between successive GCs */ + int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ TValue _registry; struct lua_State *mainthread; UpVal uvhead; /* head of double-linked list of all open upvalues */ + struct Table *mt[NUM_TAGS]; /* metatables for basic types */ TString *tmname[TM_N]; /* array with tag-method names */ } global_State; @@ -102,12 +103,13 @@ struct lua_State { StkId base; /* base of current function */ global_State *l_G; CallInfo *ci; /* call info for current function */ + const Instruction *savedpc; /* `savedpc' of current function */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ int stacksize; CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo's */ - unsigned short size_ci; /* size of array `base_ci' */ + int size_ci; /* size of array `base_ci' */ unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; @@ -159,8 +161,8 @@ union GCObject { #define obj2gco(v) (cast(GCObject *, (v))) -lua_State *luaE_newthread (lua_State *L); -void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC lua_State *luaE_newthread (lua_State *L); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); #endif diff --git a/src/lstring.h b/src/lstring.h index 88f6da8068..1d2e91ea13 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.42 2005/02/23 17:30:22 roberto Exp $ +** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -23,9 +23,9 @@ #define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) -void luaS_resize (lua_State *L, int newsize); -Udata *luaS_newudata (lua_State *L, size_t s, Table *e); -TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); #endif diff --git a/src/lstrlib.c b/src/lstrlib.c index a9c002fb10..4929a27c9f 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.109 2004/12/01 15:46:06 roberto Exp $ +** $Id: lstrlib.c,v 1.115 2005/05/17 19:49:15 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -172,11 +172,11 @@ typedef struct MatchState { struct { const char *init; ptrdiff_t len; - } capture[MAX_CAPTURES]; + } capture[LUA_MAXCAPTURES]; } MatchState; -#define ESC '%' +#define L_ESC '%' #define SPECIALS "^$*+?.([%-" @@ -198,17 +198,17 @@ static int capture_to_close (MatchState *ms) { static const char *classend (MatchState *ms, const char *p) { switch (*p++) { - case ESC: { + case L_ESC: { if (*p == '\0') - luaL_error(ms->L, "malformed pattern (ends with `%%')"); + luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ if (*p == '\0') - luaL_error(ms->L, "malformed pattern (missing `]')"); - if (*(p++) == ESC && *p != '\0') + luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); + if (*(p++) == L_ESC && *p != '\0') p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; @@ -246,7 +246,7 @@ static int matchbracketclass (int c, const char *p, const char *ec) { p++; /* skip the `^' */ } while (++p < ec) { - if (*p == ESC) { + if (*p == L_ESC) { p++; if (match_class(c, uchar(*p))) return sig; @@ -265,7 +265,7 @@ static int matchbracketclass (int c, const char *p, const char *ec) { static int singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': return 1; /* matches any char */ - case ESC: return match_class(c, uchar(*(p+1))); + case L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } @@ -327,7 +327,7 @@ static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; - if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures"); + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; @@ -371,7 +371,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case ')': { /* end capture */ return end_capture(ms, s, p+1); } - case ESC: { + case L_ESC: { switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); @@ -382,7 +382,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) { const char *ep; char previous; p += 2; if (*p != '[') - luaL_error(ms->L, "missing `[' after `%%f' in pattern"); + luaL_error(ms->L, "missing " LUA_QL("[") " after " + LUA_QL("%%f") " in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s-1); if (matchbracketclass(uchar(previous), p, ep-1) || @@ -525,8 +526,8 @@ static int str_find (lua_State *L) { static int gfind_aux (lua_State *L) { MatchState ms; - const char *s = lua_tostring(L, lua_upvalueindex(1)); - size_t ls = lua_strlen(L, lua_upvalueindex(1)); + size_t ls; + const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); const char *p = lua_tostring(L, lua_upvalueindex(2)); const char *src; ms.L = L; @@ -563,11 +564,11 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { lua_State *L = ms->L; if (lua_isstring(L, 3)) { - const char *news = lua_tostring(L, 3); - size_t l = lua_strlen(L, 3); + size_t l; + const char *news = lua_tolstring(L, 3, &l); size_t i; for (i=0; i MAX_FORMAT) /* +2 to include `%' and the specifier */ luaL_error(L, "invalid format (too long)"); - form[0] = ESC; + form[0] = L_ESC; strncpy(form+1, strfrmt, p-strfrmt+1); form[p-strfrmt+2] = 0; return p; @@ -697,16 +698,14 @@ static int str_format (lua_State *L) { luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { - if (*strfrmt != ESC) + if (*strfrmt != L_ESC) luaL_putchar(&b, *strfrmt++); - else if (*++strfrmt == ESC) + else if (*++strfrmt == L_ESC) luaL_putchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ int hasprecision = 0; - if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$') - return luaL_error(L, "obsolete option (d$) to `format'"); arg++; strfrmt = scanformat(L, strfrmt, form, &hasprecision); switch (*strfrmt++) { @@ -725,7 +724,7 @@ static int str_format (lua_State *L) { } case 'q': { addquoted(L, &b, arg); - continue; /* skip the `addsize' at the end */ + continue; /* skip the 'addsize' at the end */ } case 's': { size_t l; @@ -743,7 +742,7 @@ static int str_format (lua_State *L) { } } default: { /* also treat cases `pnLlh' */ - return luaL_error(L, "invalid option to `format'"); + return luaL_error(L, "invalid option to " LUA_QL("format")); } } luaL_addlstring(&b, buff, strlen(buff)); @@ -772,11 +771,26 @@ static const luaL_reg strlib[] = { }; +static void createmetatable (lua_State *L) { + lua_newtable(L); /* create metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); /* set string metatable */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* string library... */ + lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ + lua_getfield(L, -2, "len"); + lua_setfield(L, -2, "__siz"); + lua_pop(L, 1); /* pop metatable */ +} + + /* ** Open string library */ LUALIB_API int luaopen_string (lua_State *L) { luaL_openlib(L, LUA_STRLIBNAME, strlib, 0); + createmetatable(L); return 1; } diff --git a/src/ltable.c b/src/ltable.c index d4070dd556..d0ba365bcb 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.15 2005/01/10 18:17:39 roberto Exp $ +** $Id: ltable.c,v 2.23 2005/05/17 19:49:15 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -18,6 +18,7 @@ ** Hence even when the load factor reaches 100%, performance remains good. */ +#include #include #define ltable_c @@ -37,10 +38,10 @@ /* ** max size of array part is 2^MAXBITS */ -#if LUA_BITSINT > 26 +#if LUAI_BITSINT > 26 #define MAXBITS 26 #else -#define MAXBITS (LUA_BITSINT-2) +#define MAXBITS (LUAI_BITSINT-2) #endif #define MAXASIZE (1 << MAXBITS) @@ -119,7 +120,7 @@ static int arrayindex (const TValue *key) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); - if (num_eq(cast(lua_Number, k), nvalue(key))) + if (luai_numeq(cast(lua_Number, k), nvalue(key))) return k; } return -1; /* `key' did not match some condition */ @@ -150,7 +151,7 @@ static int findindex (lua_State *L, Table *t, StkId key) { } else n = gnext(n); } while (n); - luaG_runerror(L, "invalid key for `next'"); /* key not found */ + luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ return 0; /* to avoid warnings */ } } @@ -436,7 +437,7 @@ const TValue *luaH_getnum (Table *t, int key) { lua_Number nk = cast(lua_Number, key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && num_eq(nvalue(gkey(n)), nk)) + if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); @@ -468,8 +469,9 @@ const TValue *luaH_get (Table *t, const TValue *key) { case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; - lua_number2int(k, (nvalue(key))); - if (num_eq(cast(lua_Number, k), nvalue(key))) /* is an integer index? */ + lua_Number n = nvalue(key); + lua_number2int(k, n); + if (luai_numeq(cast(lua_Number, k), nvalue(key))) /* index is integer? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } @@ -493,7 +495,7 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && !num_eq(nvalue(key), nvalue(key))) + else if (ttisnumber(key) && !luai_numeq(nvalue(key), nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } @@ -523,3 +525,50 @@ TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { } } + +static int unbound_search (Table *t, unsigned int j) { + unsigned int i = j; /* i is zero or a present index */ + j = j+1; + /* find `i' and `j' such that i is present and j is not */ + while (!ttisnil(luaH_getnum(t, j))) { + i = j; + j = i*2; + if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getnum(t, i))) i++; + return i - 1; + } + } + /* now do a binary search between them */ + while (i < j-1) { + unsigned int m = (i+j)/2; + if (ttisnil(luaH_getnum(t, m))) j = m; + else i = m; + } + return i; +} + + +/* +** Try to find a boundary in table `t'. A `boundary' is an integer index +** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). +*/ +int luaH_getn (Table *t) { + unsigned int j = t->sizearray; + if (j > 0 && ttisnil(&t->array[j - 1])) { + /* there is a boundary in the array part: (binary) search for it */ + unsigned int i = 0; + while (j - i > 1) { + unsigned int m = (i+j)/2; + if (ttisnil(&t->array[m - 1])) j = m; + else i = m; + } + return i; + } + /* else must find a boundary in hash part */ + else if (t->node == &luaH_dummynode) /* hash part is empty? */ + return j; /* that is easy... */ + else return unbound_search(t, j); +} + diff --git a/src/ltable.h b/src/ltable.h index 9700062e30..1a798262d0 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.5 2005/01/05 18:20:51 roberto Exp $ +** $Id: ltable.h,v 2.7 2005/04/25 19:24:10 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -20,19 +20,20 @@ extern const Node luaH_dummynode; -const TValue *luaH_getnum (Table *t, int key); -TValue *luaH_setnum (lua_State *L, Table *t, int key); -const TValue *luaH_getstr (Table *t, TString *key); -TValue *luaH_setstr (lua_State *L, Table *t, TString *key); -const TValue *luaH_get (Table *t, const TValue *key); -TValue *luaH_set (lua_State *L, Table *t, const TValue *key); -Table *luaH_new (lua_State *L, int narray, int lnhash); -void luaH_resizearray (lua_State *L, Table *t, int nasize); -void luaH_free (lua_State *L, Table *t); -int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); +LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); +LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); +LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); +LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); +LUAI_FUNC void luaH_free (lua_State *L, Table *t); +LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); +LUAI_FUNC int luaH_getn (Table *t); /* exported only for debugging */ -Node *luaH_mainposition (const Table *t, const TValue *key); +LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); #endif diff --git a/src/ltablib.c b/src/ltablib.c index 792bf3134c..ab4d5db219 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.27 2004/12/07 18:28:47 roberto Exp $ +** $Id: ltablib.c,v 1.31 2005/05/17 19:49:15 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -23,7 +23,7 @@ static int foreachi (lua_State *L) { int i; int n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); - for (i=LUA_FIRSTINDEX; i < n+LUA_FIRSTINDEX; i++) { + for (i=1; i <= n; i++) { lua_pushvalue(L, 2); /* function */ lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ @@ -62,39 +62,42 @@ static int getn (lua_State *L) { static int setn (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); +#ifndef luaL_setn luaL_setn(L, 1, luaL_checkint(L, 2)); +#else + luaL_error(L, LUA_QL("setn") " is obsolete"); +#endif lua_pushvalue(L, 1); return 1; } static int tinsert (lua_State *L) { - int v = lua_gettop(L); /* number of arguments */ - int e = aux_getn(L, 1) + LUA_FIRSTINDEX; /* first empty element */ + int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ - if (v == 2) /* called with only 2 arguments */ + if (lua_isnone(L, 3)) /* called with only 2 arguments */ pos = e; /* insert new element at the end */ else { + int i; pos = luaL_checkint(L, 2); /* 2nd argument is the position */ if (pos > e) e = pos; /* `grow' array if necessary */ - v = 3; /* function may be called with more than 3 args */ - } - luaL_setn(L, 1, e - LUA_FIRSTINDEX + 1); /* new size */ - while (--e >= pos) { /* move up elements */ - lua_rawgeti(L, 1, e); - lua_rawseti(L, 1, e+1); /* t[e+1] = t[e] */ + lua_settop(L, 3); /* function may be called with more than 3 args */ + for (i = e; i > pos; i--) { /* move up elements */ + lua_rawgeti(L, 1, i-1); + lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + } } - lua_pushvalue(L, v); + luaL_setn(L, 1, e); /* new size */ lua_rawseti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { - int e = aux_getn(L, 1) + LUA_FIRSTINDEX - 1; + int e = aux_getn(L, 1); int pos = luaL_optint(L, 2, e); - if (e < LUA_FIRSTINDEX) return 0; /* table is `empty' */ - luaL_setn(L, 1, e - LUA_FIRSTINDEX); /* t.n = n-1 */ + if (e == 0) return 0; /* table is `empty' */ + luaL_setn(L, 1, e - 1); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ;posmetatable; break; default: - mt = NULL; + mt = G(L)->mt[ttype(o)]; } - return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : &luaO_nilobject); + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : &luaO_nilobject); } diff --git a/src/ltm.h b/src/ltm.h index 226feb75ea..1622b7810c 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.1 2003/12/10 12:13:36 roberto Exp $ +** $Id: ltm.h,v 2.4 2005/05/05 15:34:03 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -25,8 +25,10 @@ typedef enum { TM_SUB, TM_MUL, TM_DIV, + TM_MOD, TM_POW, TM_UNM, + TM_SIZ, TM_LT, TM_LE, TM_CONCAT, @@ -41,11 +43,12 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) +extern const char *const luaT_typenames[]; -const TValue *luaT_gettm (Table *events, TMS event, TString *ename); -const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); -void luaT_init (lua_State *L); -extern const char *const luaT_typenames[]; +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); #endif diff --git a/src/lua.c b/src/lua.c index 1d2fc75715..a942c741bb 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.135 2005/01/10 17:21:10 roberto Exp $ +** $Id: lua.c,v 1.144 2005/05/17 19:49:15 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -18,19 +18,10 @@ #include "lualib.h" -/* -** generic extra include file -*/ -#ifdef LUA_USERCONFIG -#include LUA_USERCONFIG -#endif - - - static lua_State *globalL = NULL; -static const char *progname = PROGNAME; +static const char *progname = LUA_PROGNAME; @@ -53,10 +44,11 @@ static void print_usage (void) { "usage: %s [options] [script [args]].\n" "Available options are:\n" " - execute stdin as a file\n" - " -e stat execute string `stat'\n" - " -i enter interactive mode after executing `script'\n" - " -l name load and run library `name'\n" + " -e stat execute string " LUA_QL("stat") "\n" + " -i enter interactive mode after executing " LUA_QL("script") "\n" + " -l name require library " LUA_QL("name") "\n" " -v show version information\n" + " -w trap access to undefined globals\n" " -- stop handling options\n" , progname); } @@ -110,15 +102,14 @@ static void print_version (void) { } -static int getargs (lua_State *L, char *argv[], int n) { - int i, narg; - for (i=n+1; argv[i]; i++) { - luaL_checkstack(L, 1, "too many arguments to script"); +static int getargs (lua_State *L, int argc, char **argv, int n) { + int narg = argc - (n + 1); /* number of arguments to the script */ + int i; + luaL_checkstack(L, narg + 3, "too many arguments to script"); + for (i=n+1; i < argc; i++) lua_pushstring(L, argv[i]); - } - narg = i-(n+1); /* number of arguments to the script (not to `lua.c') */ lua_newtable(L); - for (i=0; argv[i]; i++) { + for (i=0; i < argc; i++) { lua_pushstring(L, argv[i]); lua_rawseti(L, -2, i - n); } @@ -139,54 +130,18 @@ static int dostring (lua_State *L, const char *s, const char *name) { static int dolibrary (lua_State *L, const char *name) { - luaL_getfield(L, LUA_GLOBALSINDEX, "package.path"); - if (!lua_isstring(L, -1)) { - l_message(progname, "`package.path' must be a string"); - return 1; - } - name = luaL_searchpath(L, name, lua_tostring(L, -1)); - if (name == NULL) return report(L, 1); - else return dofile(L, name); -} - - - -/* -** this macro defines a function to show the prompt and reads the -** next line for manual input -*/ -#ifndef lua_readline -#define lua_readline(L,prompt) readline(L,prompt) - -/* maximum length of an input line */ -#ifndef MAXINPUT -#define MAXINPUT 512 -#endif - - -static int readline (lua_State *L, const char *prompt) { - static char buffer[MAXINPUT]; - if (prompt) { - fputs(prompt, stdout); - fflush(stdout); - } - if (fgets(buffer, sizeof(buffer), stdin) == NULL) - return 0; /* read fails */ - else { - lua_pushstring(L, buffer); - return 1; - } + lua_getglobal(L, "require"); + lua_pushstring(L, name); + return report(L, lua_pcall(L, 1, 0, 0)); } -#endif - static const char *get_prompt (lua_State *L, int firstline) { - const char *p = NULL; + const char *p; lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2"); lua_rawget(L, LUA_GLOBALSINDEX); p = lua_tostring(L, -1); - if (p == NULL) p = (firstline ? PROMPT : PROMPT2); + if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ return p; } @@ -194,7 +149,7 @@ static const char *get_prompt (lua_State *L, int firstline) { static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX && - strstr(lua_tostring(L, -1), "near `'") != NULL) { + strstr(lua_tostring(L, -1), "") != NULL) { lua_pop(L, 1); return 1; } @@ -203,23 +158,40 @@ static int incomplete (lua_State *L, int status) { } +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) + return 0; /* no input */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + static int loadline (lua_State *L) { int status; lua_settop(L, 0); - if (lua_readline(L, get_prompt(L, 1)) == 0) /* no input? */ - return -1; - if (lua_tostring(L, -1)[0] == '=') { /* line starts with `=' ? */ - lua_pushfstring(L, "return %s", lua_tostring(L, -1)+1);/* `=' -> `return' */ - lua_remove(L, -2); /* remove original line */ - } + if (!pushline(L, 1)) + return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ - if (lua_readline(L, get_prompt(L, 0)) == 0) /* no more input? */ + if (!pushline(L, 0)) /* no more input? */ return -1; - lua_concat(L, lua_gettop(L)); /* join lines */ + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ } - lua_saveline(L, lua_tostring(L, 1)); + lua_saveline(L, 1); lua_remove(L, 1); /* remove line */ return status; } @@ -237,8 +209,9 @@ static void dotty (lua_State *L) { lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(progname, lua_pushfstring(L, "error calling `print' (%s)", - lua_tostring(L, -1))); + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); } } lua_settop(L, 0); /* clear stack */ @@ -250,17 +223,17 @@ static void dotty (lua_State *L) { static int checkvar (lua_State *L) { const char *name = lua_tostring(L, 2); if (name) - luaL_error(L, "attempt to access undefined variable `%s'", name); + luaL_error(L, "attempt to access undefined variable " LUA_QS, name); return 0; } #define clearinteractive(i) (*i &= 2) -static int handle_argv (lua_State *L, char *argv[], int *interactive) { +static int handle_argv (lua_State *L, int argc, char **argv, int *interactive) { if (argv[1] == NULL) { /* no arguments? */ *interactive = 0; - if (stdin_is_tty()) + if (lua_stdin_is_tty()) dotty(L); else dofile(L, NULL); /* executes stdin as a file */ @@ -330,9 +303,9 @@ static int handle_argv (lua_State *L, char *argv[], int *interactive) { } } endloop: if (argv[i] != NULL) { - const char *filename = argv[i]; - int narg = getargs(L, argv, i); /* collect arguments */ int status; + const char *filename = argv[i]; + int narg = getargs(L, argc, argv, i); /* collect arguments */ lua_setglobal(L, "arg"); clearinteractive(interactive); status = luaL_loadfile(L, filename); @@ -371,10 +344,10 @@ static int pmain (lua_State *L) { int interactive = 1; if (s->argv[0] && s->argv[0][0]) progname = s->argv[0]; globalL = L; - luaopen_stdlibs(L); /* open libraries */ + luaL_openlibs(L); /* open libraries */ status = handle_luainit(L); if (status == 0) { - status = handle_argv(L, s->argv, &interactive); + status = handle_argv(L, s->argc, s->argv, &interactive); if (status == 0 && interactive) dotty(L); } s->status = status; @@ -382,7 +355,7 @@ static int pmain (lua_State *L) { } -int main (int argc, char *argv[]) { +int main (int argc, char **argv) { int status; struct Smain s; lua_State *L = lua_open(); /* create state */ diff --git a/src/lua.h b/src/lua.h index 1020abd123..1028e5ea14 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,8 +1,8 @@ /* -** $Id: lua.h,v 1.202 2005/02/18 12:40:02 roberto Exp $ +** $Id: lua.h,v 1.208 2005/05/17 19:49:15 roberto Exp $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil -** http://www.lua.org mailto:info@lua.org +** http://www.lua.org ** See Copyright Notice at the end of this file */ @@ -17,7 +17,7 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (work5)" +#define LUA_VERSION "Lua 5.1 (work6)" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2005 Tecgraf, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -55,10 +55,9 @@ typedef int (*lua_CFunction) (lua_State *L); /* ** functions that read/write blocks when loading/dumping Lua chunks */ -typedef const char * (*lua_Chunkreader) (lua_State *L, void *ud, size_t *sz); +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); -typedef int (*lua_Chunkwriter) (lua_State *L, const void* p, - size_t sz, void* ud); +typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); /* @@ -70,22 +69,19 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* ** basic types */ -#define LUA_TNONE (-1) +#define LUA_TNONE (-1) -#define LUA_TNIL 0 -#define LUA_TBOOLEAN 1 +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 -#define LUA_TNUMBER 3 -#define LUA_TSTRING 4 -#define LUA_TTABLE 5 -#define LUA_TFUNCTION 6 -#define LUA_TUSERDATA 7 -#define LUA_TTHREAD 8 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 -/* first index for arrays */ -#define LUA_FIRSTINDEX 1 - /* minimum Lua stack available to a C function */ #define LUA_MINSTACK 20 @@ -94,7 +90,7 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* ** generic extra include file */ -#ifdef LUA_USER_H +#if defined(LUA_USER_H) #include LUA_USER_H #endif @@ -150,7 +146,7 @@ LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); -LUA_API const char *(lua_tostring) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_objsize) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); @@ -204,11 +200,11 @@ LUA_API int (lua_setfenv) (lua_State *L, int idx); */ LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); -LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); -LUA_API int (lua_load) (lua_State *L, lua_Chunkreader reader, void *dt, +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname); -LUA_API int (lua_dump) (lua_State *L, lua_Chunkwriter writer, void *data); +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); /* @@ -227,7 +223,7 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 #define LUA_GCSTEP 4 -#define LUA_GCSETPACE 5 +#define LUA_GCSETPAUSE 5 #define LUA_GCSETSTEPMUL 6 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -278,6 +274,8 @@ LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); #define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + /* @@ -290,7 +288,8 @@ LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); #define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) - +#define lua_Chunkreader lua_Reader +#define lua_Chunkwriter lua_Writer @@ -321,6 +320,8 @@ LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); typedef struct lua_Debug lua_Debug; /* activation record */ + +/* Functions to be called by the debuger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); @@ -337,8 +338,6 @@ LUA_API int lua_gethookmask (lua_State *L); LUA_API int lua_gethookcount (lua_State *L); -#define LUA_IDSIZE 60 - struct lua_Debug { int event; const char *name; /* (n) */ @@ -348,6 +347,7 @@ struct lua_Debug { int currentline; /* (l) */ int nups; /* (u) number of upvalues */ int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ int i_ci; /* active function */ @@ -357,7 +357,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2004 Tecgraf, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2005 Tecgraf, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/luac.c b/src/luac.c index dfbcab0550..cfe00c7b76 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.49 2004/09/01 21:22:34 lhf Exp $ +** $Id: luac.c,v 1.50 2005/05/12 00:26:50 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -151,8 +151,6 @@ static int writer(lua_State* L, const void* p, size_t size, void* u) return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } -void unprint(lua_State* L, const char* name); - struct Smain { int argc; char **argv; diff --git a/src/luaconf.h b/src/luaconf.h index 04b8e99089..bc211cd39d 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.30 2005/02/28 15:59:11 roberto Exp $ +** $Id: luaconf.h,v 1.49a 2005/05/17 19:49:15 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -13,387 +13,658 @@ /* -** {====================================================== -** Index (search for keyword to find corresponding entry) -** ======================================================= +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== */ -/* }====================================================== */ - - /* -** {====================================================== -** Generic configuration -** ======================================================= +@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for +@* Lua libraries. +@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for +@* C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. */ - -/* default path */ #if defined(_WIN32) #define LUA_ROOT "C:\\Program Files\\Lua51" #define LUA_LDIR LUA_ROOT "\\lua" #define LUA_CDIR LUA_ROOT "\\dll" #define LUA_PATH_DEFAULT \ - "?.lua;" LUA_LDIR "\\?.lua;" LUA_LDIR "\\?\\init.lua" -#define LUA_CPATH_DEFAULT "?.dll;" LUA_CDIR "\\?.dll" + "?.lua;" LUA_LDIR"\\?.lua;" LUA_LDIR"\\?\\init.lua" +#define LUA_CPATH_DEFAULT \ + "?.dll;" "l?.dll;" LUA_CDIR"\\?.dll;" LUA_CDIR"\\l?.dll" #else #define LUA_ROOT "/usr/local" #define LUA_LDIR LUA_ROOT "/share/lua/5.1" #define LUA_CDIR LUA_ROOT "/lib/lua/5.1" #define LUA_PATH_DEFAULT \ - "./?.lua;" LUA_LDIR "/?.lua;" LUA_LDIR "/?/init.lua" -#define LUA_CPATH_DEFAULT "./?.so;" LUA_CDIR "/?.so" + "./?.lua;" LUA_LDIR"/?.lua;" LUA_LDIR"/?/init.lua" +#define LUA_CPATH_DEFAULT \ + "./?.so;" "./l?.so;" LUA_CDIR"/?.so;" LUA_CDIR"/l?.so" #endif +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif -/* type of numbers in Lua */ -#define LUA_NUMBER double -/* formats for Lua numbers */ -#define LUA_NUMBER_SCAN "%lf" -#define LUA_NUMBER_FMT "%.14g" +/* +@@ LUA_PATHSEP is the character that separates templates in a path. +** CHANGE it if for some reason your system cannot use a +** semicolon. (E.g., if a semicolon is a common character in +** file/directory names.) Probably you do not need to change this. +*/ +#define LUA_PATHSEP ';' /* -** type for integer functions -** on most machines, `ptrdiff_t' gives a reasonable size for integers +@@ LUA_PATH_MARK is the string that marks the substitution points in a +@* template. +** CHANGE it if for some reason your system cannot use an interrogation +** mark. (E.g., if an interogation mark is a common character in +** file/directory names.) Probably you do not need to change this. +*/ +#define LUA_PATH_MARK "?" + + +/* +@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. +** CHANGE that if ptrdiff_t is not adequate on your machine. (On most +** machines, ptrdiff_t gives a good choice between int or long.) */ #define LUA_INTEGER ptrdiff_t -/* mark for all API functions */ +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all standard library functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) + +#if defined(LUA_CORE) || defined(LUA_LIB) +#define LUA_API __declspec(__dllexport) +#else +#define LUA_API __declspec(__dllimport) +#endif + +#else + #define LUA_API extern -/* mark for auxlib functions */ -#define LUALIB_API extern +#endif -/* buffer size used by lauxlib buffer system */ -#define LUAL_BUFFERSIZE BUFSIZ +/* more often than not the libs go together with the core */ +#define LUALIB_API LUA_API -/* assertions in Lua (mainly for internal debugging) */ +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +@* exported to outside modules. +** CHANGE it if you need to mark them in some special way. Gcc (versions +** 3.2 and later) mark them as "hidden" to optimize their call when Lua +** is compiled as a shared library. +*/ +#if defined(luaall_c) +#define LUAI_FUNC static +#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) +#define LUAI_FUNC __attribute__((visibility("hidden"))) +#else +#define LUAI_FUNC extern +#endif + + +/* +@@ lua_assert describes the internal assertions in Lua. +** CHANGE that only if you need to debug Lua. +*/ #define lua_assert(c) ((void)0) -/* }====================================================== */ +/* +@@ LUA_QL describes how error messages quote program elements. +** CHANGE it if you want a different appearance. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") /* -** {====================================================== +@@ LUA_IDSIZE gives the maximum size for the description of the source +@* of a function in debug information. +** CHANGE it if you a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +** {================================================================== ** Stand-alone configuration -** ======================================================= +** =================================================================== */ -#ifdef lua_c +#if defined(lua_c) || defined(luaall_c) -/* definition of `isatty' */ -#ifdef _POSIX_C_SOURCE +/* +@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that +@* is, whether we're running lua interactively). +** CHANGE it if you have a better definition for non-POSIX/non-Windows +** systems. +*/ +#if !defined(__STRICT_ANSI__) && defined(_POSIX_C_SOURCE) #include -#define stdin_is_tty() isatty(0) -#elif defined(_WIN32) +#define lua_stdin_is_tty() isatty(0) +#elif !defined(__STRICT_ANSI__) && defined(_WIN32) #include #include -#define stdin_is_tty() _isatty(_fileno(stdin)) +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) #else -#define stdin_is_tty() 1 /* assume stdin is a tty */ +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ #endif -#define PROMPT "> " -#define PROMPT2 ">> " -#define PROGNAME "lua" +/* +@@ LUA_PROMPT is the default prompt used by stand-alone Lua. +@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. +** CHANGE them if you want different prompts. (You can also change the +** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) +*/ +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " +/* +@@ LUA_PROGNAME is the default name for the stand-alone Lua program. +** CHANGE it if your stand-alone interpreter has a different name and +** your system is not able to detect that name automatically. +*/ +#define LUA_PROGNAME "lua" /* -** this macro can be used by some `history' system to save lines -** read in manual input +@@ LUA_MAXINPUT is the maximum length for an input line in the +@* stand-alone interpreter. +** CHANGE it if you need longer lines. */ -#define lua_saveline(L,line) /* empty */ +#define LUA_MAXINPUT 512 +/* +@@ lua_readline defines how to show a prompt and then read a line from +@* the standard input. +@@ lua_saveline defines how to "save" a read line in a "history". +@@ lua_freeline defines how to free a line read by lua_readline. +** CHANGE them if you want to improve this functionality (e.g., by using +** GNU readline and history facilities). +*/ +#if !defined(__STRICT_ANSI__) && defined(LUA_USE_READLINE) +#include +#include +#include +#define lua_readline(L,b,p) (((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) free(b) +#else +#define lua_readline(L,b,p) \ + (fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) ((void)0) +#define lua_freeline(L,b) ((void)0) +#endif #endif -/* }====================================================== */ +/* }================================================================== */ + + +/* +@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles +@* as a percentage. +** CHANGE it if you want the GC to run faster or slower (higher +** values mean larger pauses which mean slower collection.) +*/ +#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ + + +/* +@@ LUAI_GCMUL defines the speed of garbage collection relative to +@* memory allocation as a percentage. +** CHANGE it if you want to change the granularity of the garbage +** collection. (Higher values mean coarser collections. 0 represents +** infinity, where each step performs a full collection.) +*/ +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ + +/* +@@ LUA_COMPAT_GETN controls compatibility with old getn behavior. +** CHANGE it to 1 if you want exact compatibility with the behavior of +** setn/getn in Lua 5.0. +*/ +#define LUA_COMPAT_GETN 0 +/* +@@ LUA_COMPAT_PATH controls compatibility about LUA_PATH. +** CHANGE it to 1 if you want 'require' to look for global LUA_PATH +** before checking package.path. +*/ +#define LUA_COMPAT_PATH 0 /* -** {====================================================== -** Core configuration -** ======================================================= +@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. +** CHANGE it to 1 if you want a global 'loadlib' function (otherwise +** the function is only available as 'package.loadlib'). */ +#define LUA_COMPAT_LOADLIB 1 -#ifdef LUA_CORE +/* +@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. +** CHANGE it to 1 if you want vararg functions that do not use '...' +** to get an 'arg' table with their extra arguments. +*/ +#define LUA_COMPAT_VARARG 1 -/* LUA-C API assertions */ -#define api_check(L,o) lua_assert(o) +/* +@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting +@* facility. +** CHANGE it to 2 if you want the old behaviour, or undefine it to turn +** off the advisory error when nesting [[...]]. +*/ +#define LUA_COMPAT_LSTR 1 + +/* +@@ luai_apicheck is the assert macro used by the Lua-C API. +** CHANGE luai_apicheck if you want Lua to perform some checks in the +** parameters it gets from API calls. This may slow down the interpreter +** a bit, but may be quite useful when debugging C code that interfaces +** with Lua. A useful redefinition is to use assert.h. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(L,o) assert(o) +#else +/* (By default lua_assert is empty, so luai_apicheck is also empty.) */ +#define luai_apicheck(L,o) lua_assert(o) +#endif -/* number of bits in an `int' */ +/* +@@ LUAI_BITSINT defines the number of bits in an int. +** CHANGE here if Lua cannot automatically detect the number of bits of +** your machine. Probably you do not need to change this. +*/ /* avoid overflows in comparison */ #if INT_MAX-20 < 32760 -#define LUA_BITSINT 16 +#define LUAI_BITSINT 16 #elif INT_MAX > 2147483640L -/* `int' has at least 32 bits */ -#define LUA_BITSINT 32 +/* int has at least 32 bits */ +#define LUAI_BITSINT 32 #else #error "you must define LUA_BITSINT with number of bits in an integer" #endif /* -** L_UINT32: unsigned integer with at least 32 bits -** L_INT32: signed integer with at least 32 bits -** LU_MEM: an unsigned integer big enough to count the total memory used by Lua -** L_MEM: a signed integer big enough to count the total memory used by Lua +@@ LUAI_UINT32 is an unsigned integer with at least 32 bits. +@@ LUAI_INT32 is an signed integer with at least 32 bits. +@@ LUAI_UMEM is an unsigned integer big enough to count the total +@* memory used by Lua. +@@ LUAI_MEM is a signed integer big enough to count the total memory +@* used by Lua. +** CHANGE here if for some weird reason the default definitions are not +** good enough for your machine. (The definitions in the 'else' +** part always works, but may waste space on machines with 64-bit +** longs.) Probably you do not need to change this. */ -#if LUA_BITSINT >= 32 -#define LUA_UINT32 unsigned int -#define LUA_INT32 int -#define LUA_MAXINT32 INT_MAX -#define LU_MEM size_t -#define L_MEM ptrdiff_t +#if LUAI_BITSINT >= 32 +#define LUAI_UINT32 unsigned int +#define LUAI_INT32 int +#define LUAI_MAXINT32 INT_MAX +#define LUAI_UMEM size_t +#define LUAI_MEM ptrdiff_t #else /* 16-bit ints */ -#define LUA_UINT32 unsigned long -#define LUA_INT32 long -#define LUA_MAXINT32 LONG_MAX -#define LU_MEM LUA_UINT32 -#define L_MEM ptrdiff_t +#define LUAI_UINT32 unsigned long +#define LUAI_INT32 long +#define LUAI_MAXINT32 LONG_MAX +#define LUAI_UMEM unsigned long +#define LUAI_MEM long #endif -/* maximum depth for calls (unsigned short) */ -#define LUA_MAXCALLS 10000 - /* -** maximum depth for C calls (unsigned short): Not too big, or may -** overflow the C stack... +@@ LUAI_MAXCALLS limits the number of nested calls. +** CHANGE it if you need really deep recursive calls. This limit is +** arbitrary; its only purpose is to stop infinite recursion before +** exhausting memory. */ -#define LUA_MAXCCALLS 200 - - -/* maximum size for the virtual stack of a C function */ -#define MAXCSTACK 2048 +#define LUAI_MAXCALLS 20000 /* -** maximum number of syntactical nested non-terminals: Not too big, -** or may overflow the C stack... +@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function +@* can use. +** CHANGE it if you need lots of (Lua) stack space for your C +** functions. This limit is arbitrary; its only purpose is to stop C +** functions to consume unlimited stack space. */ -#define LUA_MAXPARSERLEVEL 200 +#define LUAI_MAXCSTACK 2048 -/* maximum number of variables declared in a function */ -#define MAXVARS 200 /* = 199900L) -/* on machines compliant with C99, you can try `lrint' */ -#include -#define lua_number2int(i,d) ((i)=lrint(d)) -#else -#define lua_number2int(i,d) ((i)=(int)(d)) +/* +@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function +@* (must be smaller than 250). +*/ +#define LUAI_MAXUPVALUES 60 -#endif +/* +@@ LUAI_MAXEXPWHILE is the maximum size of code for expressions +@* controling a 'while' loop. +*/ +#define LUAI_MAXEXPWHILE 100 -/* function to convert a lua_Number to lua_Integer (with any rounding method) */ -#define lua_number2integer(i,n) lua_number2int((i), (n)) +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +*/ +#define LUAL_BUFFERSIZE BUFSIZ -/* function to convert a lua_Number to a string */ -#include -#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) -/* maximum size of previous conversion */ -#define MAX_NUMBER2STR 32 /* 16 digits, sign, point and \0 (+ some extra) */ +/* }================================================================== */ -/* function to convert a string to a lua_Number */ -#define lua_str2number(s,p) strtod((s), (p)) +/* +@@ lua_number2int is a macro to convert lua_Number to int. +** CHANGE that if you know a faster way to convert a lua_Number to +** int (with any rounding method and without throwing errors) in your +** system. In Pentium machines, a naive typecast from double to int +** in C is extremely slow, so any alternative is worth trying. +*/ -/* result of a `usual argument conversion' over lua_Number */ -#define LUA_UACNUMBER double +/* On a gcc/Pentium, resort to assembler */ +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__i386) +#define lua_number2int(i,d) __asm__ ("fistpl %0":"=m"(i):"t"(d):"st") +/* On Windows/Pentium, resort to assembler */ +#elif !defined(__STRICT_ANSI__) && defined(_MSC_VER) && defined(_M_IX86) +#define lua_number2int(i,d) \ + __asm fld d \ + __asm fistp i -/* primitive operators for numbers */ -#define num_add(a,b) ((a)+(b)) -#define num_sub(a,b) ((a)-(b)) -#define num_mul(a,b) ((a)*(b)) -#define num_div(a,b) ((a)/(b)) -#define num_unm(a) (-(a)) -#define num_eq(a,b) ((a)==(b)) -#define num_lt(a,b) ((a)<(b)) -#define num_le(a,b) ((a)<=(b)) -#include -#define num_pow(a,b) pow(a,b) +/* on Pentium machines compliant with C99, you can try lrint */ +#elif defined (__i386) && defined(__STDC_VERSION__) && \ + (__STDC_VERSION__ >= 199900L) +#define lua_number2int(i,d) ((i)=lrint(d)) +/* this option always works, but may be slow */ +#else +#define lua_number2int(i,d) ((i)=(int)(d)) -/* type to ensure maximum alignment */ -#define LUSER_ALIGNMENT_T union { double u; void *s; long l; } +#endif /* -** exception handling: by default, Lua handles errors with longjmp/setjmp -** when compiling as C code and with exceptions when compiling as C++ code. -** Change that if you prefer to use longjmp/setjmp even with C++. +@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. +** CHANGE (see lua_number2int). */ -#ifndef __cplusplus -/* default handling with long jumps */ -#include -#define L_THROW(L,c) longjmp((c)->b, 1) -#define L_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } -#define l_jmpbuf jmp_buf +/* On a gcc or Windows/Pentium, resort to assembler */ +#if (defined(__GNUC__) && defined(__i386)) || \ + (defined(_MSC_VER) && defined(_M_IX86)) +#define lua_number2integer(i,n) lua_number2int(i, n) +/* this option always works, but may be slow */ #else -/* C++ exceptions */ -#define L_THROW(L,c) throw(c) -#define L_TRY(L,c,a) try { a } catch(...) \ - { if ((c)->status == 0) (c)->status = -1; } -#define l_jmpbuf int /* dummy variable */ +#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) + #endif /* -** macros for thread synchronization inside Lua core machine: This is -** an attempt to simplify the implementation of a multithreaded version -** of Lua. Do not change that unless you know what you are doing. all -** accesses to the global state and to global objects are synchronized. -** Because threads can read the stack of other threads (when running -** garbage collection), a thread must also synchronize any write-access -** to its own stack. Unsynchronized accesses are allowed only when -** reading its own stack, or when reading immutable fields from global -** objects (such as string values and udata values). +** {================================================================== +@@ LUA_NUMBER is the type of numbers in Lua. +** CHANGE the following definitions only if you want to build Lua +** with a number type different from double. You may also need to +** change lua_number2int & lua_number2integer. +** =================================================================== */ -#define lua_lock(L) ((void) 0) -#define lua_unlock(L) ((void) 0) /* -** this macro allows a thread switch in appropriate places in the Lua -** core +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@* over a number. */ -#define lua_threadyield(L) {lua_unlock(L); lua_lock(L);} +#define LUA_NUMBER double +#define LUAI_UACNUMBER LUA_NUMBER +/* +@@ LUA_NUMBER_SCAN is the format for reading numbers. +@@ LUA_NUMBER_FMT is the format for writing numbers. +@@ lua_number2str converts a number to a string. +@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. +@@ lua_str2number converts a string to a number. +*/ +#define LUA_NUMBER_SCAN "%lf" +#define LUA_NUMBER_FMT "%.14g" +#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) +#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ +#define lua_str2number(s,p) strtod((s), (p)) -/* allows user-specific initialization on new threads */ -#define lua_userstateopen(L) ((void)0) +/* +@@ The luai_num* macros define the primitive operations over numbers. +*/ +#define luai_numadd(a,b) ((a)+(b)) +#define luai_numsub(a,b) ((a)-(b)) +#define luai_nummul(a,b) ((a)*(b)) +#define luai_numdiv(a,b) ((a)/(b)) +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(a,b) pow(a,b) +#define luai_numunm(a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) -#endif +/* }================================================================== */ -/* }====================================================== */ +/* +@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. +** CHANGE it if your system requires alignments larger than double. (For +** instance, if your system supports long doubles and they must be +** aligned in 16-byte boundaries, then you should add long double in the +** union.) Probably you do not need to change this. +*/ +#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } /* -** {====================================================== -** Library configuration -** ======================================================= +@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. +** CHANGE them if you prefer to use longjmp/setjmp even with C++ or +** if want/don't want to use _longjmp/_setjmp instead of regular +** longjmp/setjmp. By default, Lua handles errors with exceptions when +** compiling as C++ code, with _longjmp/_setjmp when compiling as C code +** in a Unix system, and with longjmp/setjmp otherwise. */ +#if defined(__cplusplus) +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) try { a } catch(...) \ + { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ -#ifdef LUA_LIB +#elif !defined(__STRICT_ANSI__) && (defined(unix) || defined(__unix) || \ + defined(__unix__)) +/* in Unix, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf +#else +/* default handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf -/* environment variables that hold the search path for packages */ -#define LUA_PATH "LUA_PATH" -#define LUA_CPATH "LUA_CPATH" +#endif -/* prefix for open functions in C libraries */ -#define LUA_POF "luaopen_" -/* separator for open functions in C libraries */ -#define LUA_OFSEP "_" +/* +@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern +@* can do during pattern-matching. +** CHANGE it if you need more captures. This limit is arbitrary. +*/ +#define LUA_MAXCAPTURES 32 -/* directory separator (for submodules) */ -#if defined(_WIN32) -#define LUA_DIRSEP "\\" + +/* +@@ lua_tmpnam is the function that the OS library uses to create a +@* temporary name. +@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. +** CHANGE them if you have an alternative to tmpnam (which is considered +** insecure) or if you want the original tmpnam anyway. By default, Lua +** uses tmpnam except when POSIX is available, where it uses mkstemp. +*/ +#if defined(loslib_c) || defined(luaall_c) + +#if !defined(__STRICT_ANSI__) && defined(_POSIX_C_SOURCE) +#include +#define LUA_TMPNAMBUFSIZE 32 +#define lua_tmpnam(b,e) { \ + strcpy(b, "/tmp/lua_XXXXXX"); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } #else -#define LUA_DIRSEP "/" +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } #endif -/* separator of templates in a path */ -#define LUA_PATHSEP ';' +#endif -/* wild char in each template */ -#define LUA_PATH_MARK "?" +/* +@@ LUA_DL_* define which dynamic-library system Lua should use. +** CHANGE here if Lua has problems choosing the appropriate +** dynamic-library system for your platform (either Windows' DLL, Mac's +** dyld, or Unix's dlopen). If your system is some kind of Unix, there +** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for +** it. To use dlopen you also need to adapt the src/Makefile (probably +** adding -ldl to the linker options), so Lua does not select it +** automatically. (When you change the makefile to add -ldl, you must +** also add -DLUA_USE_DLOPEN.) +** If you do not want any kind of dynamic library, undefine all these +** options (or just remove these definitions). +*/ +#if !defined(__STRICT_ANSI__) +#if defined(_WIN32) +#define LUA_DL_DLL +#elif defined(__APPLE__) && defined(__MACH__) +#define LUA_DL_DYLD +#elif defined(LUA_USE_DLOPEN) +#define LUA_DL_DLOPEN +#endif +#endif -/* maximum number of captures in pattern-matching (arbitrary limit) */ -#define MAX_CAPTURES 32 +/* +@@ lua_lock/lua_unlock are macros for thread synchronization inside the +@* Lua core. This is an attempt to simplify the implementation of a +@* multithreaded version of Lua. +** CHANGE them only if you know what you are doing. All accesses to +** the global state and to global objects are synchronized. Because +** threads can read the stack of other threads (when running garbage +** collection), a thread must also synchronize any write-access to its +** own stack. Unsynchronized accesses are allowed only when reading its +** own stack, or when reading immutable fields from global objects (such +** as string values and udata values). +*/ +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) /* -** by default, gcc does not get `os.tmpname', because it generates a warning -** when using `tmpname'. Change that if you really want (or do not want) -** `os.tmpname' available. +@@ lua_threadyield allows a thread switch in appropriate places in the core. +** CHANGE it only if you know what you are doing. (See lua_lock.) */ -#ifdef __GNUC__ -#define USE_TMPNAME 0 -#else -#define USE_TMPNAME 1 -#endif +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} /* -** Configuration for loadlib: Lua tries to guess the dynamic-library -** system that your platform uses (either Windows' DLL, Mac's dyld, or -** dlopen). If your system is some kind of Unix, there is a good chance -** that USE_DLOPEN will work for it. You may need to adapt also the -** makefile. +@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State +@* (the data goes just *before* the lua_State pointer). +** CHANGE (define) this if you really need that. This value must be +** a multiple of the maximum alignment required for your machine. */ -#if defined(_WIN32) -#define USE_DLL -#elif defined(__APPLE__) && defined(__MACH__) -#define USE_DYLD -#elif defined(__linux) || defined(sun) || defined(sgi) || defined(BSD) -#define USE_DLOPEN -#endif +#define LUAI_EXTRASPACE 0 -#endif +/* +@@ luai_userstateopen allows user-specific initialization on new threads. +** CHANGE it if you defined LUAI_EXTRASPACE and need to initialize that +** data whenever a new lua_State is created. +*/ +#define luai_userstateopen(L) ((void)0) + -/* }====================================================== */ +/* =================================================================== */ +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ -/* Local configuration */ #endif diff --git a/src/lualib.h b/src/lualib.h index a5dde23693..e1face325a 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.33 2005/01/10 16:31:30 roberto Exp $ +** $Id: lualib.h,v 1.34 2005/04/13 17:24:20 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -36,12 +36,12 @@ LUALIB_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" LUALIB_API int (luaopen_debug) (lua_State *L); - +#define LUA_LOADLIBNAME "package" LUALIB_API int (luaopen_loadlib) (lua_State *L); /* open all previous libraries */ -LUALIB_API int (luaopen_stdlibs) (lua_State *L); +LUALIB_API void (luaL_openlibs) (lua_State *L); #endif diff --git a/src/lundump.c b/src/lundump.c index e13a4e482e..8ceb571ba5 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.54 2004/11/25 09:31:41 lhf Exp $ +** $Id: lundump.c,v 1.55 2005/05/12 00:26:50 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -206,7 +206,8 @@ static Proto* LoadFunction (LoadState* S, TString* p) Proto* f=luaF_newproto(S->L); setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; - f->lineDefined=LoadInt(S); + f->linedefined=LoadInt(S); + f->lastlinedefined=LoadInt(S); f->nups=LoadByte(S); f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); diff --git a/src/lundump.h b/src/lundump.h index 1a7b897bc3..924cfb0173 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.34 2004/11/25 09:31:41 lhf Exp $ +** $Id: lundump.h,v 1.35 2005/05/12 00:26:50 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -11,16 +11,16 @@ #include "lzio.h" /* load one chunk; from lundump.c */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char *name); +LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char *name); /* find byte order; from lundump.c */ -int luaU_endianness (void); +LUAI_FUNC int luaU_endianness (void); /* dump one chunk; from ldump.c */ -int luaU_dump (lua_State* L, const Proto* f, lua_Chunkwriter w, void* data, int strip); +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Chunkwriter w, void* data, int strip); /* print one chunk; from print.c */ -void luaU_print (const Proto* f, int full); +LUAI_FUNC void luaU_print (const Proto* f, int full); /* for header of binary files -- this is Lua 5.1 */ #define VERSION 0x51 diff --git a/src/lvm.c b/src/lvm.c index 1fd2ae75cb..f591a35f89 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,10 +1,12 @@ /* -** $Id: lvm.c,v 2.26 2005/02/23 17:30:22 roberto Exp $ +** $Id: lvm.c,v 2.44 2005/05/17 19:49:15 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ +#include +#include #include #include @@ -47,8 +49,9 @@ int luaV_tostring (lua_State *L, StkId obj) { if (!ttisnumber(obj)) return 0; else { - char s[MAX_NUMBER2STR]; - lua_number2str(s, nvalue(obj)); + char s[LUAI_MAXNUMBER2STR]; + lua_Number n = nvalue(obj); + lua_number2str(s, n); setsvalue2s(L, obj, luaS_new(L, s)); return 1; } @@ -57,9 +60,8 @@ int luaV_tostring (lua_State *L, StkId obj) { static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; - CallInfo *ci = L->ci; - const Instruction *oldpc = ci->savedpc; - ci->savedpc = pc; + const Instruction *oldpc = L->savedpc; + L->savedpc = pc; if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); @@ -68,7 +70,7 @@ static void traceexec (lua_State *L, const Instruction *pc) { } } if (mask & LUA_MASKLINE) { - Proto *p = ci_func(ci)->l.p; + Proto *p = ci_func(L->ci)->l.p; int npc = pcRel(pc, p); int newline = getline(p, npc); /* call linehook when enter a new function, when jump back (loop), @@ -79,16 +81,12 @@ static void traceexec (lua_State *L, const Instruction *pc) { } -static void prepTMcall (lua_State *L, const TValue *f, +static void callTMres (lua_State *L, StkId res, const TValue *f, const TValue *p1, const TValue *p2) { + ptrdiff_t result = savestack(L, res); setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */ -} - - -static void callTMres (lua_State *L, StkId res) { - ptrdiff_t result = savestack(L, res); luaD_checkstack(L, 3); L->top += 3; luaD_call(L, L->top - 3, 1); @@ -99,15 +97,18 @@ static void callTMres (lua_State *L, StkId res) { -static void callTM (lua_State *L) { +static void callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, const TValue *p3) { + setobj2s(L, L->top, f); /* push function */ + setobj2s(L, L->top+1, p1); /* 1st argument */ + setobj2s(L, L->top+2, p2); /* 2nd argument */ + setobj2s(L, L->top+3, p3); /* 3th argument */ luaD_checkstack(L, 4); L->top += 4; luaD_call(L, L->top - 4, 0); } -StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, - const Instruction *pc) { +void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; @@ -117,30 +118,23 @@ StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); - return L->base; + return; } /* else will try the tag method */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) { - L->ci->savedpc = pc; + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); - } if (ttisfunction(tm)) { - L->ci->savedpc = pc; - prepTMcall(L, tm, t, key); - callTMres(L, val); - return L->base; + callTMres(L, val, tm, t, key); + return; } t = tm; /* else repeat with `tm' */ } - L->ci->savedpc = pc; luaG_runerror(L, "loop in gettable"); - return NULL; /* to avoid warnings */ } -StkId luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val, - const Instruction *pc) { +void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; @@ -151,26 +145,19 @@ StkId luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val, (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); - return L->base; + return; } /* else will try the tag method */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) { - L->ci->savedpc = pc; + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); - } if (ttisfunction(tm)) { - L->ci->savedpc = pc; - prepTMcall(L, tm, t, key); - setobj2s(L, L->top+3, val); /* 3th argument */ - callTM(L); - return L->base; + callTM(L, tm, t, key, val); + return; } t = tm; /* else repeat with `tm' */ } - L->ci->savedpc = pc; luaG_runerror(L, "loop in settable"); - return NULL; /* to avoid warnings */ } @@ -180,8 +167,7 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (!ttisfunction(tm)) return 0; - prepTMcall(L, tm, p1, p2); - callTMres(L, res); + callTMres(L, res, tm, p1, p2); return 1; } @@ -208,8 +194,7 @@ static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; - prepTMcall(L, tm1, p1, p2); - callTMres(L, L->top); + callTMres(L, L->top, tm1, p1, p2); return !l_isfalse(L->top); } @@ -241,7 +226,7 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return num_lt(nvalue(l), nvalue(r)); + return luai_numlt(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) @@ -255,7 +240,7 @@ static int lessequal (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return num_le(nvalue(l), nvalue(r)); + return luai_numle(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ @@ -271,7 +256,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; - case LUA_TNUMBER: return num_eq(nvalue(t1), nvalue(t2)); + case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { @@ -288,8 +273,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ - prepTMcall(L, tm, t1, t2); - callTMres(L, L->top); /* call TM */ + callTMres(L, L->top, tm, t1, t2); /* call TM */ return !l_isfalse(L->top); } @@ -328,18 +312,19 @@ void luaV_concat (lua_State *L, int total, int last) { static StkId Arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op, const Instruction *pc) { + const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; - L->ci->savedpc = pc; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { + lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { - case TM_ADD: setnvalue(ra, num_add(nvalue(b), nvalue(c))); break; - case TM_SUB: setnvalue(ra, num_sub(nvalue(b), nvalue(c))); break; - case TM_MUL: setnvalue(ra, num_mul(nvalue(b), nvalue(c))); break; - case TM_DIV: setnvalue(ra, num_div(nvalue(b), nvalue(c))); break; - case TM_POW: setnvalue(ra, num_pow(nvalue(b), nvalue(c))); break; + case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; + case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; + case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; + case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; + case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; + case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; default: lua_assert(0); break; } } @@ -354,7 +339,7 @@ static StkId Arith (lua_State *L, StkId ra, const TValue *rb, ** some macros for common tasks in `luaV_execute' */ -#define runtime_check(L, c) { if (!(c)) return 0; } +#define runtime_check(L, c) { if (!(c)) break; } #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ @@ -367,19 +352,22 @@ static StkId Arith (lua_State *L, StkId ra, const TValue *rb, #define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) -#define dojump(L,pc,i) {(pc) += (i); lua_threadyield(L);} +#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} + + +#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } StkId luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; - TValue *k; StkId base; + TValue *k; const Instruction *pc; callentry: /* entry point when calling new functions */ if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ - pc = L->ci->savedpc; + pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; @@ -389,16 +377,16 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L, pc); /***/ + traceexec(L, pc); if (L->status == LUA_YIELD) { /* did hook yield? */ - L->ci->savedpc = pc - 1; + L->savedpc = pc - 1; return NULL; } base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); - lua_assert(base == L->ci->base && base == L->base); + lua_assert(base == L->base && L->base == L->ci->base); lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); switch (GET_OPCODE(i)) { @@ -432,18 +420,18 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rb = KBx(i); sethvalue(L, &g, cl->env); lua_assert(ttisstring(rb)); - base = luaV_gettable(L, &g, rb, ra, pc); /***/ + Protect(luaV_gettable(L, &g, rb, ra)); continue; } case OP_GETTABLE: { - base = luaV_gettable(L, RB(i), RKC(i), ra, pc); /***/ + Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue; } case OP_SETGLOBAL: { TValue g; sethvalue(L, &g, cl->env); lua_assert(ttisstring(KBx(i))); - base = luaV_settable(L, &g, KBx(i), ra, pc); /***/ + Protect(luaV_settable(L, &g, KBx(i), ra)); continue; } case OP_SETUPVAL: { @@ -453,86 +441,101 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_SETTABLE: { - base = luaV_settable(L, ra, RKB(i), RKC(i), pc); /***/ + Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue; } case OP_NEWTABLE: { int b = GETARG_B(i); int c = GETARG_C(i); sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); - L->ci->savedpc = pc; - luaC_checkGC(L); /***/ - base = L->base; + Protect(luaC_checkGC(L)); continue; } case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); - base = luaV_gettable(L, rb, RKC(i), ra, pc); /***/ + Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } case OP_ADD: { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, num_add(nvalue(rb), nvalue(rc))); + lua_Number nb = nvalue(rb), nc = nvalue(rc); + setnvalue(ra, luai_numadd(nb, nc)); } else - base = Arith(L, ra, rb, rc, TM_ADD, pc); /***/ + Protect(Arith(L, ra, rb, rc, TM_ADD)); continue; } case OP_SUB: { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, num_sub(nvalue(rb), nvalue(rc))); + lua_Number nb = nvalue(rb), nc = nvalue(rc); + setnvalue(ra, luai_numsub(nb, nc)); } else - base = Arith(L, ra, rb, rc, TM_SUB, pc); /***/ + Protect(Arith(L, ra, rb, rc, TM_SUB)); continue; } case OP_MUL: { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, num_mul(nvalue(rb), nvalue(rc))); + lua_Number nb = nvalue(rb), nc = nvalue(rc); + setnvalue(ra, luai_nummul(nb, nc)); } else - base = Arith(L, ra, rb, rc, TM_MUL, pc); /***/ + Protect(Arith(L, ra, rb, rc, TM_MUL)); continue; } case OP_DIV: { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, num_div(nvalue(rb), nvalue(rc))); + lua_Number nb = nvalue(rb), nc = nvalue(rc); + setnvalue(ra, luai_numdiv(nb, nc)); + } + else + Protect(Arith(L, ra, rb, rc, TM_DIV)); + continue; + } + case OP_MOD: { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + if (ttisnumber(rb) && ttisnumber(rc)) { + lua_Number nb = nvalue(rb), nc = nvalue(rc); + setnvalue(ra, luai_nummod(nb, nc)); } else - base = Arith(L, ra, rb, rc, TM_DIV, pc); /***/ + Protect(Arith(L, ra, rb, rc, TM_MOD)); continue; } case OP_POW: { TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, num_pow(nvalue(rb), nvalue(rc))); + lua_Number nb = nvalue(rb), nc = nvalue(rc); + setnvalue(ra, luai_numpow(nb, nc)); } else - base = Arith(L, ra, rb, rc, TM_POW, pc); /***/ + Protect(Arith(L, ra, rb, rc, TM_POW)); continue; } case OP_UNM: { const TValue *rb = RB(i); TValue temp; if (tonumber(rb, &temp)) { - setnvalue(ra, num_unm(nvalue(rb))); + lua_Number nb = nvalue(rb); + setnvalue(ra, luai_numunm(nb)); } else { - setnilvalue(&temp); - L->ci->savedpc = pc; - if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) /***/ - luaG_aritherror(L, RB(i), &temp); - base = L->base; + rb = RB(i); /* `tonumber' erased `rb' */ + Protect( + if (!call_binTM(L, rb, &luaO_nilobject, ra, TM_UNM)) + luaG_aritherror(L, rb, &luaO_nilobject); + ) } continue; } @@ -541,13 +544,23 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { setbvalue(ra, res); continue; } + case OP_SIZ: { + const TValue *rb = RB(i); + if (ttype(rb) == LUA_TTABLE) { + setnvalue(ra, cast(lua_Number, luaH_getn(hvalue(rb)))); + } + else { /* try metamethod */ + Protect( + if (!call_binTM(L, rb, &luaO_nilobject, ra, TM_SIZ)) + luaG_typeerror(L, rb, "get size of"); + ) + } + continue; + } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); - L->ci->savedpc = pc; - luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ /***/ - luaC_checkGC(L); /***/ - base = L->base; + Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); setobjs2s(L, RA(i), base+b); continue; } @@ -556,24 +569,27 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_EQ: { - L->ci->savedpc = pc; - if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ - else dojump(L, pc, GETARG_sBx(*pc) + 1); - base = L->base; + Protect( + if (equalobj(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; continue; } case OP_LT: { - L->ci->savedpc = pc; - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ - else dojump(L, pc, GETARG_sBx(*pc) + 1); - base = L->base; + Protect( + if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; continue; } case OP_LE: { - L->ci->savedpc = pc; - if (lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; /***/ - else dojump(L, pc, GETARG_sBx(*pc) + 1); - base = L->base; + Protect( + if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(*pc)); + ) + pc++; continue; } case OP_TEST: { @@ -585,75 +601,71 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } continue; } - case OP_CALL: { /***/ - int pcr; + case OP_CALL: { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->ci->savedpc = pc; - pcr = luaD_precall(L, ra, nresults); - if (pcr == PCRLUA) { - nexeccalls++; - goto callentry; /* restart luaV_execute over new Lua function */ - } - else if (pcr == PCRC) { - /* it was a C function (`precall' called it); adjust results */ - if (nresults >= 0) L->top = L->ci->top; - base = L->base; - continue; - } - else { - lua_assert(pcr == PCRYIELD); - return NULL; + L->savedpc = pc; + switch (luaD_precall(L, ra, nresults)) { + case PCRLUA: { + nexeccalls++; + goto callentry; /* restart luaV_execute over new Lua function */ + } + case PCRC: { + /* it was a C function (`precall' called it); adjust results */ + if (nresults >= 0) L->top = L->ci->top; + base = L->base; + continue; + } + default: { + return NULL; + } } } - case OP_TAILCALL: { /***/ - int pcr; + case OP_TAILCALL: { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->ci->savedpc = pc; + L->savedpc = pc; lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - pcr = luaD_precall(L, ra, LUA_MULTRET); - if (pcr == PCRLUA) { - /* tail call: put new frame in place of previous one */ - CallInfo *ci = L->ci - 1; /* previous frame */ - int aux; - StkId func = ci->func; - StkId pfunc = (ci+1)->func; /* previous function index */ - if (L->openupval) luaF_close(L, base); - base = ci->base = ci->func + ((ci+1)->base - pfunc); - L->base = base; - for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ - setobjs2s(L, func+aux, pfunc+aux); - ci->top = L->top = func+aux; /* correct top */ - lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); - ci->savedpc = L->ci->savedpc; - ci->tailcalls++; /* one more call lost */ - L->ci--; /* remove new frame */ - goto callentry; - } - else if (pcr == PCRC) { - /* it was a C function (`precall' called it) */ - base = L->base; - continue; - } - else { - lua_assert(pcr == PCRYIELD); - return NULL; + switch (luaD_precall(L, ra, LUA_MULTRET)) { + case PCRLUA: { + /* tail call: put new frame in place of previous one */ + CallInfo *ci = L->ci - 1; /* previous frame */ + int aux; + StkId func = ci->func; + StkId pfunc = (ci+1)->func; /* previous function index */ + if (L->openupval) luaF_close(L, ci->base); + L->base = ci->base = ci->func + ((ci+1)->base - pfunc); + for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ + setobjs2s(L, func+aux, pfunc+aux); + ci->top = L->top = func+aux; /* correct top */ + lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); + ci->savedpc = L->savedpc; + ci->tailcalls++; /* one more call lost */ + L->ci--; /* remove new frame */ + goto callentry; + } + case PCRC: { + /* it was a C function (`precall' called it) */ + base = L->base; + continue; + } + default: { + return NULL; + } } } case OP_RETURN: { - CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); - L->ci->savedpc = pc; + L->savedpc = pc; if (--nexeccalls == 0) /* was previous function running `here'? */ return ra; /* no: return */ else { /* yes: continue its execution */ - int nresults = (ci+1)->nresults; - lua_assert(isLua(ci)); - lua_assert(GET_OPCODE(*(ci->savedpc - 1)) == OP_CALL); + int nresults = L->ci->nresults; + lua_assert(isLua(L->ci - 1)); + lua_assert(GET_OPCODE(*((L->ci - 1)->savedpc - 1)) == OP_CALL); luaD_poscall(L, nresults, ra); if (nresults >= 0) L->top = L->ci->top; goto retentry; @@ -661,27 +673,27 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); - lua_Number idx = num_add(nvalue(ra), step); /* increment index */ + lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); - if (step > 0 ? num_le(idx, limit) : num_le(limit, idx)) { + if (step > 0 ? luai_numle(idx, limit) : luai_numle(limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } continue; } - case OP_FORPREP: { /***/ + case OP_FORPREP: { const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; - L->ci->savedpc = pc; + L->savedpc = pc; /* next steps may throw errors */ if (!tonumber(init, ra)) - luaG_runerror(L, "`for' initial value must be a number"); + luaG_runerror(L, LUA_QL("for") " initial value must be a number"); else if (!tonumber(plimit, ra+1)) - luaG_runerror(L, "`for' limit must be a number"); + luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) - luaG_runerror(L, "`for' step must be a number"); - setnvalue(ra, num_sub(nvalue(ra), nvalue(pstep))); + luaG_runerror(L, LUA_QL("for") " step must be a number"); + setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); dojump(L, pc, GETARG_sBx(i)); continue; } @@ -691,10 +703,8 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ - L->ci->savedpc = pc; - luaD_call(L, cb, GETARG_C(i)); /***/ + Protect(luaD_call(L, cb, GETARG_C(i))); L->top = L->ci->top; - base = L->base; cb = RA(i) + 3; /* previous call may change the stack */ if (ttisnil(cb)) /* break loop? */ pc++; /* skip jump (break loop) */ @@ -704,27 +714,19 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } continue; } - case OP_TFORPREP: { /* for compatibility only */ - if (ttistable(ra)) { - setobjs2s(L, ra+1, ra); - setobj2s(L, ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); - } - dojump(L, pc, GETARG_sBx(i)); - continue; - } case OP_SETLIST: { int n = GETARG_B(i); int c = GETARG_C(i); int last; Table *h; - runtime_check(L, ttistable(ra)); - h = hvalue(ra); if (n == 0) { n = L->top - ra - 1; L->top = L->ci->top; } if (c == 0) c = cast(int, *pc++); - last = ((c-1)*LFIELDS_PER_FLUSH) + n + LUA_FIRSTINDEX - 1; + runtime_check(L, ttistable(ra)); + h = hvalue(ra); + last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* pre-alloc it at once */ for (; n > 0; n--) { @@ -755,9 +757,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } } setclvalue(L, ra, ncl); - L->ci->savedpc = pc; - luaC_checkGC(L); /***/ - base = L->base; + Protect(luaC_checkGC(L)); continue; } case OP_VARARG: { diff --git a/src/lvm.h b/src/lvm.h index e1e1f87a31..b00cb8f20b 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.2 2004/05/14 19:25:09 roberto Exp $ +** $Id: lvm.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -22,15 +22,15 @@ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) -int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); -int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); -const TValue *luaV_tonumber (const TValue *obj, TValue *n); -int luaV_tostring (lua_State *L, StkId obj); -StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, - const Instruction *pc); -StkId luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val, - const Instruction *pc); -StkId luaV_execute (lua_State *L, int nexeccalls); -void luaV_concat (lua_State *L, int total, int last); +LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); +LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); +LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); +LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, + StkId val); +LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, + StkId val); +LUAI_FUNC StkId luaV_execute (lua_State *L, int nexeccalls); +LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); #endif diff --git a/src/lzio.c b/src/lzio.c index 20f0724c15..abe086b429 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.29 2004/04/30 20:13:38 roberto Exp $ +** $Id: lzio.c,v 1.30 2005/05/17 19:49:15 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -43,7 +43,7 @@ int luaZ_lookahead (ZIO *z) { } -void luaZ_init (lua_State *L, ZIO *z, lua_Chunkreader reader, void *data) { +void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { z->L = L; z->reader = reader; z->data = data; diff --git a/src/lzio.h b/src/lzio.h index 4b64256e40..8f403b8e74 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.19 2003/10/03 16:05:34 roberto Exp $ +** $Id: lzio.h,v 1.21 2005/05/17 19:49:15 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -17,26 +17,16 @@ typedef struct Zio ZIO; - #define char2int(c) cast(int, cast(unsigned char, (c))) #define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) -void luaZ_init (lua_State *L, ZIO *z, lua_Chunkreader reader, void *data); -size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ -int luaZ_lookahead (ZIO *z); - - - typedef struct Mbuffer { char *buffer; size_t n; size_t buffsize; } Mbuffer; - -char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); - #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) #define luaZ_buffer(buff) ((buff)->buffer) @@ -53,18 +43,25 @@ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) +LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); +LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ +LUAI_FUNC int luaZ_lookahead (ZIO *z); + + /* --------- Private Part ------------------ */ struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ - lua_Chunkreader reader; + lua_Reader reader; void* data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; -int luaZ_fill (ZIO *z); +LUAI_FUNC int luaZ_fill (ZIO *z); #endif diff --git a/src/print.c b/src/print.c index f273ebfccc..8530870540 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.49 2004/11/25 09:31:41 lhf Exp $ +** $Id: print.c,v 1.50 2005/05/12 00:26:50 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -76,9 +76,6 @@ static void PrintCode(const Proto* f) int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); int line=getline(f,pc); -#if 0 - printf("%0*lX",Sizeof(i)*2,i); -#endif printf("\t%d\t",pc+1); if (line>0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); @@ -133,7 +130,6 @@ static void PrintCode(const Proto* f) case OP_JMP: case OP_FORLOOP: case OP_FORPREP: - case OP_TFORPREP: printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: @@ -146,28 +142,25 @@ static void PrintCode(const Proto* f) } } -static const char* Source(const Proto* f) -{ - const char* s=getstr(f->source); - if (*s=='@' || *s=='=') - return s+1; - else if (*s==LUA_SIGNATURE[0]) - return "(bstring)"; - else - return "(string)"; -} - #define SS(x) (x==1)?"":"s" #define S(x) x,SS(x) static void PrintHeader(const Proto* f) { - printf("\n%s <%s:%d> (%d instruction%s, %d bytes at %p)\n", - (f->lineDefined==0)?"main":"function",Source(f),f->lineDefined, + const char* s=getstr(f->source); + if (*s=='@' || *s=='=') + s++; + else if (*s==LUA_SIGNATURE[0]) + s="(bstring)"; + else + s="(string)"; + printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", + (f->linedefined==0)?"main":"function",s, + f->linedefined,f->lastlinedefined, S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); printf("%d%s param%s, %d stack%s, %d upvalue%s, ", - f->numparams,f->is_vararg?"+":"",SS(f->numparams),S(f->maxstacksize), - S(f->nups)); + f->numparams,f->is_vararg?"+":"",SS(f->numparams), + S(f->maxstacksize),S(f->nups)); printf("%d local%s, %d constant%s, %d function%s\n", S(f->sizelocvars),S(f->sizek),S(f->sizep)); } diff --git a/test/README b/test/README index 2a6601c5fe..0c7f38bc25 100644 --- a/test/README +++ b/test/README @@ -22,6 +22,5 @@ Here is a one-line summary of each program: table.lua make table, grouping all data for the same item trace-calls.lua trace calls trace-globals.lua trace assigments to global variables - undefined.lua catch "undefined" global variables xd.lua hex dump diff --git a/test/luac.lua b/test/luac.lua index b009ae9da5..adae1b29bb 100644 --- a/test/luac.lua +++ b/test/luac.lua @@ -3,5 +3,5 @@ assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") f=assert(io.open("luac.out","wb")) -f:write(string.dump(assert(loadfile(arg[1])))) -io.close(f) +assert(f:write(string.dump(assert(loadfile(arg[1]))))) +assert(io.close(f)) diff --git a/test/undefined.lua b/test/undefined.lua deleted file mode 100644 index efe5f2459e..0000000000 --- a/test/undefined.lua +++ /dev/null @@ -1,9 +0,0 @@ --- catch "undefined" global variables - -local f=function (t,i) error("undefined global variable `"..i.."'",2) end -setmetatable(getfenv(),{__index=f}) - --- an example -a=1 -c=3 -print(a,b,c) -- `b' is undefined From bd80c4ee9b6d9464cf9f3ff4ee41890d8b3ca9e6 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 9 Sep 2005 12:00:00 +0000 Subject: [PATCH 24/97] Lua 5.1-alpha --- COPYRIGHT | 2 +- HISTORY | 10 +- INSTALL | 15 +- MANIFEST | 210 +- Makefile | 18 +- README | 8 +- doc/contents.html | 90 +- doc/lua.1 | 9 +- doc/lua.css | 15 + doc/lua.html | 8 +- doc/luac.1 | 14 +- doc/luac.html | 13 +- doc/manual.html | 5980 ++++++++++++++++++++++++++++++++++++++++++ doc/readme.html | 3 +- etc/Makefile | 11 +- etc/README | 14 +- etc/luavs.bat | 7 + etc/noparser.c | 22 +- etc/strict.lua | 34 + src/lapi.c | 27 +- src/lauxlib.c | 181 +- src/lauxlib.h | 57 +- src/lbaselib.c | 74 +- src/lcode.c | 85 +- src/lcode.h | 5 +- src/ldblib.c | 18 +- src/ldebug.c | 24 +- src/ldo.c | 164 +- src/ldo.h | 15 +- src/ldump.c | 79 +- src/lgc.c | 19 +- src/lgc.h | 17 +- src/linit.c | 8 +- src/liolib.c | 145 +- src/llex.h | 4 +- src/llimits.h | 21 +- src/lmathlib.c | 44 +- src/loadlib.c | 373 ++- src/lobject.c | 24 +- src/lobject.h | 23 +- src/lopcodes.c | 10 +- src/lopcodes.h | 11 +- src/loslib.c | 11 +- src/lparser.c | 166 +- src/lstate.c | 5 +- src/lstate.h | 10 +- src/lstrlib.c | 117 +- src/ltable.c | 16 +- src/ltable.h | 4 +- src/ltablib.c | 14 +- src/ltm.c | 4 +- src/ltm.h | 6 +- src/lua.c | 56 +- src/lua.h | 17 +- src/luac.c | 8 +- src/luaconf.h | 307 ++- src/lualib.h | 4 +- src/lundump.c | 242 +- src/lundump.h | 49 +- src/lvm.c | 143 +- src/lvm.h | 4 +- src/lzio.c | 22 +- src/print.c | 8 +- test/luac.lua | 2 +- test/trace-calls.lua | 2 +- 65 files changed, 7696 insertions(+), 1432 deletions(-) create mode 100644 doc/lua.css create mode 100644 doc/manual.html create mode 100644 etc/luavs.bat create mode 100644 etc/strict.lua diff --git a/COPYRIGHT b/COPYRIGHT index ba49873370..282351f320 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 1994-2005 Tecgraf, PUC-Rio. +Copyright (C) 1994-2005 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/HISTORY b/HISTORY index bc7c4181be..4497c06989 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,4 @@ -This is Lua 5.1 (work). +This is Lua 5.1 (alpha). * Changes from version 5.0 to 5.1 ------------------------------- @@ -7,16 +7,16 @@ This is Lua 5.1 (work). + new semantics for control variables of fors. + new semantics for setn/getn. + new syntax/semantics for varargs. - + new long strings. - + new `mod' (`%') operator - + new operation *t (for size of t) + + new long strings and comments. + + new `mod' operator (`%') + + new length operator #t + metatables for all types API: + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + user supplies memory allocator (lua_open becomes lua_newstate). Implementation: + + new configuration scheme via luaconf.h. + incremental garbage collection. - + debug works over other threads. + better handling of end-of-line in the lexer. + fully reentrant parser (new Lua function `load') + better support for 64-bit machines (special thanks to Mike Pall). diff --git a/INSTALL b/INSTALL index 0ddd37e0cf..4f17a9e9a3 100644 --- a/INSTALL +++ b/INSTALL @@ -1,12 +1,11 @@ -This is Lua 5.1 (work). +This is Lua 5.1 (alpha). * Installation ------------ Building Lua on a Unix system should be very easy: simply doing "make" should work. This will build Lua in the src directory. - See below for customization instructions. We strongly recommend that - you enable dynamic loading. + See below for customization instructions. If you want to install Lua in an official place in your system, then do "make install". The official place and the way to install files are @@ -17,7 +16,7 @@ This is Lua 5.1 (work). follows: bin: lua luac - include: lua.h luaconf.h lualib.h lauxlib.h + include: lua.h luaconf.h lualib.h lauxlib.h lua.hpp lib: liblua.a man/man1: lua.1 luac.1 @@ -43,6 +42,9 @@ This is Lua 5.1 (work). to edit src/luaconf.h. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. + We strongly recommend that you enable dynamic loading. See src/luaconf.h + and also src/Makefile. + * Installation on Windows and other systems ----------------------------------------- The instructions for building Lua on other systems depend on the compiler @@ -60,7 +62,7 @@ This is Lua 5.1 (work). compiler: library, luac.c print.c If all you want is to build the Lua interpreter, you may put all .c files - in a single project, except for luac.c and print.c. + in a single project, except for luac.c and print.c. Or use etc/all.c. To use Lua as a library in your own programs, you'll need to know how to create and use libraries with your compiler. @@ -68,4 +70,7 @@ This is Lua 5.1 (work). As mentioned above, you may edit luaconf.h to select some features before building Lua. + If you use Visual Studio .NET, you can use etc/luavs.bat + in its "Command Prompt". + (end of INSTALL) diff --git a/MANIFEST b/MANIFEST index dbd86863c5..5731f184ef 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,104 +1,108 @@ -MANIFEST contents of Lua 5.1 (work6) distribution on Wed May 18 10:13:40 BRST 2005 -lua-5.1-work6 -lua-5.1-work6/COPYRIGHT -lua-5.1-work6/HISTORY -lua-5.1-work6/INSTALL -lua-5.1-work6/MANIFEST -lua-5.1-work6/Makefile -lua-5.1-work6/README -lua-5.1-work6/doc -lua-5.1-work6/doc/contents.html -lua-5.1-work6/doc/logo.gif -lua-5.1-work6/doc/lua.1 -lua-5.1-work6/doc/lua.html -lua-5.1-work6/doc/luac.1 -lua-5.1-work6/doc/luac.html -lua-5.1-work6/doc/readme.html -lua-5.1-work6/etc -lua-5.1-work6/etc/Makefile -lua-5.1-work6/etc/README -lua-5.1-work6/etc/all.c -lua-5.1-work6/etc/lua.hpp -lua-5.1-work6/etc/lua.ico -lua-5.1-work6/etc/lua.pc -lua-5.1-work6/etc/min.c -lua-5.1-work6/etc/noparser.c -lua-5.1-work6/src -lua-5.1-work6/src/Makefile -lua-5.1-work6/src/lapi.c -lua-5.1-work6/src/lapi.h -lua-5.1-work6/src/lauxlib.c -lua-5.1-work6/src/lauxlib.h -lua-5.1-work6/src/lbaselib.c -lua-5.1-work6/src/lcode.c -lua-5.1-work6/src/lcode.h -lua-5.1-work6/src/ldblib.c -lua-5.1-work6/src/ldebug.c -lua-5.1-work6/src/ldebug.h -lua-5.1-work6/src/ldo.c -lua-5.1-work6/src/ldo.h -lua-5.1-work6/src/ldump.c -lua-5.1-work6/src/lfunc.c -lua-5.1-work6/src/lfunc.h -lua-5.1-work6/src/lgc.c -lua-5.1-work6/src/lgc.h -lua-5.1-work6/src/linit.c -lua-5.1-work6/src/liolib.c -lua-5.1-work6/src/llex.c -lua-5.1-work6/src/llex.h -lua-5.1-work6/src/llimits.h -lua-5.1-work6/src/lmathlib.c -lua-5.1-work6/src/lmem.c -lua-5.1-work6/src/lmem.h -lua-5.1-work6/src/loadlib.c -lua-5.1-work6/src/lobject.c -lua-5.1-work6/src/lobject.h -lua-5.1-work6/src/lopcodes.c -lua-5.1-work6/src/lopcodes.h -lua-5.1-work6/src/loslib.c -lua-5.1-work6/src/lparser.c -lua-5.1-work6/src/lparser.h -lua-5.1-work6/src/lstate.c -lua-5.1-work6/src/lstate.h -lua-5.1-work6/src/lstring.c -lua-5.1-work6/src/lstring.h -lua-5.1-work6/src/lstrlib.c -lua-5.1-work6/src/ltable.c -lua-5.1-work6/src/ltable.h -lua-5.1-work6/src/ltablib.c -lua-5.1-work6/src/ltm.c -lua-5.1-work6/src/ltm.h -lua-5.1-work6/src/lua.c -lua-5.1-work6/src/lua.h -lua-5.1-work6/src/luac.c -lua-5.1-work6/src/luaconf.h -lua-5.1-work6/src/lualib.h -lua-5.1-work6/src/lundump.c -lua-5.1-work6/src/lundump.h -lua-5.1-work6/src/lvm.c -lua-5.1-work6/src/lvm.h -lua-5.1-work6/src/lzio.c -lua-5.1-work6/src/lzio.h -lua-5.1-work6/src/print.c -lua-5.1-work6/test -lua-5.1-work6/test/README -lua-5.1-work6/test/bisect.lua -lua-5.1-work6/test/cf.lua -lua-5.1-work6/test/echo.lua -lua-5.1-work6/test/env.lua -lua-5.1-work6/test/factorial.lua -lua-5.1-work6/test/fib.lua -lua-5.1-work6/test/fibfor.lua -lua-5.1-work6/test/globals.lua -lua-5.1-work6/test/hello.lua -lua-5.1-work6/test/life.lua -lua-5.1-work6/test/luac.lua -lua-5.1-work6/test/printf.lua -lua-5.1-work6/test/readonly.lua -lua-5.1-work6/test/sieve.lua -lua-5.1-work6/test/sort.lua -lua-5.1-work6/test/table.lua -lua-5.1-work6/test/trace-calls.lua -lua-5.1-work6/test/trace-globals.lua -lua-5.1-work6/test/xd.lua +MANIFEST contents of Lua 5.1 (alpha) distribution on Fri Sep 9 16:55:12 BRST 2005 +lua-5.1-alpha +lua-5.1-alpha/COPYRIGHT +lua-5.1-alpha/HISTORY +lua-5.1-alpha/INSTALL +lua-5.1-alpha/MANIFEST +lua-5.1-alpha/Makefile +lua-5.1-alpha/README +lua-5.1-alpha/doc +lua-5.1-alpha/doc/contents.html +lua-5.1-alpha/doc/logo.gif +lua-5.1-alpha/doc/lua.1 +lua-5.1-alpha/doc/lua.css +lua-5.1-alpha/doc/lua.html +lua-5.1-alpha/doc/luac.1 +lua-5.1-alpha/doc/luac.html +lua-5.1-alpha/doc/manual.html +lua-5.1-alpha/doc/readme.html +lua-5.1-alpha/etc +lua-5.1-alpha/etc/Makefile +lua-5.1-alpha/etc/README +lua-5.1-alpha/etc/all.c +lua-5.1-alpha/etc/lua.hpp +lua-5.1-alpha/etc/lua.ico +lua-5.1-alpha/etc/lua.pc +lua-5.1-alpha/etc/luavs.bat +lua-5.1-alpha/etc/min.c +lua-5.1-alpha/etc/noparser.c +lua-5.1-alpha/etc/strict.lua +lua-5.1-alpha/src +lua-5.1-alpha/src/Makefile +lua-5.1-alpha/src/lapi.c +lua-5.1-alpha/src/lapi.h +lua-5.1-alpha/src/lauxlib.c +lua-5.1-alpha/src/lauxlib.h +lua-5.1-alpha/src/lbaselib.c +lua-5.1-alpha/src/lcode.c +lua-5.1-alpha/src/lcode.h +lua-5.1-alpha/src/ldblib.c +lua-5.1-alpha/src/ldebug.c +lua-5.1-alpha/src/ldebug.h +lua-5.1-alpha/src/ldo.c +lua-5.1-alpha/src/ldo.h +lua-5.1-alpha/src/ldump.c +lua-5.1-alpha/src/lfunc.c +lua-5.1-alpha/src/lfunc.h +lua-5.1-alpha/src/lgc.c +lua-5.1-alpha/src/lgc.h +lua-5.1-alpha/src/linit.c +lua-5.1-alpha/src/liolib.c +lua-5.1-alpha/src/llex.c +lua-5.1-alpha/src/llex.h +lua-5.1-alpha/src/llimits.h +lua-5.1-alpha/src/lmathlib.c +lua-5.1-alpha/src/lmem.c +lua-5.1-alpha/src/lmem.h +lua-5.1-alpha/src/loadlib.c +lua-5.1-alpha/src/lobject.c +lua-5.1-alpha/src/lobject.h +lua-5.1-alpha/src/lopcodes.c +lua-5.1-alpha/src/lopcodes.h +lua-5.1-alpha/src/loslib.c +lua-5.1-alpha/src/lparser.c +lua-5.1-alpha/src/lparser.h +lua-5.1-alpha/src/lstate.c +lua-5.1-alpha/src/lstate.h +lua-5.1-alpha/src/lstring.c +lua-5.1-alpha/src/lstring.h +lua-5.1-alpha/src/lstrlib.c +lua-5.1-alpha/src/ltable.c +lua-5.1-alpha/src/ltable.h +lua-5.1-alpha/src/ltablib.c +lua-5.1-alpha/src/ltm.c +lua-5.1-alpha/src/ltm.h +lua-5.1-alpha/src/lua.c +lua-5.1-alpha/src/lua.h +lua-5.1-alpha/src/luac.c +lua-5.1-alpha/src/luaconf.h +lua-5.1-alpha/src/lualib.h +lua-5.1-alpha/src/lundump.c +lua-5.1-alpha/src/lundump.h +lua-5.1-alpha/src/lvm.c +lua-5.1-alpha/src/lvm.h +lua-5.1-alpha/src/lzio.c +lua-5.1-alpha/src/lzio.h +lua-5.1-alpha/src/print.c +lua-5.1-alpha/test +lua-5.1-alpha/test/README +lua-5.1-alpha/test/bisect.lua +lua-5.1-alpha/test/cf.lua +lua-5.1-alpha/test/echo.lua +lua-5.1-alpha/test/env.lua +lua-5.1-alpha/test/factorial.lua +lua-5.1-alpha/test/fib.lua +lua-5.1-alpha/test/fibfor.lua +lua-5.1-alpha/test/globals.lua +lua-5.1-alpha/test/hello.lua +lua-5.1-alpha/test/life.lua +lua-5.1-alpha/test/luac.lua +lua-5.1-alpha/test/printf.lua +lua-5.1-alpha/test/readonly.lua +lua-5.1-alpha/test/sieve.lua +lua-5.1-alpha/test/sort.lua +lua-5.1-alpha/test/table.lua +lua-5.1-alpha/test/trace-calls.lua +lua-5.1-alpha/test/trace-globals.lua +lua-5.1-alpha/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index beb36e869d..58cbcca47f 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ INSTALL_DATA= cp # What to install. TO_BIN= lua luac -TO_INC= lua.h luaconf.h lualib.h lauxlib.h +TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp TO_LIB= liblua.a TO_MAN= lua.1 luac.1 @@ -49,6 +49,22 @@ install: all local: $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -p" INSTALL_DATA="cp -p" +# convenience targets for usual platforms + +ansi: + cd src; $(MAKE) MYCFLAGS=-DLUA_ANSI + +linux: + cd src; $(MAKE) MYCFLAGS=-DLUA_USE_DLOPEN MYLIBS="-Wl,-E -ldl" + +bsd: + cd src; $(MAKE) MYCFLAGS=-DLUA_USE_DLOPEN MYLIBS="-Wl,-E" + +mingw: + cd src; $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ + "AR=gcc -shared -o" "RANLIB=strip --strip-unneeded" \ + "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" MYLDFLAGS=-s" lua.exe + # echo config parameters echo: @echo "" diff --git a/README b/README index 1efe91ffaf..668f569d08 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Lua 5.1 (work). +This is Lua 5.1 (alpha). See HISTORY for a summary of changes since the last released version. * What is Lua? @@ -27,9 +27,9 @@ See HISTORY for a summary of changes since the last released version. * Origin ------ - Lua is developed at Tecgraf, the Computer Graphics Technology Group - of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). - Tecgraf is a laboratory of the Department of Computer Science. + Lua is developed at Lua.org, a laboratory of the Department of Computer + Science of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro + in Brazil). For more information about the authors, see http://www.lua.org/authors.html . (end of README) diff --git a/doc/contents.html b/doc/contents.html index 06bd6fb4c7..9db0cafa11 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -1,32 +1,25 @@ -Lua: 5.0 reference manual - contents +Lua 5.1 reference manual - contents +

        -Lua -Reference manual for Lua 5.0 +Lua +Lua 5.1 Reference Manual

        -Lua 5.0 Reference Manual -[ -top -| -ps -| -pdf -] -

        - Copyright -© 2003 Tecgraf, PUC-Rio. All rights reserved. +© 2005 Lua.org, PUC-Rio. All rights reserved. +


        -
      • 3 - The Application Program Interface -
      • 4 - The Debug Interface +
      • 4 - The Auxiliary Library
      • 5 - Standard Libraries
      • 6 - Lua Stand-alone
      • The Complete Syntax of Lua @@ -116,7 +96,7 @@


        Last update: -Wed May 7 18:34:34 EST 2003 +Fri Sep 9 14:44:10 BRST 2005 diff --git a/doc/lua.1 b/doc/lua.1 index c9bba7d700..39c7d8e483 100644 --- a/doc/lua.1 +++ b/doc/lua.1 @@ -1,5 +1,5 @@ -.\" lua.man,v 1.8 2003/04/02 00:05:20 lhf Exp -.TH LUA 1 "2003/04/02 00:05:20" +.\" $Id: lua.man,v 1.9 2005/09/02 16:29:34 lhf Exp $ +.TH LUA 1 "$Date: 2005/09/02 16:29:34 $" .SH NAME lua \- Lua interpreter .SH SYNOPSIS @@ -141,9 +141,9 @@ enter interactive mode after .I script is executed. .TP -.BI \-l " file" +.BI \-l " module" call -.BI require( file ) +.BI require( module ) before executing .IR script. Typically used to load libraries @@ -163,5 +163,4 @@ R. Ierusalimschy, L. H. de Figueiredo, and W. Celes -(lua@tecgraf.puc-rio.br) .\" EOF diff --git a/doc/lua.css b/doc/lua.css new file mode 100644 index 0000000000..90f62312d0 --- /dev/null +++ b/doc/lua.css @@ -0,0 +1,15 @@ +body { + color: #000000 ; + background-color: #FFFFFF ; + font-family: sans-serif ; +} + +a:link { + color: #000080 ; +} + +a:link:hover, a:visited:hover { + color: #000080 ; + background-color: #E0E0FF ; +} + diff --git a/doc/lua.html b/doc/lua.html index 073d4b525a..3bc0d8aed4 100644 --- a/doc/lua.html +++ b/doc/lua.html @@ -1,7 +1,8 @@ - + LUA man page + @@ -147,9 +148,9 @@

        OPTIONS

        script is executed.

        --l "file" +-l "module" call -require( file) +require( module) before executing script. Typically used to load libraries @@ -169,7 +170,6 @@

        AUTHORS

        L. H. de Figueiredo, and W. Celes -(lua AT tecgraf.puc-rio.br) diff --git a/doc/luac.1 b/doc/luac.1 index c6523060f8..7a44e2f2f2 100644 --- a/doc/luac.1 +++ b/doc/luac.1 @@ -1,5 +1,5 @@ -.\" luac.man,v 1.25 2002/12/13 11:45:12 lhf Exp -.TH LUAC 1 "2002/12/13 11:45:12" +.\" $Id: luac.man,v 1.26 2005/09/02 16:29:34 lhf Exp $ +.TH LUAC 1 "$Date: 2005/09/02 16:29:34 $" .SH NAME luac \- Lua compiler .SH SYNOPSIS @@ -38,14 +38,7 @@ option. .LP The binary files created by .B luac -are portable to all architectures with the same word size. -This means that -binary files created on a 32-bit platform (such as Intel) -can be read without change in another 32-bit platform (such as Sparc), -even if the byte order (``endianness'') is different. -On the other hand, -binary files created on a 16-bit platform cannot be read in a 32-bit platform, -nor vice-versa. +are portable only among architectures with the same word size and byte order. .LP In the command line, you can mix @@ -132,5 +125,4 @@ Error messages should be self explanatory. L. H. de Figueiredo, R. Ierusalimschy and W. Celes -(lua@tecgraf.puc-rio.br) .\" EOF diff --git a/doc/luac.html b/doc/luac.html index 3a71622e0b..586b38e869 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -1,7 +1,8 @@ - + LUAC man page + @@ -44,14 +45,7 @@

        DESCRIPTION

        The binary files created by luac -are portable to all architectures with the same word size. -This means that -binary files created on a 32-bit platform (such as Intel) -can be read without change in another 32-bit platform (such as Sparc), -even if the byte order (``endianness'') is different. -On the other hand, -binary files created on a 16-bit platform cannot be read in a 32-bit platform, -nor vice-versa. +are portable only among architectures with the same word size and byte order.

        In the command line, you can mix @@ -138,7 +132,6 @@

        AUTHORS

        L. H. de Figueiredo, R. Ierusalimschy and W. Celes -(lua AT tecgraf.puc-rio.br) diff --git a/doc/manual.html b/doc/manual.html new file mode 100644 index 0000000000..b55232bd42 --- /dev/null +++ b/doc/manual.html @@ -0,0 +1,5980 @@ + + + + +Lua 5.1 Reference Manual + + + + + +
        +

        +[Lua logo] +Lua 5.1 Reference Manual +

        + +by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes +

        + +Copyright +© 2005 Lua.org, PUC-Rio. All rights reserved. + +


        + +

        +

        + + + + +

        +

        1 - Introduction

        + +

        Lua is an extension programming language designed to support +general procedural programming with data description +facilities. +It also offers good support for object-oriented programming, +functional programming, and data-driven programming. +Lua is intended to be used as a powerful, light-weight +configuration language for any program that needs one. +Lua is implemented as a library, written in clean C +(that is, in the common subset of ANSI C and C++). + +

        Being an extension language, Lua has no notion of a "main" program: +it only works embedded in a host client, +called the embedding program or simply the host. +This host program can invoke functions to execute a piece of Lua code, +can write and read Lua variables, +and can register C functions to be called by Lua code. +Through the use of C functions, Lua can be augmented to cope with +a wide range of different domains, +thus creating customized programming languages sharing a syntactical framework. + +

        The Lua distribution includes a stand-alone embedding program, +lua, that uses the Lua library to offer a complete Lua interpreter. + +

        Lua is free software, +and is provided as usual with no guarantees, +as stated in its copyright notice. +The implementation described in this manual is available +at Lua's official web site, www.lua.org. + +

        Like any other reference manual, +this document is dry in places. +For a discussion of the decisions behind the design of Lua, +see the papers below, +which are available at Lua's web site. +

          +
        • +R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. +Lua—an extensible extension language. +Software: Practice & Experience 26:6 (1996) 635–652. +
        • +L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. +The design and implementation of a language for extending applications. +Proceedings of XXI Brazilian Seminar on Software and Hardware +(1994) 273–283. +
        • +L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. +Lua: an extensible embedded language. +Dr. Dobb's Journal 21:12 (Dec 1996) 26–33. +
        • +R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. +The evolution of an extension language: a history of Lua, +Proceedings of V Brazilian Symposium on Programming Languages (2001) B-14–B-28. +
        + +

        Lua means "moon" in Portuguese and is pronounced LOO-ah. + +

        +

        2 - The Language

        + +

        This section describes the lexis, the syntax, and the semantics of Lua. +In other words, +this section describes +which tokens are valid, +how they can be combined, +and what their combinations mean. + +

        The language constructs will be explained using the usual extended BNF, +in which +{a} means 0 or more a's, and +[a] means an optional a. +Non-terminals are shown in italics, +keywords are shown in bold, +and other terminal symbols are shown in typewriter font, +enclosed in single quotes. + +

        2.1 - Lexical Conventions

        + +

        Names in Lua can be any string of letters, +digits, and underscores, +not beginning with a digit. +This coincides with the definition of names in most languages. +(The definition of letter depends on the current locale: +any character considered alphabetic by the current locale +can be used in an identifier.) + +

        The following keywords are reserved +and cannot be used as names: + +

        +       and       break     do        else      elseif
        +       end       false     for       function  if
        +       in        local     nil       not       or
        +       repeat    return    then      true      until     while
        +
        + +

        Lua is a case-sensitive language: +and is a reserved word, but And and AND +are two different, valid names. +As a convention, names starting with an underscore followed by +uppercase letters (such as _VERSION) +are reserved for internal variables used by Lua. + +

        The following strings denote other tokens: +

        +       +     -     *     /     %     ^     #
        +       ==    ~=    <=    >=    <     >     =
        +       (     )     {     }     [     ]
        +       ;     :     ,     .     ..    ...
        +
        + +

        Literal strings +can be delimited by matching single or double quotes, +and can contain the following C-like escape sequences: +

          +
        • \a — bell +
        • \b — backspace +
        • \f — form feed +
        • \n — newline +
        • \r — carriage return +
        • \t — horizontal tab +
        • \v — vertical tab +
        • \\ — backslash +
        • \" — quotation mark +
        • \' — apostrophe +
        +Moreover, a `\newline´ +(that is, a backslash followed by a real newline) +results in a newline in the string. +A character in a string may also be specified by its numerical value +using the escape sequence `\ddd´, +where ddd is a sequence of up to three decimal digits. +Strings in Lua may contain any 8-bit value, including embedded zeros, +which can be specified as `\0´. + +

        Literal strings can also be defined using a long format +enclosed by l-brackets (long brackets). +We define an opening l-bracket of level n as an opening +square bracket followed by n equal signs followed by another +opening square bracket. +So, an opening l-bracket of level 0 is written as [[, +an opening l-bracket of level 1 is written as [=[, +and so on. +A closing l-bracket is defined similarly; +for instance, a closing l-bracket of level 4 is written as ]====]. +A long string starts with an opening l-bracket of any level and +ends at the first closing l-bracket of the same level. +Literals in this bracketed form may run for several lines, +do not interpret any escape sequences, +and ignore l-brackets of any other level. + +

        For convenience, +when the opening l-bracket is immediately followed by a newline, +the newline is not included in the string. +As an example, in a system using ASCII +(in which `a´ is coded as 97, +newline is coded as 10, and `1´ is coded as 49), +the four literals below denote the same string: +

        +      (1)   "alo\n123\""
        +      (2)   '\97lo\10\04923"'
        +      (3)   [[alo
        +            123"]]
        +      (4)   [==[
        +            alo
        +            123"]==]
        +
        + +

        Numerical constants may be written with an optional decimal part +and an optional decimal exponent. +Examples of valid numerical constants are +

        +       3     3.0     3.1416  314.16e-2   0.31416E1
        +
        + +

        Comments start anywhere outside a string with a +double hyphen (--). +If the text immediately after -- is not an opening l-bracket, +the comment is a short comment, +which runs until the end of the line. +Otherwise, it is a long comment, +which runs until the corresponding closing l-bracket. + +

        2.2 - Values and Types

        + +

        Lua is a dynamically typed language. +That means that +variables do not have types; only values do. +There are no type definitions in the language. +All values carry their own type. + +

        There are eight basic types in Lua: +nil, boolean, number, +string, function, userdata, +thread, and table. +Nil is the type of the value nil, +whose main property is to be different from any other value; +usually it represents the absence of a useful value. +Boolean is the type of the values false and true. +In Lua, both nil and false make a condition false; +any other value makes it true. +Number represents real (double-precision floating-point) numbers. +(It is easy to build Lua interpreters that use other +internal representations for numbers, +such as single-precision float or long integers. +See file luaconf.h.) +String represents arrays of characters. + +Lua is 8-bit clean: +Strings may contain any 8-bit character, +including embedded zeros ('\0') (see 2.1). + +

        Functions are first-class values in Lua. +That means that functions can be stored in variables, +passed as arguments to other functions, and returned as results. +Lua can call (and manipulate) functions written in Lua and +functions written in C +(see 2.5.8). + +

        The type userdata is provided to allow arbitrary C data to +be stored in Lua variables. +This type corresponds to a block of raw memory +and has no pre-defined operations in Lua, +except assignment and identity test. +However, by using metatables, +the programmer can define operations for userdata values +(see 2.8). +Userdata values cannot be created or modified in Lua, +only through the C API. +This guarantees the integrity of data owned by the host program. + +

        The type thread represents independent threads of execution +and it is used to implement coroutines (see 2.11). + +

        The type table implements associative arrays, +that is, arrays that can be indexed not only with numbers, +but with any value (except nil). +Moreover, +tables can be heterogeneous, +that is, they can contain values of all types (except nil). +Tables are the sole data structuring mechanism in Lua; +they may be used to represent ordinary arrays, +symbol tables, sets, records, graphs, trees, etc. +To represent records, Lua uses the field name as an index. +The language supports this representation by +providing a.name as syntactic sugar for a["name"]. +There are several convenient ways to create tables in Lua +(see 2.5.7). + +

        Like indices, +the value of a table field can be of any type (except nil). +In particular, +because functions are first class values, +table fields may contain functions. +Thus tables may also carry methods (see 2.5.9). + +

        Tables, functions, and userdata values are objects: +variables do not actually contain these values, +only references to them. +Assignment, parameter passing, and function returns +always manipulate references to such values; +these operations do not imply any kind of copy. + +

        The library function type returns a string describing the type +of a given value. + +

        2.2.1 - Coercion

        + +

        Lua provides automatic conversion between +string and number values at run time. +Any arithmetic operation applied to a string tries to convert +that string to a number, following the usual rules. +Conversely, whenever a number is used where a string is expected, +the number is converted to a string, in a reasonable format. +For complete control of how numbers are converted to strings, +use the format function from the string library +(see string.format). + +

        2.3 - Variables

        + +

        Variables are places that store values. + +There are three kinds of variables in Lua: +global variables, local variables, and table fields. + +

        A single name can denote a global variable or a local variable +(or a formal parameter of a function, +which is a particular form of local variable): +

        +	var ::= Name
        +
        +Variables are assumed to be global unless explicitly declared local +(see 2.4.7). +Local variables are lexically scoped: +Local variables can be freely accessed by functions +defined inside their scope (see 2.6). + +

        Before the first assignment to a variable, its value is nil. + +

        Square brackets are used to index a table: +

        +	var ::= prefixexp `[´ exp `]´
        +
        +The first expression (prefixexp) should result in a table value; +the second expression (exp) +identifies a specific entry inside that table. +The expression denoting the table to be indexed has a restricted syntax; +see 2.5 for details. + +

        The syntax var.NAME is just syntactic sugar for +var["NAME"]: +

        +	var ::= prefixexp `.´ Name
        +
        + +

        The meaning of accesses to global variables +and table fields can be changed via metatables. +An access to an indexed variable t[i] is equivalent to +a call gettable_event(t,i). +(See 2.8 for a complete description of the +gettable_event function. +This function is not defined or callable in Lua. +We use it here only for explanatory purposes.) + +

        All global variables live as fields in ordinary Lua tables, +called environment tables or simply +environments (see 2.9). +Each function has its own reference to an environment, +so that all global variables in that function +will refer to that environment table. +When a function is created, +it inherits the environment from the function that created it. +To replace or get the environment table of a Lua function, +you call setfenv or getfenv. +(You can only manipulate the environment of C functions +through the debug library; (see 5.9).) + +

        An access to a global variable x +is equivalent to _env.x, +which in turn is equivalent to +

        +       gettable_event(_env, "x")
        +
        +where _env is the environment of the running function. +(See 2.8 for a complete description of the +gettable_event function. +This function is not defined or callable in Lua. +Similarly, the _env variable is not defined in Lua. +We use them here only for explanatory purposes.) + +

        2.4 - Statements

        + +

        Lua supports an almost conventional set of statements, +similar to those in Pascal or C. +This set includes +assignment, control structures, procedure calls, +table constructors, and variable declarations. + +

        2.4.1 - Chunks

        + +

        The unit of execution of Lua is called a chunk. +A chunk is simply a sequence of statements, +which are executed sequentially. +Each statement can be optionally followed by a semicolon: +

        +	chunk ::= {stat [`;´]}
        +
        + +

        Lua handles a chunk as the body of an anonymous function +with a variable number of arguments +(see 2.5.9). +As such, chunks can define local variables, +receive arguments, and return values. + +

        A chunk may be stored in a file or in a string inside the host program. +When a chunk is executed, first it is pre-compiled into opcodes for +a virtual machine, +and then the compiled code is executed +by an interpreter for the virtual machine. + +

        Chunks may also be pre-compiled into binary form; +see program luac for details. +Programs in source and compiled forms are interchangeable; +Lua automatically detects the file type and acts accordingly. + + +

        2.4.2 - Blocks

        +A block is a list of statements; +syntactically, a block is equal to a chunk: +
        +	block ::= chunk
        +
        + +

        A block may be explicitly delimited to produce a single statement: +

        +	stat ::= do block end
        +
        +Explicit blocks are useful +to control the scope of variable declarations. +Explicit blocks are also sometimes used to +add a return or break statement in the middle +of another block (see 2.4.4). + + +

        2.4.3 - Assignment

        + +

        Lua allows multiple assignment. +Therefore, the syntax for assignment +defines a list of variables on the left side +and a list of expressions on the right side. +The elements in both lists are separated by commas: +

        +	stat ::= varlist1 `=´ explist1
        +	varlist1 ::= var {`,´ var}
        +	explist1 ::= exp {`,´ exp}
        +
        +Expressions are discussed in 2.5. + +

        Before the assignment, +the list of values is adjusted to the length of +the list of variables. +If there are more values than needed, +the excess values are thrown away. +If there are fewer values than needed, +the list is extended with as many nil's as needed. +If the list of expressions ends with a function call, +then all values returned by that function call enter in the list of values, +before the adjustment +(except when the call is enclosed in parentheses; see 2.5). + +

        The assignment statement first evaluates all its expressions +and only then are the assignments performed. +Thus the code +

        +       i = 3
        +       i, a[i] = i+1, 20
        +
        +sets a[3] to 20, without affecting a[4] +because the i in a[i] is evaluated (to 3) +before it is assigned 4. +Similarly, the line +
        +       x, y = y, x
        +
        +exchanges the values of x and y. + +

        The meaning of assignments to global variables +and table fields can be changed via metatables. +An assignment to an indexed variable t[i] = val is equivalent to +settable_event(t,i,val). +(See 2.8 for a complete description of the +settable_event function. +This function is not defined or callable in Lua. +We use it here only for explanatory purposes.) + +

        An assignment to a global variable x = val +is equivalent to the assignment +_env.x = val, +which in turn is equivalent to +

        +       settable_event(_env, "x", val)
        +
        +where _env is the environment of the running function. +(The _env variable is not defined in Lua. +We use it here only for explanatory purposes.) + +

        2.4.4 - Control Structures

        +The control structures +if, while, and repeat have the usual meaning and +familiar syntax: + + + +
        +	stat ::= while exp do block end
        +	stat ::= repeat block until exp
        +	stat ::= if exp then block {elseif exp then block} [else block] end
        +
        +Lua also has a for statement, in two flavors (see 2.4.5). + +

        The condition expression exp of a +control structure may return any value. +Both false and nil are considered false. +All values different from nil and false are considered true +(in particular, the number 0 and the empty string are also true). + +

        In the repeatuntil loop, +the inner block does not end at the until keyword, +but only after the condition. +That means the condition can refer to local variables +declared inside the loop. + +

        The return statement is used to return values +from a function or from a chunk. + +Functions and chunks may return more than one value, +so the syntax for the return statement is +

        +	stat ::= return [explist1]
        +
        + +

        The break statement can be used to terminate the execution of a +while, repeat, or for loop, +skipping to the next statement after the loop: + +

        +	stat ::= break
        +
        +A break ends the innermost enclosing loop. + +

        For syntactic reasons, return and break +statements can only be written as the last statement of a block. +If it is really necessary to return or break in the +middle of a block, +then an explicit inner block can be used, +as in the idioms +`do return end´ and +`do break end´, +because now return and break are the last statements in +their (inner) blocks. + +

        2.4.5 - For Statement

        + +

        The for statement has two forms: +one numeric and one generic. + + +

        The numeric for loop repeats a block of code while a +control variable runs through an arithmetic progression. +It has the following syntax: +

        +	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end
        +
        +The block is repeated for name starting at the value of +the first exp, until it passes the second exp by steps of the +third exp. +More precisely, a for statement like +
        +       for var = e1, e2, e3 do block end
        +
        +is equivalent to the code: +
        +       do
        +         local _var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
        +         if not (_var and _limit and _step) then error() end
        +         while (_step>0 and _var<=_limit) or (_step<=0 and _var>=_limit) do
        +           local var = _var
        +           block
        +           _var = _var + _step
        +         end
        +       end
        +
        +Note the following: +
          +
        • All three control expressions are evaluated only once, +before the loop starts. +They must all result in numbers. +
        • _var, _limit, and _step are invisible variables. +The names are here for explanatory purposes only. +
        • If the third expression (the step) is absent, +then a step of 1 is used. +
        • You can use break to exit a for loop. +
        • The loop variable var is local to the loop; +you cannot use its value after the for ends or is broken. +If you need the value of the loop variable var, +then assign it to another variable before breaking or exiting the loop. +
        + +

        The generic for statement works over functions, +called iterators. +For each iteration, it calls its iterator function to produce a new value, +stopping when the new value is nil. +The generic for loop has the following syntax: +

        +	stat ::= for Name {`,´ Name} in explist1 do block end
        +
        +A for statement like +
        +       for var_1, ..., var_n in explist do block end
        +
        +is equivalent to the code: +
        +       do
        +         local _f, _s, _var = explist
        +         while true do
        +           local var_1, ... , var_n = _f(_s, _var)
        +           _var = var_1
        +           if _var == nil then break end
        +           block
        +         end
        +       end
        +
        +Note the following: +
          +
        • explist is evaluated only once. +Its results are an iterator function, +a state, and an initial value for the first iterator variable. +
        • _f, _s, and _var are invisible variables. +The names are here for explanatory purposes only. +
        • You can use break to exit a for loop. +
        • The loop variables var_i are local to the loop; +you cannot use their values after the for ends. +If you need these values, +then assign them to other variables before breaking or exiting the loop. +
        + +

        2.4.6 - Function Calls as Statements

        +To allow possible side-effects, +function calls can be executed as statements: +
        +	stat ::= functioncall
        +
        +In this case, all returned values are thrown away. +Function calls are explained in 2.5.8. + +

        2.4.7 - Local Declarations

        +Local variables may be declared anywhere inside a block. +The declaration may include an initial assignment: +
        +	stat ::= local namelist [`=´ explist1]
        +	namelist ::= Name {`,´ Name}
        +
        +If present, an initial assignment has the same semantics +of a multiple assignment (see 2.4.3). +Otherwise, all variables are initialized with nil. + +

        A chunk is also a block (see 2.4.1), +so local variables can be declared in a chunk outside any explicit block. +The scope of such local variables extends until the end of the chunk. + +

        The visibility rules for local variables are explained in 2.6. + +

        2.5 - Expressions

        + +

        +The basic expressions in Lua are the following: +

        +	exp ::= prefixexp
        +	exp ::= nil | false | true
        +	exp ::= Number
        +	exp ::= Literal
        +	exp ::= function
        +	exp ::= tableconstructor
        +	exp ::= `...´
        +	exp ::= exp binop exp
        +	exp ::= unop exp
        +	prefixexp ::= var | functioncall | `(´ exp `)´
        +
        + +

        Numbers and literal strings are explained in 2.1; +variables are explained in 2.3; +function definitions are explained in 2.5.9; +function calls are explained in 2.5.8; +table constructors are explained in 2.5.7. +Vararg expressions, +denoted by three dots (...), can only be used inside +vararg functions; +they are explained in 2.5.9. + + +

        Binary operators comprise arithmetic operators (see 2.5.1), +relational operators (see 2.5.2), and logical operators (see 2.5.3). +Unary operators comprise the unary minus (see 2.5.1), +the unary not (see 2.5.3), +and the unary length operator (see 2.5.5). + +

        Both function calls and vararg expressions may result in multiple values. +If the expression is used as a statement (see 2.4.6) +(only possible for function calls), +then its return list is adjusted to zero elements, +thus discarding all returned values. +If the expression is used inside another expression +or in the middle of a list of expressions, +then its result list is adjusted to one element, +thus discarding all values except the first one. +If the expression is used as the last element of a list of expressions, +then no adjustment is made, +unless the call is enclosed in parentheses. + +

        Here are some examples: +

        +       f()                -- adjusted to 0 results
        +       g(f(), x)          -- f() is adjusted to 1 result
        +       g(x, f())          -- g gets x plus all values returned by f()
        +       a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
        +       a,b = ...          -- a gets the first vararg parameter, b gets
        +                          -- the second (both a and b may get nil if there is
        +                          -- no corresponding vararg parameter)
        +       a,b,c = x, f()     -- f() is adjusted to 2 results
        +       a,b,c = f()        -- f() is adjusted to 3 results
        +       return f()         -- returns all values returned by f()
        +       return ...         -- returns all received vararg parameters
        +       return x,y,f()     -- returns x, y, and all values returned by f()
        +       {f()}              -- creates a list with all values returned by f()
        +       {...}              -- creates a list with all vararg parameters
        +       {f(), nil}         -- f() is adjusted to 1 result
        +
        + +

        An expression enclosed in parentheses always results in only one value. +Thus, +(f(x,y,z)) is always a single value, +even if f returns several values. +(The value of (f(x,y,z)) is the first value returned by f +or nil if f does not return any values.) + +

        2.5.1 - Arithmetic Operators

        +Lua supports the usual arithmetic operators: +the binary + (addition), +- (subtraction), * (multiplication), +/ (division), % (modulus), and ^ (exponentiation); +and unary - (negation). +If the operands are numbers, or strings that can be converted to +numbers (see 2.2.1), +then all operations have the usual meaning. +Exponentiation works for any exponent. +For instance, x^-0.5 computes the inverse of the square root of x. +Modulus is defined as +
        +  a % b == a - math.floor(a/b)*b
        +
        +That is, it is the remaining of a division that rounds +the quotient towards minus infinity. + +

        2.5.2 - Relational Operators

        +The relational operators in Lua are +
        +       ==    ~=    <     >     <=    >=
        +
        +These operators always result in false or true. + +

        Equality (==) first compares the type of its operands. +If the types are different, then the result is false. +Otherwise, the values of the operands are compared. +Numbers and strings are compared in the usual way. +Objects (tables, userdata, threads, and functions) +are compared by reference: +Two objects are considered equal only if they are the same object. +Every time you create a new object (a table, userdata, or function), +this new object is different from any previously existing object. + +

        You can change the way that Lua compares tables and userdata +using the "eq" metamethod (see 2.8). + +

        The conversion rules of 2.2.1 +do not apply to equality comparisons. +Thus, "0"==0 evaluates to false, +and t[0] and t["0"] denote different +entries in a table. + + +

        The operator ~= is exactly the negation of equality (==). + +

        The order operators work as follows. +If both arguments are numbers, then they are compared as such. +Otherwise, if both arguments are strings, +then their values are compared according to the current locale. +Otherwise, Lua tries to call the "lt" or the "le" +metamethod (see 2.8). + +

        2.5.3 - Logical Operators

        +The logical operators in Lua are + +
        +       and   or    not
        +
        +Like the control structures (see 2.4.4), +all logical operators consider both false and nil as false +and anything else as true. + + +

        The operator not always returns false or true. + +

        The conjunction operator and returns its first argument +if this value is false or nil; +otherwise, and returns its second argument. +The disjunction operator or returns its first argument +if this value is different from nil and false; +otherwise, or returns its second argument. +Both and and or use short-cut evaluation, +that is, +the second operand is evaluated only if necessary. +For example, +

        +       10 or error()       -> 10
        +       nil or "a"          -> "a"
        +       nil and 10          -> nil
        +       false and error()   -> false
        +       false and nil       -> false
        +       false or nil        -> nil
        +       10 and 20           -> 20
        +
        + +

        2.5.4 - Concatenation

        +The string concatenation operator in Lua is +denoted by two dots (`..´). +If both operands are strings or numbers, then they are converted to +strings according to the rules mentioned in 2.2.1. +Otherwise, the "concat" metamethod is called (see 2.8). + +

        2.5.5 - The Length Operator

        + +

        The length operator is denoted by the prefix #. +The length of a string is its number of bytes +(that is, the usual meaning of string length when each +character is one byte). +The length of a table t is defined to be any +integer index n +such that t[n] is not nil and t[n+1] is nil; +moreover, if t[1] is nil, n may be zero. + +

        For a regular array, with non-nil values from 1 to a given n, +its length is exactly that n, +the index of its last value. +If the array has "holes" +(that is, nil values between other non-nil values), +then #t may be any of the indices that precede a nil value +(that is, it may consider any such nil value as the end of +the array). + +

        2.5.6 - Precedence

        +Operator precedence in Lua follows the table below, +from lower to higher priority: +
        +       or
        +       and
        +       <     >     <=    >=    ~=    ==
        +       ..
        +       +     -
        +       *     /     %
        +       not   #     - (unary)
        +       ^
        +
        +You can use parentheses to change the precedences of an expression. +The concatenation (`..´) and exponentiation (`^´) +operators are right associative. +All other binary operators are left associative. + +

        2.5.7 - Table Constructors

        +Table constructors are expressions that create tables. +Every time a constructor is evaluated, a new table is created. +Constructors can be used to create empty tables, +or to create a table and initialize some of its fields. +The general syntax for constructors is +
        +	tableconstructor ::= `{´ [fieldlist] `}´
        +	fieldlist ::= field {fieldsep field} [fieldsep]
        +	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
        +	fieldsep ::= `,´ | `;´
        +
        + +

        Each field of the form [exp1] = exp2 adds to the new table an entry +with key exp1 and value exp2. +A field of the form name = exp is equivalent to +["name"] = exp. +Finally, fields of the form exp are equivalent to +[i] = exp, where i are consecutive numerical integers, +starting with 1. +Fields in the other formats do not affect this counting. +For example, +

        +       a = {[f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45}
        +
        +is equivalent to +
        +       do
        +         local temp = {}
        +         temp[f(1)] = g
        +         temp[1] = "x"         -- 1st exp
        +         temp[2] = "y"         -- 2nd exp
        +         temp.x = 1            -- temp["x"] = 1
        +         temp[3] = f(x)        -- 3rd exp
        +         temp[30] = 23
        +         temp[4] = 45          -- 4th exp
        +         a = temp
        +       end
        +
        + +

        If the last field in the list has the form exp +and the expression is a function call or a vararg expression, +then all values returned by that expression enter the list consecutively +(see 2.5.8). +To avoid this, +enclose the function call (or the vararg expression) +in parentheses (see 2.5). + +

        The field list may have an optional trailing separator, +as a convenience for machine-generated code. + +

        2.5.8 - Function Calls

        +A function call in Lua has the following syntax: +
        +	functioncall ::= prefixexp args
        +
        +In a function call, +first prefixexp and args are evaluated. +If the value of prefixexp has type function, +then that function is called +with the given arguments. +Otherwise, its "call" metamethod is called, +having as first parameter the value of prefixexp, +followed by the original call arguments +(see 2.8). + +

        The form +

        +	functioncall ::= prefixexp `:´ Name args
        +
        +can be used to call "methods". +A call v:name(...) +is syntactic sugar for v.name(v,...), +except that v is evaluated only once. + +

        Arguments have the following syntax: +

        +	args ::= `(´ [explist1] `)´
        +	args ::= tableconstructor
        +	args ::= Literal
        +
        +All argument expressions are evaluated before the call. +A call of the form f{...} is syntactic sugar for +f({...}), that is, +the argument list is a single new table. +A call of the form f'...' +(or f"..." or f[[...]]) is syntactic sugar for +f('...'), that is, +the argument list is a single literal string. + +

        As an exception to the free-format syntax of Lua, +you cannot put a line break before the `(´ in a function call. +That restriction avoids some ambiguities in the language. +If you write +

        +       a = f
        +       (g).x(a)
        +
        +Lua would read that as a = f(g).x(a). +So, if you want two statements, you must add a semi-colon between them. +If you actually want to call f, +you must remove the line break before (g). + +

        A call of the form return functioncall is called +a tail call. +Lua implements proper tail calls +(or proper tail recursion): +In a tail call, +the called function reuses the stack entry of the calling function. +Therefore, there is no limit on the number of nested tail calls that +a program can execute. +However, a tail call erases any debug information about the +calling function. +Note that a tail call only happens with a particular syntax, +where the return has one single function call as argument; +this syntax makes the calling function returns exactly +the returns of the called function. +So, all the following examples are not tail calls: +

        +  return (f(x))        -- results adjusted to 1
        +  return 2 * f(x)
        +  return x, f(x)       -- additional results
        +  f(x); return         -- results discarded
        +  return x or f(x)     -- results adjusted to 1
        +
        + +

        2.5.9 - Function Definitions

        + +

        The syntax for function definition is +

        +	function ::= function funcbody
        +	funcbody ::= `(´ [parlist1] `)´ block end
        +
        + +

        The following syntactic sugar simplifies function definitions: +

        +	stat ::= function funcname funcbody
        +	stat ::= local function Name funcbody
        +	funcname ::= Name {`.´ Name} [`:´ Name]
        +
        +The statement +
        +       function f () ... end
        +
        +translates to +
        +       f = function () ... end
        +
        +The statement +
        +       function t.a.b.c.f () ... end
        +
        +translates to +
        +       t.a.b.c.f = function () ... end
        +
        +The statement +
        +       local function f () ... end
        +
        +translates to +
        +       local f; f = function () ... end
        +
        + +

        A function definition is an executable expression, +whose value has type function. +When Lua pre-compiles a chunk, +all its function bodies are pre-compiled too. +Then, whenever Lua executes the function definition, +the function is instantiated (or closed). +This function instance (or closure) +is the final value of the expression. +Different instances of the same function +may refer to different external local variables +and may have different environment tables. + +

        Parameters act as local variables that are +initialized with the argument values: +

        +	parlist1 ::= namelist [`,´ `...´] | `...´
        +
        +When a function is called, +the list of arguments is adjusted to +the length of the list of parameters, +unless the function is a variadic or vararg function, +which is +indicated by three dots (`...´) at the end of its parameter list. +A vararg function does not adjust its argument list; +instead, it collects all extra arguments and supplies them +to the function through a vararg expression, +which is also written as three dots. +The value of this expression is a list of all actual extra arguments, +similar to a function with multiple results. +If a vararg expression is used inside another expression +or in the middle of a list of expressions, +then its return list is adjusted to one element. +If the expression is used as the last element of a list of expressions, +then no adjustment is made +(unless the call is enclosed in parentheses). + +

        As an example, consider the following definitions: +

        +       function f(a, b) end
        +       function g(a, b, ...) end
        +       function r() return 1,2,3 end
        +
        +Then, we have the following mapping from arguments to parameters and +to the vararg expression: +
        +       CALL            PARAMETERS
        +
        +       f(3)             a=3, b=nil
        +       f(3, 4)          a=3, b=4
        +       f(3, 4, 5)       a=3, b=4
        +       f(r(), 10)       a=1, b=10
        +       f(r())           a=1, b=2
        +
        +       g(3)             a=3, b=nil, ... ->  (nothing)
        +       g(3, 4)          a=3, b=4,   ... ->  (nothing)
        +       g(3, 4, 5, 8)    a=3, b=4,   ... ->  5  8
        +       g(5, r())        a=5, b=1,   ... ->  2  3
        +
        + +

        Results are returned using the return statement (see 2.4.4). +If control reaches the end of a function +without encountering a return statement, +then the function returns with no results. + +

        The colon syntax +is used for defining methods, +that is, functions that have an implicit extra parameter self. +Thus, the statement +

        +       function t.a.b.c:f (...) ... end
        +
        +is syntactic sugar for +
        +       t.a.b.c.f = function (self, ...) ... end
        +
        + +

        2.6 - Visibility Rules

        + + +

        Lua is a lexically scoped language. +The scope of variables begins at the first statement after +their declaration and lasts until the end of the innermost block that +includes the declaration. +For instance: +

        +  x = 10                -- global variable
        +  do                    -- new block
        +    local x = x         -- new `x', with value 10
        +    print(x)            --> 10
        +    x = x+1
        +    do                  -- another block
        +      local x = x+1     -- another `x'
        +      print(x)          --> 12
        +    end
        +    print(x)            --> 11
        +  end
        +  print(x)              --> 10  (the global one)
        +
        +Notice that, in a declaration like local x = x, +the new x being declared is not in scope yet, +and so the second x refers to the outside variable. + +

        Because of the lexical scoping rules, +local variables can be freely accessed by functions +defined inside their scope. +For instance: +

        +  local counter = 0
        +  function inc (x)
        +    counter = counter + x
        +    return counter
        +  end
        +
        +A local variable used by an inner function is called +an upvalue, or external local variable, +inside the inner function. + +

        Notice that each execution of a local statement +defines new local variables. +Consider the following example: +

        +  a = {}
        +  local x = 20
        +  for i=1,10 do
        +    local y = 0
        +    a[i] = function () y=y+1; return x+y end
        +  end
        +
        +The loop creates ten closures +(that is, ten instances of the anonymous function). +Each of these closures uses a different y variable, +while all of them share the same x. + +

        2.7 - Error Handling

        + +

        Because Lua is an extension language, +all Lua actions start from C code in the host program +calling a function from the Lua library (see ). +Whenever an error occurs during Lua compilation or execution, +control returns to C, +which can take appropriate measures +(such as print an error message). + +

        Lua code can explicitly generate an error by calling the +error function. +If you need to catch errors in Lua, +you can use the pcall function. + +

        2.8 - Metatables

        + +

        Every value in Lua may have a metatable. +This metatable is an ordinary Lua table +that defines the behavior of the original value +under certain special operations. +You can change several aspects of the behavior +of operations over a value by setting specific fields in its metatable. +For instance, when a non-numeric value is the operand of an addition, +Lua checks for a function in the field "__add" in its metatable. +If it finds one, +Lua calls that function to perform the addition. + +

        We call the keys in a metatable events +and the values metamethods. +In the previous example, the event is "add" +and the metamethod is the function that performs the addition. + +

        You can query the metatable of any value +through the getmetatable function. + +

        You can replace the metatable of tables +through the setmetatable +function. +You cannot change the metatable of other types from Lua +(except using the debug library); +you must use the C API for that. + +

        Tables and userdata have individual metatables +(although multiple tables and userdata can share +a same table as their metatable); +values of all other types share one single metatable per type. +So, there is one single metatable for all numbers, +and for all strings, etc. + +

        A metatable may control how an object behaves in arithmetic operations, +order comparisons, concatenation, and indexing. +A metatable can also define a function to be called when a userdata +is garbage collected. +For each of those operations Lua associates a specific key +called an event. +When Lua performs one of those operations over a value, +it checks whether that value has a metatable with the corresponding event. +If so, the value associated with that key (the metamethod) +controls how Lua will perform the operation. + +

        Metatables control the operations listed next. +Each operation is identified by its corresponding name. +The key for each operation is a string with its name prefixed by +two underscores; +for instance, the key for operation "add" is the +string "__add". +The semantics of these operations is better explained by a Lua function +describing how the interpreter executes that operation. + +

        The code shown here in Lua is only illustrative; +the real behavior is hard coded in the interpreter +and it is much more efficient than this simulation. +All functions used in these descriptions +(rawget, tonumber, etc.) +are described in 5.1. +In particular, to retrieve the metamethod of a given object, +we use the expression +

        +  metatable(obj)[event]
        +
        +This should be read as +
        +  rawget(metatable(obj) or {}, event)
        +
        +That is, the access to a metamethod does not invoke other metamethods, +and the access to objects with no metatables does not fail +(it simply results in nil). + +

          +
        • "add": +the + operation. + +

          The function getbinhandler below defines how Lua chooses a handler +for a binary operation. +First, Lua tries the first operand. +If its type does not define a handler for the operation, +then Lua tries the second operand. +

          + function getbinhandler (op1, op2, event)
          +   return metatable(op1)[event] or metatable(op2)[event]
          + end
          +
          +Using that function, +the behavior of the op1 + op2 is +
          + function add_event (op1, op2)
          +   local o1, o2 = tonumber(op1), tonumber(op2)
          +   if o1 and o2 then  -- both operands are numeric?
          +     return o1 + o2   -- `+' here is the primitive `add'
          +   else  -- at least one of the operands is not numeric
          +     local h = getbinhandler(op1, op2, "__add")
          +     if h then
          +       -- call the handler with both operands
          +       return h(op1, op2)
          +     else  -- no handler available: default behavior
          +       error("...")
          +     end
          +   end
          + end
          +
          + +

        • "sub": +the - operation. +Behavior similar to the "add" operation. + +

        • "mul": +the * operation. +Behavior similar to the "add" operation. + +

        • "div": +the / operation. +Behavior similar to the "add" operation. + +

        • "mod": +the % operation. +Behavior similar to the "add" operation, +with the operation +o1 - floor(o1/o2)*o2 as the primitive operation. + +

        • "pow": +the ^ (exponentiation) operation. +Behavior similar to the "add" operation, +with the function pow (from the C math library) +as the primitive operation. + +

        • "unm": +the unary - operation. +
          + function unm_event (op)
          +   local o = tonumber(op)
          +   if o then  -- operand is numeric?
          +     return -o  -- `-' here is the primitive `unm'
          +   else  -- the operand is not numeric.
          +     -- Try to get a handler from the operand
          +     local h = metatable(op).__unm
          +     if h then
          +       -- call the handler with the operand
          +       return h(op)
          +     else  -- no handler available: default behavior
          +       error("...")
          +     end
          +   end
          + end
          +
          + +

        • "concat": +the .. (concatenation) operation. +
          + function concat_event (op1, op2)
          +   if (type(op1) == "string" or type(op1) == "number") and
          +      (type(op2) == "string" or type(op2) == "number") then
          +     return op1 .. op2  -- primitive string concatenation
          +   else
          +     local h = getbinhandler(op1, op2, "__concat")
          +     if h then
          +       return h(op1, op2)
          +     else
          +       error("...")
          +     end
          +   end
          + end
          +
          + +

        • "len": +the # operation. +
          + function len_event (op)
          +   if type(op) == "string" then
          +     return strlen(op)         -- primitive string length
          +   elseif type(op) == "table" then
          +     return #op                -- primitive table length
          +   else
          +     local h = metatable(op).__len
          +     if h then
          +       -- call the handler with the operand
          +       return h(op)
          +     else  -- no handler available: default behavior
          +       error("...")
          +     end
          +   end
          + end
          +
          +See 2.5.5 for a description of the length of a table. + +

        • "eq": +the == operation. +The function getcomphandler defines how Lua chooses a metamethod +for comparison operators. +A metamethod only is selected when both objects +being compared have the same type +and the same metamethod for the selected operation. +
          + function getcomphandler (op1, op2, event)
          +   if type(op1) ~= type(op2) then return nil end
          +   local mm1 = metatable(op1)[event]
          +   local mm2 = metatable(op2)[event]
          +   if mm1 == mm2 then return mm1 else return nil end
          + end
          +
          +The "eq" event is defined as follows: +
          + function eq_event (op1, op2)
          +   if type(op1) ~= type(op2) then  -- different types?
          +     return false   -- different objects
          +   end
          +   if op1 == op2 then   -- primitive equal?
          +     return true   -- objects are equal
          +   end
          +   -- try metamethod
          +   local h = getcomphandler(op1, op2, "__eq")
          +   if h then
          +     return h(op1, op2)
          +   else
          +     return false
          +   end
          + end
          +
          +a ~= b is equivalent to not (a == b). + +

        • "lt": +the < operation. +
          + function lt_event (op1, op2)
          +   if type(op1) == "number" and type(op2) == "number" then
          +     return op1 < op2   -- numeric comparison
          +   elseif type(op1) == "string" and type(op2) == "string" then
          +     return op1 < op2   -- lexicographic comparison
          +   else
          +     local h = getcomphandler(op1, op2, "__lt")
          +     if h then
          +       return h(op1, op2)
          +     else
          +       error("...");
          +     end
          +   end
          + end
          +
          +a > b is equivalent to b < a. + +

        • "le": +the <= operation. +
          + function le_event (op1, op2)
          +   if type(op1) == "number" and type(op2) == "number" then
          +     return op1 <= op2   -- numeric comparison
          +   elseif type(op1) == "string" and type(op2) == "string" then
          +     return op1 <= op2   -- lexicographic comparison
          +   else
          +     local h = getcomphandler(op1, op2, "__le")
          +     if h then
          +       return h(op1, op2)
          +     else
          +       h = getcomphandler(op1, op2, "__lt")
          +       if h then
          +         return not h(op2, op1)
          +       else
          +         error("...");
          +       end
          +     end
          +   end
          + end
          +
          +a >= b is equivalent to b <= a. +Note that, in the absence of a "le" metamethod, +Lua tries the "lt", assuming that a <= b is +equivalent to not (b < a). + +

        • "index": +The indexing access table[key]. +
          + function gettable_event (table, key)
          +   local h
          +   if type(table) == "table" then
          +     local v = rawget(table, key)
          +     if v ~= nil then return v end
          +     h = metatable(table).__index
          +     if h == nil then return nil end
          +   else
          +     h = metatable(table).__index
          +     if h == nil then
          +       error("...");
          +     end
          +   end
          +   if type(h) == "function" then
          +     return h(table, key)      -- call the handler
          +   else return h[key]          -- or repeat operation on it
          +   end
          + end
          +
          + +

        • "newindex": +The indexing assignment table[key] = value. +
          + function settable_event (table, key, value)
          +   local h
          +   if type(table) == "table" then
          +     local v = rawget(table, key)
          +     if v ~= nil then rawset(table, key, value); return end
          +     h = metatable(table).__newindex
          +     if h == nil then rawset(table, key, value); return end
          +   else
          +     h = metatable(table).__newindex
          +     if h == nil then
          +       error("...");
          +     end
          +   end
          +   if type(h) == "function" then
          +     return h(table, key,value)    -- call the handler
          +   else h[key] = value             -- or repeat operation on it
          +   end
          + end
          +
          + +

        • "call": +called when Lua calls a value. +
          + function function_event (func, ...)
          +   if type(func) == "function" then
          +     return func(unpack(arg))   -- primitive call
          +   else
          +     local h = metatable(func).__call
          +     if h then
          +       return h(func, unpack(arg))
          +     else
          +       error("...")
          +     end
          +   end
          + end
          +
          + +

        + +

        2.9 - Environments

        + +

        Besides metatables, +objects of types thread, function, and userdata +have another table associated with them, +called environment. +Like metatables, environments are regular tables and +multiple objects can share the same environment. + +

        Environments associated with userdata has no meaning for Lua. +It is only a feature for programmers to associate a table to +a userdata. + +

        Environments associated with threads are called +global environments. +They are used as the default environment for threads and +non-nested functions created by that thread +(through loadfile, loadstring or load) +and can be directly accessed by C code (see 3.3). + +

        Environments associated with C functions can be directly +accessed by C code (see 3.3). +They are used as the default environment for other C functions +created by that function. + +

        Environments associated with Lua functions are used to resolve +all accesses to global variables within that function (see 2.3). +They are used as the default environment for other Lua functions +created by that function. + +

        You can change the environment of a Lua function of the +running thread calling setfenv. +You can get the environment of a Lua function or the running thread +calling getfenv. +To manipulate the environment of other objects +(userdata, C functions, other threads) you must +use the C API. + +

        2.10 - Garbage Collection

        + +

        Lua does automatic memory management. +That means that +you do not have to worry about allocating memory for new objects +and freeing it when the objects are no longer needed. +Lua manages memory automatically by running +a garbage collector from time to time +to collect all dead objects +(that is, those objects that are no longer accessible from Lua). +All objects in Lua are subject to automatic management: +tables, userdata, functions, threads, and strings. + +

        Lua 5.1 implements an incremental mark-and-sweep collector. +It uses two numbers to control its garbage-collection cycles. +One number, the garbage-collector pause, +controls how long the collector waits before starting a new cycle. +Larger values make the collector less aggressive. +Values smaller than 1 mean the collector will not wait to +start a new cycle. +A value of 2 means that the collector waits more or less to double +the total memory in use before starting a new cycle. + +

        The other number, the garbage-collector multiplier, +controls the relative speed of the collector relative to +memory allocation. +Larger values make the collector more aggressive but also increases +the size of each incremental step. +Values smaller than 1 make the collector too slow and +may result in the collector never finishing a cycle. +The default, 2, means that the collector runs at "twice" +the speed of memory allocation. + +

        You can change those numbers calling lua_gc in C +or collectgarbage in Lua. +Both get as arguments percentage points +(so an argument 100 means a real value of 1). +With those functions you can also get direct control +of the collector (e.g., stop and restart it). + +

        2.10.1 - Garbage-Collection Metamethods

        + +

        Using the C API, +you can set garbage-collector metamethods for userdata (see 2.8). +These metamethods are also called finalizers. +Finalizers allow you to coordinate Lua's garbage collection +with external resource management +(such as closing files, network or database connections, +or freeing your own memory). + +

        Free userdata with a field __gc in their metatables are not +collected immediately by the garbage collector. +Instead, Lua puts them in a list. +After the collection, +Lua does the equivalent of the following function +for each userdata in that list: +

        + function gc_event (udata)
        +   local h = metatable(udata).__gc
        +   if h then
        +     h(udata)
        +   end
        + end
        +
        + +

        At the end of each garbage-collection cycle, +the finalizers for userdata are called in reverse +order of their creation, +among those collected in that cycle. +That is, the first finalizer to be called is the one associated +with the userdata created last in the program. + +

        2.10.2 - Weak Tables

        + +

        A weak table is a table whose elements are +weak references. +A weak reference is ignored by the garbage collector. +In other words, +if the only references to an object are weak references, +then the garbage collector will collect that object. + +

        A weak table can have weak keys, weak values, or both. +A table with weak keys allows the collection of its keys, +but prevents the collection of its values. +A table with both weak keys and weak values allows the collection of +both keys and values. +In any case, if either the key or the value is collected, +the whole pair is removed from the table. +The weakness of a table is controlled by the value of the +__mode field of its metatable. +If the __mode field is a string containing the character `k´, +the keys in the table are weak. +If __mode contains `v´, +the values in the table are weak. + +

        After you use a table as a metatable, +you should not change the value of its field __mode. +Otherwise, the weak behavior of the tables controlled by this +metatable is undefined. + +

        2.11 - Coroutines

        + +

        Lua supports coroutines, +also called collaborative multithreading. +A coroutine in Lua represents an independent thread of execution. +Unlike threads in multithread systems, however, +a coroutine only suspends its execution by explicitly calling +a yield function. + +

        You create a coroutine with a call to coroutine.create. +Its sole argument is a function +that is the main function of the coroutine. +The create function only creates a new coroutine and +returns a handle to it (an object of type thread); +it does not start the coroutine execution. + +

        When you first call coroutine.resume, +passing as its first argument +the thread returned by coroutine.create, +the coroutine starts its execution, +at the first line of its main function. +Extra arguments passed to coroutine.resume are given as +parameters for the coroutine main function. +After the coroutine starts running, +it runs until it terminates or yields. + +

        A coroutine can terminate its execution in two ways: +Normally, when its main function returns +(explicitly or implicitly, after the last instruction); +and abnormally, if there is an unprotected error. +In the first case, coroutine.resume returns true, +plus any values returned by the coroutine main function. +In case of errors, coroutine.resume returns false +plus an error message. + +

        A coroutine yields by calling coroutine.yield. +When a coroutine yields, +the corresponding coroutine.resume returns immediately, +even if the yield happens inside nested function calls +(that is, not in the main function, +but in a function directly or indirectly called by the main function). +In the case of a yield, coroutine.resume also returns true, +plus any values passed to coroutine.yield. +The next time you resume the same coroutine, +it continues its execution from the point where it yielded, +with the call to coroutine.yield returning any extra +arguments passed to coroutine.resume. + +

        The coroutine.wrap function creates a coroutine +like coroutine.create, +but instead of returning the coroutine itself, +it returns a function that, when called, resumes the coroutine. +Any arguments passed to that function +go as extra arguments to resume. +The function returns all the values returned by resume, +except the first one (the boolean error code). +Unlike coroutine.resume, +this function does not catch errors; +any error is propagated to the caller. + +

        As an example, +consider the next code: +

        +function foo1 (a)
        +  print("foo", a)
        +  return coroutine.yield(2*a)
        +end
        +
        +co = coroutine.create(function (a,b)
        +      print("co-body", a, b)
        +      local r = foo1(a+1)
        +      print("co-body", r)
        +      local r, s = coroutine.yield(a+b, a-b)
        +      print("co-body", r, s)
        +      return b, "end"
        +end)
        +       
        +a, b = coroutine.resume(co, 1, 10)
        +print("main", a, b)
        +a, b, c = coroutine.resume(co, "r")
        +print("main", a, b, c)
        +a, b, c = coroutine.resume(co, "x", "y")
        +print("main", a, b, c)
        +a, b = coroutine.resume(co, "x", "y")
        +print("main", a, b)
        +
        +When you run it, it produces the following output: +
        +co-body 1       10
        +foo     2
        +main    true    4
        +co-body r
        +main    true    11      -9
        +co-body x       y
        +main    true    10      end
        +main    false   cannot resume dead coroutine
        +
        + +

        +

        3 - The Application Program Interface

        + + +

        This section describes the C API for Lua, that is, +the set of C functions available to the host program to communicate +with Lua. +All API functions and related types and constants +are declared in the header file lua.h. + +

        Even when we use the term "function", +any facility in the API may be provided as a macro instead. +All such macros use each of its arguments exactly once +(except for the first argument, which is always a Lua state), +and so do not generate hidden side-effects. + +

        Like in most C libraries, +the Lua API functions do not check their arguments. +However, you can change this behavior by compiling Lua +with a proper definition for the macro luai_apicheck, +in file luaconf.h. + +

        3.1 - The Stack

        + +

        Lua uses a virtual stack to pass values to and from C. +Each element in this stack represents a Lua value +(nil, number, string, etc.). + +

        Whenever Lua calls C, the called function gets a new stack, +which is independent of previous stacks and of stacks of +C functions that are still active. +That stack initially contains any arguments to the C function, +and it is where the C function pushes its results +to be returned to the caller (see lua_CFunction). + +

        For convenience, +most query operations in the API do not follow a strict stack discipline. +Instead, they can refer to any element in the stack +by using an index: +A positive index represents an absolute stack position +(starting at 1); +a negative index represents an offset from the top of the stack. +More specifically, if the stack has n elements, +then index 1 represents the first element +(that is, the element that was pushed onto the stack first) +and +index n represents the last element; +index -1 also represents the last element +(that is, the element at the top) +and index -n represents the first element. +We say that an index is valid +if it lies between 1 and the stack top +(that is, if 1 <= abs(index) <= top). + + +

        3.2 - Stack Size

        + +

        When you interact with Lua API, +you are responsible for controlling stack overflow. +You can use the function lua_checkstack +to grow the stack size. + +

        Whenever Lua calls C, +it ensures that at least LUA_MINSTACK stack positions are available. +LUA_MINSTACK is defined as 20, +so that usually you do not have to worry about stack space +unless your code has loops pushing elements onto the stack. + +

        Most query functions accept as indices any value inside the +available stack space, that is, indices up to the maximum stack size +you have set through lua_checkstack. +Such indices are called acceptable indices. +More formally, we define an acceptable index +as follows: +

        +     (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
        +
        +Note that 0 is never an acceptable index. + +

        3.3 - Pseudo-Indices

        + +

        Unless otherwise noted, +any function that accepts valid indices can also be called with +pseudo-indices, +which represent some Lua values that are accessible to the C code +but are not in the stack. +Pseudo-indices are used to access the thread environment, +the function environment, +the registry, +and the upvalues of a C function (see 3.4). + +

        The thread environment (where global variables live) is +always at pseudo-index LUA_GLOBALSINDEX. +The environment of the running C function is always +at pseudo-index LUA_ENVIRONINDEX. + +

        To access and change the value of global variables, +you can use regular table operations over an environment table. +For instance, to access the value of a global variable, do +

        +       lua_getfield(L, LUA_GLOBALSINDEX, varname);
        +
        + +

        3.4 - C Closures

        + +

        When a C function is created, +it is possible to associate some values with it, +thus creating a C closure; +these values are then accessible to the function whenever it is called +(see lua_pushcclosure). + +

        Whenever a C function is called, +its associated values are located at specific pseudo-indices. +Those pseudo-indices are produced by the macro +lua_upvalueindex. +The first value associated with a function is at position +lua_upvalueindex(1), and so on. +Any access to lua_upvalueindex(n), +where n is greater than the number of upvalues of the +current function, +produces an acceptable (but invalid) index. + +

        3.5 - Registry

        + +

        Lua provides a registry, +a pre-defined table that can be used by any C code to +store whatever Lua value it needs to store. +This table is always located at pseudo-index +LUA_REGISTRYINDEX. +Any C library can store data into this table, +as long as it chooses keys different from other libraries. +Typically, you should use as key a string containing your library name +or a light userdata with the address of a C object in your code. + +

        The integer keys in the registry are used by the reference mechanism, +implemented by the auxiliary library, +and therefore should not be used by other purposes. + +

        3.6 - Error Handling in C

        + +

        Internally, Lua uses the C longjmp facility to handle errors. +When Lua faces any error +(such as memory allocation errors, type errors, syntax errors) +it raises an error, that is, it does a long jump. +A protected environment uses setjmp +to set a recover point; +any error jumps to the most recent active recover point. + +

        Almost any function in the API may raise an error, +for instance due to a memory allocation error. +The following functions run in protected mode +(that is, they create a protected environment to run), +so they never raise an error: +lua_newstate, lua_close, lua_load, +lua_pcall, and lua_cpcall. + +

        Inside a C function you can raise an error calling lua_error. + +

        3.7 - Functions and Types

        + +

        Here we list all functions and types from the C API in +alphabetical order. + +

        +


        lua_Alloc

        +
        +          typedef void * (*lua_Alloc) (void *ud,
        +                                       void *ptr,
        +                                       size_t osize,
        +                                       size_t nsize);
        +
        +
        + + +

        The allocator function used by Lua states. +The allocator function must provide a +functionality similar to realloc, +but not exactly the same. +Its arguments are ud, +the opaque pointer passed to lua_newstate; +ptr, a pointer to the block being allocated/reallocated/freed; +osize, the original size of the block; +nsize, the new size of the block. +ptr is NULL if and only if osize is zero. +When nsize is zero, the allocator must return NULL; +if osize is not zero, +it should free the block pointed by ptr. +When nsize is not zero, the allocator returns NULL +if and only if it cannot fill the request. +When nsize is not zero and osize is zero, +the allocator behaves like malloc. +When nsize and osize are not zero, +the allocator behaves like realloc. +Lua assumes that the allocator never fails when +osize >= nsize. + +

        A simple implementation for the allocator function could be like this: +

        +static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
        +  (void)ud;     /* not used */
        +  (void)osize;  /* not used */
        +  if (nsize == 0) {
        +    free(ptr);  /* ANSI ensures that free(NULL) has no effect */
        +    return NULL;
        +  }
        +  else
        +    /* ANSI ensures that realloc(NULL, size) == malloc(size) */
        +    return realloc(ptr, nsize);
        +}
        +
        + +

        +


        lua_atpanic

        +
        +          lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
        +
        + + +

        Sets a new panic function and returns the old one. + +

        If an error happens outside any protected environment, +Lua calls a panic function +and then calls exit(EXIT_FAILURE). +Your new panic function may avoid the application exit by +never returning (e.g., doing a long jump). + +

        The panic function can access the error message at the top of the stack. + +

        +


        lua_call

        +
        +          void lua_call (lua_State *L, int nargs, int nresults);
        +
        + + +

        Calls a function. + +

        To call a function you must use the following protocol: +First, the function to be called is pushed onto the stack; +then, the arguments to the function are pushed +in direct order, that is, the first argument is pushed first. +Finally you call lua_call; +nargs is the number of arguments that you pushed onto the stack. +All arguments and the function value are popped from the stack, +and the function results are pushed. +The number of results are adjusted to nresults, +unless nresults is LUA_MULTRET. +In that case, all results from the function are pushed. +Lua takes care that the returned values fit into the stack space. +The function results are pushed onto the stack in direct order +(the first result is pushed first), +so that after the call the last result is on the top. + +

        Any error inside the called function is propagated upwards +(with a longjmp). + +

        The following example shows how the host program may do the +equivalent to this Lua code: +

        +       a = f("how", t.x, 14)
        +
        +Here it is in C: +
        +    lua_getfield(L, LUA_GLOBALSINDEX, "t");     /* global `t' (for later use) */
        +    lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* function to be called */
        +    lua_pushstring(L, "how");                                 /* 1st argument */
        +    lua_getfield(L, -3, "x");                 /* push result of t.x (2nd arg) */
        +    lua_pushinteger(L, 14);                                   /* 3rd argument */
        +    lua_call(L, 3, 1);         /* call function with 3 arguments and 1 result */
        +    lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global variable `a' */
        +    lua_pop(L, 1);                               /* remove `t' from the stack */
        +
        +Note that the code above is "balanced": +at its end, the stack is back to its original configuration. +This is considered good programming practice. + +

        +


        lua_CFunction

        +
        +          typedef int (*lua_CFunction) (lua_State *L);
        +
        + + +

        Type for C functions. + +

        In order to communicate properly with Lua, +a C function must follow the following protocol, +which defines the way parameters and results are passed: +A C function receives its arguments from Lua in its stack +in direct order (the first argument is pushed first). +So, when the function starts, +its first argument (if any) is at index 1. +To return values to Lua, a C function just pushes them onto the stack, +in direct order (the first result is pushed first), +and returns the number of results. +Any other value in the stack below the results will be properly +discharged by Lua. +Like a Lua function, a C function called by Lua can also return +many results. + +

        As an example, the following function receives a variable number +of numerical arguments and returns their average and sum: +

        +       static int foo (lua_State *L) {
        +         int n = lua_gettop(L);    /* number of arguments */
        +         lua_Number sum = 0;
        +         int i;
        +         for (i = 1; i <= n; i++) {
        +           if (!lua_isnumber(L, i)) {
        +             lua_pushstring(L, "incorrect argument to function `average'");
        +             lua_error(L);
        +           }
        +           sum += lua_tonumber(L, i);
        +         }
        +         lua_pushnumber(L, sum/n);        /* first result */
        +         lua_pushnumber(L, sum);         /* second result */
        +         return 2;                   /* number of results */
        +       }
        +
        + +

        +


        lua_checkstack

        +
        +          int lua_checkstack (lua_State *L, int extra);
        +
        + + +

        Grows the stack size to top + extra elements; +it returns false if it cannot grow the stack to that size. +This function never shrinks the stack; +if the stack is already larger than the new size, +it is left unchanged. + +

        +


        lua_close

        +
        +          void lua_close (lua_State *L);
        +
        + + +

        Destroys all objects in the given Lua state +(calling the corresponding garbage-collection metamethods, if any) +and frees all dynamic memory used by that state. +On several platforms, you may not need to call this function, +because all resources are naturally released when the host program ends. +On the other hand, long-running programs, +such as a daemon or a web server, +might need to release states as soon as they are not needed, +to avoid growing too large. + +

        +


        lua_concat

        +
        +          void lua_concat (lua_State *L, int n);
        +
        + + +

        Concatenates the n values at the top of the stack, +pops them, and leaves the result at the top. +If n is 1, the result is that single string +(that is, the function does nothing); +if n is 0, the result is the empty string. +Concatenation is done following the usual semantics of Lua +(see 2.5.4). + +

        +


        lua_cpcall

        +
        +          int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
        +
        + + +

        Calls the C function func in protected mode. +func starts with only one element in its stack, +a light userdata containing ud. +In case of errors, +lua_cpcall returns the same error codes as lua_pcall, +plus the error object on the top of the stack; +otherwise, it returns zero, and does not change the stack. +Any value returned by func is discarded. + +

        +


        lua_createtable

        +
        +          void lua_createtable (lua_State *L, int narr, int nrec);
        +
        + + +

        Creates a new empty table and pushes it onto the stack. +The new table has space pre-allocated +for narr array elements plus nrec non-array elements. +This pre-allocation is useful when you know exactly how many elements +the table will have. +Otherwise you can use the function lua_newtable. + +

        +


        lua_dump

        +
        +          int lua_dump (lua_State *L, lua_Writer writer, void *data);
        +
        + + +

        Dumps a function as a binary chunk. +This function receives a Lua function on the top of the stack +and produces a binary chunk that, +if loaded again, +results in a function equivalent to the one dumped. +As it produces parts of the chunk, +lua_dump calls function writer (see lua_Writer) +to write them. + +

        The value returned is the error code returned by the last +call to the writer; +0 means no errors. + +

        This function does not pop the function from the stack. + +

        +


        lua_equal

        +
        +          int lua_equal (lua_State *L, int index1, int index2);
        +
        + + +

        Returns 1 if the two values in acceptable indices index1 and +index2 are equal, +following the semantics of the Lua = operator +(that is, may call metamethods). +Otherwise returns 0. +Also returns 0 if any of the indices are non valid. + +

        +


        lua_error

        +
        +          int lua_error (lua_State *L);
        +
        + + +

        Generates a Lua error. +The error message (which actually can be any type of object) +must be on the stack top. +This function does a long jump, +and therefore never returns. + +

        +


        lua_gc

        +
        +          int lua_gc (lua_State *L, int what, int data);
        +
        + + +

        Controls the garbage collector. + +

        This function performs several tasks, +according to the value of the parameter what: +

          +
        • LUA_GCSTOP— stops the garbage collector. +
        • LUA_GCRESTART— restarts the garbage collector. +
        • LUA_GCCOLLECT— performs a full garbage-collection cycle. +
        • LUA_GCCOUNT— returns the current +amount of memory (in Kbytes) in use by Lua. +
        • LUA_GCSTEP— performs an incremental step of +garbage collection. +The step "size" is controlled by data +(larger values mean more steps) in a non-specified way. +If you want to control the step size +you must tune experimentally the value of data. +The function returns 1 if that step finished a +garbage-collection cycle. +
        • LUA_GCSETPAUSE— +sets data/100 as the new value +for the pause of the collector (see 2.10). +
        • LUA_GCSETSTEPMUL— +sets arg/100 as the new value for the step multiplier of +the collector (see 2.10). +
        + +

        +


        lua_getallocf

        +
        +          lua_Alloc lua_getallocf (lua_State *L, void **ud);
        +
        + + +

        Returns the allocator function of a given state. +If ud is not NULL Lua stores in *ud the +opaque pointer passed to lua_newstate. + +

        +


        lua_getfenv

        +
        +          void lua_getfenv (lua_State *L, int index);
        +
        + + +

        Pushes on the stack the environment table of +the value at the given index. + +

        +


        lua_getfield

        +
        +          void lua_getfield (lua_State *L, int index, const char *k);
        +
        + + +

        Pushes onto the stack the value t[k], +where t is the value at the given valid index index. +As in Lua, this function may trigger a metamethod +for the "index" event (see 2.8). + +

        +


        lua_getmetatable

        +
        +          int lua_getmetatable (lua_State *L, int index);
        +
        + + +

        Pushes onto the stack the metatable of the value at the given +acceptable index. +If the index is not valid, +or if the value does not have a metatable, +returns 0 and pushes nothing on the stack. + +

        +


        lua_gettable

        +
        +          void lua_gettable (lua_State *L, int index);
        +
        + + +

        Pushes onto the stack the value t[k], +where t is the value at the given valid index index +and k is the value at the top of the stack. + +

        This function pops the key from the stack +(putting the resulting value in its place). +As in Lua, this function may trigger a metamethod +for the "index" event (see 2.8). + +

        +


        lua_gettop

        +
        +          int lua_gettop (lua_State *L);
        +
        + + +

        Returns the index of the top element in the stack. +Because indices start at 1, +that result is equal to the number of elements in the stack +(and so 0 means an empty stack). + +

        +


        lua_insert

        +
        +          void lua_insert (lua_State *L, int index);
        +
        + + +

        Moves the top element into the given valid index, +shifting up the elements above that position to open space. +Cannot be called with a pseudo-index, +because a pseudo-index is not an actual stack position. + +

        +


        lua_Integer

        +
        +          typedef ptrdiff_t lua_Integer;
        +
        + + +

        The type used by the Lua API to represent integral values. + +

        By default it is a ptrdiff_t, +which is usually the largest type the machine handles +"comfortably". + +

        +


        lua_isboolean

        +
        +          int lua_isboolean (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index has type boolean, +and 0 otherwise. + +

        +


        lua_iscfunction

        +
        +          int lua_iscfunction (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a C function, +and 0 otherwise. + +

        +


        lua_isfunction

        +
        +          int lua_isfunction (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a function +(either C or Lua), and 0 otherwise. + +

        +


        lua_islightuserdata

        +
        +          int lua_islightuserdata (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a light userdata, +and 0 otherwise. + +

        +


        lua_isnil

        +
        +          int lua_isnil (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is nil, +and 0 otherwise. + +

        +


        lua_isnumber

        +
        +          int lua_isnumber (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a number +or a string convertible to a number, +and 0 otherwise. + +

        +


        lua_isstring

        +
        +          int lua_isstring (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a string +or a number (which is always convertible to a string), +and 0 otherwise. + +

        +


        lua_istable

        +
        +          int lua_istable (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a table, +and 0 otherwise. + +

        +


        lua_isthread

        +
        +          int lua_isthread (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a thread, +and 0 otherwise. + +

        +


        lua_isuserdata

        +
        +          int lua_isuserdata (lua_State *L, int index);
        +
        + + +

        Returns 1 if the value at the given acceptable index is a userdata +(either full or light), and 0 otherwise. + +

        +


        lua_lessthan

        +
        +          int lua_lessthan (lua_State *L, int index1, int index2);
        +
        + + +

        Returns 1 if the value in acceptable index index1 is smaller +than the value in acceptable index index2, +following the semantics of the Lua < operator +(that is, may call metamethods). +Otherwise returns 0. +Also returns 0 if any of the indices are non valid. + +

        +


        lua_load

        +
        +          int lua_load (lua_State *L, lua_Reader reader, void *data,
        +                                      const char *chunkname);
        +
        +
        + + +

        Loads a Lua chunk. +If there are no errors, +lua_load pushes the compiled chunk as a Lua +function on top of the stack. +Otherwise, it pushes an error message. +The return values of lua_load are: +

          +
        • 0 — no errors; +
        • LUA_ERRSYNTAX — +syntax error during pre-compilation. +
        • LUA_ERRMEM — +memory allocation error. +
        + +

        lua_load automatically detects whether the chunk is text or binary, +and loads it accordingly (see program luac). + +

        lua_load uses a user-supplied reader function to read the chunk +(see lua_Reader). +The data argument is an opaque value passed to the reader function. + +

        The chunkname argument gives the chunk name. +It is used for error messages and debug information (see 3.8). + +

        +


        lua_newstate

        +
        +          lua_State *lua_newstate (lua_Alloc f, void *ud);
        +
        + + +

        Creates a new, independent state. +Returns NULL if cannot create the state +(not enough memory). +The argument f is the allocator function; +Lua does all memory allocation for that state through that function. +The second argument, ud, is an opaque pointer that Lua +simply passes to the allocator in every call. + +

        +


        lua_newtable

        +
        +          void lua_newtable (lua_State *L);
        +
        + + +

        Creates a new empty table and pushes it onto the stack. +Equivalent to lua_createtable(L, 0, 0). + +

        +


        lua_newthread

        +
        +          lua_State *lua_newthread (lua_State *L);
        +
        + + +

        Creates a new thread, pushes it on the stack, +and returns a pointer to a lua_State that represents this new thread. +The new state returned by this function shares with the original state +all global objects (such as tables), +but has an independent run-time stack. + +

        There is no explicit function to close or to destroy a thread. +Threads are subject to garbage collection, +like any Lua object. + +

        +


        lua_newuserdata

        +
        +          void *lua_newuserdata (lua_State *L, size_t size);
        +
        + + +

        This function allocates a new block of memory with the given size, +pushes on the stack a new full userdata with the block address, +and returns this address. + +

        Userdata represents C values in Lua. +A full userdata represents a block of memory. +It is an object (like a table): +You must create it, it can have its own metatable, +and you can detect when it is being collected. +A full userdata is only equal to itself (under raw equality). + +

        When Lua collects a full userdata, +it calls the userdata's gc metamethod, if any, +and then it frees the userdata's corresponding memory. + +

        +


        lua_next

        +
        +          int lua_next (lua_State *L, int index);
        +
        + + +

        Pops a key from the stack, +and pushes a key-value pair from the table +(the "next" pair after the given key). +If there are no more elements, +then lua_next returns 0 (and pushes nothing). + +

        A typical traversal looks like this: +

        +       /* table is in the stack at index `t' */
        +       lua_pushnil(L);  /* first key */
        +       while (lua_next(L, t) != 0) {
        +         /* `key' is at index -2 and `value' at index -1 */
        +         printf("%s - %s\n",
        +           lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
        +         lua_pop(L, 1);  /* removes `value'; keeps `key' for next iteration */
        +       }
        +
        + +

        While traversing a table, +do not call lua_tolstring directly on a key, +unless you know that the key is actually a string. +Recall that lua_tolstring changes +the value at the given index; +this confuses the next call to lua_next. + +

        +


        lua_Number

        +
        +          typedef double lua_Number;
        +
        + + +

        The type of numbers in Lua. + +

        Through the configuration file you can change +Lua to operate with other type for numbers (e.g., float or long). + +

        +


        lua_objlen

        +
        +          size_t lua_objlen (lua_State *L, int index);
        +
        + + +

        Returns the "length" of the value at the given acceptable index: +For strings, this is the string length; +for tables, this is the result of the length operator (`#´). +for userdata, this is the size of the block of memory allocated +for the userdatum. +For other values, returns 0. + +

        +


        lua_pcall

        +
        +          lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
        +
        + + +

        Calls a function in protected mode. + +

        Both nargs and nresults have the same meaning as +in lua_call. +If there are no errors during the call, +lua_pcall behaves exactly like lua_call. +However, if there is any error, +lua_pcall catches it, +pushes a single value on the stack (the error message), +and returns an error code. +Like lua_call, +lua_pcall always removes the function +and its arguments from the stack. + +

        If errfunc is 0, +then the error message returned is exactly the original error message. +Otherwise, errfunc is the stack index of an +error handler function. +(In the current implementation, that index cannot be a pseudo-index.) +In case of runtime errors, +that function will be called with the error message +and its return value will be the message returned by lua_pcall. + +

        Typically, the error handler function is used to add more debug +information to the error message, such as a stack traceback. +Such information cannot be gathered after the return of lua_pcall, +since by then the stack has unwound. + +

        The lua_pcall function returns 0 in case of success +or one of the following error codes +(defined in lua.h): +

          +
        • LUA_ERRRUN — a runtime error. +
        • LUA_ERRMEM — memory allocation error. +For such errors, Lua does not call the error handler function. +
        • LUA_ERRERR — +error while running the error handler function. +
        + +

        +


        lua_pop

        +
        +          void lua_pop (lua_State *L, int n);
        +
        + + +

        Pops n elements from the stack. + +

        +


        lua_pushboolean

        +
        +          void lua_pushboolean (lua_State *L, int b);
        +
        + + +

        Pushes a boolean value with value b onto the stack. + +

        +


        lua_pushcclosure

        +
        +          void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
        +
        + + +

        Pushes a new C closure onto the stack. + +

        When a C function is created, +it is possible to associate some values with it, +thus creating a C closure (see 3.4); +these values are then accessible to the function whenever it is called. +To associate values with a C function, +first these values should be pushed onto the stack +(when there are multiple values, the first value is pushed first). +Then the function lua_pushcclosure +is used to create and push the C function onto the stack, +with the argument n telling how many values should be +associated with the function. +lua_pushcclosure also pops these values from the stack. + +

        +


        lua_pushcfunction

        +
        +          void lua_pushcfunction (lua_State *L, lua_CFunction f);
        +
        + + +

        Pushes a C function onto the stack. +This function is equivalent to lua_pushcclosure(L, f, 0);. + +

        +


        lua_pushfstring

        +
        +          const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
        +
        + + +

        Pushes onto the stack a formatted string +and returns a pointer to that string. +It is similar to the C function sprintf +but with some important differences: +

          +
        • You do not have to allocate the space for the result: +The result is a Lua string and Lua takes care of memory allocation +(and deallocation, through garbage collection). +
        • The conversion specifiers are quite restricted. +There are no flags, widths, or precisions. +The conversion specifiers can be simply +`%%´ (inserts a `%´ in the string), +`%s´ (inserts a zero-terminated string, with no size restrictions), +`%f´ (inserts a lua_Number), +`%p´ (inserts a pointer as an hexadecimal numeral), +`%d´ (inserts an int), and +`%c´ (inserts an int as a character). +
        + +

        +


        lua_pushinteger

        +
        +          void lua_pushinteger (lua_State *L, lua_Integer n);
        +
        + + +

        Pushes a number with value n onto the stack. + +

        +


        lua_pushlightuserdata

        +
        +          void lua_pushlightuserdata (lua_State *L, void *p);
        +
        + + +

        Pushes a light userdata onto the stack. + +

        Userdata represents C values in Lua. +A light userdata represents a pointer. +It is a value (like a number): +You do not create it, it has no metatables, +it is not collected (as it was never created). +A light userdata is equal to "any" +light userdata with the same C address. + +

        +


        lua_pushlstring

        +
        +          void lua_pushlstring (lua_State *L, const char *s, size_t len);
        +
        + + +

        Pushes the string pointed by s with size len +onto the stack. +Lua makes (or reuses) an internal copy of the given string, +so the memory at s can be freed or reused immediately after +the function returns. + +

        +


        lua_pushnil

        +
        +          void lua_pushnil (lua_State *L);
        +
        + + +

        Pushes a nil value onto the stack. + +

        +


        lua_pushnumber

        +
        +          void lua_pushnumber (lua_State *L, lua_Number n);
        +
        + + +

        Pushes a number with value n onto the stack. + +

        +


        lua_pushstring

        +
        +          void lua_pushstring (lua_State *L, const char *s);
        +
        + + +

        Pushes the zero-terminated string pointed by s +onto the stack. +Lua makes (or reuses) an internal copy of the given string, +so the memory at s can be freed or reused immediately after +the function returns. + +

        +


        lua_pushvalue

        +
        +          void lua_pushvalue (lua_State *L, int index);
        +
        + + +

        Pushes a copy of the element at the given valid index +onto the stack. + +

        +


        lua_pushvfstring

        +
        +          const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
        +
        + + +

        Equivalent to lua_pushfstring, except that it receives a va_list +instead of a variable number of arguments. + +

        +


        lua_rawequal

        +
        +          int lua_rawequal (lua_State *L, int index1, int index2);
        +
        + + +

        Returns 1 if the two values in acceptable indices index1 and +index2 are primitively equal +(that is, without calling metamethods). +Otherwise returns 0. +Also returns 0 if any of the indices are non valid. + +

        +


        lua_rawget

        +
        +          void lua_rawget (lua_State *L, int index);
        +
        + + +

        Similar to lua_gettable, but doing a raw indexing +(i.e., without metamethods). + +

        +


        lua_rawgeti

        +
        +          void lua_rawgeti (lua_State *L, int index, int n);
        +
        + + +

        Pushes onto the stack the value t[n], +where t is the value at the given valid index index. +The access is raw, +that is, it does not invoke metamethods. + +

        +


        lua_rawset

        +
        +          void lua_rawset (lua_State *L, int index);
        +
        + + +

        Similar to lua_settable, but doing a raw assignment +(i.e., without metamethods). + +

        +


        lua_rawseti

        +
        +          void lua_rawseti (lua_State *L, int index, int n);
        +
        + + +

        Does the equivalent to t[n] = v, +where t is the value at the given valid index index +and v is the value at the top of the stack, + +

        This function pops the value from the stack. +The assignment is raw, +that is, it does not invoke metamethods. + +

        +


        lua_Reader

        +
        +          typedef const char * (*lua_Reader)
        +                               (lua_State *L, void *data, size_t *size);
        +
        +
        + + +

        The reader function used by lua_load. +Every time it needs another piece of the chunk, +lua_load calls the reader, +passing along its data parameter. +The reader must return a pointer to a block of memory +with a new piece of the chunk +and set size to the block size. +To signal the end of the chunk, the reader returns NULL. +The reader function may return pieces of any size greater than zero. + +

        +


        lua_remove

        +
        +          void lua_remove (lua_State *L, int index);
        +
        + + +

        Removes the element at the given valid index, +shifting down the elements above that position to fill the gap. +Cannot be called with a pseudo-index, +because a pseudo-index is not an actual stack position. + +

        +


        lua_replace

        +
        +          void lua_replace (lua_State *L, int index);
        +
        + + +

        Moves the top element into the given position (and pops it), +without shifting any element +(therefore replacing the value at the given position). + +

        +


        lua_resume

        +
        +          int lua_resume (lua_State *L, int narg);
        +
        + + +

        Starts and resumes a coroutine in a given thread. + +

        To start a coroutine, you first create a new thread +(see lua_newthread); +then you push on its stack the body function plus any eventual arguments; +then you call lua_resume, +with narg being the number of arguments. +This call returns when the coroutine suspends or finishes its execution. +When it returns, the stack contains all values passed to lua_yield, +or all values returned by the body function. +lua_resume returns 0 if there are no errors running the coroutine, +or an error code (see lua_pcall). +In case of errors, +the stack is not unwound, +so you can use the debug API over it; +The error message is on the top of the stack. +To restart a coroutine, you put on its stack only the values to +be passed as results from yield, +and then call lua_resume. + +

        +


        lua_setfenv

        +
        +          int lua_setfenv (lua_State *L, int index);
        +
        + + +

        Pops a table from the stack and sets it as +the new environment for the value at the given index. +If the value at the given index is +neither a function nor a thread nor a userdata, +lua_setfenv returns 0 (false). + +

        +


        lua_setfield

        +
        +          void lua_setfield (lua_State *L, int index, const char *k);
        +
        + + +

        Does the equivalent to t[k] = v, +where t is the value at the given valid index index +and v is the value at the top of the stack, + +

        This function pops the value from the stack. +As in Lua, this function may trigger a metamethod +for the "newindex" event (see 2.8). + +

        +


        lua_setmetatable

        +
        +          int lua_setmetatable (lua_State *L, int index);
        +
        + + +

        Pops a table from the stack and +sets it as the new metatable for the value at the given +acceptable index. + +

        +


        lua_settable

        +
        +          void lua_settable (lua_State *L, int index);
        +
        + + +

        Does the equivalent to t[k] = v, +where t is the value at the given valid index index, +v is the value at the top of the stack, +and k is the value just below the top. + +

        This function pops both the key and the value from the stack. +As in Lua, this function may trigger a metamethod +for the "newindex" event (see 2.8). + +

        +


        lua_settop

        +
        +          void lua_settop (lua_State *L, int index);
        +
        + + +

        Accepts any acceptable index, or 0, +and sets the stack top to that index. +If the new top is larger than the old one, +then the new elements are filled with nil. +If index is 0, then all stack elements are removed. + +

        +


        lua_State

        +
        +          typedef struct lua_State lua_State;
        +
        + + +

        Opaque structure that keeps the whole state of a Lua interpreter. +The Lua library is fully reentrant: +it has no global variables. +All information about a state is kept in this structure. + +

        A pointer to this state must be passed as the first argument to +every function in the library, except to lua_newstate, +which creates a Lua state from scratch. + +

        +


        lua_toboolean

        +
        +          int lua_toboolean (lua_State *L, int index);
        +
        + + +

        Converts the Lua value at the given acceptable index to a C boolean +value ((0 or 1). +Like all tests in Lua, +lua_toboolean returns 1 for any Lua value +different from false and nil; +otherwise it returns 0. +It also returns 0 when called with a non-valid index. +(If you want to accept only real boolean values, +use lua_isboolean to test the value's type.) + +

        +


        lua_tocfunction

        +
        +          lua_CFunction lua_tocfunction (lua_State *L, int index);
        +
        + + +

        Converts a value at the given acceptable index to a C function. +That value must be a C function; +otherwise, returns NULL. + +

        +


        lua_tointeger

        +
        +          lua_Integer lua_tointeger (lua_State *L, int idx);
        +
        + + +

        Converts the Lua value at the given acceptable index +to the signed integral type lua_Integer. +The Lua value must be a number or a string convertible to number +(see 2.2.1); +otherwise, lua_tointeger returns 0. + +

        If the number is not an integer, +it is truncated in some non-specified way. + +

        +


        lua_tolstring

        +
        +          const char *lua_tolstring (lua_State *L, int index, size_t *len);
        +
        + + +

        Converts the Lua value at the given acceptable index to a string +(const char*). +If len is not NULL, +it also sets *len with the string length. +The Lua value must be a string or a number; +otherwise, the function returns NULL. +If the value is a number, +then lua_tolstring also +changes the actual value in the stack to a string. +(This change confuses lua_next +when lua_tolstring is applied to keys.) + +

        lua_tolstring returns a fully aligned pointer +to a string inside the Lua state. +This string always has a zero ('\0') +after its last character (as in C), +but may contain other zeros in its body. +Because Lua has garbage collection, +there is no guarantee that the pointer returned by lua_tolstring +will be valid after the corresponding value is removed from the stack. + +

        +


        lua_tonumber

        +
        +          lua_Number lua_tonumber (lua_State *L, int index);
        +
        + + +

        Converts the Lua value at the given acceptable index +to a number (see lua_Number). +The Lua value must be a number or a string convertible to number +(see 2.2.1); +otherwise, lua_tonumber returns 0. + +

        +


        lua_topointer

        +
        +          const void *lua_topointer (lua_State *L, int index);
        +
        + + +

        Converts the value at the given acceptable index to a generic +C pointer (void *). +The value may be a userdata, a table, a thread, or a function; +otherwise, lua_topointer returns NULL. +Lua ensures that different objects return different pointers. +There is no direct way to convert the pointer back to its original value. + +

        Typically this function is used for debug information. + +

        +


        lua_tostring

        +
        +          const char *lua_tostring (lua_State *L, int index);
        +
        + + +

        Equivalent to lua_tolstring with len equal to NULL. + +

        +


        lua_tothread

        +
        +          lua_State *lua_tothread (lua_State *L, int index);
        +
        + + +

        Converts the value at the given acceptable index to a Lua thread +(represented as lua_State *). +This value must be a thread; +otherwise, the function returns NULL. + +

        +


        lua_touserdata

        +
        +          void *lua_touserdata (lua_State *L, int index);
        +
        + + +

        If the value at the given acceptable index is a full userdata, +returns its block address. +If the value is a light userdata, +returns its pointer. +Otherwise, returns NULL. + +

        +


        lua_type

        +
        +          int lua_type (lua_State *L, int index);
        +
        + + +

        Returns the type of a value in the given acceptable index, +or LUA_TNONE for a non-valid index +(that is, an index to an "empty" stack position). +The types returned by lua_type are coded by the following constants +defined in lua.h: +LUA_TNIL, +LUA_TNUMBER, +LUA_TBOOLEAN, +LUA_TSTRING, +LUA_TTABLE, +LUA_TFUNCTION, +LUA_TUSERDATA, +LUA_TTHREAD, +LUA_TLIGHTUSERDATA. + +

        +


        lua_Writer

        +
        +          typedef int (*lua_Writer)
        +                          (lua_State *L, const void* p, size_t sz, void* ud);
        +
        +
        + + +

        The writer function used by lua_dump. +Every time it produces another piece of chunk, +lua_dump calls the writer, +passing along the buffer to be written (p), +its size (sz), +and the data parameter supplied to lua_dump. + +

        The writer returns an error code: +0 means no errors; +any other value means an error and stops lua_dump from +calling the writer again. + +

        +


        lua_xmove

        +
        +          void lua_xmove (lua_State *from, lua_State *to, int n);
        +
        + + +

        Exchange values between different threads of the same global state. + +

        This function pops n values from the stack from, +and pushes them into the stack to. + +

        +


        lua_yield

        +
        +          int lua_yield  (lua_State *L, int nresults);
        +
        + + +

        Yields a coroutine. + +

        This function can only be called as the +return expression of a C function, as follows: +

        +       return lua_yield (L, nresults);
        +
        +When a C function calls lua_yield in that way, +the running coroutine suspends its execution, +and the call to lua_resume that started this coroutine returns. +The parameter nresults is the number of values from the stack +that are passed as results to lua_resume. + +

        +

        3.8 - The Debug Interface

        + +

        Lua has no built-in debugging facilities. +Instead, it offers a special interface +by means of functions and hooks. +This interface allows the construction of different +kinds of debuggers, profilers, and other tools +that need "inside information" from the interpreter. + +

        +


        lua_Debug

        +
        +          typedef struct lua_Debug {
        +            int event;
        +            const char *name;      /* (n) */
        +            const char *namewhat;  /* (n) */
        +            const char *what;      /* (S) */
        +            const char *source;    /* (S) */
        +            int currentline;       /* (l) */
        +            int nups;              /* (u) number of upvalues */
        +            int linedefined;       /* (S) */
        +            int lastlinedefined;   /* (S) */
        +            char short_src[LUA_IDSIZE]; /* (S) */
        +
        +

        /* private part */ + ... + } lua_Debug; + +

        + + +

        A structure used to carry different pieces of +information about an active function. +lua_getstack fills only the private part +of this structure, for later use. +To fill the other fields of lua_Debug with useful information, +call lua_getinfo. + +

        The fields of lua_Debug have the following meaning: +

          +
        • source +If the function was defined in a string, +then source is that string. +If the function was defined in a file, +then source starts with a `@´ followed by the file name. + +

        • short_src +A "printable" version of source, to be used in error messages. + +

        • linedefined +the line number where the definition of the function starts. + +

        • lastlinedefined +the line number where the definition of the function ends. + +

        • what the string "Lua" if this is a Lua function, +"C" if this is a C function, +"main" if this is the main part of a chunk, +and "tail" if this was a function that did a tail call. +In the latter case, +Lua has no other information about this function. + +

        • currentline +the current line where the given function is executing. +When no line information is available, +currentline is set to -1. + +

        • name +a reasonable name for the given function. +Because functions in Lua are first class values, +they do not have a fixed name: +Some functions may be the value of multiple global variables, +while others may be stored only in a table field. +The lua_getinfo function checks how the function was +called to find a suitable name. +If it cannot find a name, +then name is set to NULL. + +

        • namewhat +Explains the name field. +The value of namewhat can be +"global", "local", "method", +"field", "upvalue", or "" (the empty string), +according to how the function was called. +(Lua uses the empty string when no other option seems to apply.) + +

        • nups +The number of upvalues of the function. + +

        + +

        +


        lua_gethook

        +
        +          lua_Hook lua_gethook (lua_State *L);
        +
        + + +

        Returns the current hook function. + +

        +


        lua_gethookcount

        +
        +          int lua_gethookcount (lua_State *L);
        +
        + + +

        Returns the current hook count. + +

        +


        lua_gethookmask

        +
        +          int lua_gethookmask (lua_State *L);
        +
        + + +

        Returns the current hook mask. + +

        +


        lua_getinfo

        +
        +          int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
        +
        + + +

        Fills the fields of lua_Debug with useful information. + +

        This function returns 0 on error +(for instance, an invalid option in what). +Each character in the string what +selects some fields of the structure ar to be filled, +as indicated by the letter in parentheses in the definition of lua_Debug: +`S´ fills in the fields source, linedefined, +lastlinedefined, +and what; +`l´ fills in the field currentline, etc. +Moreover, `f´ pushes onto the stack the function that is +running at the given level. + +

        To get information about a function that is not active +(that is, not in the stack), +you push it onto the stack +and start the what string with the character `>´. +For instance, to know in which line a function f was defined, +you can write the following code: +

        +       lua_Debug ar;
        +       lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* get global `f' */
        +       lua_getinfo(L, ">S", &ar);
        +       printf("%d\n", ar.linedefined);
        +
        + +

        +


        lua_getlocal

        +
        +          const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
        +
        + + +

        Gets information about a local variable of a given activation record. +The parameter ar must be a valid activation record that was +filled by a previous call to lua_getstack or +given as argument to a hook (see lua_Hook). +The index n selects which local variable to inspect +(1 is the first parameter or active local variable, and so on, +until the last active local variable). +lua_getlocal pushes the variable's value onto the stack, +and returns its name. + +

        Returns NULL (and pushes nothing) +when the index is greater than +the number of active local variables. + +

        +


        lua_getstack

        +
        +          int lua_getstack (lua_State *L, int level, lua_Debug *ar);
        +
        + + +

        Get information about the interpreter runtime stack. + +

        This function fills parts of a lua_Debug structure with +an identification of the activation record +of the function executing at a given level. +Level 0 is the current running function, +whereas level n+1 is the function that has called level n. +When there are no errors, lua_getstack returns 1; +when called with a level greater than the stack depth, +it returns 0. + +

        +


        lua_getupvalue

        +
        +          const char *lua_getupvalue (lua_State *L, int funcindex, int n);
        +
        + + +

        Gets information about a closure's upvalue. +(For Lua functions, +upvalues are the external local variables that the function uses, +and that consequently are included in its closure.) +lua_getupvalue gets the index n of an upvalue, +pushes the upvalue's value onto the stack, +and returns its name. +funcindex points to the closure in the stack. +(Upvalues have no particular order, +as they are active through the whole function.) + +

        Returns NULL (and pushes nothing) +when the index is greater than the number of upvalues. +For C functions, this function uses the empty string "" +as a name for all upvalues. + +

        +


        lua_Hook

        +
        +          typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
        +
        + + +

        Type for debugging hook functions. + +

        Whenever a hook is called, its ar argument has its field +event set to the specific event that triggered the hook. +Lua identifies these events with the following constants: +LUA_HOOKCALL, LUA_HOOKRET, +LUA_HOOKTAILRET, LUA_HOOKLINE, +and LUA_HOOKCOUNT. +Moreover, for line events, the field currentline is also set. +To get the value of any other field in ar, +the hook must call lua_getinfo. +For return events, event may be LUA_HOOKRET, +the normal value, or LUA_HOOKTAILRET. +In the latter case, Lua is simulating a return from +a function that did a tail call; +in this case, it is useless to call lua_getinfo. + +

        While Lua is running a hook, it disables other calls to hooks. +Therefore, if a hook calls back Lua to execute a function or a chunk, +that execution occurs without any calls to hooks. + +

        +


        lua_sethook

        +
        +          int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
        +
        + + +

        Sets the debugging hook function. + +

        func is the hook function. +mask specifies on which events the hook will be called: +It is formed by a disjunction of the constants +LUA_MASKCALL, +LUA_MASKRET, +LUA_MASKLINE, +and LUA_MASKCOUNT. +The count argument is only meaningful when the mask +includes LUA_MASKCOUNT. +For each event, the hook is called as explained below: +

          +
        • The call hook is called when the interpreter calls a function. +The hook is called just after Lua enters the new function. +
        • The return hook is called when the interpreter returns from a function. +The hook is called just before Lua leaves the function. +
        • The line hook is called when the interpreter is about to +start the execution of a new line of code, +or when it jumps back in the code (even to the same line). +(This event only happens while Lua is executing a Lua function.) +
        • The count hook is called after the interpreter executes every +count instructions. +(This event only happens while Lua is executing a Lua function.) +
        + +

        A hook is disabled by setting mask to zero. + +

        +


        lua_setlocal

        +
        +          const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
        +
        + + +

        Sets the value of a local variable of a given activation record. +Parameters ar and n are like in lua_getlocal +(see ). +lua_setlocal assigns the value at the top of the stack +to the variable and returns its name. +It also pops the value from the stack. + +

        Returns NULL (and pops nothing) +when the index is greater than +the number of active local variables. + +

        +


        lua_setupvalue

        +
        +          const char *lua_setupvalue (lua_State *L, int funcindex, int n);
        +
        + + +

        Sets the value of a closure's upvalue. +Parameters funcindex and n are like in lua_getupvalue +(see ). +It assigns the value at the top of the stack +to the upvalue and returns its name. +It also pops the value from the stack. + +

        Returns NULL (and pops nothing) +when the index is greater than the number of upvalues. + +

        +

        4 - The Auxiliary Library

        + +

        +The auxiliary library provides several convenient functions +to interface C with Lua. +While the basic API provides the primitive functions for all +interactions between C and Lua, +the auxiliary library provides higher-level functions for some +common tasks. + +

        All functions from the auxiliary library +are defined in header file lauxlib.h and +have a prefix luaL_. + +

        All functions in the auxiliary library are build on +top of the basic API, so they provide nothing that cannot +be done with that API. + +

        Several functions in the auxiliary library are used to +check C function arguments. +Their names are always luaL_check* or luaL_opt*. +All those functions raise an error if the check is not satisfied. +Because the error message is formatted for arguments +(e.g., "bad argument #1"), +you should not use those functions for other stack values. + +

        4.1 - Functions and Types

        + +

        Here we list all functions and types from the auxiliary library +in alphabetical order. + +

        +


        luaL_addchar

        +
        +          void luaL_addchar (luaL_Buffer B, char c);
        +
        + + +

        Adds the character c to the buffer B +(see luaL_Buffer). + +

        +


        luaL_addlstring

        +
        +          void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
        +
        + + +

        Adds the string pointed by s with length l to +the buffer B +(see luaL_Buffer). + +

        +


        luaL_addsize

        +
        +          void luaL_addsize (luaL_Buffer B, size_t n);
        +
        + + +

        Adds a string of length n previously copied to the +buffer area (see luaL_prepbuffer) to the buffer B +(see luaL_Buffer). + +

        +


        luaL_addstring

        +
        +          void luaL_addstring (luaL_Buffer *B, const char *s);
        +
        + + +

        Adds the zero-terminated string pointed by s +to the buffer B +(see luaL_Buffer). + +

        +


        luaL_addvalue

        +
        +          void luaL_addvalue (luaL_Buffer *B);
        +
        + + +

        Adds the value at the top of the stack +to the buffer B +(see luaL_Buffer). +Pops the value. + +

        This is the only function on string buffers that can (and must) +be called with an extra element on the stack, +which is the value to be added to the buffer. + +

        +


        luaL_argcheck

        +
        +          void luaL_argcheck (lua_State *L, int cond, int numarg,
        +                              const char *extramsg);
        +
        + + +

        Checks whether cond is true. +If not, raise an error with message +"bad argument #<numarg> to <func> (<extramsg>)", +where func is retrieved from the call stack. + +

        +


        luaL_argerror

        +
        +          int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
        +
        + + +

        Raises an error with message +"bad argument #<numarg> to <func> (<extramsg>)", +where func is retrieved from the call stack. + +

        This function never returns. + +

        +


        luaL_Buffer

        +
        +          typedef struct luaL_Buffer luaL_Buffer;
        +
        + + +

        Type for a string buffer. + +

        A string buffer allows C code to build Lua strings piecemeal. +Its pattern of use is as follows: +

          +
        • Fist you declare a variable b of type luaL_Buffer. +
        • Then you initialize it with a call luaL_buffinit(L, &b);. +
        • Then you add string pieces to the buffer calling any of +the luaL_add* functions. +
        • You finish calling luaL_pushresult(&b). +That call leaves the final string on the top of the stack. +
        + +

        During its normal operation a string buffer uses a +variable number of stack slots. +So, while using a buffer, you cannot assume that you know where +is the top of the stack. +You can use the stack between successive calls to buffer operations, +as long as that use is balanced, that is, +when you call a buffer operation the stack is at the same level +it was immediately after the previous buffer operation. +(The only exception to this rule is luaL_addvalue.) +After calling luaL_pushresult the stack is back to its +level when the buffer was initialized, +plus the final string on its top. + +

        +


        luaL_buffinit

        +
        +          void luaL_buffinit (lua_State *L, luaL_Buffer *B);
        +
        + + +

        Initializes a buffer B. +This function does not allocate any space; +the buffer must be declared as a variable +(see luaL_Buffer). + +

        +


        luaL_callmeta

        +
        +          int luaL_callmeta (lua_State *L, int obj, const char *e);
        +
        + + +

        Calls a metamethod. + +

        If the object at index obj has a metatable and that +metatable has a field e, +calls that field passing the object as argument. +In that case the function returns 1 and pushes on the +stack the value returned by the call. +If there is no metatable or no metamethod returns 0 +(without pushing any value on the stack). + +

        +


        luaL_checkany

        +
        +          void luaL_checkany (lua_State *L, int narg);
        +
        + + +

        Checks whether the function has an argument narg. + +

        +


        luaL_checkint

        +
        +          int luaL_checkint (lua_State *L, int narg);
        +
        + + +

        Checks whether the function argument narg is a number +and returns that number casted to an int. + +

        +


        luaL_checkinteger

        +
        +          lua_Integer luaL_checkinteger (lua_State *L, int numArg);
        +
        + + +

        Checks whether the function argument narg is a number +and returns that number casted to a lua_Integer. + +

        +


        luaL_checklong

        +
        +          long luaL_checklong (lua_State *L, int narg);
        +
        + + +

        Checks whether the function argument narg is a number +and returns that number casted to a long. + +

        +


        luaL_checklstring

        +
        +          const char *luaL_checklstring (lua_State *L, int numArg, size_t *l);
        +
        + + +

        Checks whether the function argument narg is a string +and returns that string; +if l is not NULL fills the position *l +with the string's length. + +

        +


        luaL_checknumber

        +
        +          lua_Number luaL_checknumber (lua_State *L, int numArg);
        +
        + + +

        Checks whether the function argument narg is a number +and returns that number. + +

        +


        luaL_checkoption

        +
        +          int luaL_checkoption (lua_State *L, int narg, const char *def,
        +                                const char *const lst[]);
        +
        + + +

        Checks whether the function argument narg is a string and +searches for that string into the array lst +(which must be NULL-terminated). +If def is not NULL, +uses def as a default value when +the function has no argument narg or if that argument is nil. + +

        Returns the index in the array where the string was found. +Raises an error if the argument is not a string or +if the string cannot be found. + +

        +


        luaL_checkstack

        +
        +          void luaL_checkstack (lua_State *L, int sz, const char *msg);
        +
        + + +

        Grows the stack size to top + sz elements, +raising an error if the stack cannot grow to that size. +msg is an additional text to go into the error message. + +

        +


        luaL_checkstring

        +
        +          const char *luaL_checkstring (lua_State *L, int narg);
        +
        + + +

        Checks whether the function argument narg is a string +and returns that string. + +

        +


        luaL_checktype

        +
        +          void luaL_checktype (lua_State *L, int narg, int t);
        +
        + + +

        Checks whether the function argument narg has type t. + +

        +


        luaL_checkudata

        +
        +          void *luaL_checkudata (lua_State *L, int ud, const char *tname);
        +
        + + +

        Checks whether the function argument narg is a userdata +of the type tname (see luaL_newmetatable). + +

        +


        luaL_error

        +
        +          int luaL_error (lua_State *L, const char *fmt, ...);
        +
        + + +

        Raises an error. +The error message format is given by fmt +plus any extra argument, +following the same rules of lua_pushfstring. +It also adds at the beginning of the message the file name and +the line number where the error occurred, +if that information is available. + +

        This function never returns. + +

        +


        luaL_getmetafield

        +
        +          int luaL_getmetafield (lua_State *L, int obj, const char *e);
        +
        + + +

        Pushes on the stack the field e from the metatable +of the object at index obj. +If the object does not have a metatable, +or if the metatable does not have that field, +returns 0 (false) and pushes nothing. + +

        +


        luaL_getmetatable

        +
        +          void luaL_getmetatable (lua_State *L, const char *tname);
        +
        + + +

        Pushes on the stack the metatable associated to name tname +in the registry (see luaL_newmetatable). + +

        +


        luaL_gsub

        +
        +          const char *luaL_gsub (lua_State *L, const char *s,
        +                                 const char *p, const char *r);
        +
        + + +

        Creates a copy of string s changing any occurrence of p +by the string r. +Pushes the resulting string on the stack and returns it. + +

        +


        luaL_loadbuffer

        +
        +          int luaL_loadbuffer (lua_State *L, const char *buff,
        +                               size_t sz, const char *name);
        +
        + + +

        Loads a buffer as a Lua chunk. +This function uses lua_load to load the chunk in the +buffer pointed by buff with size sz. + +

        This function returns the same results as lua_load. +name is the chunk name, +used for debug information and error messages. + +

        +


        luaL_loadfile

        +
        +          int luaL_loadfile (lua_State *L, const char *filename);
        +
        + + +

        Loads a file as a Lua chunk. +This function uses lua_load to load the chunk in the file +named filename. +If the file's first line starts with a # it is ignored. + +

        This function returns the same results as lua_load, +but it has an extra error code LUA_ERRFILE +if it cannot open the file. + +

        +


        luaL_loadstring

        +
        +          int luaL_loadstring (lua_State *L, const char *s);
        +
        + + +

        Loads a string as a Lua chunk. +This function uses lua_load to load the chunk in +the zero-terminated string s. + +

        This function returns the same results as lua_load. + +

        +


        luaL_newmetatable

        +
        +          int luaL_newmetatable (lua_State *L, const char *tname);
        +
        + + +

        If the register already has the key "tname", +returns 0. +Otherwise, +creates a new table to be used as metatables for userdata, +adds it to the register with key "tname", +and returns 1. + +

        In both cases pushes on the stack the final value associated +with "tname" in the registry. + +

        +


        luaL_newstate

        +
        +          lua_State *luaL_newstate (void);
        +
        + + +

        Creates a new Lua state, calling lua_newstate with an +allocation function based on the standard C realloc function +and setting a panic function ((see lua_atpanic)) that prints +an error message to the standard error output in case of fatal +errors. + +

        Returns the new state, +or NULL if there is a memory allocation error. + +

        +


        luaL_optint

        +
        +          int luaL_optint (lua_State *L, int narg, int d);
        +
        + + +

        If the function argument narg is a number, +returns that number casted to an int. +If that argument is absent or is nil, +returns d. +Otherwise, raise an error. + +

        +


        luaL_optinteger

        +
        +          lua_Integer luaL_optinteger (lua_State *L, int nArg, lua_Integer d);
        +
        + + +

        If the function argument narg is a number, +returns that number casted to a lua_Integer. +If that argument is absent or is nil, +returns d. +Otherwise, raise an error. + +

        +


        luaL_optlong

        +
        +          long luaL_optlong (lua_State *L, int narg, long d);
        +
        + + +

        If the function argument narg is a number, +returns that number casted to a long. +If that argument is absent or is nil, +returns d. +Otherwise, raise an error. + +

        +


        luaL_optlstring

        +
        +          const char *luaL_optlstring (lua_State *L, int numArg,
        +                                       const char *d, size_t *l);
        +
        + + +

        If the function argument narg is a string, +returns that string. +If that argument is absent or is nil, +returns d. +Otherwise, raise an error. + +

        If l is not NULL fills the position *l +with the results's length. + +

        +


        luaL_optnumber

        +
        +          lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number d);
        +
        + + +

        If the function argument narg is a number, +returns that number. +If that argument is absent or is nil, +returns d. +Otherwise, raise an error. + +

        +


        luaL_optstring

        +
        +          const char *luaL_optstring (lua_State *L, int narg, const char *d);
        +
        + + +

        If the function argument narg is a string, +returns that string. +If that argument is absent or is nil, +returns d. +Otherwise, raise an error. + +

        +


        luaL_prepbuffer

        +
        +          char *luaL_prepbuffer (luaL_Buffer *B);
        +
        + + +

        Returns an address to a space of size LUAL_BUFFERSIZE +wherein you can copy a string to be added to buffer B +(see luaL_Buffer). +After copying the string into that space you must call +luaL_addsize with the size of the string to actually add +it to the buffer. + +

        +


        luaL_pushresult

        +
        +          void luaL_pushresult (luaL_Buffer *B);
        +
        + + +

        Finishes the use of buffer B leaving the final string on +the top of the stack. + +

        +


        luaL_ref

        +
        +          int luaL_ref (lua_State *L, int t);
        +
        + + +

        Creates and returns a reference, +in the table at index t, +for the object at the top of the stack (and pops the object). + +

        A reference is a unique integer key. +As long as you do not add integer keys into table t, +luaL_ref ensures the uniqueness of the key it returns. +You can retrieve an object referred by reference r +calling lua_rawgeti(L, t, r). +Function luaL_unref frees a reference and its associated object. + +

        Whenever the object at the top of the stack is nil, +luaL_ref returns the same reference LUA_REFNIL. +The constant LUA_NOREF is garanteed to be different +from any reference returned by luaL_ref. + +

        +


        luaL_Reg

        +
        +          typedef struct luaL_Reg {
        +            const char *name;
        +            lua_CFunction func;
        +          } luaL_Reg;
        +
        +
        + + +

        Format for arrays of functions to be registered by +luaL_register. +name is the function name and func is a pointer to +the function. +Any array of luaL_Reg must end with an sentinel entry +wherein both name and func are NULL. + +

        +


        luaL_register

        +
        +          void luaL_register (lua_State *L, const char *libname,
        +                              const luaL_Reg *l);
        +
        + + +

        Opens a library. + +

        When called with libname equal to NULL, +simply registers all functions in the list l +(see luaL_Reg) into the table on the top of the stack. + +

        When called with a non-null libname, +creates a new table t, +sets it as the value of the variable libname, +sets it as the value of package.loaded[libname], +and registers on it all functions in the list l. +If there is a table in package.loaded[libname] or in +variable libname, +reuses that table instead of creating a new one. + +

        In any case the function leaves the table +on the top of the stack. + +

        +


        luaL_typename

        +
        +          const char *luaL_typename (lua_State *L, int idx);
        +
        + + +

        Returns the name of the type of the value at index idx. + +

        +


        luaL_typerror

        +
        +          int luaL_typerror (lua_State *L, int narg, const char *tname);
        +
        + + +

        Generates an error with a message like +

        +<location>: bad argument <narg> to <function> (<tname> expected, got <realt>)
        +
        +where <location> is produced by luaL_where, +<function> is the name of the current function, +and <realt> is the type name of the actual argument. + +

        +


        luaL_unref

        +
        +          void luaL_unref (lua_State *L, int t, int ref);
        +
        + + +

        Releases reference ref from the table at index t +(see luaL_ref). +The entry is removed from the table, +so that the referred object can be collected. +The reference ref is also freed to be used again. + +

        If ref is LUA_NOREF or LUA_REFNIL, +luaL_unref does nothing. + +

        +


        luaL_where

        +
        +          void luaL_where (lua_State *L, int lvl);
        +
        + + +

        Pushes on the stack a string identifying the current position +of the control at level lvl in the call stack. +Typically this string has the format <chunkname>:<currentline>:. +Level 0 is the running function, +level 1 is the function that called the running function. + +

        This function is used to build a prefix for error messages. + +

        +

        5 - Standard Libraries

        + +

        The standard libraries provide useful functions +that are implemented directly through the C API. +Some of these functions provide essential services to the language +(e.g., type and getmetatable); +others provide access to "outside" services (e.g., I/O); +and others could be implemented in Lua itself, +but are quite useful or have critical performance to +deserve an implementation in C (e.g., sort). + +

        All libraries are implemented through the official C API +and are provided as separate C modules. +Currently, Lua has the following standard libraries: +

          +
        • basic library; +
        • package library; +
        • string manipulation; +
        • table manipulation; +
        • mathematical functions (sin, log, etc.); +
        • input and output; +
        • operating system facilities; +
        • debug facilities. +
        +Except for the basic and package libraries, +each library provides all its functions as fields of a global table +or as methods of its objects. + +

        To have access to these libraries, +the C host program must first call the function +luaL_openlibs; +or else it can open them individually calling +luaopen_base (for the basic library), +luaopen_package (for the package library), +luaopen_string (for the string library), +luaopen_table (for the table library), +luaopen_math (for the mathematical library), +luaopen_io (for the I/O and the Operating System libraries), +and luaopen_debug (for the debug library). +These functions are declared in lualib.h. + +

        5.1 - Basic Functions

        + +

        The basic library provides some core functions to Lua. +If you do not include this library in your application, +you should check carefully whether you need to provide some alternative +implementation for some of its facilities. + +


        assert (v [, message])

        +Issues an error when +the value of its argument v is nil or false; +otherwise, returns all its arguments. +message is an error message; +when absent, it defaults to "assertion failed!" + +


        collectgarbage (opt [, arg])

        + +

        This function is a generic interface to the garbage collector. +It performs different functions according to its first argument, opt: +

          +
        • "stop" stops the garbage collector. +
        • "restart" restarts the garbage collector. +
        • "collect" performs a full garbage-collection cycle. +
        • "count" returns the total memory in use by Lua (in Kbytes). +
        • "step" performs a garbage-collection step. +The step "size" is controlled by arg +(larger values mean more steps) in a non-specified way. +If you want to control the step size +you must tune experimentally the value of arg. +
        • "steppause" +sets arg/100 as the new value for the pause of +the collector (see 2.10). +
        • "setstepmul" +sets arg/100 as the new value for the step multiplier of +the collector (see 2.10). +
        + +


        dofile (filename)

        +Opens the named file and executes its contents as a Lua chunk. +When called without arguments, +dofile executes the contents of the standard input (stdin). +Returns any value returned by the chunk. +In case of errors, dofile propagates the error +to its caller (that is, it does not run in protected mode). + +


        error (message [, level])

        +Terminates the last protected function called +and returns message as the error message. +Function error never returns. + +

        Usually, error adds some information about the error position +at the beginning of the message. +The level argument specifies how to get the error position. +With level 1 (the default), the error position is where the +error function was called. +Level 2 points the error to where the function +that called error was called; and so on. +Passing a level 0 avoids the addition of error position information +to the message. + +


        _G

        +A global variable (not a function) that +holds the global environment (that is, _G._G = _G). +Lua itself does not use this variable; +changing its value does not affect any environment. +(Use setfenv to change environments.) + +


        getfenv (f)

        +Returns the current environment in use by the function. +f can be a Lua function or a number, +which specifies the function at that stack level: +Level 1 is the function calling getfenv. +If the given function is not a Lua function, +or if f is 0, +getfenv returns the global environment. +The default for f is 1. + +


        getmetatable (object)

        + +

        If object does not have a metatable, returns nil. +Otherwise, +if the object's metatable has a "__metatable" field, +returns the associated value. +Otherwise, returns the metatable of the given object. + +


        ipairs (t)

        + +

        Returns an iterator function, the table t, and 0, +so that the construction +

        +       for i,v in ipairs(t) do ... end
        +
        +will iterate over the pairs (1,t[1]), (2,t[2]), ..., +up to the first integer key with a nil value in the table. + +


        load (func [, chunkname])

        + +

        Loads a chunk using function func to get its pieces. +Each call to func must return a string that concatenates +with previous results. +A return of nil (or no value) signals the end of the chunk. + +

        If there are no errors, +returns the compiled chunk as a function; +otherwise, returns nil plus the error message. +The environment of the returned function is the global environment. + +

        chunkname is used as the chunk name for error messages +and debug information. + +


        loadfile (filename)

        + +

        Similar to load, +but gets the chunk from file filename. + +


        loadstring (string [, chunkname])

        + +

        Similar to load, +but gets the chunk from the given string. + +

        To load and run a given string, use the idiom +

        +      assert(loadstring(s))()
        +
        + +


        next (table [, index])

        + +

        Allows a program to traverse all fields of a table. +Its first argument is a table and its second argument +is an index in this table. +next returns the next index of the table and the +value associated with the index. +When called with nil as its second argument, +next returns the first index +of the table and its associated value. +When called with the last index, +or with nil in an empty table, +next returns nil. +If the second argument is absent, then it is interpreted as nil. + +

        Lua has no declaration of fields; +There is no difference between a +field not present in a table or a field with value nil. +Therefore, next only considers fields with non-nil values. +The order in which the indices are enumerated is not specified, +even for numeric indices. +(To traverse a table in numeric order, +use a numerical for or the ipairs function.) + +

        The behavior of next is undefined if, +during the traversal, +you assign any value to a non-existent field in the table. + +


        pairs (t)

        + +

        Returns the next function and the table t (plus a nil), +so that the construction +

        +       for k,v in pairs(t) do ... end
        +
        +will iterate over all key–value pairs of table t. + +


        pcall (f, arg1, arg2, ...)

        + +

        Calls function f with +the given arguments in protected mode. +That means that any error inside f is not propagated; +instead, pcall catches the error +and returns a status code. +Its first result is the status code (a boolean), +which is true if the call succeeds without errors. +In such case, pcall also returns all results from the call, +after this first result. +In case of any error, pcall returns false plus the error message. + +


        print (e1, e2, ...)

        +Receives any number of arguments, +and prints their values in stdout, +using the tostring function to convert them to strings. +This function is not intended for formatted output, +but only as a quick way to show a value, +typically for debugging. +For formatted output, use format (see 5.4). + +


        rawequal (v1, v2)

        +Checks whether v1 is equal to v2, +without invoking any metamethod. +Returns a boolean. + +


        rawget (table, index)

        +Gets the real value of table[index], +without invoking any metamethod. +table must be a table; +index is any value different from nil. + +


        rawset (table, index, value)

        +Sets the real value of table[index] to value, +without invoking any metamethod. +table must be a table, +index is any value different from nil, +and value is any Lua value. + +


        select (index, ...)

        + +

        If index is a number, +returns all argument after argument number index. +Otherwise, index must be the string "#", +and select returns the total number of extra arguments it received. + +


        setfenv (f, table)

        + +

        Sets the environment to be used by the given function. +f can be a Lua function or a number, +which specifies the function at that stack level: +Level 1 is the function calling setfenv. +setfenv returns the given function. + +

        As a special case, when f is 0 setfenv changes +the environment of the running thread. +In this case, setfenv returns no values. + +


        setmetatable (table, metatable)

        + +

        Sets the metatable for the given table. +(You cannot change the metatable of other types from Lua.) +If metatable is nil, +removes the metatable of the given table. +If the original metatable has a "__metatable" field, +raises an error. + +

        This function returns table. + +


        tonumber (e [, base])

        +Tries to convert its argument to a number. +If the argument is already a number or a string convertible +to a number, then tonumber returns that number; +otherwise, it returns nil. + +

        An optional argument specifies the base to interpret the numeral. +The base may be any integer between 2 and 36, inclusive. +In bases above 10, the letter `A´ (in either upper or lower case) +represents 10, `B´ represents 11, and so forth, +with `Z´ representing 35. +In base 10 (the default), the number may have a decimal part, +as well as an optional exponent part (see 2.2.1). +In other bases, only unsigned integers are accepted. + +


        tostring (e)

        +Receives an argument of any type and +converts it to a string in a reasonable format. +For complete control of how numbers are converted, +use string.format (see 5.4). + +

        If the metatable of e has a "__tostring" field, +tostring calls the corresponding value +with e as argument, +and uses the result of the call as its result. + +


        type (v)

        +Returns the type of its only argument, coded as a string. +The possible results of this function are +"nil" (a string, not the value nil), +"number", +"string", +"boolean, +"table", +"function", +"thread", +and "userdata". + +


        unpack (list [, i [, j]])

        +Returns the elements from the given list. +This function is equivalent to +
        +  return list[i], list[i+1], ..., list[j]
        +
        +except that the above code can be written only for a fixed number +of elements. +By default, i is 1 and j is the length of the list, +as defined by the length operator. + +


        _VERSION

        +A global variable (not a function) that +holds a string containing the current interpreter version. +The current contents of this variable is "Lua 5.1". + +


        xpcall (f, err)

        + +

        This function is similar to pcall, +except that you can set a new error handler. + +

        xpcall calls function f in protected mode, +using err as the error handler. +Any error inside f is not propagated; +instead, xpcall catches the error, +calls the err function with the original error object, +and returns a status code. +Its first result is the status code (a boolean), +which is true if the call succeeds without errors. +In such case, xpcall also returns all results from the call, +after this first result. +In case of any error, +xpcall returns false plus the result from err. + +

        5.2 - Coroutine Manipulation

        + +

        The operations related to coroutines comprise a sub-library of +the basic library and come inside the table coroutine. +See 2.11 for a general description of coroutines. + +


        coroutine.create (f)

        + +

        Creates a new coroutine, with body f. +f must be a Lua function. +Returns this new coroutine, +an object with type "thread". + +


        coroutine.resume (co, val1, ...)

        + +

        Starts or continues the execution of coroutine co. +The first time you resume a coroutine, +it starts running its body. +The arguments val1, ... go as the arguments to the body function. +If the coroutine has yielded, +resume restarts it; +the arguments val1, ... go as the results from the yield. + +

        If the coroutine runs without any errors, +resume returns true plus any values passed to yield +(if the coroutine yields) or any values returned by the body function +(if the coroutine terminates). +If there is any error, +resume returns false plus the error message. + +


        coroutine.running ()

        + +

        Returns the running coroutine, +or nil when called by the main thread. + +


        coroutine.status (co)

        + +

        Returns the status of coroutine co, as a string: +"running", +if the coroutine is running (that is, it called status); +"suspended", if the coroutine is suspended in a call to yield, +or if it has not started running yet; +"normal" if the coroutine is active but not running +(that is, it has resumed another coroutine); +and "dead" if the coroutine has finished its body function, +or if it has stopped with an error. + +


        coroutine.wrap (f)

        + +

        Creates a new coroutine, with body f. +f must be a Lua function. +Returns a function that resumes the coroutine each time it is called. +Any arguments passed to the function behave as the +extra arguments to resume. +Returns the same values returned by resume, +except the first boolean. +In case of error, propagates the error. + +


        coroutine.yield (val1, ...)

        + +

        Suspends the execution of the calling coroutine. +The coroutine cannot be running neither a C function, +nor a metamethod, nor an iterator. +Any arguments to yield go as extra results to resume. + +

        5.3 - Packages and Modules

        + +

        The package library provides basic +facilities for packages and modules in Lua. +It exports two of its functions directly in the global environment: +require and module. +Everything else is exported in a table package. + +


        module (name [, ...])

        + +

        Creates a module. +If there is a table in package.loaded[name], +that table is the module. +Otherwise, if there is a global table t with the given name, +that table is the module. +Otherwise creates a new table t and +sets it as the value of the global name and +the value of package.loaded[name]. +This function also initializes t._NAME with the given name, +t._M with the module (t itself), +and t._PACKAGE with the package name +(the full module name minus last component; see below). +Finally, module sets t as the new environment +of the current function and the new value of package.loaded[name], +so that require returns t. + +

        If name is a compound name +(that is, one with components separated by dots) +module creates (or reuses, if they already exists) +tables for each component. +For instance, if name is a.b.c, +module stores the module table in field c of +field b of global a. + +

        This function may receive optional options after +the module name, +where each option is a function to be applied over the module. + +


        require (modname)

        + +

        Loads the given module. +The function starts by looking into the table package.loaded +to determine whether modname is already loaded. +If it is, then require returns the value stored +at package.loaded[modname]. +Otherwise, it tries to find a loader for that module. + +

        To find a loader, +first require queries package.preload[modname]. +If it is a true value, +that value (which should be a function) is the loader. +Otherwise require searches for a Lua loader using the +path stored in package.path. +if that also fails, it searches for a C loader using the +path stored in package.cpath. +If that also fails, +it tries an all-in-one loader. + +

        When loading a C library, +require first uses a dynamic link facility to link the +application with the library. +Then it tries to find a C function inside that library to +be used as the loader. +The name of that C function is the string "luaopen_" +concatenated with a copy of the module name wherein each dot +is replaced by an underscore. +Moreover, if the module name has a colon, +its prefix up to (and including) the first colon is removed. +For instance, if the module name is a.v1:b.c, +the function name will be luaopen_b_c. + +

        If require finds neither a Lua library nor a +C library for a module, +it calls the all-in-one loader. +That loader searches the C path for a library for +the root name of the given module. +For instance, when requiring a.b.c, +it will search for a C library for a. +If found, it looks into it for an open function for +the submodule; +in our example, that would be luaopen_a_b_c. +With that facility, a package can pack several C submodules +into one single library, +with each submodule keeping its original open function. + +

        Once a loader is found, +require calls the loader with a sinle argument, modname. +If the loader returns any value, +require assigns it to package.loaded[modname]. +If the loader returns no value and +has not assigned any value to package.loaded[modname], +require assigns true to that entry. +In any case, require returns the +final value of package.loaded[modname]. + +

        If there is any error loading or running the module, +or if it cannot find any loader for that module, +then require signals an error. + +


        package.cpath

        + +

        The path used by require to search for a C loader. + +

        Lua initializes the C path package.cpath in the same way +it initializes the Lua path package.path, +using the environment variable LUA_CPATH +(plus another compiled-defined default path). + +


        package.loaded

        + +

        A table used by require to control which +modules are already loaded. +When you require a module modname and +package.loaded[modname] is not false, +require simply returns the value stored there. + +


        package.loadlib (libname, funcname)

        + +

        Links the program with the dynamic C library libname. +Inside this library, looks for a function funcname +and returns this function as a C function. + +

        libname must be the complete file name of the C library, +including any eventual path and extension. + +

        This function is not supported by ANSI C. +As such, it is only available on some platforms +(Windows, Linux, Solaris, BSD, plus other Unix systems that +support the dlfcn standard). + +


        package.path

        + +

        The path used by require to search for a Lua loader. + +

        At start-up, Lua initializes this variable with +the value of the environment variable LUA_PATH or +with a compiled-defined default path, +if the environment variable is not defined. +Any ";;" in the value of the environment variable +is replaced by the default path. + +

        A path is a sequence of templates separated by semicolons. +For each template, require will change each interrogation +mark in the template by filename, +which is modname with each dot replaced by a +"directory separator" (such as "/" in Unix); +then it will try to load the resulting file name. +So, for instance, if the Lua path is +

        +  "./?.lua;./?.lc;/usr/local/?/init.lua"
        +
        +the search for a Lua loader for module mod +will try to load the files +./mod.lua, ./mod.lc, and +/usr/local/mod/init.lua, in that order. + +


        package.preload

        + +

        A table to store loaders for specific modules +(see require). + +


        package.seeall (module)

        + +

        Sets a metatable for module with +its __index field refering to the global environment, +so that this module inherits undefined values +from the global environment. +To be used as an option to function module. + +

        5.4 - String Manipulation

        + +

        This library provides generic functions for string manipulation, +such as finding and extracting substrings, and pattern matching. +When indexing a string in Lua, the first character is at position 1 +(not at 0, as in C). +Indices are allowed to be negative and are interpreted as indexing backwards, +from the end of the string. +Thus, the last character is at position -1, and so on. + +

        The string library provides all its functions inside the table +string. +It also sets a metatable for strings +wherein __index points to itself. +Therefore, you can use the string function is object-oriented style. +For instance, string.byte(s, i) +can be written as s:byte(i). + +


        string.byte (s [, i [, j]])

        +Returns the internal numerical codes of the characters s[i], +s[i+1], ..., s[j]. +The default value for i is 1; +the default value for j is i. + +

        Note that numerical codes are not necessarily portable across platforms. + +


        string.char (i1, i2, ...)

        +Receives 0 or more integers. +Returns a string with length equal to the number of arguments, +in which each character has the internal numerical code equal +to its correspondent argument. + +

        Note that numerical codes are not necessarily portable across platforms. + +


        string.dump (function)

        + +

        Returns a binary representation of the given function, +so that a later loadstring on that string returns +a copy of the function. +function must be a Lua function. + +


        string.find (s, pattern [, init [, plain]])

        +Looks for the first match of +pattern in the string s. +If it finds one, then find returns the indices of s +where this occurrence starts and ends; +otherwise, it returns nil. +A third, optional numerical argument init specifies +where to start the search; +its default value is 1 and may be negative. +A value of true as a fourth, optional argument plain +turns off the pattern matching facilities, +so the function does a plain "find substring" operation, +with no characters in pattern being considered "magic". +Note that if plain is given, then init must be given too. + +


        string.format (formatstring, e1, e2, ...)

        +Returns a formatted version of its variable number of arguments +following the description given in its first argument (which must be a string). +The format string follows the same rules as the printf family of +standard C functions. +The only differences are that the options/modifiers +*, l, L, n, p, +and h are not supported, +and there is an extra option, q. +The q option formats a string in a form suitable to be safely read +back by the Lua interpreter: +The string is written between double quotes, +and all double quotes, newlines, and backslashes in the string +are correctly escaped when written. +For instance, the call +
        +       string.format('%q', 'a string with "quotes" and \n new line')
        +
        +will produce the string: +
        +"a string with \"quotes\" and \
        + new line"
        +
        + +

        The options c, d, E, e, f, +g, G, i, o, u, X, and x all +expect a number as argument, +whereas q and s expect a string. + +

        This function does not accept string values +containing embedded zeros. + +


        string.gmatch (s, pat)

        +Returns an iterator function that, +each time it is called, +returns the next captures from pattern pat over string s. + +

        If pat specifies no captures, +then the whole match is produced in each call. + +

        As an example, the following loop +

        +  s = "hello world from Lua"
        +  for w in string.gmatch(s, "%a+") do
        +    print(w)
        +  end
        +
        +will iterate over all the words from string s, +printing one per line. +The next example collects all pairs key=value from the +given string into a table: +
        +  t = {}
        +  s = "from=world, to=Lua"
        +  for k, v in string.gmatch(s, "(%w+)=(%w+)") do
        +    t[k] = v
        +  end
        +
        + +


        string.gsub (s, pat, repl [, n])

        +Returns a copy of s +in which all occurrences of the pattern pat have been +replaced by a replacement string specified by repl. +gsub also returns, as a second value, +the total number of substitutions made. + +

        If repl is a string, then its value is used for replacement. +The character % works as an escape character: +Any sequence in repl of the form %n, +with n between 1 and 9, +stands for the value of the n-th captured substring (see below). +The sequence %0 stands for the whole match. +The sequence %% stands for a single %. + +

        If repl is a function, then this function is called every time a +match occurs, with all captured substrings passed as arguments, +in order; +if the pattern specifies no captures, +then the whole match is passed as a sole argument. +If the value returned by this function is a string, +then it is used as the replacement string; +otherwise, the replacement string is the empty string. + +

        The optional last parameter n limits +the maximum number of substitutions to occur. +For instance, when n is 1 only the first occurrence of +pat is replaced. + +

        Here are some examples: +

        +   x = string.gsub("hello world", "(%w+)", "%1 %1")
        +   --> x="hello hello world world"
        +
        +   x = string.gsub("hello world", "%w+", "%0 %0", 1)
        +   --> x="hello hello world"
        +
        +   x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
        +   --> x="world hello Lua from"
        +
        +   x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
        +   --> x="home = /home/roberto, user = roberto"
        +
        +   x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
        +         return loadstring(s)()
        +       end)
        +   --> x="4+5 = 9"
        +
        +   local t = {name="lua", version="5.0"}
        +   x = string.gsub("$name_$version.tar.gz", "%$(%w+)", function (v)
        +         return t[v]
        +       end)
        +   --> x="lua_5.0.tar.gz"
        +
        + +


        string.len (s)

        +Receives a string and returns its length. +The empty string "" has length 0. +Embedded zeros are counted, +so "a\000bc\000" has length 5. + +


        string.lower (s)

        +Receives a string and returns a copy of that string with all +uppercase letters changed to lowercase. +All other characters are left unchanged. +The definition of what is an uppercase letter depends on the current locale. + +


        string.match (s, pattern [, init])

        +Looks for the first match of +pattern in the string s. +If it finds one, then match returns +the captures from the pattern; +otherwise it returns nil. +If pattern specifies no captures, +then the whole match is returned. +A third, optional numerical argument init specifies +where to start the search; +its default value is 1 and may be negative. + +


        string.rep (s, n)

        +Returns a string that is the concatenation of n copies of +the string s. + +


        string.reverse (s)

        +Returns a string that is the string s reversed. + +


        string.sub (s, i [, j])

        +Returns the substring of s that +starts at i and continues until j; +i and j may be negative. +If j is absent, then it is assumed to be equal to -1 +(which is the same as the string length). +In particular, +the call string.sub(s,1,j) returns a prefix of s +with length j, +and string.sub(s, -i) returns a suffix of s +with length i. + +


        string.upper (s)

        +Receives a string and returns a copy of that string with all +lowercase letters changed to uppercase. +All other characters are left unchanged. +The definition of what is a lowercase letter depends on the current locale. + +

        Patterns

        + +

        +A character class is used to represent a set of characters. +The following combinations are allowed in describing a character class: +

          +
        • x (where x is not one of the magic characters +^$()%.[]*+-?) +— represents the character x itself. +
        • . — (a dot) represents all characters. +
        • %a — represents all letters. +
        • %c — represents all control characters. +
        • %d — represents all digits. +
        • %l — represents all lowercase letters. +
        • %p — represents all punctuation characters. +
        • %s — represents all space characters. +
        • %u — represents all uppercase letters. +
        • %w — represents all alphanumeric characters. +
        • %x — represents all hexadecimal digits. +
        • %z — represents the character with representation 0. +
        • %x (where x is any non-alphanumeric character) — +represents the character x. +This is the standard way to escape the magic characters. +Any punctuation character (even the non magic) +can be preceded by a `%´ +when used to represent itself in a pattern. + +

        • [set] — +represents the class which is the union of all +characters in set. +A range of characters may be specified by +separating the end characters of the range with a `-´. +All classes %x described above may also be used as +components in set. +All other characters in set represent themselves. +For example, [%w_] (or [_%w]) +represents all alphanumeric characters plus the underscore, +[0-7] represents the octal digits, +and [0-7%l%-] represents the octal digits plus +the lowercase letters plus the `-´ character. + +

          The interaction between ranges and classes is not defined. +Therefore, patterns like [%a-z] or [a-%%] +have no meaning. + +

        • [^set] — +represents the complement of set, +where set is interpreted as above. +
        +For all classes represented by single letters (%a, %c, etc.), +the corresponding uppercase letter represents the complement of the class. +For instance, %S represents all non-space characters. + +

        The definitions of letter, space, and other character groups +depend on the current locale. +In particular, the class [a-z] may not be equivalent to %l. + +

        +A pattern item may be +

          +
        • +a single character class, +which matches any single character in the class; +
        • +a single character class followed by `*´, +which matches 0 or more repetitions of characters in the class. +These repetition items will always match the longest possible sequence; +
        • +a single character class followed by `+´, +which matches 1 or more repetitions of characters in the class. +These repetition items will always match the longest possible sequence; +
        • +a single character class followed by `-´, +which also matches 0 or more repetitions of characters in the class. +Unlike `*´, +these repetition items will always match the shortest possible sequence; +
        • +a single character class followed by `?´, +which matches 0 or 1 occurrence of a character in the class; +
        • +%n, for n between 1 and 9; +such item matches a substring equal to the n-th captured string +(see below); +
        • +%bxy, where x and y are two distinct characters; +such item matches strings that start with x, end with y, +and where the x and y are balanced. +This means that, if one reads the string from left to right, +counting +1 for an x and -1 for a y, +the ending y is the first y where the count reaches 0. +For instance, the item %b() matches expressions with +balanced parentheses. +
        + +

        +A pattern is a sequence of pattern items. +A `^´ at the beginning of a pattern anchors the match at the +beginning of the subject string. +A `$´ at the end of a pattern anchors the match at the +end of the subject string. +At other positions, +`^´ and `$´ have no special meaning and represent themselves. + +

        +A pattern may contain sub-patterns enclosed in parentheses; +they describe captures. +When a match succeeds, the substrings of the subject string +that match captures are stored (captured) for future use. +Captures are numbered according to their left parentheses. +For instance, in the pattern "(a*(.)%w(%s*))", +the part of the string matching "a*(.)%w(%s*)" is +stored as the first capture (and therefore has number 1); +the character matching . is captured with number 2, +and the part matching %s* has number 3. + +

        As a special case, the empty capture () captures +the current string position (a number). +For instance, if we apply the pattern "()aa()" on the +string "flaaap", there will be two captures: 3 and 5. + +

        A pattern cannot contain embedded zeros. Use %z instead. + +

        5.5 - Table Manipulation

        +This library provides generic functions for table manipulation. +It provides all its functions inside the table table. + +

        Most functions in the table library assume that the table +represents an array or a list. +For those functions, when we talk about "the length" of a table +we mean the result of the length operator. + +


        table.concat (table [, sep [, i [, j]]])

        +Returns table[i]..sep..table[i+1] ... sep..table[j]. +The default value for sep is the empty string, +the default for i is 1, +and the default for j is the length of the table. +If i is greater than j, returns the empty string. + +


        table.sort (table [, comp])

        +Sorts table elements in a given order, in-place, +from table[1] to table[n], +where n is the length of the table. +If comp is given, +then it must be a function that receives two table elements, +and returns true +when the first is less than the second +(so that not comp(a[i+1],a[i]) will be true after the sort). +If comp is not given, +then the standard Lua operator < is used instead. + +

        The sort algorithm is not stable, +that is, elements considered equal by the given order +may have their relative positions changed by the sort. + +


        table.insert (table, [pos,] value)

        + +

        Inserts element value at position pos in table, +shifting up other elements to open space, if necessary. +The default value for pos is n+1, +where n is the length of the table (see 2.5.5), +so that a call table.insert(t,x) inserts x at the end +of table t. + +


        table.remove (table [, pos])

        + +

        Removes from table the element at position pos, +shifting down other elements to close the space, if necessary. +Returns the value of the removed element. +The default value for pos is n, +where n is the length of the table, +so that a call table.remove(t) removes the last element +of table t. + +

        5.6 - Mathematical Functions

        + +

        This library is an interface to the standard C math library. +It provides all its functions inside the table math. +The library provides the following functions: + + + + + + + +

        +       math.abs     math.acos    math.asin    math.atan    math.atan2
        +       math.ceil    math.cosh    math.cos     math.deg     math.exp
        +       math.floor   math.fmod    math.frexp   math.ldexp   math.log
        +       math.log10   math.max     math.min     math.modf    math.pow
        +       math.rad     math.random  math.randomseed           math.sin
        +       math.sinh    math.sqrt    math.tan     math.tanh
        +
        +plus a variable math.pi and +a variable math.huge, +with the value HUGE_VAL. +Most of those functions +are only interfaces to the corresponding functions in the C library. +All trigonometric functions work in radians. +The functions math.deg and math.rad convert +between radians and degrees. + +

        The function math.max returns the maximum +value of its numeric arguments. +Similarly, math.min computes the minimum. +Both can be used with 1, 2, or more arguments. + +

        The function math.modf corresponds to the modf C function. +It returns two values: +The integral part and the fractional part of its argument. +The function math.frexp also returns 2 values: +The normalized fraction and the exponent of its argument. + +

        The functions math.random and math.randomseed +are interfaces to the simple random generator functions +rand and srand that are provided by ANSI C. +(No guarantees can be given for their statistical properties.) +When called without arguments, +math.random returns a pseudo-random real number +in the range [0,1). +When called with a number n, +math.random returns +a pseudo-random integer in the range [1,n]. +When called with two arguments, +l and u, +math.random returns a pseudo-random +integer in the range [l,u]. +The math.randomseed function sets a "seed" +for the pseudo-random generator: +Equal seeds produce equal sequences of numbers. + +

        5.7 - Input and Output Facilities

        + +

        The I/O library provides two different styles for file manipulation. +The first one uses implicit file descriptors, +that is, there are operations to set a default input file and a +default output file, +and all input/output operations are over those default files. +The second style uses explicit file descriptors. + +

        When using implicit file descriptors, +all operations are supplied by table io. +When using explicit file descriptors, +the operation io.open returns a file descriptor +and then all operations are supplied as methods of the file descriptor. + +

        The table io also provides +three predefined file descriptors with their usual meanings from C: +io.stdin, io.stdout, and io.stderr. + +

        Unless otherwise stated, +all I/O functions return nil on failure +(plus an error message as a second result) +and some value different from nil on success. + +


        io.close ([file])

        + +

        Equivalent to file:close(). +Without a file, closes the default output file. + +


        io.flush ()

        + +

        Equivalent to file:flush over the default output file. + +


        io.input ([file])

        + +

        When called with a file name, it opens the named file (in text mode), +and sets its handle as the default input file. +When called with a file handle, +it simply sets that file handle as the default input file. +When called without parameters, +it returns the current default input file. + +

        In case of errors this function raises the error, +instead of returning an error code. + +


        io.lines ([filename])

        + +

        Opens the given file name in read mode +and returns an iterator function that, +each time it is called, +returns a new line from the file. +Therefore, the construction +

        +       for line in io.lines(filename) do ... end
        +
        +will iterate over all lines of the file. +When the iterator function detects the end of file, +it returns nil (to finish the loop) and automatically closes the file. + +

        The call io.lines() (without a file name) is equivalent +to io.input():lines(), that is, it iterates over the +lines of the default input file. +In that case it does not close the file when the loop ends. + +


        io.open (filename [, mode])

        + +

        This function opens a file, +in the mode specified in the string mode. +It returns a new file handle, +or, in case of errors, nil plus an error message. + +

        The mode string can be any of the following: +

          +
        • "r" read mode (the default); +
        • "w" write mode; +
        • "a" append mode; +
        • "r+" update mode, all previous data is preserved; +
        • "w+" update mode, all previous data is erased; +
        • "a+" append update mode, previous data is preserved, + writing is only allowed at the end of file. +
        +The mode string may also have a b at the end, +which is needed in some systems to open the file in binary mode. +This string is exactly what is used in the +standard C function fopen. + +


        io.output ([file])

        + +

        Similar to io.input, but operates over the default output file. + +


        io.popen ([prog [, mode]])

        + +

        Starts program prog in a separated process and returns +a file handle that you can use to read data from that program +(if mode is "r", the default) +or to write data to that program +(if mode is "w"). + +

        This function is system dependent and is not available +in all platforms. + +


        io.read (format1, ...)

        + +

        Equivalent to io.input():read. + +


        io.tmpfile ()

        + +

        Returns a handle for a temporary file. +This file is open in update mode +and it is automatically removed when the program ends. + +


        io.type (obj)

        + +

        Checks whether obj is a valid file handle. +Returns the string "file" if obj is an open file handle, +"closed file" if obj is a closed file handle, +and nil if obj is not a file handle. + +


        io.write (value1, ...)

        + +

        Equivalent to io.output():write. + +


        file:close ()

        + +

        Closes file. +Note that files are automatically closed when garbage collected, +but that takes an unpredictable time to happen. + +


        file:flush ()

        + +

        Saves any written data to file. + +


        file:lines ()

        + +

        Returns an iterator function that, +each time it is called, +returns a new line from the file. +Therefore, the construction +

        +       for line in file:lines() do ... end
        +
        +will iterate over all lines of the file. +(Unlike io.lines, this function does not close the file +when the loop ends.) + +


        file:read (format1, ...)

        + +

        Reads the file file, +according to the given formats, which specify what to read. +For each format, +the function returns a string (or a number) with the characters read, +or nil if it cannot read data with the specified format. +When called without formats, +it uses a default format that reads the entire next line +(see below). + +

        The available formats are +

          +
        • "*n" reads a number; +this is the only format that returns a number instead of a string. +
        • "*a" reads the whole file, starting at the current position. +On end of file, it returns the empty string. +
        • "*l" reads the next line (skipping the end of line), +returning nil on end of file. +This is the default format. +
        • number reads a string with up to that number of characters, +returning nil on end of file. +If number is zero, +it reads nothing and returns an empty string, +or nil on end of file. +
        + +


        file:seek ([whence] [, offset])

        + +

        Sets and gets the file position, +measured from the beginning of the file, +to the position given by offset plus a base +specified by the string whence, as follows: +

          +
        • "set" base is position 0 (beginning of the file); +
        • "cur" base is current position; +
        • "end" base is end of file; +
        +In case of success, function seek returns the final file position, +measured in bytes from the beginning of the file. +If this function fails, it returns nil, +plus a string describing the error. + +

        The default value for whence is "cur", +and for offset is 0. +Therefore, the call file:seek() returns the current +file position, without changing it; +the call file:seek("set") sets the position to the +beginning of the file (and returns 0); +and the call file:seek("end") sets the position to the +end of the file, and returns its size. + +


        file:setvbuf (mode [, size])

        + +

        Sets the buffering mode for an output file. +There are three available modes: +

          +
        • "no" no buffering; any output operation appear immediately. +
        • "full" full buffering; output operation is performed only +when the buffer is full (or when you flush the file (see 5.7)). +
        • "line" line buffering; output is buffered until a newline is +output or there is any input from some special files +(such as a terminal device). +
        +For the last two cases, sizes +specifies the size of the buffer, in bytes. +The default is an appropriate size. + +


        file:write (value1, ...)

        + +

        Writes the value of each of its arguments to +the filehandle file. +The arguments must be strings or numbers. +To write other values, +use tostring or string.format before write. + +

        5.8 - Operating System Facilities

        + +

        This library is implemented through table os. + +


        os.clock ()

        + +

        Returns an approximation of the amount of CPU time +used by the program, in seconds. + +


        os.date ([format [, time]])

        + +

        Returns a string or a table containing date and time, +formatted according to the given string format. + +

        If the time argument is present, +this is the time to be formatted +(see the os.time function for a description of this value). +Otherwise, date formats the current time. + +

        If format starts with `!´, +then the date is formatted in Coordinated Universal Time. +After that optional character, +if format is *t, +then date returns a table with the following fields: +year (four digits), month (1--12), day (1--31), +hour (0--23), min (0--59), sec (0--61), +wday (weekday, Sunday is 1), +yday (day of the year), +and isdst (daylight saving flag, a boolean). + +

        If format is not *t, +then date returns the date as a string, +formatted according to the same rules as the C function strftime. + +

        When called without arguments, +date returns a reasonable date and time representation that depends on +the host system and on the current locale +(that is, os.date() is equivalent to os.date("%c")). + +


        os.difftime (t2, t1)

        + +

        Returns the number of seconds from time t1 to time t2. +In Posix, Windows, and some other systems, +this value is exactly t2-t1. + +


        os.execute (command)

        + +

        This function is equivalent to the C function system. +It passes command to be executed by an operating system shell. +It returns a status code, which is system-dependent. + +


        os.exit ([code])

        + +

        Calls the C function exit, +with an optional code, +to terminate the host program. +The default value for code is the success code. + +


        os.getenv (varname)

        + +

        Returns the value of the process environment variable varname, +or nil if the variable is not defined. + +


        os.remove (filename)

        + +

        Deletes the file with the given name. +If this function fails, it returns nil, +plus a string describing the error. + +


        os.rename (oldname, newname)

        + +

        Renames file named oldname to newname. +If this function fails, it returns nil, +plus a string describing the error. + +


        os.setlocale (locale [, category])

        + +

        Sets the current locale of the program. +locale is a string specifying a locale; +category is an optional string describing which category to change: +"all", "collate", "ctype", +"monetary", "numeric", or "time"; +the default category is "all". +The function returns the name of the new locale, +or nil if the request cannot be honored. + +


        os.time ([table])

        + +

        Returns the current time when called without arguments, +or a time representing the date and time specified by the given table. +This table must have fields year, month, and day, +and may have fields hour, min, sec, and isdst +(for a description of these fields, see the os.date function). + +

        The returned value is a number, whose meaning depends on your system. +In Posix, Windows, and some other systems, this number counts the number +of seconds since some given start time (the "epoch"). +In other systems, the meaning is not specified, +and the number returned by time can be used only as an argument to +date and difftime. + +


        os.tmpname ()

        + +

        Returns a string with a file name that can +be used for a temporary file. +The file must be explicitly opened before its use +and removed when no longer needed. + +

        5.9 - The Reflexive Debug Interface

        + +

        The debug library provides +the functionality of the debug interface to Lua programs. +You should exert care when using this library. +The functions provided here should be used exclusively for debugging +and similar tasks, such as profiling. +Please resist the temptation to use them as a +usual programming tool: +They can be very slow. +Moreover, several of its functions +violate some assumptions about Lua code +(e.g., that local variables cannot be accessed from outside or +that userdata metatables cannot be changed by Lua code) +and therefore can compromise some otherwise secure code. + +

        All functions in this library are provided +inside a debug table. + +


        debug.debug ()

        + +

        Enters an interactive mode with the user, +running each string that the user enters. +Using simple commands and other debug facilities, +the user can inspect global and local variables, +change their values, evaluate expressions, and so on. +A line containing only the word cont finishes this function, +so that the caller continues its execution. + +

        Note that commands for debug.debug are not lexically nested +with any function, so they have no direct access to local variables. + +


        debug.getfenv (o)

        +Returns the environment of object o. + +


        debug.gethook ()

        + +

        Returns the current hook settings, as three values: +the current hook function, the current hook mask, +and the current hook count +(as set by the debug.sethook function). + +


        debug.getinfo (function [, what])

        + +

        This function returns a table with information about a function. +You can give the function directly, +or you can give a number as the value of function, +which means the function running at level function of the call stack: +Level 0 is the current function (getinfo itself); +level 1 is the function that called getinfo; +and so on. +If function is a number larger than the number of active functions, +then getinfo returns nil. + +

        The returned table contains all the fields returned by lua_getinfo, +with the string what describing which fields to fill in. +The default for what is to get all information available. +If present, +the option `f´ +adds a field named func with the function itself. + +

        For instance, the expression debug.getinfo(1,"n").name returns +the name of the current function, if a reasonable name can be found, +and debug.getinfo(print) returns a table with all available information +about the print function. + +


        debug.getlocal (level, local)

        + +

        This function returns the name and the value of the local variable +with index local of the function at level level of the stack. +(The first parameter or local variable has index 1, and so on, +until the last active local variable.) +The function returns nil if there is no local +variable with the given index, +and raises an error when called with a level out of range. +(You can call debug.getinfo to check whether the level is valid.) + +


        debug.getmetatable (object)

        + +

        If object does not have a metatable, returns nil. +Otherwise, returns the metatable of the given object. + +


        debug.getupvalue (func, up)

        + +

        This function returns the name and the value of the upvalue +with index up of the function func. +The function returns nil if there is no upvalue with the given index. + +


        debug.setfenv (o, table)

        + +

        Sets the environment of the given object. + +


        debug.sethook (hook, mask [, count])

        + +

        Sets the given function as a hook. +The string mask and the number count describe +when the hook will be called. +The string mask may have the following characters, +with the given meaning: +

          +
        • "c" The hook is called every time Lua calls a function; +
        • "r" The hook is called every time Lua returns from a function; +
        • "l" The hook is called every time Lua enters a new line of code. +
        +With a count different from zero, +the hook is called after every count instructions. + +

        When called without arguments, +the debug.sethook function turns off the hook. + +

        When the hook is called, its first parameter is always a string +describing the event that triggered its call: +"call", "return" (or "tail return"), +"line", and "count". +Moreover, for line events, +it also gets as its second parameter the new line number. +Inside a hook, +you can call getinfo with level 2 to get more information about +the running function +(level 0 is the getinfo function, +and level 1 is the hook function), +unless the event is "tail return". +In this case, Lua is only simulating the return, +and a call to getinfo will return invalid data. + +


        debug.setlocal (level, local, value)

        + +

        This function assigns the value value to the local variable +with index local of the function at level level of the stack. +The function returns nil if there is no local +variable with the given index, +and raises an error when called with a level out of range. +(You can call getinfo to check whether the level is valid.) +Otherwise, it returns the name of the local variable. + +


        debug.setmetatable (o, metatable)

        + +

        Sets the metatable for the given object. + +


        debug.setupvalue (func, up, value)

        + +

        This function assigns the value value to the upvalue +with index up of the function func. +The function returns nil if there is no upvalue +with the given index. +Otherwise, it returns the name of the upvalue. + +


        debug.traceback ([message])

        + +

        Returns a string with a traceback of the call stack. +An optional message string is appended +at the beginning of the traceback. +This function is typically used with xpcall to produce +better error messages. + +

        +

        6 - Lua Stand-alone

        + +

        Although Lua has been designed as an extension language, +to be embedded in a host C program, +it is also frequently used as a stand-alone language. +An interpreter for Lua as a stand-alone language, +called simply lua, +is provided with the standard distribution. +The stand-alone interpreter includes +all standard libraries plus the reflexive debug interface. +Its usage is: +

        +      lua [options] [script [args]]
        +
        +The options are: +
          +
        • - executes stdin as a file; +
        • -e stat executes string stat; +
        • -l mod "requires" mod; +
        • -i enters interactive mode after running script; +
        • -v prints version information; +
        • -- stop handling options. +
        +After handling its options, lua runs the given script, +passing to it the given args. +When called without arguments, +lua behaves as lua -v -i when stdin is a terminal, +and as lua - otherwise. + +

        Before running any argument, +the interpreter checks for an environment variable LUA_INIT. +If its format is @filename, +then lua executes the file. +Otherwise, lua executes the string itself. + +

        All options are handled in order, except -i. +For instance, an invocation like +

        +       $ lua -e'a=1' -e 'print(a)' script.lua
        +
        +will first set a to 1, then print a, +and finally run the file script.lua. +(Here $ is the shell prompt. Your prompt may be different.) + +

        Before starting to run the script, +lua collects all arguments in the command line +in a global table called arg. +The script name is stored in index 0, +the first argument after the script name goes to index 1, +and so on. +Any arguments before the script name +(that is, the interpreter name plus the options) +go to negative indices. +For instance, in the call +

        +       $ lua -la.lua b.lua t1 t2
        +
        +the interpreter first runs the file a.lua, +then creates a table +
        +       arg = { [-2] = "lua", [-1] = "-la.lua", [0] = "b.lua",
        +               [1] = "t1", [2] = "t2" }
        +
        +and finally runs the file b.lua. +The script is called with arg[1], arg[2], ... +as arguments; +it can access those arguments with the vararg expression .... + +

        In interactive mode, +if you write an incomplete statement, +the interpreter waits for its completion. + +

        If the global variable _PROMPT is defined as a string, +then its value is used as the prompt. +Therefore, the prompt can be changed directly on the command line: +

        +       $ lua -e"_PROMPT='myprompt> '" -i
        +
        +(the outer pair of quotes is for the shell, +the inner is for Lua), +or in any Lua programs by assigning to _PROMPT. +Note the use of -i to enter interactive mode; otherwise, +the program would end just after the assignment to _PROMPT. + +

        To allow the use of Lua as a +script interpreter in Unix systems, +the stand-alone interpreter skips +the first line of a chunk if it starts with #. +Therefore, Lua scripts can be made into executable programs +by using chmod +x and the #! form, +as in +

        +#!/usr/local/bin/lua
        +
        +(Of course, +the location of the Lua interpreter may be different in your machine. +If lua is in your PATH, +then +
        +#!/usr/bin/env lua
        +
        +is a more portable solution.) + +


        + +

        Incompatibilities with Previous Version

        + + +

        Here we list the incompatibilities when moving a program +from Lua 5.0 to Lua 5.1. +You can avoid most of the incompatibilities compiling Lua with +appropriate options. +However, +all those compatibility options will be removed in the next version. + +

        Incompatibilities with version 5.0

        + +

        Changes in the Language

        +
          +
        • +The vararg system changed from the pseudo-argument arg with a +table with the extra arguments to the vararg expression. +(Option LUA_COMPAT_VARARG) + +

        • +There was a subtle change in the scope of the implicit +variables of the for constructor. + +

        • +The long string/long comment syntax ([[...]]) does not allow nesting. +You can use the new syntax ([=[...]=]) in those cases. +(Option LUA_COMPAT_LSTR) + +

        + +

        Changes in the Libraries

        +
          +
        • +Function string.find does not return its captures. +Use string.match for that. +(Option LUA_COMPAT_FIND) + +

        • +Function string.gfind was renamed string.gmatch. +(Option LUA_COMPAT_GFIND) + +

        • +Function table.setn was deprecated. +Function table.getn corresponds +to the new length operator (#); +use the operator instead of the function. +(Option LUA_COMPAT_GETN) + +

        • +Function loadlib was renamed package.loadlib. +(Option LUA_COMPAT_LOADLIB) + +

        • +Function math.mod was renamed math.fmod. +(Option LUA_COMPAT_MOD) + +

        • +There was substantial changes in function require due to +the new module system. +However, the new behavior is mostly compatible with the old, +but it gets the path from package.path instead +of from LUA_PATH. + +

        • +Function collectgarbage has different arguments. +Function gcinfo is deprecated; +use collectgarbage("count") instead. + +

        + +

        Changes in the API

        +
          +
        • +Function lua_open was replaced by lua_newstate to +allow the user to set an allocation function. +You can use luaL_newstate from the standard library to +create a state with a standard allocation function +(based on realloc). + +

        • +Functions luaL_getn and luaL_setn +(from the auxiliary library) are deprecated. +Use lua_objlen instead of luaL_getn +and nothing instead of luaL_setn. + +

        • +Function luaL_openlib was replaced by luaL_register. + +

        + +

        + +

        The Complete Syntax of Lua

        + + +

        + +

        +
        +

        chunk ::= {stat [`;´]} + +

        block ::= chunk + +

        stat ::= varlist1 `=´ explist1 | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | return [explist1] | break | for Name `=´ exp `,´ exp [`,´ exp] do block end | for namelist in explist1 do block end | function funcname funcbody | local function Name funcbody | local namelist [init] + +

        funcname ::= Name {`.´ Name} [`:´ Name] + +

        varlist1 ::= var {`,´ var} + +

        var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name + +

        namelist ::= Name {`,´ Name} + +

        init ::= `=´ explist1 + +

        explist1 ::= {exp `,´} exp + +

        exp ::= nil | false | true | Number | Literal | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp + +

        prefixexp ::= var | functioncall | `(´ exp `)´ + +

        functioncall ::= prefixexp args | prefixexp `:´ Name args + +

        args ::= `(´ [explist1] `)´ | tableconstructor | Literal + +

        function ::= function funcbody + +

        funcbody ::= `(´ [parlist1] `)´ block end + +

        parlist1 ::= namelist [`,´ `...´] | `...´ + +

        tableconstructor ::= `{´ [fieldlist] `}´ + fieldlist ::= field {fieldsep field} [fieldsep] + field ::= `[´ exp `]´ `=´ exp | name `=´ exp | exp + fieldsep ::= `,´ | `;´ + +

        binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | and | or + +

        unop ::= `-´ | not | `#´ + +

        + +

        + +

        + +


        + +Last update: +Wed Sep 7 13:53:49 BRT 2005 + + + diff --git a/doc/readme.html b/doc/readme.html index 2eab92029a..db20a69a00 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -1,6 +1,7 @@ Lua documentation + @@ -24,7 +25,7 @@


        Last update: -Wed Dec 22 13:55:42 BRST 2004 +Wed Sep 7 12:57:50 BRST 2005 diff --git a/etc/Makefile b/etc/Makefile index fc3d1468f4..2dfc937ce7 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -14,13 +14,12 @@ MYLDFLAGS= -Wl,-E MYLIBS= -lm -ldl RM= rm -f -ALL= min noparser.o 1 - all: - @echo 'choose a target:' $(ALL) + @echo 'choose a target: min noparser one clean' min: min.c - $(CC) $(CFLAGS) -o $@ $@.c -L$(LIB) -llua $(MYLIBS) + $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS) + echo 'print"Hello there!"' | ./a.out noparser: noparser.o $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) @@ -28,9 +27,9 @@ noparser: noparser.o -./a.out luac.out -./a.out -e'a=1' -1: +one: $(CC) $(CFLAGS) all.c $(MYLIBS) ./a.out $(TST)/hello.lua clean: - $(RM) $(ALL) a.out core core.* *.o luac.out + $(RM) noparser.o a.out core core.* *.o luac.out diff --git a/etc/README b/etc/README index 476267694e..5e42ec5652 100644 --- a/etc/README +++ b/etc/README @@ -3,19 +3,21 @@ Unlike the code in ../src, everything here is in the public domain. all.c Full Lua interpreter in a single file. - Do "make 1". + Do "make one". lua.hpp - Lua header files for C++. - This keeps the C interface to Lua. But Lua also compiles as clean C++. + Lua header files for C++ using 'extern "C"'. lua.ico - A Lua icon for Windows (and web sites, as favicon.ico). + A Lua icon for Windows (and web sites: save as favicon.ico). Drawn by hand by Markus Gritsch . lua.pc pkg-config data for Lua +luavs.bat + Script to build Lua under "Visual Studio .NET Command Prompt". + min.c A minimal Lua interpreter. Good for learning and for starting your own. @@ -23,3 +25,7 @@ min.c noparser.c Linking with noparser.o avoids loading the parsing modules in lualib.a. Do "make noparser" to see a demo. + +strict.lua + Traps uses of undeclared global variables. + diff --git a/etc/luavs.bat b/etc/luavs.bat new file mode 100644 index 0000000000..eea175e3e0 --- /dev/null +++ b/etc/luavs.bat @@ -0,0 +1,7 @@ +cd src +cl /O2 /W3 /c /DLUA_BUILD_AS_DLL l*.c +del lua.obj luac.obj +link /DLL /out:lua51.dll l*.obj +cl /O2 /W3 /c /DLUA_BUILD_AS_DLL lua.c +link /out:lua.exe lua.obj lua51.lib +cd .. diff --git a/etc/noparser.c b/etc/noparser.c index 9396ad6025..13ba546239 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -18,13 +18,14 @@ #include "lparser.h" #include "lzio.h" -void luaX_init (lua_State *L) { +LUAI_FUNC void luaX_init (lua_State *L) { UNUSED(L); } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { +LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { UNUSED(z); UNUSED(buff); + UNUSED(name); lua_pushliteral(L,"parser not loaded"); lua_error(L); return NULL; @@ -33,10 +34,17 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { #ifdef NODUMP #include "lundump.h" -int luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data, int strip) -{ - return 0; - lua_pushliteral(L,"dumper not loaded"); - lua_error(L); +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { + UNUSED(f); + UNUSED(w); + UNUSED(data); + UNUSED(strip); +#if 1 + UNUSED(L); + return 0; +#else + lua_pushliteral(L,"dumper not loaded"); + lua_error(L); +#endif } #endif diff --git a/etc/strict.lua b/etc/strict.lua new file mode 100644 index 0000000000..7c9fa15947 --- /dev/null +++ b/etc/strict.lua @@ -0,0 +1,34 @@ +-- +-- strict.lua +-- checks uses of undeclared global variables +-- All global variables must be 'declared' through a regular assignment +-- (even assigning nil will do) in a main chunk before being used +-- anywhere or assigned to inside a function. +-- + +local mt = getmetatable(_G) +if mt == nil then + mt = {} + setmetatable(_G, mt) +end + +mt.__declared = {} + +mt.__newindex = function (t, n, v) + if not mt.__declared[n] then + local w = debug.getinfo(2, "S").what + if w ~= "main" and w ~= "C" then + error("assign to undeclared variable '"..n.."'", 2) + end + mt.__declared[n] = true + end + rawset(t, n, v) +end + +mt.__index = function (t, n) + if not mt.__declared[n] and debug.getinfo(2, "S").what ~= "C" then + error("variable '"..n.."' is not declared", 2) + end + return rawget(t, n) +end + diff --git a/src/lapi.c b/src/lapi.c index 1fe7916ad6..b85e1dc54b 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.41 2005/05/17 19:49:15 roberto Exp $ +** $Id: lapi.c,v 2.48 2005/09/01 17:42:22 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -113,11 +113,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { if (from == to) return; lua_lock(to); api_checknelems(from, n); - api_check(L, G(from) == G(to)); + api_check(from, G(from) == G(to)); + api_check(from, to->ci->top - to->top >= n); from->top -= n; for (i = 0; i < n; i++) { - setobj2s(to, to->top, from->top + i); - api_incr_top(to); + setobj2s(to, to->top++, from->top + i); } lua_unlock(to); } @@ -153,7 +153,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API int lua_gettop (lua_State *L) { - return (L->top - L->base); + return cast(int, L->top - L->base); } @@ -344,6 +344,7 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { return NULL; } luaC_checkGC(L); + o = index2adr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); } if (len != NULL) *len = tsvalue(o)->len; @@ -351,7 +352,7 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { } -LUA_API size_t lua_objsize (lua_State *L, int idx) { +LUA_API size_t lua_objlen (lua_State *L, int idx) { StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TSTRING: return tsvalue(o)->len; @@ -618,6 +619,9 @@ LUA_API void lua_getfenv (lua_State *L, int idx) { case LUA_TUSERDATA: sethvalue(L, L->top, uvalue(o)->env); break; + case LUA_TTHREAD: + setobj2s(L, L->top, gt(thvalue(o))); + break; default: setnilvalue(L->top); break; @@ -736,6 +740,9 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { case LUA_TUSERDATA: uvalue(o)->env = hvalue(L->top - 1); break; + case LUA_TTHREAD: + sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); + break; default: res = 0; break; @@ -868,7 +875,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { if (isLfunction(o)) status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); else - status = 0; + status = 1; lua_unlock(L); return status; } @@ -969,10 +976,10 @@ LUA_API int lua_next (lua_State *L, int idx) { LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); - luaC_checkGC(L); api_checknelems(L, n); if (n >= 2) { - luaV_concat(L, n, L->top - L->base - 1); + luaC_checkGC(L); + luaV_concat(L, n, cast(int, L->top - L->base) - 1); L->top -= (n-1); } else if (n == 0) { /* push empty string */ @@ -985,7 +992,7 @@ LUA_API void lua_concat (lua_State *L, int n) { LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { - *ud = G(L)->ud; + if (ud) *ud = G(L)->ud; return G(L)->frealloc; } diff --git a/src/lauxlib.c b/src/lauxlib.c index 964f5eb05d..b643d6c3ff 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.133 2005/05/17 19:49:15 roberto Exp $ +** $Id: lauxlib.c,v 1.152 2005/09/06 17:20:11 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -42,7 +42,8 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; - lua_getstack(L, 0, &ar); + if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ @@ -65,7 +66,7 @@ LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { static void tag_error (lua_State *L, int narg, int tag) { - luaL_typerror(L, narg, lua_typename(L, tag)); + luaL_typerror(L, narg, lua_typename(L, tag)); } @@ -95,12 +96,16 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { /* }====================================================== */ -LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { +LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, narg, def) : + luaL_checkstring(L, narg); int i; - for (i=0; list[i]; i++) - if (strcmp(list[i], name) == 0) + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) return i; - return -1; /* name not found */ + return luaL_argerror(L, narg, + lua_pushfstring(L, "invalid option " LUA_QS, name)); } @@ -112,31 +117,17 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { lua_newtable(L); /* create metatable */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ - lua_pushvalue(L, -1); - lua_pushstring(L, tname); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ return 1; } -LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) { - lua_getfield(L, LUA_REGISTRYINDEX, tname); -} - - LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { - const char *tn; - if (!lua_getmetatable(L, ud)) return NULL; /* no metatable? */ - lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[metatable] */ - tn = lua_tostring(L, -1); - if (tn && (strcmp(tn, tname) == 0)) { - lua_pop(L, 1); - return lua_touserdata(L, ud); - } - else { - lua_pop(L, 1); - return NULL; - } + void *p = lua_touserdata(L, ud); + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ + if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2)) + luaL_typerror(L, ud, tname); + lua_pop(L, 2); /* remove both metatables */ + return p; } @@ -230,26 +221,27 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { } -LUALIB_API void luaL_openlib (lua_State *L, const char *libname, - const luaL_reg *l, int nup) { +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l) { + luaI_openlib(L, libname, l, 0); +} + + +LUALIB_API void luaI_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { if (libname) { /* check whether lib already exists */ - luaL_getfield(L, LUA_GLOBALSINDEX, libname); - if (lua_isnil(L, -1)) { /* not found? */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, -1, libname); /* get _LOADED[libname] */ + if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ - lua_newtable(L); /* create it */ - if (lua_getmetatable(L, LUA_GLOBALSINDEX)) - lua_setmetatable(L, -2); /* share metatable with global table */ - /* register it with given name */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, libname) != NULL) + luaL_error(L, "name conflict for module " LUA_QS, libname); lua_pushvalue(L, -1); - luaL_setfield(L, LUA_GLOBALSINDEX, libname); + lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ } - else if (!lua_istable(L, -1)) - luaL_error(L, "name conflict for library " LUA_QS, libname); - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_pushvalue(L, -2); - lua_setfield(L, -2, libname); /* _LOADED[modname] = new table */ - lua_pop(L, 1); /* remove _LOADED table */ + lua_remove(L, -2); /* remove _LOADED table */ lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { @@ -270,7 +262,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** ======================================================= */ -#ifndef luaL_getn +#if defined(LUA_COMPAT_GETN) static int checkint (lua_State *L, int topop) { int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; @@ -313,7 +305,7 @@ LUALIB_API int luaL_getn (lua_State *L, int t) { if ((n = checkint(L, 2)) >= 0) return n; lua_getfield(L, t, "n"); /* else try t.n */ if ((n = checkint(L, 1)) >= 0) return n; - return lua_objsize(L, t); + return lua_objlen(L, t); } #endif @@ -321,21 +313,11 @@ LUALIB_API int luaL_getn (lua_State *L, int t) { /* }====================================================== */ -static const char *pushnexttemplate (lua_State *L, const char *path) { - const char *l; - if (*path == '\0') return NULL; /* no more templates */ - if (*path == LUA_PATHSEP) path++; /* skip separator */ - l = strchr(path, LUA_PATHSEP); /* find next separator */ - if (l == NULL) l = path+strlen(path); - lua_pushlstring(L, path, l - path); /* template */ - return l; -} - LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r) { const char *wild; - int l = strlen(p); + size_t l = strlen(p); luaL_Buffer b; luaL_buffinit(L, &b); while ((wild = strstr(s, p)) != NULL) { @@ -343,65 +325,19 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, luaL_addstring(&b, r); /* push replacement in place of pattern */ s = wild + l; /* continue after `p' */ } - luaL_addstring(&b, s); /* push last suffix (`n' already includes this) */ + luaL_addstring(&b, s); /* push last suffix */ luaL_pushresult(&b); return lua_tostring(L, -1); } -static int readable (const char *fname) { - int err; - FILE *f = fopen(fname, "r"); /* try to open file */ - if (f == NULL) return 0; /* open failed */ - getc(f); /* try to read it */ - err = ferror(f); - fclose(f); - return (err == 0); -} - - -LUALIB_API const char *luaL_searchpath (lua_State *L, const char *name, - const char *path) { - const char *p = path; - for (;;) { - const char *fname; - if ((p = pushnexttemplate(L, p)) == NULL) { - lua_pushfstring(L, "no readable " LUA_QS " in path " LUA_QS "", - name, path); - return NULL; - } - fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); - lua_remove(L, -2); /* remove path template */ - if (readable(fname)) /* does file exist and is readable? */ - return fname; /* return that file name */ - lua_pop(L, 1); /* remove file name */ - } -} - - -LUALIB_API const char *luaL_getfield (lua_State *L, int idx, - const char *fname) { +LUALIB_API const char *luaL_findtable (lua_State *L, int idx, + const char *fname) { const char *e; lua_pushvalue(L, idx); - while ((e = strchr(fname, '.')) != NULL) { - lua_pushlstring(L, fname, e - fname); - lua_rawget(L, -2); - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - if (!lua_istable(L, -1)) return fname; - } - lua_pushstring(L, fname); - lua_rawget(L, -2); /* get last field */ - lua_remove(L, -2); /* remove previous table */ - return NULL; -} - - -LUALIB_API const char *luaL_setfield (lua_State *L, int idx, - const char *fname) { - const char *e; - lua_pushvalue(L, idx); - while ((e = strchr(fname, '.')) != NULL) { + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); lua_pushlstring(L, fname, e - fname); lua_rawget(L, -2); if (lua_isnil(L, -1)) { /* no such field? */ @@ -411,17 +347,13 @@ LUALIB_API const char *luaL_setfield (lua_State *L, int idx, lua_pushvalue(L, -2); lua_settable(L, -4); /* set new table into field */ } - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - if (!lua_istable(L, -1)) { + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ lua_pop(L, 2); /* remove table and value */ - return fname; + return fname; /* return problematic part of the name */ } - } - lua_pushstring(L, fname); - lua_pushvalue(L, -3); /* move value to the top */ - lua_rawset(L, -3); /* set last field */ - lua_pop(L, 2); /* remove value and table */ + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); return NULL; } @@ -480,7 +412,7 @@ LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { while (l--) - luaL_putchar(B, *s++); + luaL_addchar(B, *s++); } @@ -538,7 +470,7 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ - ref = lua_objsize(L, t); + ref = lua_objlen(L, t); ref++; /* create new reference */ } lua_rawseti(L, t, ref); @@ -661,6 +593,12 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, } +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { + return luaL_loadbuffer(L, s, strlen(s), s); +} + + + /* }====================================================== */ @@ -671,21 +609,22 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { free(ptr); return NULL; } - else + else return realloc(ptr, nsize); } static int panic (lua_State *L) { (void)L; /* to avoid warnings */ - fprintf(stderr, "PANIC: unprotected error during Lua-API call\n"); + fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); return 0; } LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); - lua_atpanic(L, &panic); + if (L) lua_atpanic(L, &panic); return L; } diff --git a/src/lauxlib.h b/src/lauxlib.h index 83c807e90f..aa07cb2b00 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.75 2005/03/29 16:20:48 roberto Exp $ +** $Id: lauxlib.h,v 1.85 2005/09/06 17:19:51 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -15,24 +15,34 @@ #include "lua.h" -#if !LUA_COMPAT_GETN -#define luaL_getn(L,i) lua_objsize(L, i) +#if defined(LUA_COMPAT_GETN) +LUALIB_API int (luaL_getn) (lua_State *L, int t); +LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); +#else +#define luaL_getn(L,i) ((int)lua_objlen(L, i)) #define luaL_setn(L,i,j) ((void)0) /* no op! */ #endif +#if defined(LUA_COMPAT_OPENLIB) +#define luaI_openlib luaL_openlib +#endif + /* extra error code for `luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) -typedef struct luaL_reg { +typedef struct luaL_Reg { const char *name; lua_CFunction func; -} luaL_reg; +} luaL_Reg; + -LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, - const luaL_reg *l, int nup); +LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); @@ -53,36 +63,31 @@ LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int narg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); -LUALIB_API void (luaL_getmetatable) (lua_State *L, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); -LUALIB_API int (luaL_findstring) (const char *st, const char *const lst[]); - -LUALIB_API const char *(luaL_searchpath) (lua_State *L, const char *name, - const char *path); +LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, + const char *const lst[]); LUALIB_API int (luaL_ref) (lua_State *L, int t); LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); -LUALIB_API int (luaL_getn) (lua_State *L, int t); -LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); - LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); -LUALIB_API const char *(luaL_getfield) (lua_State *L, int idx, - const char *fname); -LUALIB_API const char *(luaL_setfield) (lua_State *L, int idx, - const char *fname); + +LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, + const char *fname); + @@ -103,6 +108,13 @@ LUALIB_API const char *(luaL_setfield) (lua_State *L, int idx, #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) +#define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0)) + +#define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, 0, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + + /* ** {====================================================== ** Generic Buffer manipulation @@ -118,10 +130,13 @@ typedef struct luaL_Buffer { char buffer[LUAL_BUFFERSIZE]; } luaL_Buffer; -#define luaL_putchar(B,c) \ +#define luaL_addchar(B,c) \ ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ (*(B)->p++ = (char)(c))) +/* compatibility only */ +#define luaL_putchar(B,c) luaL_addchar(B,c) + #define luaL_addsize(B,n) ((B)->p += (n)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); @@ -149,6 +164,8 @@ LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); #define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) +#define luaL_reg luaL_Reg + #endif diff --git a/src/lbaselib.c b/src/lbaselib.c index d69d83ff76..fb21da4b19 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.176 2005/05/17 19:49:15 roberto Exp $ +** $Id: lbaselib.c,v 1.182 2005/08/26 17:36:32 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -133,7 +133,7 @@ static void getfunc (lua_State *L) { static int luaB_getfenv (lua_State *L) { getfunc(L); if (lua_iscfunction(L, -1)) /* is a C function? */ - lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the global env. */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ else lua_getfenv(L, -1); return 1; @@ -145,7 +145,10 @@ static int luaB_setfenv (lua_State *L) { getfunc(L); lua_pushvalue(L, 2); if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { - lua_replace(L, LUA_GLOBALSINDEX); + /* change environment of current thread */ + lua_pushthread(L); + lua_insert(L, -2); + lua_setfenv(L, -2); return 0; } else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) @@ -192,9 +195,8 @@ static int luaB_collectgarbage (lua_State *L) { "count", "step", "setpause", "setstepmul", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; - int o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts); + int o = luaL_checkoption(L, 1, "collect", opts); int ex = luaL_optinteger(L, 2, 0); - luaL_argcheck(L, o >= 0, 1, "invalid option"); lua_pushinteger(L, lua_gc(L, optsnum[o], ex)); return 1; } @@ -268,15 +270,7 @@ static int luaB_loadstring (lua_State *L) { static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); - const char *path = luaL_optstring(L, 2, NULL); - int status; - if (path == NULL) - status = luaL_loadfile(L, fname); - else { - fname = luaL_searchpath(L, fname, path); - status = (fname) ? luaL_loadfile(L, fname) : 1; - } - return load_aux(L, status); + return load_aux(L, luaL_loadfile(L, fname)); } @@ -331,13 +325,6 @@ static int luaB_assert (lua_State *L) { } -static int luaB_getn (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushinteger(L, lua_objsize(L, 1)); - return 1; -} - - static int luaB_unpack (lua_State *L) { int i = luaL_optint(L, 2, 1); int e = luaL_optint(L, 3, -1); @@ -442,32 +429,31 @@ static int luaB_newproxy (lua_State *L) { } -static const luaL_reg base_funcs[] = { +static const luaL_Reg base_funcs[] = { + {"assert", luaB_assert}, + {"collectgarbage", luaB_collectgarbage}, + {"dofile", luaB_dofile}, {"error", luaB_error}, - {"getmetatable", luaB_getmetatable}, - {"setmetatable", luaB_setmetatable}, + {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, - {"setfenv", luaB_setfenv}, + {"getmetatable", luaB_getmetatable}, + {"loadfile", luaB_loadfile}, + {"load", luaB_load}, + {"loadstring", luaB_loadstring}, {"next", luaB_next}, + {"pcall", luaB_pcall}, {"print", luaB_print}, + {"rawequal", luaB_rawequal}, + {"rawget", luaB_rawget}, + {"rawset", luaB_rawset}, + {"select", luaB_select}, + {"setfenv", luaB_setfenv}, + {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, - {"assert", luaB_assert}, - {"getn", luaB_getn}, {"unpack", luaB_unpack}, - {"select", luaB_select}, - {"rawequal", luaB_rawequal}, - {"rawget", luaB_rawget}, - {"rawset", luaB_rawset}, - {"pcall", luaB_pcall}, {"xpcall", luaB_xpcall}, - {"collectgarbage", luaB_collectgarbage}, - {"gcinfo", luaB_gcinfo}, - {"loadfile", luaB_loadfile}, - {"dofile", luaB_dofile}, - {"loadstring", luaB_loadstring}, - {"load", luaB_load}, {NULL, NULL} }; @@ -593,13 +579,13 @@ static int luaB_corunning (lua_State *L) { } -static const luaL_reg co_funcs[] = { +static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, - {"wrap", luaB_cowrap}, {"resume", luaB_coresume}, - {"yield", luaB_yield}, - {"status", luaB_costatus}, {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, {NULL, NULL} }; @@ -616,7 +602,7 @@ static void auxopen (lua_State *L, const char *name, static void base_open (lua_State *L) { lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ + luaL_register(L, NULL, base_funcs); /* open lib into global table */ lua_pushliteral(L, LUA_VERSION); lua_setglobal(L, "_VERSION"); /* set global _VERSION */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */ @@ -641,7 +627,7 @@ static void base_open (lua_State *L) { LUALIB_API int luaopen_base (lua_State *L) { base_open(L); - luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); + luaL_register(L, LUA_COLIBNAME, co_funcs); return 2; } diff --git a/src/lcode.c b/src/lcode.c index 1e8d80fb21..04838f331e 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.12 2005/03/16 16:59:21 roberto Exp $ +** $Id: lcode.c,v 2.16 2005/08/29 20:49:21 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -53,6 +53,11 @@ int luaK_jump (FuncState *fs) { } +void luaK_ret (FuncState *fs, int first, int nret) { + luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); +} + + static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); @@ -101,49 +106,50 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) { ** check whether list has any jump that do not produce a value ** (or produce an inverted value) */ -static int need_value (FuncState *fs, int list, int cond) { +static int need_value (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) { Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1; + if (GET_OPCODE(i) != OP_TESTSET) return 1; } return 0; /* not found */ } static void patchtestreg (Instruction *i, int reg) { - if (reg == NO_REG) reg = GETARG_B(*i); - SETARG_A(*i, reg); + if (reg != NO_REG) + SETARG_A(*i, reg); + else /* no register to put value; change TESTSET to TEST */ + *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); } -static void patchlistaux (FuncState *fs, int list, - int ttarget, int treg, int ftarget, int freg, int dtarget) { +static void removevalues (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction *i = getjumpcontrol(fs, list); + if (GET_OPCODE(*i) == OP_TESTSET) + patchtestreg(i, NO_REG); + } +} + + +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, + int dtarget) { while (list != NO_JUMP) { int next = getjump(fs, list); Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) != OP_TEST) { - lua_assert(dtarget != NO_JUMP); - fixjump(fs, list, dtarget); /* jump to default target */ - } - else { - if (GETARG_C(*i)) { - lua_assert(ttarget != NO_JUMP); - patchtestreg(i, treg); - fixjump(fs, list, ttarget); - } - else { - lua_assert(ftarget != NO_JUMP); - patchtestreg(i, freg); - fixjump(fs, list, ftarget); - } + if (GET_OPCODE(*i) == OP_TESTSET) { + patchtestreg(i, reg); + fixjump(fs, list, vtarget); } + else + fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } static void dischargejpc (FuncState *fs) { - patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); + patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } @@ -153,7 +159,7 @@ void luaK_patchlist (FuncState *fs, int list, int target) { luaK_patchtohere(fs, list); else { lua_assert(target < fs->pc); - patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); + patchlistaux(fs, list, target, NO_REG, target); } } @@ -223,7 +229,7 @@ static int addk (FuncState *fs, TValue *k, TValue *v) { MAXARG_Bx, "constant table overflow"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[fs->nk], v); - luaC_barriert(L, f, v); + luaC_barrier(L, f, v); return fs->nk++; } } @@ -373,7 +379,7 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ - if (need_value(fs, e->t, 1) || need_value(fs, e->f, 0)) { + if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = NO_JUMP; /* first jump (over LOAD ops.) */ if (e->k != VJMP) fj = luaK_jump(fs); @@ -382,8 +388,8 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); - patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f); - patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t); + patchlistaux(fs, e->f, final, reg, p_f); + patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; e->info = reg; @@ -492,7 +498,8 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { static void invertjump (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->info); - lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TEST); + lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && + GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } @@ -502,13 +509,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ - return condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond); + return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); - return condjump(fs, OP_TEST, NO_REG, e->info, cond); + return condjump(fs, OP_TESTSET, NO_REG, e->info, cond); } @@ -535,6 +542,8 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } } luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ + luaK_patchtohere(fs, e->t); + e->t = NO_JUMP; } @@ -560,6 +569,8 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { } } luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ + luaK_patchtohere(fs, e->f); + e->f = NO_JUMP; } @@ -593,6 +604,8 @@ static void codenot (FuncState *fs, expdesc *e) { } /* interchange true and false lists */ { int temp = e->f; e->f = e->t; e->t = temp; } + removevalues(fs, e->f); + removevalues(fs, e->t); } @@ -607,7 +620,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { case OPR_MINUS: { luaK_exp2val(fs, e); if (e->k == VK && ttisnumber(&fs->f->k[e->info])) - e->info = luaK_numberK(fs, luai_numunm(nvalue(&fs->f->k[e->info]))); + e->info = luaK_numberK(fs, luai_numunm(L, nvalue(&fs->f->k[e->info]))); else { luaK_exp2anyreg(fs, e); freeexp(fs, e); @@ -620,10 +633,10 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { codenot(fs, e); break; } - case OPR_SIZE: { + case OPR_LEN: { luaK_exp2anyreg(fs, e); freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_SIZ, 0, e->info, 0); + e->info = luaK_codeABC(fs, OP_LEN, 0, e->info, 0); e->k = VRELOCABLE; break; } @@ -636,14 +649,10 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { luaK_goiftrue(fs, v); - luaK_patchtohere(fs, v->t); - v->t = NO_JUMP; break; } case OPR_OR: { luaK_goiffalse(fs, v); - luaK_patchtohere(fs, v->f); - v->f = NO_JUMP; break; } case OPR_CONCAT: { diff --git a/src/lcode.h b/src/lcode.h index 19a3284e01..ed1a95bc98 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ +** $Id: lcode.h,v 1.45 2005/08/29 20:49:21 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -34,7 +34,7 @@ typedef enum BinOpr { #define binopistest(op) ((op) >= OPR_NE) -typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_SIZE, OPR_NOUNOPR } UnOpr; +typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define getcode(fs,e) ((fs)->f->code[(e)->info]) @@ -65,6 +65,7 @@ LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_jump (FuncState *fs); +LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); diff --git a/src/ldblib.c b/src/ldblib.c index 6c1a17762d..e7458634ab 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.98 2005/05/17 19:49:15 roberto Exp $ +** $Id: ldblib.c,v 1.101 2005/08/26 17:36:32 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -365,26 +365,26 @@ static int db_errorfb (lua_State *L) { } -static const luaL_reg dblib[] = { - {"getmetatable", db_getmetatable}, - {"setmetatable", db_setmetatable}, +static const luaL_Reg dblib[] = { + {"debug", db_debug}, {"getfenv", db_getfenv}, - {"setfenv", db_setfenv}, - {"getlocal", db_getlocal}, - {"getinfo", db_getinfo}, {"gethook", db_gethook}, + {"getinfo", db_getinfo}, + {"getlocal", db_getlocal}, + {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, + {"setfenv", db_setfenv}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, + {"setmetatable", db_setmetatable}, {"setupvalue", db_setupvalue}, - {"debug", db_debug}, {"traceback", db_errorfb}, {NULL, NULL} }; LUALIB_API int luaopen_debug (lua_State *L) { - luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); + luaL_register(L, LUA_DBLIBNAME, dblib); return 1; } diff --git a/src/ldebug.c b/src/ldebug.c index 73a604ffb0..11166c0a69 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.20 2005/05/17 19:49:15 roberto Exp $ +** $Id: ldebug.c,v 2.26 2005/08/04 13:37:38 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -92,7 +92,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { } if (level == 0 && ci > L->base_ci) { /* level found? */ status = 1; - ar->i_ci = ci - L->base_ci; + ar->i_ci = cast(int, ci - L->base_ci); } else if (level < 0) { /* level is of a lost tail call? */ status = 1; @@ -152,6 +152,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { if (cl->c.isC) { ar->source = "=[C]"; ar->linedefined = -1; + ar->lastlinedefined = -1; ar->what = "C"; } else { @@ -164,7 +165,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { } -static void info_tailcall (lua_State *L, lua_Debug *ar) { +static void info_tailcall (lua_Debug *ar) { ar->name = ar->namewhat = ""; ar->what = "tail"; ar->lastlinedefined = ar->linedefined = ar->currentline = -1; @@ -194,7 +195,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, Closure *f, CallInfo *ci) { int status = 1; if (f == NULL) { - info_tailcall(L, ar); + info_tailcall(ar); return status; } for (; *what; what++) { @@ -275,8 +276,11 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { static int precheck (const Proto *pt) { check(pt->maxstacksize <= MAXSTACK); + lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); + lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || + (pt->is_vararg & VARARG_HASARG)); + check(pt->sizeupvalues <= pt->nups); check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); - lua_assert(pt->numparams+pt->is_vararg <= pt->maxstacksize); check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); return 1; } @@ -389,8 +393,8 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { } case OP_TFORLOOP: { check(c >= 1); /* at least one result (control variable) */ - checkreg(pt, a+3+c); /* space for results */ - if (reg >= a+3) last = pc; /* affect all regs above its call base */ + checkreg(pt, a+2+c); /* space for results */ + if (reg >= a+2) last = pc; /* affect all regs above its base */ break; } case OP_FORLOOP: @@ -440,7 +444,8 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_VARARG: { - check(pt->is_vararg & NEWSTYLEVARARG); + check((pt->is_vararg & VARARG_ISVARARG) && + !(pt->is_vararg & VARARG_NEEDSARG)); b--; if (b == LUA_MULTRET) check(checkopenop(pt, pc)); checkreg(pt, a+b-1); @@ -546,7 +551,8 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? - getobjname(L, L->ci, o - L->base, &name) : NULL; + getobjname(L, L->ci, cast(int, o - L->base), &name) : + NULL; if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); diff --git a/src/ldo.c b/src/ldo.c index 09e0a44dc4..d7645835d4 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.23 2005/05/03 19:01:17 roberto Exp $ +** $Id: ldo.c,v 2.33 2005/09/09 18:16:28 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -48,7 +48,7 @@ struct lua_longjmp { }; -static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { +void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); @@ -68,14 +68,41 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { } +static void restore_stack_limit (lua_State *L) { + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ + int inuse = cast(int, L->ci - L->base_ci); + if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUAI_MAXCALLS); + } +} + + +static void resetstack (lua_State *L, int status) { + L->ci = L->base_ci; + L->base = L->ci->base; + luaF_close(L, L->base); /* close eventual pending closures */ + luaD_seterrorobj(L, status, L->base); + L->nCcalls = 0; + L->allowhook = 1; + restore_stack_limit(L); + L->errfunc = 0; + L->errorJmp = NULL; +} + + void luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { L->errorJmp->status = errcode; LUAI_THROW(L, L->errorJmp); } else { - L->status = errcode; - if (G(L)->panic) G(L)->panic(L); + L->status = cast(lu_byte, errcode); + if (G(L)->panic) { + resetstack(L, errcode); + lua_unlock(L); + G(L)->panic(L); + } exit(EXIT_FAILURE); } } @@ -93,16 +120,6 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { return lj.status; } - -static void restore_stack_limit (lua_State *L) { - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); - if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ - int inuse = (L->ci - L->base_ci); - if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUAI_MAXCALLS); - } -} - /* }====================================================== */ @@ -116,9 +133,8 @@ static void correctstack (lua_State *L, TValue *oldstack) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; - lua_assert(lua_checkpc(L, ci)); } - L->base = L->ci->base; + L->base = (L->base - oldstack) + L->stack; } @@ -173,7 +189,7 @@ void luaD_callhook (lua_State *L, int event, int line) { if (event == LUA_HOOKTAILRET) ar.i_ci = 0; /* tail call; no debug information about it */ else - ar.i_ci = L->ci - L->base_ci; + ar.i_ci = cast(int, L->ci - L->base_ci); luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; lua_assert(L->ci->top <= L->stack_last); @@ -189,18 +205,17 @@ void luaD_callhook (lua_State *L, int event, int line) { } -static StkId adjust_varargs (lua_State *L, int nfixargs, int actual, - int style) { +static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; + int nfixargs = p->numparams; Table *htab = NULL; StkId base, fixed; - if (actual < nfixargs) { - for (; actual < nfixargs; ++actual) - setnilvalue(L->top++); - } -#if LUA_COMPAT_VARARG - if (style != NEWSTYLEVARARG) { /* compatibility with old-style vararg */ + for (; actual < nfixargs; ++actual) + setnilvalue(L->top++); +#if defined(LUA_COMPAT_VARARG) + if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ int nvar = actual - nfixargs; /* number of extra arguments */ + lua_assert(p->is_vararg & VARARG_HASARG); luaC_checkGC(L); htab = luaH_new(L, nvar, 1); /* create `arg' table */ for (i=0; ip; - if (p->is_vararg) { /* varargs? */ - int nargs = L->top - restorestack(L, funcr) - 1; - luaD_checkstack(L, p->maxstacksize + nargs); - base = adjust_varargs(L, p->numparams, nargs, p->is_vararg); - func = restorestack(L, funcr); - } - else { - luaD_checkstack(L, p->maxstacksize); - func = restorestack(L, funcr); + luaD_checkstack(L, p->maxstacksize); + func = restorestack(L, funcr); + if (!p->is_vararg) /* no varargs? */ base = func + 1; + else { /* vararg function */ + int nargs = cast(int, L->top - func) - 1; + base = adjust_varargs(L, p, nargs); + func = restorestack(L, funcr); /* previous call may change the stack */ } ci = inc_ci(L); /* now `enter' new function */ ci->func = func; @@ -281,6 +294,11 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; + if (L->hookmask & LUA_MASKCALL) { + L->savedpc++; /* hooks assume 'pc' is already incremented */ + luaD_callhook(L, LUA_HOOKCALL, -1); + L->savedpc--; /* correct 'pc' */ + } return PCRLUA; } else { /* if is a C function, call it */ @@ -292,13 +310,14 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); + ci->nresults = nresults; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); if (n >= 0) { /* no yielding? */ - luaD_poscall(L, nresults, L->top - n); + luaD_poscall(L, L->top - n); return PCRC; } else { @@ -320,22 +339,24 @@ static StkId callrethooks (lua_State *L, StkId firstResult) { } -void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { +int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; + int wanted, i; + CallInfo *ci; if (L->hookmask & LUA_MASKRET) firstResult = callrethooks(L, firstResult); - res = L->ci->func; /* res == final position of 1st result */ - L->ci--; - L->base = L->ci->base; /* restore base */ - L->savedpc = L->ci->savedpc; /* restore savedpc */ + ci = L->ci--; + res = ci->func; /* res == final position of 1st result */ + wanted = ci->nresults; + L->base = (ci - 1)->base; /* restore base */ + L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ /* move results to correct place */ - while (wanted != 0 && firstResult < L->top) { + for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); - wanted--; - } - while (wanted-- > 0) + while (i-- > 0) setnilvalue(res++); L->top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ } @@ -352,38 +373,34 @@ void luaD_call (lua_State *L, StkId func, int nResults) { else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - if (luaD_precall(L, func, nResults) == PCRLUA) { /* is a Lua function? */ - StkId firstResult = luaV_execute(L, 1); /* call it */ - luaD_poscall(L, nResults, firstResult); - } + if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ + luaV_execute(L, 1); /* call it */ L->nCcalls--; luaC_checkGC(L); } static void resume (lua_State *L, void *ud) { - StkId firstResult; - int nargs = *cast(int *, ud); + StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; - if (L->status != LUA_YIELD) { - lua_assert(ci == L->base_ci && nargs < L->top - L->base); - luaD_precall(L, L->top - (nargs + 1), LUA_MULTRET); /* start coroutine */ + if (L->status != LUA_YIELD) { /* start coroutine */ + lua_assert(ci == L->base_ci && firstArg > L->base); + if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) + return; } else { /* resuming from previous yield */ if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ - int nresults = ci->nresults; lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); - luaD_poscall(L, nresults, L->top - nargs); /* complete it */ - if (nresults >= 0) L->top = L->ci->top; - } /* else yielded inside a hook: just continue its execution */ + if (luaD_poscall(L, firstArg)) /* complete it... */ + L->top = L->ci->top; /* and correct top if not multiple results */ + } + else /* yielded inside a hook: just continue its execution */ + L->base = L->ci->base; } L->status = 0; - firstResult = luaV_execute(L, L->ci - L->base_ci); - if (firstResult != NULL) { /* return? */ - luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ - } + luaV_execute(L, cast(int, L->ci - L->base_ci)); } @@ -399,17 +416,18 @@ static int resume_error (lua_State *L, const char *msg) { LUA_API int lua_resume (lua_State *L, int nargs) { int status; lua_lock(L); - lua_assert(L->errfunc == 0 && L->nCcalls == 0); if (L->status != LUA_YIELD) { if (L->status != 0) return resume_error(L, "cannot resume dead coroutine"); else if (L->ci != L->base_ci) return resume_error(L, "cannot resume non-suspended coroutine"); } - status = luaD_rawrunprotected(L, resume, &nargs); + luai_userstateresume(L, nargs); + lua_assert(L->errfunc == 0 && L->nCcalls == 0); + status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status != 0) { /* error? */ - L->status = status; /* mark thread as `dead' */ - seterrorobj(L, status, L->top); + L->status = cast(lu_byte, status); /* mark thread as `dead' */ + luaD_seterrorobj(L, status, L->top); } else status = L->status; @@ -419,19 +437,11 @@ LUA_API int lua_resume (lua_State *L, int nargs) { LUA_API int lua_yield (lua_State *L, int nresults) { - CallInfo *ci; + luai_userstateyield(L, nresults); lua_lock(L); - ci = L->ci; if (L->nCcalls > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - if (!f_isLua(ci)) { /* usual yield */ - if (L->top - nresults > L->base) { /* is there garbage in the stack? */ - int i; - for (i=0; ibase + i, L->top - nresults + i); - L->top = L->base + nresults; - } - } /* else it's an yield inside a hook: nothing to do */ + L->base = L->top - nresults; /* protect stack slots below */ L->status = LUA_YIELD; lua_unlock(L); return -1; @@ -441,7 +451,7 @@ LUA_API int lua_yield (lua_State *L, int nresults) { int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; - int oldnCcalls = L->nCcalls; + unsigned short oldnCcalls = L->nCcalls; ptrdiff_t old_ci = saveci(L, L->ci); lu_byte old_allowhooks = L->allowhook; ptrdiff_t old_errfunc = L->errfunc; @@ -450,7 +460,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, if (status != 0) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close eventual pending closures */ - seterrorobj(L, status, oldtop); + luaD_seterrorobj(L, status, oldtop); L->nCcalls = oldnCcalls; L->ci = restoreci(L, old_ci); L->base = L->ci->base; diff --git a/src/ldo.h b/src/ldo.h index b355b7e8cb..b2de92bb80 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ +** $Id: ldo.h,v 2.7 2005/08/24 16:15:49 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,16 +13,6 @@ #include "lzio.h" -/* -** macro to control inclusion of some hard tests on stack reallocation -*/ -#ifndef HARDSTACKTESTS -#define condhardstacktests(x) ((void)0) -#else -#define condhardstacktests(x) x -#endif - - #define luaD_checkstack(L,n) \ if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ luaD_growstack(L, n); \ @@ -53,7 +43,7 @@ LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); -LUAI_FUNC void luaD_poscall (lua_State *L, int wanted, StkId firstResult); +LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); @@ -61,6 +51,7 @@ LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); +LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); #endif diff --git a/src/ldump.c b/src/ldump.c index 0c9f00d182..e580047bd2 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.10 2005/05/12 00:26:50 lhf Exp $ +** $Id: ldump.c,v 1.12 2005/06/08 14:40:44 lhf Exp $ ** save pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -16,17 +16,20 @@ #include "lstate.h" #include "lundump.h" -#define DumpVector(b,n,size,D) DumpBlock(b,(n)*(size),D) -#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D) - typedef struct { lua_State* L; - lua_Chunkwriter writer; + lua_Writer writer; void* data; int strip; int status; } DumpState; +#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) +#define DumpLines(f,D) DumpVector(f->lineinfo,f->sizelineinfo,sizeof(int),D) +#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D) +#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) +#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) + static void DumpBlock(const void* b, size_t size, DumpState* D) { if (D->status==0) @@ -37,45 +40,43 @@ static void DumpBlock(const void* b, size_t size, DumpState* D) } } -static void DumpByte(int y, DumpState* D) +static void DumpChar(int y, DumpState* D) { char x=(char)y; - DumpBlock(&x,sizeof(x),D); + DumpVar(x,D); } static void DumpInt(int x, DumpState* D) { - DumpBlock(&x,sizeof(x),D); + DumpVar(x,D); } -static void DumpSize(size_t x, DumpState* D) +static void DumpNumber(lua_Number x, DumpState* D) { - DumpBlock(&x,sizeof(x),D); + DumpVar(x,D); } -static void DumpNumber(lua_Number x, DumpState* D) +static void DumpVector(const void* b, int n, size_t size, DumpState* D) { - DumpBlock(&x,sizeof(x),D); + DumpInt(n,D); + DumpMem(b,n,size,D); } static void DumpString(const TString* s, DumpState* D) { if (s==NULL || getstr(s)==NULL) - DumpSize(0,D); + { + size_t size=0; + DumpVar(size,D); + } else { size_t size=s->tsv.len+1; /* include trailing '\0' */ - DumpSize(size,D); + DumpVar(size,D); DumpBlock(getstr(s),size,D); } } -static void DumpCode(const Proto* f, DumpState* D) -{ - DumpInt(f->sizecode,D); - DumpVector(f->code,f->sizecode,sizeof(*f->code),D); -} - static void DumpLocals(const Proto* f, DumpState* D) { int i,n=f->sizelocvars; @@ -88,12 +89,6 @@ static void DumpLocals(const Proto* f, DumpState* D) } } -static void DumpLines(const Proto* f, DumpState* D) -{ - DumpInt(f->sizelineinfo,D); - DumpVector(f->lineinfo,f->sizelineinfo,sizeof(*f->lineinfo),D); -} - static void DumpUpvalues(const Proto* f, DumpState* D) { int i,n=f->sizeupvalues; @@ -105,18 +100,18 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D); static void DumpConstants(const Proto* f, DumpState* D) { - int i,n; - DumpInt(n=f->sizek,D); + int i,n=f->sizek; + DumpInt(n,D); for (i=0; ik[i]; - DumpByte(ttype(o),D); + DumpChar(ttype(o),D); switch (ttype(o)) { case LUA_TNIL: break; case LUA_TBOOLEAN: - DumpByte(bvalue(o),D); + DumpChar(bvalue(o),D); break; case LUA_TNUMBER: DumpNumber(nvalue(o),D); @@ -129,7 +124,8 @@ static void DumpConstants(const Proto* f, DumpState* D) break; } } - DumpInt(n=f->sizep,D); + n=f->sizep; + DumpInt(n,D); for (i=0; ip[i],f->source,D); } @@ -138,10 +134,10 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpString((f->source==p) ? NULL : f->source,D); DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); - DumpByte(f->nups,D); - DumpByte(f->numparams,D); - DumpByte(f->is_vararg,D); - DumpByte(f->maxstacksize,D); + DumpChar(f->nups,D); + DumpChar(f->numparams,D); + DumpChar(f->is_vararg,D); + DumpChar(f->maxstacksize,D); if (D->strip) DumpInt(0,D); else DumpLines(f,D); if (D->strip) DumpInt(0,D); else DumpLocals(f,D); if (D->strip) DumpInt(0,D); else DumpUpvalues(f,D); @@ -151,20 +147,15 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) static void DumpHeader(DumpState* D) { - DumpLiteral(LUA_SIGNATURE,D); - DumpByte(VERSION,D); - DumpByte(luaU_endianness(),D); - DumpByte(sizeof(int),D); - DumpByte(sizeof(size_t),D); - DumpByte(sizeof(Instruction),D); - DumpByte(sizeof(lua_Number),D); - DumpNumber(TEST_NUMBER,D); + char h[LUAC_HEADERSIZE]; + luaU_header(h); + DumpBlock(h,LUAC_HEADERSIZE,D); } /* ** dump Lua function as precompiled chunk */ -int luaU_dump (lua_State* L, const Proto* f, lua_Chunkwriter w, void* data, int strip) +int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { DumpState D; D.L=L; diff --git a/src/lgc.c b/src/lgc.c index 9257d2bcd8..0f30104f5d 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.32 2005/05/05 15:34:03 roberto Exp $ +** $Id: lgc.c,v 2.36 2005/08/24 17:06:36 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -240,8 +240,8 @@ static void traverseclosure (global_State *g, Closure *cl) { static void checkstacksizes (lua_State *L, StkId max) { - int ci_used = L->ci - L->base_ci; /* number of `ci' in use */ - int s_used = max - L->stack; /* part of stack in use */ + int ci_used = cast(int, L->ci - L->base_ci); /* number of `ci' in use */ + int s_used = cast(int, max - L->stack); /* part of stack in use */ if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ return; /* do not touch the stacks */ if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) @@ -287,7 +287,6 @@ static l_mem propagatemark (global_State *g) { black2gray(o); /* keep it gray */ return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h); - break; } case LUA_TFUNCTION: { Closure *cl = gco2cl(o); @@ -295,7 +294,6 @@ static l_mem propagatemark (global_State *g) { traverseclosure(g, cl); return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : sizeLclosure(cl->l.nupvalues); - break; } case LUA_TTHREAD: { lua_State *th = gco2th(o); @@ -306,7 +304,6 @@ static l_mem propagatemark (global_State *g) { traversestack(g, th); return sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * th->size_ci; - break; } case LUA_TPROTO: { Proto *p = gco2p(o); @@ -318,7 +315,6 @@ static l_mem propagatemark (global_State *g) { sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues; - break; } default: lua_assert(0); return 0; } @@ -528,10 +524,10 @@ static void remarkupvals (global_State *g) { static void atomic (lua_State *L) { global_State *g = G(L); size_t udsize; /* total size of userdata to be finalized */ - /* remark objects cautch by write barrier */ - propagateall(g); /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); + /* traverse objects cautch by write barrier and by 'remarkupvals' */ + propagateall(g); /* remark weak tables */ g->gray = g->weak; g->weak = NULL; @@ -673,12 +669,13 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { } -void luaC_barrierback (lua_State *L, GCObject *o) { +void luaC_barrierback (lua_State *L, Table *t) { global_State *g = G(L); + GCObject *o = obj2gco(t); lua_assert(isblack(o) && !isdead(g, o)); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); black2gray(o); /* make table gray (again) */ - gco2h(o)->gclist = g->grayagain; + t->gclist = g->grayagain; g->grayagain = o; } diff --git a/src/lgc.h b/src/lgc.h index 4fc4a81e93..5f69acb1e3 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.13 2005/04/25 19:24:10 roberto Exp $ +** $Id: lgc.h,v 2.15 2005/08/24 16:15:49 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -77,23 +77,24 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_checkGC(L) { if (G(L)->totalbytes >= G(L)->GCthreshold) \ +#define luaC_checkGC(L) { \ + condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ + if (G(L)->totalbytes >= G(L)->GCthreshold) \ luaC_step(L); } #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),gcvalue(v)); } -#define luaC_barriert(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ - luaC_barrierback(L,obj2gco(p)); } +#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ + luaC_barrierback(L,t); } #define luaC_objbarrier(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),obj2gco(o)); } -#define luaC_objbarriert(L,p,o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ - luaC_barrierback(L,obj2gco(p)); } +#define luaC_objbarriert(L,t,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); LUAI_FUNC void luaC_callGCTM (lua_State *L); @@ -103,7 +104,7 @@ LUAI_FUNC void luaC_fullgc (lua_State *L); LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); -LUAI_FUNC void luaC_barrierback (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); #endif diff --git a/src/linit.c b/src/linit.c index afcd338bec..d30ff1e3aa 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.11 2005/04/13 17:24:20 roberto Exp $ +** $Id: linit.c,v 1.13 2005/08/26 17:36:32 roberto Exp $ ** Initialization of libraries for lua.c ** See Copyright Notice in lua.h */ @@ -14,7 +14,7 @@ #include "lauxlib.h" -static const luaL_reg lualibs[] = { +static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, @@ -22,13 +22,13 @@ static const luaL_reg lualibs[] = { {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, - {LUA_LOADLIBNAME, luaopen_loadlib}, + {LUA_LOADLIBNAME, luaopen_package}, {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { - const luaL_reg *lib = lualibs; + const luaL_Reg *lib = lualibs; for (; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_pushstring(L, lib->name); diff --git a/src/liolib.c b/src/liolib.c index 1dba7eff83..a7f8743fa4 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.60 2005/05/16 21:19:00 roberto Exp $ +** $Id: liolib.c,v 2.67 2005/08/26 17:36:32 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -20,8 +20,8 @@ -#define IO_INPUT 1 -#define IO_OUTPUT 2 +#define IO_INPUT 1 +#define IO_OUTPUT 2 static const char *const fnames[] = {"input", "output"}; @@ -50,17 +50,17 @@ static void fileerror (lua_State *L, int arg, const char *filename) { } -static FILE **topfile (lua_State *L) { - FILE **f = (FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE); - if (f == NULL) luaL_argerror(L, 1, "bad file"); - return f; -} +#define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) static int io_type (lua_State *L) { - FILE **f = (FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE); - if (f == NULL) lua_pushnil(L); - else if (*f == NULL) + void *ud; + luaL_checkany(L, 1); + ud = lua_touserdata(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); + if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + lua_pushnil(L); /* not a file */ + else if (*((FILE **)ud) == NULL) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); @@ -91,29 +91,45 @@ static FILE **newfile (lua_State *L) { } +/* +** this function has a separated environment, which defines the +** correct __close for 'popen' files +*/ +static int io_pclose (lua_State *L) { + FILE **p = topfile(L); + int ok = lua_pclose(L, *p); + if (ok) *p = NULL; + return pushresult(L, ok, NULL); +} + + +static int io_fclose (lua_State *L) { + FILE **p = topfile(L); + int ok = (fclose(*p) == 0); + if (ok) *p = NULL; + return pushresult(L, ok, NULL); +} + + static int aux_close (lua_State *L) { - FILE *f = tofile(L); - if (f == stdin || f == stdout || f == stderr) - return 0; /* file cannot be closed */ - else { - int ok = (fclose(f) == 0); - if (ok) - *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ - return ok; - } + lua_getfenv(L, 1); + lua_getfield(L, -1, "__close"); + return (lua_tocfunction(L, -1))(L); } static int io_close (lua_State *L) { if (lua_isnone(L, 1)) lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); - return pushresult(L, aux_close(L), NULL); + tofile(L); /* make sure argument is a file */ + return aux_close(L); } static int io_gc (lua_State *L) { - FILE **f = topfile(L); - if (*f != NULL) /* ignore closed files */ + FILE *f = *topfile(L); + /* ignore closed files and standard files */ + if (f != NULL && f != stdin && f != stdout && f != stderr) aux_close(L); return 0; } @@ -138,6 +154,15 @@ static int io_open (lua_State *L) { } +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + FILE **pf = newfile(L); + *pf = lua_popen(L, filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} + + static int io_tmpfile (lua_State *L) { FILE **pf = newfile(L); *pf = tmpfile(); @@ -148,7 +173,6 @@ static int io_tmpfile (lua_State *L) { static FILE *getiofile (lua_State *L, int findex) { FILE *f; lua_rawgeti(L, LUA_ENVIRONINDEX, findex); - lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); f = *(FILE **)lua_touserdata(L, -1); if (f == NULL) luaL_error(L, "standard %s file is closed", fnames[findex - 1]); @@ -169,7 +193,6 @@ static int g_iofile (lua_State *L, int f, const char *mode) { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } - lua_assert(luaL_checkudata(L, -1, LUA_FILEHANDLE)); lua_rawseti(L, LUA_ENVIRONINDEX, f); } /* return current value */ @@ -352,7 +375,7 @@ static int io_readline (lua_State *L) { luaL_error(L, "file is already closed"); sucess = read_line(L, f); if (ferror(f)) - luaL_error(L, "%s", strerror(errno)); + return luaL_error(L, "%s", strerror(errno)); if (sucess) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ @@ -400,9 +423,8 @@ static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); - int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); + int op = luaL_checkoption(L, 2, "cur", modenames); lua_Integer offset = luaL_optinteger(L, 3, 0); - luaL_argcheck(L, op != -1, 2, "invalid mode"); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ @@ -417,9 +439,10 @@ static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; FILE *f = tofile(L); - int op = luaL_findstring(luaL_checkstring(L, 2), modenames); - luaL_argcheck(L, op != -1, 2, "invalid mode"); - return pushresult(L, setvbuf(f, NULL, mode[op], 0) == 0, NULL); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, BUFSIZ); + int res = setvbuf(f, NULL, mode[op], sz); + return pushresult(L, res == 0, NULL); } @@ -434,13 +457,14 @@ static int f_flush (lua_State *L) { } -static const luaL_reg iolib[] = { - {"input", io_input}, - {"output", io_output}, - {"lines", io_lines}, +static const luaL_Reg iolib[] = { {"close", io_close}, {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, {"type", io_type}, @@ -449,14 +473,14 @@ static const luaL_reg iolib[] = { }; -static const luaL_reg flib[] = { +static const luaL_Reg flib[] = { + {"close", io_close}, {"flush", f_flush}, - {"read", f_read}, {"lines", f_lines}, + {"read", f_read}, {"seek", f_seek}, {"setvbuf", f_setvbuf}, {"write", f_write}, - {"close", io_close}, {"__gc", io_gc}, {"__tostring", io_tostring}, {NULL, NULL} @@ -467,34 +491,41 @@ static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_openlib(L, NULL, flib, 0); /* file methods */ + luaL_register(L, NULL, flib); /* file methods */ } -static void createupval (lua_State *L) { - lua_newtable(L); - /* create (and set) default files */ - *newfile(L) = stdin; - lua_rawseti(L, -2, IO_INPUT); - *newfile(L) = stdout; - lua_rawseti(L, -2, IO_OUTPUT); +static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { + *newfile(L) = f; + if (k > 0) { + lua_pushvalue(L, -1); + lua_rawseti(L, LUA_ENVIRONINDEX, k); + } + lua_setfield(L, -2, fname); } - LUALIB_API int luaopen_io (lua_State *L) { createmeta(L); - createupval(L); - lua_pushvalue(L, -1); + /* create new (private) environment */ + lua_newtable(L); lua_replace(L, LUA_ENVIRONINDEX); - luaL_openlib(L, LUA_IOLIBNAME, iolib, 0); - /* put predefined file handles into `io' table */ - lua_rawgeti(L, -2, IO_INPUT); /* get current input from upval */ - lua_setfield(L, -2, "stdin"); /* io.stdin = upval[IO_INPUT] */ - lua_rawgeti(L, -2, IO_OUTPUT); /* get current output from upval */ - lua_setfield(L, -2, "stdout"); /* io.stdout = upval[IO_OUTPUT] */ - *newfile(L) = stderr; - lua_setfield(L, -2, "stderr"); /* io.stderr = newfile(stderr) */ + /* open library */ + luaL_register(L, LUA_IOLIBNAME, iolib); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, 0, "stderr"); + /* create environment for 'popen' */ + lua_getfield(L, -1, "popen"); + lua_newtable(L); + lua_pushcfunction(L, io_pclose); + lua_setfield(L, -2, "__close"); + lua_setfenv(L, -2); + lua_pop(L, 1); /* pop 'popen' */ + /* set default close function */ + lua_pushcfunction(L, io_fclose); + lua_setfield(L, LUA_ENVIRONINDEX, "__close"); return 1; } diff --git a/src/llex.h b/src/llex.h index 8bff8f43c6..08a0b25413 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.54 2005/04/25 19:24:10 roberto Exp $ +** $Id: llex.h,v 1.55 2005/06/06 13:30:25 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -37,7 +37,7 @@ enum RESERVED { /* array with token `names' */ -extern const char *const luaX_tokens []; +LUAI_DATA const char *const luaX_tokens []; typedef union { diff --git a/src/llimits.h b/src/llimits.h index 7a536a1624..68c28c8c7e 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.65 2005/03/09 16:28:07 roberto Exp $ +** $Id: llimits.h,v 1.67 2005/08/24 16:15:49 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -93,4 +93,23 @@ typedef lu_int32 Instruction; #endif +#ifndef lua_lock +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +#ifndef luai_threadyield +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#ifndef HARDSTACKTESTS +#define condhardstacktests(x) ((void)0) +#else +#define condhardstacktests(x) x +#endif + #endif diff --git a/src/lmathlib.c b/src/lmathlib.c index bba99b0dc9..d181a73194 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.63 2005/03/04 18:57:03 roberto Exp $ +** $Id: lmathlib.c,v 1.67 2005/08/26 17:36:32 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -88,7 +88,7 @@ static int math_floor (lua_State *L) { return 1; } -static int math_mod (lua_State *L) { +static int math_fmod (lua_State *L) { lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } @@ -212,35 +212,35 @@ static int math_randomseed (lua_State *L) { } -static const luaL_reg mathlib[] = { +static const luaL_Reg mathlib[] = { {"abs", math_abs}, - {"sin", math_sin}, - {"sinh", math_sinh}, - {"cos", math_cos}, - {"cosh", math_cosh}, - {"tan", math_tan}, - {"tanh", math_tanh}, - {"asin", math_asin}, {"acos", math_acos}, - {"atan", math_atan}, + {"asin", math_asin}, {"atan2", math_atan2}, + {"atan", math_atan}, {"ceil", math_ceil}, + {"cosh", math_cosh}, + {"cos", math_cos}, + {"deg", math_deg}, + {"exp", math_exp}, {"floor", math_floor}, - {"mod", math_mod}, - {"modf", math_modf}, + {"fmod", math_fmod}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, - {"sqrt", math_sqrt}, - {"min", math_min}, - {"max", math_max}, - {"log", math_log}, {"log10", math_log10}, - {"exp", math_exp}, - {"deg", math_deg}, + {"log", math_log}, + {"max", math_max}, + {"min", math_min}, + {"modf", math_modf}, {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, + {"sinh", math_sinh}, + {"sin", math_sin}, + {"sqrt", math_sqrt}, + {"tanh", math_tanh}, + {"tan", math_tan}, {NULL, NULL} }; @@ -249,11 +249,15 @@ static const luaL_reg mathlib[] = { ** Open math library */ LUALIB_API int luaopen_math (lua_State *L) { - luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); + luaL_register(L, LUA_MATHLIBNAME, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, HUGE_VAL); lua_setfield(L, -2, "huge"); +#if defined(LUA_COMPAT_MOD) + lua_getfield(L, -1, "fmod"); + lua_setfield(L, -2, "mod"); +#endif return 1; } diff --git a/src/loadlib.c b/src/loadlib.c index 1ae9ab57ad..767fdb8e84 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.28 2005/05/17 19:49:15 roberto Exp $ +** $Id: loadlib.c,v 1.44 2005/09/06 17:20:25 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -38,6 +38,13 @@ #define LIB_FAIL "open" +/* error codes for ll_loadfunc */ +#define ERRLIB 1 +#define ERRFUNC 2 + +#define setprogdir(L) ((void)0) + + static void ll_unloadlib (void *lib); static void *ll_load (lua_State *L, const char *path); static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); @@ -88,6 +95,21 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #include +#undef setprogdir + +void setprogdir (lua_State *L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/sizeof(char); + DWORD n = GetModuleFileName(NULL, buff, nsize); + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) + luaL_error(L, "unable to get ModuleFileName"); + *lb = '\0'; + luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + lua_remove(L, -2); /* remove original string */ +} + + static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; @@ -267,96 +289,148 @@ static void **ll_register (lua_State *L, const char *path) { */ static int gctm (lua_State *L) { void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); - if (lib) { - if (*lib) ll_unloadlib(*lib); - *lib = NULL; /* mark library as closed */ - } + if (*lib) ll_unloadlib(*lib); + *lib = NULL; /* mark library as closed */ return 0; } static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { - const char *reason; void **reg = ll_register(L, path); if (*reg == NULL) *reg = ll_load(L, path); if (*reg == NULL) - reason = LIB_FAIL; + return ERRLIB; /* unable to load library */ else { lua_CFunction f = ll_sym(L, *reg, sym); - if (f) { - lua_pushcfunction(L, f); - return 1; /* return function */ - } - reason = "init"; + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); + return 0; /* return function */ } - lua_pushnil(L); - lua_insert(L, -2); - lua_pushstring(L, reason); - return 3; /* return nil, ll_error, reason */ } static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); - return ll_loadfunc(L, path, init); + int stat = ll_loadfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } } /* ** {====================================================== -** `require' and `module' functions +** 'require' function ** ======================================================= */ -static int loader_Lua (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); - const char *path = NULL; -#if LUA_COMPAT_PATH - /* try first `LUA_PATH' for compatibility */ - lua_pushstring(L, "LUA_PATH"); - lua_rawget(L, LUA_GLOBALSINDEX); +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ + if (f == NULL) return 0; /* open failed */ + fclose(f); + return 1; +} + + +static const char *pushnexttemplate (lua_State *L, const char *path) { + const char *l; + while (*path == *LUA_PATHSEP) path++; /* skip separators */ + if (*path == '\0') return NULL; /* no more templates */ + l = strchr(path, *LUA_PATHSEP); /* find next separator */ + if (l == NULL) l = path + strlen(path); + lua_pushlstring(L, path, l - path); /* template */ + return l; +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname) { + const char *path; + name = luaL_gsub(L, name, ".", LUA_DIRSEP); + lua_getfield(L, LUA_ENVIRONINDEX, pname); path = lua_tostring(L, -1); -#endif - if (!path) { - lua_pop(L, 1); - lua_getfield(L, LUA_ENVIRONINDEX, "path"); - path = lua_tostring(L, -1); - } if (path == NULL) - luaL_error(L, LUA_QL("package.path") " must be a string"); - fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return 0; /* library not found in this path */ - if (luaL_loadfile(L, fname) != 0) - luaL_error(L, "error loading package " LUA_QS " (%s)", - name, lua_tostring(L, -1)); + luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + while ((path = pushnexttemplate(L, path)) != NULL) { + const char *filename; + filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pop(L, 2); /* remove path template and file name */ + } + return NULL; /* not found */ +} + + +static void loaderror (lua_State *L) { + luaL_error(L, "error loading module " LUA_QS " (%s)", + lua_tostring(L, 1), lua_tostring(L, -1)); +} + + +static int loader_Lua (lua_State *L) { + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path"); + if (filename == NULL) return 0; /* library not found in this path */ + if (luaL_loadfile(L, filename) != 0) + loaderror(L); return 1; /* library loaded successfully */ } +static const char *mkfuncname (lua_State *L, const char *modname) { + const char *funcname; + const char *mark = strchr(modname, *LUA_IGMARK); + if (mark) modname = mark + 1; + funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); + funcname = lua_pushfstring(L, POF"%s", funcname); + lua_remove(L, -2); /* remove 'gsub' result */ + return funcname; +} + + static int loader_C (lua_State *L) { - const char *name = luaL_checkstring(L, 1); - const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); - const char *path; const char *funcname; - lua_getfield(L, LUA_ENVIRONINDEX, "cpath"); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, LUA_QL("package.cpath") " must be a string"); - fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return 0; /* library not found in this path */ - funcname = luaL_gsub(L, name, ".", LUA_OFSEP); - funcname = lua_pushfstring(L, "%s%s", POF, funcname); - if (ll_loadfunc(L, fname, funcname) != 1) - luaL_error(L, "error loading package " LUA_QS " (%s)", - name, lua_tostring(L, -2)); + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath"); + if (filename == NULL) return 0; /* library not found in this path */ + funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + loaderror(L); return 1; /* library loaded successfully */ } +static int loader_Croot (lua_State *L) { + const char *funcname; + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath"); + if (filename == NULL) return 0; /* root not found */ + funcname = mkfuncname(L, name); + if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if (stat == ERRFUNC) return 0; /* function not found */ + else + loaderror(L); /* real error */ + } + return 1; +} + + static int loader_preload (lua_State *L) { lua_getfield(L, LUA_ENVIRONINDEX, "preload"); if (!lua_istable(L, -1)) @@ -366,38 +440,58 @@ static int loader_preload (lua_State *L) { } +static const int sentinel = 0; + + static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); int i; - lua_settop(L, 1); + lua_settop(L, 1); /* _LOADED table will be at index 2 */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded; return its result */ - /* else must load it; first mark it as loaded */ - lua_pushboolean(L, 1); - lua_setfield(L, 2, name); /* _LOADED[name] = true */ - /* iterate over available loaders */ + if (lua_toboolean(L, -1)) { /* is it there? */ + if (lua_touserdata(L, -1) == &sentinel) /* check loops */ + luaL_error(L, "loop or previous error loading module " LUA_QS, name); + return 1; /* package is already loaded */ + } + /* else must load it; iterate over available loaders */ lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.loaders") " must be a table"); - for (i=1;; i++) { + for (i=1; ; i++) { lua_rawgeti(L, -1, i); /* get a loader */ if (lua_isnil(L, -1)) - return luaL_error(L, "package " LUA_QS " not found", name); + luaL_error(L, "module " LUA_QS " not found", name); lua_pushstring(L, name); lua_call(L, 1, 1); /* call it */ - if (lua_isnil(L, -1)) lua_pop(L, 1); + if (lua_isnil(L, -1)) lua_pop(L, 1); /* did not found module */ else break; /* module loaded successfully */ } - lua_pushvalue(L, 1); /* pass name as argument to module */ + lua_pushlightuserdata(L, (void *)&sentinel); + lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ + lua_pushstring(L, name); /* pass name as argument to module */ lua_call(L, 1, 1); /* run loaded module */ if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* update _LOADED[name] with returned value */ - lua_getfield(L, 2, name); /* return _LOADED[name] */ + lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ + lua_getfield(L, 2, name); + if (lua_touserdata(L, -1) == &sentinel) { /* module did not set a value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* _LOADED[name] = true */ + } return 1; } +/* }====================================================== */ + + + +/* +** {====================================================== +** 'module' function +** ======================================================= +*/ + static void setfenv (lua_State *L) { lua_Debug ar; @@ -405,49 +499,72 @@ static void setfenv (lua_State *L) { lua_getinfo(L, "f", &ar); lua_pushvalue(L, -2); lua_setfenv(L, -2); + lua_pop(L, 1); +} + + +static void dooptions (lua_State *L, int n) { + int i; + for (i = 2; i <= n; i++) { + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } +} + + +static void modinit (lua_State *L, const char *modname) { + const char *dot; + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == NULL) dot = modname; + else dot++; + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, dot - modname); + lua_setfield(L, -2, "_PACKAGE"); } static int ll_module (lua_State *L) { const char *modname = luaL_checkstring(L, 1); - const char *dot; - lua_settop(L, 1); + int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - /* try to find given table */ - luaL_getfield(L, LUA_GLOBALSINDEX, modname); - if (lua_isnil(L, -1)) { /* not found? */ + lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ + if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ - lua_newtable(L); /* create it */ - /* register it with given name */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, modname) != NULL) + return luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); - luaL_setfield(L, LUA_GLOBALSINDEX, modname); + lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ } - else if (!lua_istable(L, -1)) - return luaL_error(L, "name conflict for module " LUA_QS, modname); /* check whether table already has a _NAME field */ lua_getfield(L, -1, "_NAME"); if (!lua_isnil(L, -1)) /* is table an initialized module? */ lua_pop(L, 1); else { /* no; initialize it */ lua_pop(L, 1); - lua_newtable(L); /* create new metatable */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setfield(L, -2, "__index"); /* mt.__index = _G */ - lua_setmetatable(L, -2); - lua_pushvalue(L, -1); - lua_setfield(L, -2, "_M"); /* module._M = module */ - lua_pushstring(L, modname); - lua_setfield(L, -2, "_NAME"); - dot = strrchr(modname, '.'); /* look for last dot in module name */ - if (dot == NULL) dot = modname; - else dot++; - /* set _PACKAGE as package name (full module name minus last part) */ - lua_pushlstring(L, modname, dot - modname); - lua_setfield(L, -2, "_PACKAGE"); + modinit(L, modname); } lua_pushvalue(L, -1); - lua_setfield(L, 2, modname); /* _LOADED[modname] = new table */ setfenv(L); + dooptions(L, loaded - 1); + return 0; +} + + +static int ll_seeall (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (!lua_getmetatable(L, 1)) { + lua_newtable(L); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ return 0; } @@ -455,28 +572,57 @@ static int ll_module (lua_State *L) { /* }====================================================== */ -static const luaL_reg ll_funcs[] = { - {"require", ll_require}, + +/* auxiliary mark (for internal use) */ +#define AUXMARK "\1" + +static void setpath (lua_State *L, const char *fieldname, const char *envname, + const char *def) { + const char *path = getenv(envname); + if (path == NULL) /* no environment variable? */ + lua_pushstring(L, def); /* use default */ + else { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, + LUA_PATHSEP AUXMARK LUA_PATHSEP); + luaL_gsub(L, path, AUXMARK, def); + lua_remove(L, -2); + } + setprogdir(L); + lua_setfield(L, -2, fieldname); +} + + +static const luaL_Reg pk_funcs[] = { + {"loadlib", ll_loadlib}, + {"seeall", ll_seeall}, + {NULL, NULL} +}; + + +static const luaL_Reg ll_funcs[] = { {"module", ll_module}, + {"require", ll_require}, {NULL, NULL} }; static const lua_CFunction loaders[] = - {loader_preload, loader_C, loader_Lua, NULL}; + {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; -LUALIB_API int luaopen_loadlib (lua_State *L) { - const char *path; +LUALIB_API int luaopen_package (lua_State *L) { int i; /* create new type _LOADLIB */ luaL_newmetatable(L, "_LOADLIB"); lua_pushcfunction(L, gctm); lua_setfield(L, -2, "__gc"); /* create `package' table */ - lua_newtable(L); - lua_pushvalue(L, -1); - lua_setglobal(L, LUA_LOADLIBNAME); + luaL_register(L, LUA_LOADLIBNAME, pk_funcs); +#if defined(LUA_COMPAT_LOADLIB) + lua_getfield(L, -1, "loadlib"); + lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); +#endif lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, "_PACKAGE"); lua_pushvalue(L, -1); @@ -488,33 +634,22 @@ LUALIB_API int luaopen_loadlib (lua_State *L) { lua_pushcfunction(L, loaders[i]); lua_rawseti(L, -2, i+1); } - /* put it in field `loaders' */ - lua_setfield(L, -2, "loaders"); - /* set field `path' */ - path = getenv(LUA_PATH); - if (path == NULL) path = LUA_PATH_DEFAULT; - lua_pushstring(L, path); - lua_setfield(L, -2, "path"); - /* set field `cpath' */ - path = getenv(LUA_CPATH); - if (path == NULL) path = LUA_CPATH_DEFAULT; - lua_pushstring(L, path); - lua_setfield(L, -2, "cpath"); + lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ + setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ + setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ + /* store config information */ + lua_pushstring(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" + LUA_EXECDIR "\n" LUA_IGMARK); + lua_setfield(L, -2, "config"); /* set field `loaded' */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); /* set field `preload' */ lua_newtable(L); lua_setfield(L, -2, "preload"); - /* create `loadlib' function */ - lua_pushcfunction(L, ll_loadlib); -#if LUA_COMPAT_LOADLIB - lua_pushvalue(L, -1); - lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); -#endif - lua_setfield(L, -2, "loadlib"); lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_openlib(L, NULL, ll_funcs, 0); /* open lib into global table */ - return 1; + luaL_register(L, NULL, ll_funcs); /* open lib into global table */ + lua_pop(L, 1); + return 1; /* return 'package' table */ } diff --git a/src/lobject.c b/src/lobject.c index 98b083519c..9aa9760f75 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.13 2005/05/16 21:19:00 roberto Exp $ +** $Id: lobject.c,v 2.18 2005/08/01 04:22:23 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -75,7 +75,7 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { case LUA_TNIL: return 1; case LUA_TNUMBER: - return luai_numeq(nvalue(t1), nvalue(t2)); + return luai_numeq(L, nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: @@ -89,11 +89,11 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { int luaO_str2d (const char *s, lua_Number *result) { char *endptr; - lua_Number res = lua_str2number(s, &endptr); - if (endptr == s) return 0; /* no conversion */ + *result = lua_str2number(s, &endptr); + if (endptr == s) return 0; /* conversion failed */ + if (*endptr == '\0') return 1; /* most common case */ while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ - *result = res; return 1; } @@ -116,7 +116,9 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { incr_top(L); switch (*(e+1)) { case 's': { - pushstr(L, va_arg(argp, char *)); + const char *s = va_arg(argp, char *); + if (s == NULL) s = "(null)"; + pushstr(L, s); break; } case 'c': { @@ -159,7 +161,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { fmt = e+2; } pushstr(L, fmt); - luaV_concat(L, n+1, L->top - L->base - 1); + luaV_concat(L, n+1, cast(int, L->top - L->base) - 1); L->top -= n; return svalue(L->top - 1); } @@ -175,26 +177,26 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { } -void luaO_chunkid (char *out, const char *source, int bufflen) { +void luaO_chunkid (char *out, const char *source, size_t bufflen) { if (*source == '=') { strncpy(out, source+1, bufflen); /* remove first char */ out[bufflen-1] = '\0'; /* ensures null termination */ } else { /* out = "source", or "...source" */ if (*source == '@') { - int l; + size_t l; source++; /* skip the `@' */ bufflen -= sizeof(" '...' "); l = strlen(source); strcpy(out, ""); - if (l>bufflen) { + if (l > bufflen) { source += (l-bufflen); /* get last part of file name */ strcat(out, "..."); } strcat(out, source); } else { /* out = [string "string"] */ - int len = strcspn(source, "\n\r"); /* stop at first newline */ + size_t len = strcspn(source, "\n\r"); /* stop at first newline */ bufflen -= sizeof(" [string \"...\"] "); if (len > bufflen) len = bufflen; strcpy(out, "[string \""); diff --git a/src/lobject.h b/src/lobject.h index 4a77a539df..1709fa3ca1 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.13 2005/05/05 20:47:02 roberto Exp $ +** $Id: lobject.h,v 2.17 2005/06/13 14:19:00 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -17,15 +17,17 @@ /* tags for values visible from Lua */ -#define NUM_TAGS LUA_TTHREAD +#define LAST_TAG LUA_TTHREAD + +#define NUM_TAGS (LAST_TAG+1) /* ** Extra tags for non-values */ -#define LUA_TPROTO (NUM_TAGS+1) -#define LUA_TUPVAL (NUM_TAGS+2) -#define LUA_TDEADKEY (NUM_TAGS+3) +#define LUA_TPROTO (LAST_TAG+1) +#define LUA_TUPVAL (LAST_TAG+2) +#define LUA_TDEADKEY (LAST_TAG+3) /* @@ -254,8 +256,10 @@ typedef struct Proto { } Proto; -/* mask for new-style vararg */ -#define NEWSTYLEVARARG 2 +/* masks for new-style vararg */ +#define VARARG_HASARG 1 +#define VARARG_ISVARARG 2 +#define VARARG_NEEDSARG 4 typedef struct LocVar { @@ -357,7 +361,7 @@ typedef struct Table { -extern const TValue luaO_nilobject; +LUAI_DATA const TValue luaO_nilobject; #define ceillog2(x) (luaO_log2((x)-1) + 1) @@ -369,7 +373,8 @@ LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); -LUAI_FUNC void luaO_chunkid (char *out, const char *source, int len); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); #endif + diff --git a/src/lopcodes.c b/src/lopcodes.c index 46b30ba923..5e3bc5f775 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.33 2005/05/04 20:42:28 roberto Exp $ +** $Id: lopcodes.c,v 1.35 2005/08/29 20:49:21 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -36,13 +36,14 @@ const char *const luaP_opnames[NUM_OPCODES+1] = { "POW", "UNM", "NOT", - "SIZ", + "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", + "TESTSET", "CALL", "TAILCALL", "RETURN", @@ -81,13 +82,14 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_SIZ */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ - ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 0, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ diff --git a/src/lopcodes.h b/src/lopcodes.h index 77f60c000e..b08b679874 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.119 2005/05/04 20:42:28 roberto Exp $ +** $Id: lopcodes.h,v 1.122 2005/08/29 20:49:21 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -176,7 +176,7 @@ OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ OP_UNM,/* A B R(A) := -R(B) */ OP_NOT,/* A B R(A) := not R(B) */ -OP_SIZ,/* A B R(A) := size of R(B) */ +OP_LEN,/* A B R(A) := length of R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ @@ -186,7 +186,8 @@ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ -OP_TEST,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ @@ -248,7 +249,7 @@ enum OpArgMask { OpArgK /* argument is a constant or register/constant */ }; -extern const lu_byte luaP_opmodes[NUM_OPCODES]; +LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) #define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) @@ -257,7 +258,7 @@ extern const lu_byte luaP_opmodes[NUM_OPCODES]; #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) -extern const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ +LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ diff --git a/src/loslib.c b/src/loslib.c index 52532143e9..4cee7ba5c5 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.9 2005/05/17 19:49:15 roberto Exp $ +** $Id: loslib.c,v 1.13 2005/09/09 18:22:46 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -93,6 +93,8 @@ static void setfield (lua_State *L, const char *key, int value) { } static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ lua_pushboolean(L, value); lua_setfield(L, -2, key); } @@ -197,9 +199,8 @@ static int io_setloc (lua_State *L) { static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; const char *l = lua_tostring(L, 1); - int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames); + int op = luaL_checkoption(L, 2, "all", catnames); luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); - luaL_argcheck(L, op != -1, 2, "invalid option"); lua_pushstring(L, setlocale(cat[op], l)); return 1; } @@ -210,7 +211,7 @@ static int io_exit (lua_State *L) { return 0; /* to avoid warnings */ } -static const luaL_reg syslib[] = { +static const luaL_Reg syslib[] = { {"clock", io_clock}, {"date", io_date}, {"difftime", io_difftime}, @@ -230,7 +231,7 @@ static const luaL_reg syslib[] = { LUALIB_API int luaopen_os (lua_State *L) { - luaL_openlib(L, LUA_OSLIBNAME, syslib, 0); + luaL_register(L, LUA_OSLIBNAME, syslib); return 1; } diff --git a/src/lparser.c b/src/lparser.c index 54facfc460..91dc4fff19 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.27 2005/05/17 19:49:15 roberto Exp $ +** $Id: lparser.c,v 2.35 2005/08/29 20:49:21 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -239,35 +239,35 @@ static void markupval (FuncState *fs, int level) { } -static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { - if (fs == NULL) /* no more levels? */ +static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { + if (fs == NULL) { /* no more levels? */ init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ + return VGLOBAL; + } else { int v = searchvar(fs, n); /* look up at current level */ if (v >= 0) { init_exp(var, VLOCAL, v); if (!base) markupval(fs, v); /* local will be used as an upval */ + return VLOCAL; } else { /* not found at current level; try upper one */ - singlevaraux(fs->prev, n, var, 0); - if (var->k == VGLOBAL) { - if (base) - var->info = luaK_stringK(fs, n); /* info points to global name */ - } - else { /* LOCAL or UPVAL */ - var->info = indexupvalue(fs, n, var); - var->k = VUPVAL; /* upvalue in this level */ - } + if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) + return VGLOBAL; + var->info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ + var->k = VUPVAL; /* upvalue in this level */ + return VUPVAL; } } } -static TString *singlevar (LexState *ls, expdesc *var, int base) { +static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); - singlevaraux(ls->fs, varname, var, base); - return varname; + FuncState *fs = ls->fs; + if (singlevaraux(fs, varname, var, 1) == VGLOBAL) + var->info = luaK_stringK(fs, varname); /* info points to global name */ } @@ -300,7 +300,7 @@ static void enterlevel (LexState *ls) { #define leavelevel(ls) ((ls)->L->nCcalls--) -static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; bl->nactvar = fs->nactvar; @@ -317,6 +317,7 @@ static void leaveblock (FuncState *fs) { removevars(fs->ls, bl->nactvar); if (bl->upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + lua_assert(!bl->isbreakable || !bl->upval); /* loops have no body */ lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ luaK_patchtohere(fs, bl->breaklist); @@ -374,7 +375,7 @@ static void close_func (LexState *ls) { FuncState *fs = ls->fs; Proto *f = fs->f; removevars(ls, 0); - luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ + luaK_ret(fs, 0, 0); /* final return */ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); @@ -402,7 +403,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { lexstate.buff = buff; luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); - funcstate.f->is_vararg = NEWSTYLEVARARG; + funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); @@ -525,7 +526,6 @@ static void constructor (LexState *ls, expdesc *t) { checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); - testnext(ls, ';'); /* compatibility only */ if (ls->t.token == '}') break; closelistfield(fs, &cc); switch(ls->t.token) { @@ -572,9 +572,12 @@ static void parlist (LexState *ls) { } case TK_DOTS: { /* param -> `...' */ next(ls); +#if defined(LUA_COMPAT_VARARG) /* use `arg' as default name */ new_localvarliteral(ls, "arg", nparams++); - f->is_vararg = 1; + f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; +#endif + f->is_vararg |= VARARG_ISVARARG; break; } default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); @@ -582,7 +585,7 @@ static void parlist (LexState *ls) { } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); - f->numparams = fs->nactvar - f->is_vararg; + f->numparams = fs->nactvar - (f->is_vararg & VARARG_HASARG); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -690,7 +693,7 @@ static void prefixexp (LexState *ls, expdesc *v) { return; } case TK_NAME: { - singlevar(ls, v, 1); + singlevar(ls, v); return; } default: { @@ -766,7 +769,7 @@ static void simpleexp (LexState *ls, expdesc *v) { FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); - fs->f->is_vararg = NEWSTYLEVARARG; + fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } @@ -792,7 +795,7 @@ static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; - case '*': return OPR_SIZE; + case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } @@ -979,78 +982,68 @@ static int cond (LexState *ls) { expr(ls, &v); /* read condition */ if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ luaK_goiftrue(ls->fs, &v); - luaK_patchtohere(ls->fs, v.t); return v.f; } -/* -** The while statement optimizes its code by coding the condition -** after its body (and thus avoiding one jump in the loop). -*/ - +static void breakstat (LexState *ls) { + FuncState *fs = ls->fs; + BlockCnt *bl = fs->bl; + int upval = 0; + while (bl && !bl->isbreakable) { + upval |= bl->upval; + bl = bl->previous; + } + if (!bl) + luaX_syntaxerror(ls, "no loop to break"); + if (upval) + luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); + luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); +} -/* -** the call `luaK_goiffalse' may grow the size of an expression by -** at most this: -*/ -#define EXTRAEXP 5 static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ - Instruction codeexp[LUAI_MAXEXPWHILE + EXTRAEXP]; - int lineexp; - int i; - int sizeexp; FuncState *fs = ls->fs; - int whileinit, blockinit, expinit; - expdesc v; + int whileinit; + int condexit; BlockCnt bl; next(ls); /* skip WHILE */ - whileinit = luaK_jump(fs); /* jump to condition (which will be moved) */ - expinit = luaK_getlabel(fs); - expr(ls, &v); /* parse condition */ - if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */ - lineexp = ls->linenumber; - luaK_goiffalse(fs, &v); - luaK_concat(fs, &v.f, fs->jpc); - fs->jpc = NO_JUMP; - sizeexp = fs->pc - expinit; /* size of expression code */ - if (sizeexp > LUAI_MAXEXPWHILE) - luaX_syntaxerror(ls, LUA_QL("while") " condition too complex"); - for (i = 0; i < sizeexp; i++) /* save `exp' code */ - codeexp[i] = fs->f->code[expinit + i]; - fs->pc = expinit; /* remove `exp' code */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); enterblock(fs, &bl, 1); checknext(ls, TK_DO); - blockinit = luaK_getlabel(fs); block(ls); - luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ - /* move `exp' back to code */ - if (v.t != NO_JUMP) v.t += fs->pc - expinit; - if (v.f != NO_JUMP) v.f += fs->pc - expinit; - for (i=0; i REPEAT block UNTIL cond */ + int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); - int flist; - BlockCnt bl; - enterblock(fs, &bl, 1); - next(ls); - block(ls); + BlockCnt bl1, bl2; + enterblock(fs, &bl1, 1); /* loop block */ + enterblock(fs, &bl2, 0); /* scope block */ + next(ls); /* skip REPEAT */ + chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); - flist = cond(ls); - luaK_patchlist(fs, flist, repeat_init); - leaveblock(fs); + condexit = cond(ls); /* read condition (inside scope block) */ + if (!bl2.upval) { /* no upvalues? */ + leaveblock(fs); /* finish scope */ + luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ + } + else { /* complete semantics when there are upvalues */ + breakstat(ls); /* if condition then break */ + luaK_patchtohere(ls->fs, condexit); /* else... */ + leaveblock(fs); /* finish scope... */ + luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ + } + leaveblock(fs); /* finish loop */ } @@ -1150,12 +1143,12 @@ static void forstat (LexState *ls, int line) { static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ - int flist; + int condexit; next(ls); /* skip IF or ELSEIF */ - flist = cond(ls); + condexit = cond(ls); checknext(ls, TK_THEN); block(ls); /* `then' part */ - return flist; + return condexit; } @@ -1219,7 +1212,7 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {field} [`:' NAME] */ int needself = 0; - singlevar(ls, v, 1); + singlevar(ls, v); while (ls->t.token == '.') field(ls, v); if (ls->t.token == ':') { @@ -1285,25 +1278,7 @@ static void retstat (LexState *ls) { } } } - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); -} - - -static void breakstat (LexState *ls) { - /* stat -> BREAK */ - FuncState *fs = ls->fs; - BlockCnt *bl = fs->bl; - int upval = 0; - next(ls); /* skip BREAK */ - while (bl && !bl->isbreakable) { - upval |= bl->upval; - bl = bl->previous; - } - if (!bl) - luaX_syntaxerror(ls, "no loop to break"); - if (upval) - luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); - luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); + luaK_ret(fs, first, nret); } @@ -1349,6 +1324,7 @@ static int statement (LexState *ls) { return 1; /* must be last statement */ } case TK_BREAK: { /* stat -> breakstat */ + next(ls); /* skip BREAK */ breakstat(ls); return 1; /* must be last statement */ } diff --git a/src/lstate.c b/src/lstate.c index 41162dac87..2a4ace1284 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.31 2005/05/05 15:34:03 roberto Exp $ +** $Id: lstate.c,v 2.33 2005/08/25 15:39:16 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -72,7 +72,6 @@ static void f_luaopen (lua_State *L, void *ud) { UNUSED(ud); stack_init(L, L); /* init stack */ sethvalue(L, gt(L), luaH_new(L, 0, 20)); /* table of globals */ - hvalue(gt(L))->metatable = luaH_new(L, 0, 0); /* globals metatable */ sethvalue(L, registry(L), luaH_new(L, 6, 20)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); @@ -83,7 +82,7 @@ static void f_luaopen (lua_State *L, void *ud) { static void preinit_state (lua_State *L, global_State *g) { - L->l_G = g; + G(L) = g; L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; diff --git a/src/lstate.h b/src/lstate.h index 7dafa4d589..e8bc15ab9a 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.21 2005/05/05 15:34:03 roberto Exp $ +** $Id: lstate.h,v 2.23 2005/07/09 13:22:34 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -19,10 +19,10 @@ struct lua_longjmp; /* defined in ldo.c */ /* table of globals */ -#define gt(L) (&L->_gt) +#define gt(L) (&L->l_gt) /* registry */ -#define registry(L) (&G(L)->_registry) +#define registry(L) (&G(L)->l_registry) /* extra stack space to handle TM calls and some other extras */ @@ -86,7 +86,7 @@ typedef struct global_State { int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ - TValue _registry; + TValue l_registry; struct lua_State *mainthread; UpVal uvhead; /* head of double-linked list of all open upvalues */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */ @@ -117,7 +117,7 @@ struct lua_State { int basehookcount; int hookcount; lua_Hook hook; - TValue _gt; /* table of globals */ + TValue l_gt; /* table of globals */ TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; diff --git a/src/lstrlib.c b/src/lstrlib.c index 4929a27c9f..4cf5836aae 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.115 2005/05/17 19:49:15 roberto Exp $ +** $Id: lstrlib.c,v 1.123 2005/08/26 17:36:32 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -58,7 +58,7 @@ static int str_reverse (lua_State *L) { luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); - while (l--) luaL_putchar(&b, s[l]); + while (l--) luaL_addchar(&b, s[l]); luaL_pushresult(&b); return 1; } @@ -71,7 +71,7 @@ static int str_lower (lua_State *L) { const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; icapture[i].len; + ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); @@ -485,15 +485,15 @@ static int push_captures (MatchState *ms, const char *s, const char *e) { } -static int str_find (lua_State *L) { +static int str_find_aux (lua_State *L, int find) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; if (init < 0) init = 0; else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; - if (lua_toboolean(L, 4) || /* explicit request? */ - strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ + if (find && (lua_toboolean(L, 4) || /* explicit request? */ + strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { @@ -513,18 +513,37 @@ static int str_find (lua_State *L) { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { - lua_pushinteger(L, s1-s+1); /* start */ - lua_pushinteger(L, res-s); /* end */ - return push_captures(&ms, NULL, 0) + 2; + if (find) { + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ +#if defined(LUA_COMPAT_FIND) + return push_captures(&ms, NULL, 0) + 2; +#else + return 2; +#endif + + } + else + return push_captures(&ms, s1, res); } - } while (s1++L; @@ -569,14 +594,18 @@ static void add_s (MatchState *ms, luaL_Buffer *b, size_t i; for (i=0; isrc) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) - luaL_putchar(&b, *src++); + luaL_addchar(&b, *src++); else break; if (anchor) break; } @@ -644,12 +673,12 @@ static int str_gsub (lua_State *L) { static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); - luaL_putchar(b, '"'); + luaL_addchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': { - luaL_putchar(b, '\\'); - luaL_putchar(b, *s); + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); break; } case '\0': { @@ -657,13 +686,13 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { break; } default: { - luaL_putchar(b, *s); + luaL_addchar(b, *s); break; } } s++; } - luaL_putchar(b, '"'); + luaL_addchar(b, '"'); } @@ -699,9 +728,9 @@ static int str_format (lua_State *L) { luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { if (*strfrmt != L_ESC) - luaL_putchar(&b, *strfrmt++); + luaL_addchar(&b, *strfrmt++); else if (*++strfrmt == L_ESC) - luaL_putchar(&b, *strfrmt++); /* %% */ + luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ @@ -753,20 +782,22 @@ static int str_format (lua_State *L) { } -static const luaL_reg strlib[] = { - {"len", str_len}, - {"sub", str_sub}, - {"reverse", str_reverse}, - {"lower", str_lower}, - {"upper", str_upper}, - {"char", str_char}, - {"rep", str_rep}, +static const luaL_Reg strlib[] = { {"byte", str_byte}, - {"format", str_format}, + {"char", str_char}, {"dump", str_dump}, {"find", str_find}, - {"gfind", gfind}, + {"format", str_format}, + {"gfind", gfind_nodef}, + {"gmatch", gmatch}, {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, {NULL, NULL} }; @@ -779,8 +810,6 @@ static void createmetatable (lua_State *L) { lua_pop(L, 1); /* pop dummy string */ lua_pushvalue(L, -2); /* string library... */ lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ - lua_getfield(L, -2, "len"); - lua_setfield(L, -2, "__siz"); lua_pop(L, 1); /* pop metatable */ } @@ -789,7 +818,11 @@ static void createmetatable (lua_State *L) { ** Open string library */ LUALIB_API int luaopen_string (lua_State *L) { - luaL_openlib(L, LUA_STRLIBNAME, strlib, 0); + luaL_register(L, LUA_STRLIBNAME, strlib); +#if defined(LUA_COMPAT_GFIND) + lua_getfield(L, -1, "gmatch"); + lua_setfield(L, -2, "gfind"); +#endif createmetatable(L); return 1; } diff --git a/src/ltable.c b/src/ltable.c index d0ba365bcb..979cc5ca97 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.23 2005/05/17 19:49:15 roberto Exp $ +** $Id: ltable.c,v 2.26 2005/07/11 14:01:37 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -120,7 +120,7 @@ static int arrayindex (const TValue *key) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); - if (luai_numeq(cast(lua_Number, k), nvalue(key))) + if (luai_numeq(L, cast(lua_Number, k), nvalue(key))) return k; } return -1; /* `key' did not match some condition */ @@ -145,7 +145,7 @@ static int findindex (lua_State *L, Table *t, StkId key) { if (luaO_rawequalObj(key2tval(n), key) || (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && gcvalue(gkey(n)) == gcvalue(key))) { - i = n - gnode(t, 0); /* key index in hash table */ + i = cast(int, n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ return i + t->sizearray; } @@ -376,7 +376,7 @@ void luaH_free (lua_State *L, Table *t) { } -static Node *getfreepos (lua_State *L, Table *t) { +static Node *getfreepos (Table *t) { while (t->lastfree-- > t->node) { if (ttisnil(gkey(t->lastfree))) return t->lastfree; @@ -397,7 +397,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { Node *mp = luaH_mainposition(t, key); if (!ttisnil(gval(mp)) || mp == &luaH_dummynode) { Node *othern; - Node *n = getfreepos(L, t); /* get a free place */ + Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ return luaH_set(L, t, key); /* re-insert key into grown table */ @@ -437,7 +437,7 @@ const TValue *luaH_getnum (Table *t, int key) { lua_Number nk = cast(lua_Number, key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) + if (ttisnumber(gkey(n)) && luai_numeq(L, nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); @@ -471,7 +471,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { int k; lua_Number n = nvalue(key); lua_number2int(k, n); - if (luai_numeq(cast(lua_Number, k), nvalue(key))) /* index is integer? */ + if (luai_numeq(L, cast(lua_Number, k), nvalue(key))) /* index is int? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } @@ -495,7 +495,7 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && !luai_numeq(nvalue(key), nvalue(key))) + else if (ttisnumber(key) && !luai_numeq(L, nvalue(key), nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } diff --git a/src/ltable.h b/src/ltable.h index 1a798262d0..14a20448a6 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.7 2005/04/25 19:24:10 roberto Exp $ +** $Id: ltable.h,v 2.8 2005/06/06 13:30:25 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -18,7 +18,7 @@ #define key2tval(n) (cast(const TValue *, gkey(n))) -extern const Node luaH_dummynode; +LUAI_DATA const Node luaH_dummynode; LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); diff --git a/src/ltablib.c b/src/ltablib.c index ab4d5db219..348b6ed5a8 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.31 2005/05/17 19:49:15 roberto Exp $ +** $Id: ltablib.c,v 1.35 2005/08/26 17:36:32 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -109,7 +109,7 @@ static int tremove (lua_State *L) { } -static int str_concat (lua_State *L) { +static int tconcat (lua_State *L) { luaL_Buffer b; size_t lsep; const char *sep = luaL_optlstring(L, 2, "", &lsep); @@ -236,21 +236,21 @@ static int sort (lua_State *L) { /* }====================================================== */ -static const luaL_reg tab_funcs[] = { - {"concat", str_concat}, +static const luaL_Reg tab_funcs[] = { + {"concat", tconcat}, {"foreach", foreach}, {"foreachi", foreachi}, {"getn", getn}, - {"setn", setn}, - {"sort", sort}, {"insert", tinsert}, {"remove", tremove}, + {"setn", setn}, + {"sort", sort}, {NULL, NULL} }; LUALIB_API int luaopen_table (lua_State *L) { - luaL_openlib(L, LUA_TABLIBNAME, tab_funcs, 0); + luaL_register(L, LUA_TABLIBNAME, tab_funcs); return 1; } diff --git a/src/ltm.c b/src/ltm.c index 6f2223a705..591134da54 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.5 2005/05/05 15:34:03 roberto Exp $ +** $Id: ltm.c,v 2.6 2005/05/20 15:53:42 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -32,7 +32,7 @@ void luaT_init (lua_State *L) { "__index", "__newindex", "__gc", "__mode", "__eq", "__add", "__sub", "__mul", "__div", "__mod", - "__pow", "__unm", "__siz", "__lt", "__le", + "__pow", "__unm", "__len", "__lt", "__le", "__concat", "__call" }; int i; diff --git a/src/ltm.h b/src/ltm.h index 1622b7810c..866c79668d 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.4 2005/05/05 15:34:03 roberto Exp $ +** $Id: ltm.h,v 2.6 2005/06/06 13:30:25 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -28,7 +28,7 @@ typedef enum { TM_MOD, TM_POW, TM_UNM, - TM_SIZ, + TM_LEN, TM_LT, TM_LE, TM_CONCAT, @@ -43,7 +43,7 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) -extern const char *const luaT_typenames[]; +LUAI_DATA const char *const luaT_typenames[]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); diff --git a/src/lua.c b/src/lua.c index a942c741bb..14c5e20dff 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.144 2005/05/17 19:49:15 roberto Exp $ +** $Id: lua.c,v 1.150 2005/09/06 17:19:33 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -48,15 +48,16 @@ static void print_usage (void) { " -i enter interactive mode after executing " LUA_QL("script") "\n" " -l name require library " LUA_QL("name") "\n" " -v show version information\n" - " -w trap access to undefined globals\n" " -- stop handling options\n" , progname); + fflush(stderr); } static void l_message (const char *pname, const char *msg) { if (pname) fprintf(stderr, "%s: ", pname); fprintf(stderr, "%s\n", msg); + fflush(stderr); } @@ -72,14 +73,19 @@ static int report (lua_State *L, int status) { static int traceback (lua_State *L) { - luaL_getfield(L, LUA_GLOBALSINDEX, "debug.traceback"); - if (!lua_isfunction(L, -1)) + lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(L, -1)) { lua_pop(L, 1); - else { - lua_pushvalue(L, 1); /* pass error message */ - lua_pushinteger(L, 2); /* skip this function and traceback */ - lua_call(L, 2, 1); /* call debug.traceback */ + return 1; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) { + lua_pop(L, 2); + return 1; } + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ return 1; } @@ -138,8 +144,7 @@ static int dolibrary (lua_State *L, const char *name) { static const char *get_prompt (lua_State *L, int firstline) { const char *p; - lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2"); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ @@ -148,13 +153,16 @@ static const char *get_prompt (lua_State *L, int firstline) { static int incomplete (lua_State *L, int status) { - if (status == LUA_ERRSYNTAX && - strstr(lua_tostring(L, -1), "") != NULL) { - lua_pop(L, 1); - return 1; + if (status == LUA_ERRSYNTAX) { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); + if (strstr(msg, LUA_QL("")) == tp) { + lua_pop(L, 1); + return 1; + } } - else - return 0; + return 0; /* else... */ } @@ -216,18 +224,11 @@ static void dotty (lua_State *L) { } lua_settop(L, 0); /* clear stack */ fputs("\n", stdout); + fflush(stdout); progname = oldprogname; } -static int checkvar (lua_State *L) { - const char *name = lua_tostring(L, 2); - if (name) - luaL_error(L, "attempt to access undefined variable " LUA_QS, name); - return 0; -} - - #define clearinteractive(i) (*i &= 2) static int handle_argv (lua_State *L, int argc, char **argv, int *interactive) { @@ -265,13 +266,6 @@ static int handle_argv (lua_State *L, int argc, char **argv, int *interactive) { print_version(); break; } - case 'w': { - if (lua_getmetatable(L, LUA_GLOBALSINDEX)) { - lua_pushcfunction(L, checkvar); - lua_setfield(L, -2, "__index"); - } - break; - } case 'e': { const char *chunk = argv[i] + 2; clearinteractive(interactive); diff --git a/src/lua.h b/src/lua.h index 1028e5ea14..339e076fdd 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,8 +1,7 @@ /* -** $Id: lua.h,v 1.208 2005/05/17 19:49:15 roberto Exp $ +** $Id: lua.h,v 1.212 2005/08/25 20:02:08 roberto Exp $ ** Lua - An Extensible Extension Language -** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil -** http://www.lua.org +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ @@ -17,9 +16,9 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (work6)" +#define LUA_VERSION "Lua 5.1 (alpha)" #define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2005 Tecgraf, PUC-Rio" +#define LUA_COPYRIGHT "Copyright (C) 1994-2005 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -39,7 +38,7 @@ #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) -/* return codes for `lua_pcall', `lua_resume', and `lua_status' */ +/* thread status; 0 is OK */ #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 @@ -147,7 +146,7 @@ LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_objsize) (lua_State *L, int idx); +LUA_API size_t (lua_objlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); @@ -257,7 +256,7 @@ LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) -#define lua_strlen(L,i) lua_objsize(L, (i)) +#define lua_strlen(L,i) lua_objlen(L, (i)) #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) @@ -357,7 +356,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2005 Tecgraf, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2005 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/luac.c b/src/luac.c index cfe00c7b76..374ea3ac16 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.50 2005/05/12 00:26:50 lhf Exp $ +** $Id: luac.c,v 1.51 2005/06/02 13:39:23 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -53,7 +53,7 @@ static void cannot(const char* what) static void usage(const char* message) { if (*message=='-') - fprintf(stderr,"%s: unrecognized option `%s'\n",progname,message); + fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, @@ -61,7 +61,7 @@ static void usage(const char* message) "Available options are:\n" " - process stdin\n" " -l list\n" - " -o name output to file `name' (default is \"%s\")\n" + " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" @@ -92,7 +92,7 @@ static int doargs(int argc, char* argv[]) else if (IS("-o")) /* output file */ { output=argv[++i]; - if (output==NULL || *output==0) usage("`-o' needs argument"); + if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument"); if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ diff --git a/src/luaconf.h b/src/luaconf.h index bc211cd39d..d6d4a2a739 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.49a 2005/05/17 19:49:15 roberto Exp $ +** $Id: luaconf.h,v 1.65 2005/09/09 18:24:42 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -21,6 +21,16 @@ +/* +@@ LUA_ANSI controls the use of non-ansi features. +** CHANGE it (define it) if you want Lua to avoid the use of any +** non-ansi feature or library. +*/ +#if defined(__STRICT_ANSI__) +#define LUA_ANSI +#endif + + /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for @* Lua libraries. @@ -31,22 +41,27 @@ ** non-conventional directories. */ #if defined(_WIN32) -#define LUA_ROOT "C:\\Program Files\\Lua51" -#define LUA_LDIR LUA_ROOT "\\lua" -#define LUA_CDIR LUA_ROOT "\\dll" +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" #define LUA_PATH_DEFAULT \ - "?.lua;" LUA_LDIR"\\?.lua;" LUA_LDIR"\\?\\init.lua" -#define LUA_CPATH_DEFAULT \ - "?.dll;" "l?.dll;" LUA_CDIR"\\?.dll;" LUA_CDIR"\\l?.dll" + ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" +#define LUA_CPATH_DEFAULT \ + ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" #else -#define LUA_ROOT "/usr/local" -#define LUA_LDIR LUA_ROOT "/share/lua/5.1" -#define LUA_CDIR LUA_ROOT "/lib/lua/5.1" +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/5.1/" +#define LUA_CDIR LUA_ROOT "lib/lua/5.1/" #define LUA_PATH_DEFAULT \ - "./?.lua;" LUA_LDIR"/?.lua;" LUA_LDIR"/?/init.lua" -#define LUA_CPATH_DEFAULT \ - "./?.so;" "./l?.so;" LUA_CDIR"/?.so;" LUA_CDIR"/l?.so" + "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" +#define LUA_CPATH_DEFAULT \ + "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" #endif @@ -64,21 +79,20 @@ /* @@ LUA_PATHSEP is the character that separates templates in a path. -** CHANGE it if for some reason your system cannot use a -** semicolon. (E.g., if a semicolon is a common character in -** file/directory names.) Probably you do not need to change this. -*/ -#define LUA_PATHSEP ';' - - -/* @@ LUA_PATH_MARK is the string that marks the substitution points in a @* template. -** CHANGE it if for some reason your system cannot use an interrogation -** mark. (E.g., if an interogation mark is a common character in -** file/directory names.) Probably you do not need to change this. -*/ +@@ LUA_EXECDIR in a Windows path is replaced by the executable's +@* directory. +@@ LUA_IGMARK is a mark to ignore all before it when bulding the +@* luaopen_ function name. +** CHANGE them if for some reason your system cannot use those +** characters. (E.g., if one of those characters is a common character +** in file/directory names.) Probably you do not need to change them. +*/ +#define LUA_PATHSEP ";" #define LUA_PATH_MARK "?" +#define LUA_EXECDIR "!" +#define LUA_IGMARK ":" /* @@ -100,9 +114,9 @@ #if defined(LUA_BUILD_AS_DLL) #if defined(LUA_CORE) || defined(LUA_LIB) -#define LUA_API __declspec(__dllexport) +#define LUA_API __declspec(dllexport) #else -#define LUA_API __declspec(__dllimport) +#define LUA_API __declspec(dllimport) #endif #else @@ -118,19 +132,26 @@ /* @@ LUAI_FUNC is a mark for all extern functions that are not to be @* exported to outside modules. -** CHANGE it if you need to mark them in some special way. Gcc (versions -** 3.2 and later) mark them as "hidden" to optimize their call when Lua -** is compiled as a shared library. +@@ LUAI_DATA is a mark for all extern (const) variables that are not to +@* be exported to outside modules. +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. */ #if defined(luaall_c) #define LUAI_FUNC static -#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) -#define LUAI_FUNC __attribute__((visibility("hidden"))) +#define LUAI_DATA /* empty */ +#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) +#define LUAI_FUNC __attribute__((visibility("hidden"))) extern +#define LUAI_DATA LUAI_FUNC #else #define LUAI_FUNC extern +#define LUAI_DATA extern #endif + /* @@ lua_assert describes the internal assertions in Lua. ** CHANGE that only if you need to debug Lua. @@ -149,7 +170,7 @@ /* @@ LUA_IDSIZE gives the maximum size for the description of the source @* of a function in debug information. -** CHANGE it if you a different size. +** CHANGE it if you want a different size. */ #define LUA_IDSIZE 60 @@ -168,10 +189,10 @@ ** CHANGE it if you have a better definition for non-POSIX/non-Windows ** systems. */ -#if !defined(__STRICT_ANSI__) && defined(_POSIX_C_SOURCE) +#if !defined(LUA_ANSI) && defined(_POSIX_C_SOURCE) #include #define lua_stdin_is_tty() isatty(0) -#elif !defined(__STRICT_ANSI__) && defined(_WIN32) +#elif !defined(LUA_ANSI) && defined(_WIN32) #include #include #define lua_stdin_is_tty() _isatty(_fileno(stdin)) @@ -214,7 +235,7 @@ ** CHANGE them if you want to improve this functionality (e.g., by using ** GNU readline and history facilities). */ -#if !defined(__STRICT_ANSI__) && defined(LUA_USE_READLINE) +#if defined(LUA_USE_READLINE) #include #include #include @@ -239,49 +260,52 @@ /* @@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles @* as a percentage. -** CHANGE it if you want the GC to run faster or slower (higher -** values mean larger pauses which mean slower collection.) +** CHANGE it if you want the GC to run faster or slower (higher values +** mean larger pauses which mean slower collection.) You can also change +** this value dynamically. */ #define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ /* -@@ LUAI_GCMUL defines the speed of garbage collection relative to +@@ LUAI_GCMUL defines the default speed of garbage collection relative to @* memory allocation as a percentage. ** CHANGE it if you want to change the granularity of the garbage ** collection. (Higher values mean coarser collections. 0 represents -** infinity, where each step performs a full collection.) +** infinity, where each step performs a full collection.) You can also +** change this value dynamically. */ #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ + /* @@ LUA_COMPAT_GETN controls compatibility with old getn behavior. -** CHANGE it to 1 if you want exact compatibility with the behavior of -** setn/getn in Lua 5.0. +** CHANGE it (define it) if you want exact compatibility with the +** behavior of setn/getn in Lua 5.0. */ -#define LUA_COMPAT_GETN 0 +#undef LUA_COMPAT_GETN /* -@@ LUA_COMPAT_PATH controls compatibility about LUA_PATH. -** CHANGE it to 1 if you want 'require' to look for global LUA_PATH -** before checking package.path. +@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. +** CHANGE it to undefined as soon as you do not need a global 'loadlib' +** function (the function is still available as 'package.loadlib'). */ -#define LUA_COMPAT_PATH 0 +#undef LUA_COMPAT_LOADLIB /* -@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. -** CHANGE it to 1 if you want a global 'loadlib' function (otherwise -** the function is only available as 'package.loadlib'). +@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. +** CHANGE it to undefined as soon as your programs use only '...' to +** access vararg parameters (instead of the old 'arg' table). */ -#define LUA_COMPAT_LOADLIB 1 +#define LUA_COMPAT_VARARG /* -@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. -** CHANGE it to 1 if you want vararg functions that do not use '...' -** to get an 'arg' table with their extra arguments. +@@ LUA_COMPAT_MOD controls compatibility with old math.mod function. +** CHANGE it to undefined as soon as your programs use 'math.fmod' or +** the new '%' operator instead of 'math.mod'. */ -#define LUA_COMPAT_VARARG 1 +#define LUA_COMPAT_MOD /* @@ LUA_COMPAT_LSTR controls compatibility with old long string nesting @@ -291,6 +315,31 @@ */ #define LUA_COMPAT_LSTR 1 +/* +@@ LUA_COMPAT_FIND controls compatibility with old 'string.find' behavior. +** CHANGE it to undefined as soon as your programs use 'string.find' only +** to find patterns. +*/ +#define LUA_COMPAT_FIND + +/* +@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. +** CHANGE it to undefined as soon as you rename 'string.gfind' to +** 'string.gmatch'. +*/ +#define LUA_COMPAT_GFIND + + +/* +@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' +@* behavior. +** CHANGE it to undefined as soon as you replace to 'luaL_registry' +** your uses of 'luaL_openlib' +*/ +#define LUA_COMPAT_OPENLIB + + + /* @@ luai_apicheck is the assert macro used by the Lua-C API. ** CHANGE luai_apicheck if you want Lua to perform some checks in the @@ -406,13 +455,6 @@ #define LUAI_MAXUPVALUES 60 -/* -@@ LUAI_MAXEXPWHILE is the maximum size of code for expressions -@* controling a 'while' loop. -*/ -#define LUAI_MAXEXPWHILE 100 - - /* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. */ @@ -424,47 +466,25 @@ /* @@ lua_number2int is a macro to convert lua_Number to int. -** CHANGE that if you know a faster way to convert a lua_Number to +@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. +** CHANGE them if you know a faster way to convert a lua_Number to ** int (with any rounding method and without throwing errors) in your ** system. In Pentium machines, a naive typecast from double to int ** in C is extremely slow, so any alternative is worth trying. */ -/* On a gcc/Pentium, resort to assembler */ -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__i386) -#define lua_number2int(i,d) __asm__ ("fistpl %0":"=m"(i):"t"(d):"st") - -/* On Windows/Pentium, resort to assembler */ -#elif !defined(__STRICT_ANSI__) && defined(_MSC_VER) && defined(_M_IX86) -#define lua_number2int(i,d) \ - __asm fld d \ - __asm fistp i - - -/* on Pentium machines compliant with C99, you can try lrint */ -#elif defined (__i386) && defined(__STDC_VERSION__) && \ - (__STDC_VERSION__ >= 199900L) -#define lua_number2int(i,d) ((i)=lrint(d)) - -/* this option always works, but may be slow */ -#else -#define lua_number2int(i,d) ((i)=(int)(d)) - -#endif - - -/* -@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. -** CHANGE (see lua_number2int). -*/ -/* On a gcc or Windows/Pentium, resort to assembler */ -#if (defined(__GNUC__) && defined(__i386)) || \ - (defined(_MSC_VER) && defined(_M_IX86)) +/* On a Pentium, resort to a trick */ +#if !defined(LUA_ANSI) && !defined(__SSE2__) && \ + (defined(__i386) || defined (_M_IX86)) +union luai_Cast { double l_d; long l_l; }; +#define lua_number2int(i,d) \ + { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } #define lua_number2integer(i,n) lua_number2int(i, n) /* this option always works, but may be slow */ #else -#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) +#define lua_number2int(i,d) ((i)=(int)(d)) +#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) #endif @@ -479,13 +499,13 @@ ** =================================================================== */ +#define LUA_NUMBER double /* @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' @* over a number. */ -#define LUA_NUMBER double -#define LUAI_UACNUMBER LUA_NUMBER +#define LUAI_UACNUMBER double /* @@ -505,16 +525,16 @@ /* @@ The luai_num* macros define the primitive operations over numbers. */ -#define luai_numadd(a,b) ((a)+(b)) -#define luai_numsub(a,b) ((a)-(b)) -#define luai_nummul(a,b) ((a)*(b)) -#define luai_numdiv(a,b) ((a)/(b)) -#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) -#define luai_numpow(a,b) pow(a,b) -#define luai_numunm(a) (-(a)) -#define luai_numeq(a,b) ((a)==(b)) -#define luai_numlt(a,b) ((a)<(b)) -#define luai_numle(a,b) ((a)<=(b)) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numdiv(L,a,b) ((a)/(b)) +#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(L,a,b) pow(a,b) +#define luai_numunm(L,a) (-(a)) +#define luai_numeq(L,a,b) ((a)==(b)) +#define luai_numlt(L,a,b) ((a)<(b)) +#define luai_numle(L,a,b) ((a)<=(b)) /* }================================================================== */ @@ -531,11 +551,11 @@ /* @@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. -** CHANGE them if you prefer to use longjmp/setjmp even with C++ or -** if want/don't want to use _longjmp/_setjmp instead of regular +** CHANGE them if you prefer to use longjmp/setjmp even with C++ +** or if want/don't to use _longjmp/_setjmp instead of regular ** longjmp/setjmp. By default, Lua handles errors with exceptions when -** compiling as C++ code, with _longjmp/_setjmp when compiling as C code -** in a Unix system, and with longjmp/setjmp otherwise. +** compiling as C++ code, with _longjmp/_setjmp when asked to use them, +** and with longjmp/setjmp otherwise. */ #if defined(__cplusplus) /* C++ exceptions */ @@ -544,8 +564,7 @@ { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ -#elif !defined(__STRICT_ANSI__) && (defined(unix) || defined(__unix) || \ - defined(__unix__)) +#elif defined(LUA_USE_ULONGJMP) /* in Unix, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } @@ -578,7 +597,7 @@ */ #if defined(loslib_c) || defined(luaall_c) -#if !defined(__STRICT_ANSI__) && defined(_POSIX_C_SOURCE) +#if !defined(LUA_ANSI) && defined(_POSIX_C_SOURCE) #include #define LUA_TMPNAMBUFSIZE 32 #define lua_tmpnam(b,e) { \ @@ -593,6 +612,30 @@ #endif + +/* +@@ lua_popen spawns a new process connected to the current one through +@* the file streams. +** CHANGE it if you have a way to implement it in your system. +*/ +#if !defined(LUA_ANSI) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 2 + +#define lua_popen(L,c,m) popen(c,m) +#define lua_pclose(L,file) (pclose(file) != -1) + +#elif !defined(LUA_ANSI) && defined(_WIN32) + +#define lua_popen(L,c,m) _popen(c,m) +#define lua_pclose(L,file) (_pclose(file) != -1) + +#else + +#define lua_popen(L,c,m) \ + ((void)c, (void)m, luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) +#define lua_pclose(L,file) ((void)file, 0) + +#endif + /* @@ LUA_DL_* define which dynamic-library system Lua should use. ** CHANGE here if Lua has problems choosing the appropriate @@ -606,7 +649,7 @@ ** If you do not want any kind of dynamic library, undefine all these ** options (or just remove these definitions). */ -#if !defined(__STRICT_ANSI__) +#if !defined(LUA_ANSI) #if defined(_WIN32) #define LUA_DL_DLL #elif defined(__APPLE__) && defined(__MACH__) @@ -617,29 +660,6 @@ #endif -/* -@@ lua_lock/lua_unlock are macros for thread synchronization inside the -@* Lua core. This is an attempt to simplify the implementation of a -@* multithreaded version of Lua. -** CHANGE them only if you know what you are doing. All accesses to -** the global state and to global objects are synchronized. Because -** threads can read the stack of other threads (when running garbage -** collection), a thread must also synchronize any write-access to its -** own stack. Unsynchronized accesses are allowed only when reading its -** own stack, or when reading immutable fields from global objects (such -** as string values and udata values). -*/ -#define lua_lock(L) ((void) 0) -#define lua_unlock(L) ((void) 0) - - -/* -@@ lua_threadyield allows a thread switch in appropriate places in the core. -** CHANGE it only if you know what you are doing. (See lua_lock.) -*/ -#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} - - /* @@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State @* (the data goes just *before* the lua_State pointer). @@ -650,11 +670,15 @@ /* -@@ luai_userstateopen allows user-specific initialization on new threads. -** CHANGE it if you defined LUAI_EXTRASPACE and need to initialize that -** data whenever a new lua_State is created. +@@ luai_userstate* allow user-specific actions on threads. +** CHANGE them if you defined LUAI_EXTRASPACE and need to do something +** extra when a thread is created/deleted/resumed/yielded. */ -#define luai_userstateopen(L) ((void)0) +#define luai_userstateopen(L) ((void)0) +#define luai_userstatefree(L) ((void)0) +#define luai_userstateresume(L,n) ((void)0) +#define luai_userstateyield(L,n) ((void)0) + @@ -668,3 +692,4 @@ #endif + diff --git a/src/lualib.h b/src/lualib.h index e1face325a..f52bb888bd 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.34 2005/04/13 17:24:20 roberto Exp $ +** $Id: lualib.h,v 1.35 2005/08/10 18:06:58 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -37,7 +37,7 @@ LUALIB_API int (luaopen_math) (lua_State *L); LUALIB_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" -LUALIB_API int (luaopen_loadlib) (lua_State *L); +LUALIB_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ diff --git a/src/lundump.c b/src/lundump.c index 8ceb571ba5..726d021d44 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,11 +1,10 @@ /* -** $Id: lundump.c,v 1.55 2005/05/12 00:26:50 lhf Exp $ +** $Id: lundump.c,v 1.58 2005/09/02 01:54:47 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ -#include -#include +#include #define lundump_c #define LUA_CORE @@ -21,113 +20,89 @@ #include "lundump.h" #include "lzio.h" -#define LoadByte (lu_byte) ezgetc +#ifdef LUAC_TRUST_BINARIES +#define IF(c,s) +#else +#define IF(c,s) if (c) error(S,s) +#endif typedef struct { lua_State* L; ZIO* Z; Mbuffer* b; - int swap; const char* name; +#ifdef LUAC_SWAP_ON_LOAD + int swap; +#endif } LoadState; -static void error (LoadState* S, const char* fmt, ...) -{ - const char *msg; - va_list argp; - va_start(argp,fmt); - msg=luaO_pushvfstring(S->L,fmt,argp); - va_end(argp); - luaO_pushfstring(S->L,"%s: %s",S->name,msg); - luaD_throw(S->L,LUA_ERRSYNTAX); -} +#ifdef LUAC_SWAP_ON_LOAD +static void LoadMem (LoadState* S, void* b, int n, size_t size); +#else +#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) +#endif -static int ezgetc (LoadState* S) -{ - int c=zgetc(S->Z); - if (c==EOZ) error(S,"unexpected end of file"); - return c; -} +#define LoadByte(S) (lu_byte)LoadChar(S) +#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) +#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) -static void ezread (LoadState* S, void* b, int n) +static void error(LoadState* S, const char* why) { - int r=luaZ_read(S->Z,b,n); - if (r!=0) error(S,"unexpected end of file"); + luaO_pushfstring(S->L,"%s: %s",S->name,why); + luaD_throw(S->L,LUA_ERRSYNTAX); } -static void LoadBlock (LoadState* S, void* b, size_t size) +static void LoadBlock(LoadState* S, void* b, size_t size) { - if (S->swap) - { - char* p=(char*) b+size-1; - int n=size; - while (n--) *p--=(char)ezgetc(S); - } - else - ezread(S,b,size); + size_t r=luaZ_read(S->Z,b,size); + IF (r!=0, "unexpected end"); } -static void LoadVector (LoadState* S, void* b, int m, size_t size) +static int LoadChar(LoadState* S) { - if (S->swap) - { - char* q=(char*) b; - while (m--) - { - char* p=q+size-1; - int n=size; - while (n--) *p--=(char)ezgetc(S); - q+=size; - } - } - else - ezread(S,b,m*size); -} - -static int LoadInt (LoadState* S) -{ - int x; - LoadBlock(S,&x,sizeof(x)); - if (x<0) error(S,"bad integer"); + char x; + LoadVar(S,x); return x; } -static size_t LoadSize (LoadState* S) +static int LoadInt(LoadState* S) { - size_t x; - LoadBlock(S,&x,sizeof(x)); + int x; + LoadVar(S,x); + IF (x<0, "bad integer"); return x; } -static lua_Number LoadNumber (LoadState* S) +static lua_Number LoadNumber(LoadState* S) { lua_Number x; - LoadBlock(S,&x,sizeof(x)); + LoadVar(S,x); return x; } -static TString* LoadString (LoadState* S) +static TString* LoadString(LoadState* S) { - size_t size=LoadSize(S); + size_t size; + LoadVar(S,size); if (size==0) return NULL; else { char* s=luaZ_openspace(S->L,S->b,size); - ezread(S,s,size); + LoadBlock(S,s,size); return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ } } -static void LoadCode (LoadState* S, Proto* f) +static void LoadCode(LoadState* S, Proto* f) { - int size=LoadInt(S); - f->code=luaM_newvector(S->L,size,Instruction); - f->sizecode=size; - LoadVector(S,f->code,size,sizeof(Instruction)); + int n=LoadInt(S); + f->code=luaM_newvector(S->L,n,Instruction); + f->sizecode=n; + LoadVector(S,f->code,n,sizeof(Instruction)); } -static void LoadLocals (LoadState* S, Proto* f) +static void LoadLocals(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); @@ -142,29 +117,27 @@ static void LoadLocals (LoadState* S, Proto* f) } } -static void LoadLines (LoadState* S, Proto* f) +static void LoadLines(LoadState* S, Proto* f) { - int size=LoadInt(S); - f->lineinfo=luaM_newvector(S->L,size,int); - f->sizelineinfo=size; - LoadVector(S,f->lineinfo,size,sizeof(int)); + int n=LoadInt(S); + f->lineinfo=luaM_newvector(S->L,n,int); + f->sizelineinfo=n; + LoadVector(S,f->lineinfo,n,sizeof(int)); } -static void LoadUpvalues (LoadState* S, Proto* f) +static void LoadUpvalues(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); - if (n!=0 && n!=f->nups) - error(S,"bad nupvalues (read %d; expected %d)",n,f->nups); f->upvalues=luaM_newvector(S->L,n,TString*); f->sizeupvalues=n; for (i=0; iupvalues[i]=NULL; for (i=0; iupvalues[i]=LoadString(S); } -static Proto* LoadFunction (LoadState* S, TString* p); +static Proto* LoadFunction(LoadState* S, TString* p); -static void LoadConstants (LoadState* S, Proto* f) +static void LoadConstants(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); @@ -174,14 +147,14 @@ static void LoadConstants (LoadState* S, Proto* f) for (i=0; ik[i]; - int t=LoadByte(S); + int t=LoadChar(S); switch (t) { case LUA_TNIL: setnilvalue(o); break; case LUA_TBOOLEAN: - setbvalue(o,LoadByte(S)); + setbvalue(o,LoadChar(S)); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); @@ -190,7 +163,7 @@ static void LoadConstants (LoadState* S, Proto* f) setsvalue2n(S->L,o,LoadString(S)); break; default: - error(S,"bad constant type (%d)",t); + IF (1, "bad constant"); break; } } @@ -201,7 +174,7 @@ static void LoadConstants (LoadState* S, Proto* f) for (i=0; ip[i]=LoadFunction(S,f->source); } -static Proto* LoadFunction (LoadState* S, TString* p) +static Proto* LoadFunction(LoadState* S, TString* p) { Proto* f=luaF_newproto(S->L); setptvalue2s(S->L,S->L->top,f); incr_top(S->L); @@ -217,46 +190,21 @@ static Proto* LoadFunction (LoadState* S, TString* p) LoadUpvalues(S,f); LoadConstants(S,f); LoadCode(S,f); -#ifndef TRUST_BINARIES - if (!luaG_checkcode(f)) error(S,"bad code"); -#endif + IF (!luaG_checkcode(f), "bad code"); S->L->top--; return f; } -static void LoadSignature (LoadState* S) -{ - const char* s=LUA_SIGNATURE; - while (*s!=0 && ezgetc(S)==*s) - ++s; - if (*s!=0) error(S,"bad signature"); -} - -static void TestSize (LoadState* S, int s, const char* what) -{ - int r=LoadByte(S); - if (r!=s) - error(S,"bad size of %s (read %d; expected %d)",what,r,s); -} - -#define V(v) v/16,v%16 - -static void LoadHeader (LoadState* S) +static void LoadHeader(LoadState* S) { - int version; - lua_Number x,tx=TEST_NUMBER; - LoadSignature(S); - version=LoadByte(S); - if (version!=VERSION) - error(S,"bad version (read %d.%d; expected %d.%d)",V(version),V(VERSION)); - S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */ - TestSize(S,sizeof(int),"int"); - TestSize(S,sizeof(size_t),"size_t"); - TestSize(S,sizeof(Instruction),"instruction"); - TestSize(S,sizeof(lua_Number),"number"); - x=LoadNumber(S); - if (x!=tx) - error(S,"unknown number format"); + char h[LUAC_HEADERSIZE]; + char s[LUAC_HEADERSIZE]; + luaU_header(h); + LoadBlock(S,s,LUAC_HEADERSIZE); +#ifdef LUAC_SWAP_ON_LOAD + S->swap=(s[6]!=h[6]); s[6]=h[6]; +#endif + IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); } /* @@ -279,10 +227,64 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) } /* -** find byte order +* make header */ -int luaU_endianness (void) +void luaU_header (char* h) { int x=1; - return *(char*)&x; + memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); + h+=sizeof(LUA_SIGNATURE)-1; + *h++=(char)LUAC_VERSION; + *h++=(char)LUAC_FORMAT; + *h++=(char)*(char*)&x; + *h++=(char)sizeof(int); + *h++=(char)sizeof(size_t); + *h++=(char)sizeof(Instruction); + *h++=(char)sizeof(lua_Number); + *h++=(char)(((lua_Number)0.5)==0); } + +#ifdef LUAC_SWAP_ON_LOAD +static void LoadMem (LoadState* S, void* b, int n, size_t size) +{ + LoadBlock(S,b,n*size); + if (S->swap) + { + char* p=(char*) b; + char c; + switch (size) + { + case 1: + break; + case 2: + while (n--) + { + c=p[0]; p[0]=p[1]; p[1]=c; + p+=2; + } + break; + case 4: + while (n--) + { + c=p[0]; p[0]=p[3]; p[3]=c; + c=p[1]; p[1]=p[2]; p[2]=c; + p+=4; + } + break; + case 8: + while (n--) + { + c=p[0]; p[0]=p[7]; p[7]=c; + c=p[1]; p[1]=p[6]; p[6]=c; + c=p[2]; p[2]=p[5]; p[5]=c; + c=p[3]; p[3]=p[4]; p[4]=c; + p+=8; + } + break; + default: + IF(1, "bad size"); + break; + } + } +} +#endif diff --git a/src/lundump.h b/src/lundump.h index 924cfb0173..5de3c46e4a 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.35 2005/05/12 00:26:50 lhf Exp $ +** $Id: lundump.h,v 1.38 2005/09/02 01:54:47 lhf Exp $ ** load pre-compiled Lua chunks ** See Copyright Notice in lua.h */ @@ -10,22 +10,53 @@ #include "lobject.h" #include "lzio.h" +/* make it work with Lua 5.0 */ +#ifndef LUA_VERSION_NUM +#define LUAI_FUNC +#define lua_Writer lua_Chunkwriter +#endif + /* load one chunk; from lundump.c */ -LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char *name); +LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); -/* find byte order; from lundump.c */ -LUAI_FUNC int luaU_endianness (void); +/* make header; from lundump.c */ +LUAI_FUNC void luaU_header (char* h); /* dump one chunk; from ldump.c */ -LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Chunkwriter w, void* data, int strip); +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); /* print one chunk; from print.c */ LUAI_FUNC void luaU_print (const Proto* f, int full); /* for header of binary files -- this is Lua 5.1 */ -#define VERSION 0x51 - -/* for testing native format of lua_Numbers */ -#define TEST_NUMBER ((lua_Number)31415926.0) +#define LUAC_VERSION 0x51 + +/* for header of binary files -- this is the official format */ +#define LUAC_FORMAT 0 + +/* size of header of binary files */ +#define LUAC_HEADERSIZE 12 + +/* make it work with Lua 5.0 */ +#ifndef LUA_VERSION_NUM +#define LUA_SIGNATURE "\033Lua" +#define TValue TObject +#define rawtsvalue tsvalue +#define linedefined lineDefined +#define lastlinedefined lineDefined +#define setptvalue2s(L,t,f) +#undef setsvalue2n +#define setsvalue2n(L,x,y) setsvalue(x,y) +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") +#undef LUAC_VERSION +#define LUAC_VERSION 0x50 +#ifdef lapi_c +#define luaU_dump(L,f,w,d) (luaU_dump)(L,f,w,d,0) +#endif +#ifdef ldo_c +#define luaU_undump(L,z,b) (luaU_undump)(L,z,b,z->name) +#endif +#endif #endif diff --git a/src/lvm.c b/src/lvm.c index f591a35f89..92c853b27c 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.44 2005/05/17 19:49:15 roberto Exp $ +** $Id: lvm.c,v 2.55 2005/09/09 18:23:35 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -226,7 +226,7 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numlt(nvalue(l), nvalue(r)); + return luai_numlt(L, nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) @@ -240,7 +240,7 @@ static int lessequal (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numle(nvalue(l), nvalue(r)); + return luai_numle(L, nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ @@ -256,7 +256,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; - case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); + case LUA_TNUMBER: return luai_numeq(L, nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { @@ -311,26 +311,26 @@ void luaV_concat (lua_State *L, int total, int last) { } -static StkId Arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op) { +static void Arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { - case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; - case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; - case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; - case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; - case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; - case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; + case TM_ADD: setnvalue(ra, luai_numadd(L, nb, nc)); break; + case TM_SUB: setnvalue(ra, luai_numsub(L, nb, nc)); break; + case TM_MUL: setnvalue(ra, luai_nummul(L, nb, nc)); break; + case TM_DIV: setnvalue(ra, luai_numdiv(L, nb, nc)); break; + case TM_MOD: setnvalue(ra, luai_nummod(L, nb, nc)); break; + case TM_POW: setnvalue(ra, luai_numpow(L, nb, nc)); break; + case TM_UNM: setnvalue(ra, luai_numunm(L, nb)); break; default: lua_assert(0); break; } } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); - return L->base; } @@ -358,15 +358,12 @@ static StkId Arith (lua_State *L, StkId ra, const TValue *rb, #define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } -StkId luaV_execute (lua_State *L, int nexeccalls) { +void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; - callentry: /* entry point when calling new functions */ - if (L->hookmask & LUA_MASKCALL) - luaD_callhook(L, LUA_HOOKCALL, -1); - retentry: /* entry point when returning to old functions */ + reentry: /* entry point */ pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; @@ -380,7 +377,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { traceexec(L, pc); if (L->status == LUA_YIELD) { /* did hook yield? */ L->savedpc = pc - 1; - return NULL; + return; } base = L->base; } @@ -462,7 +459,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numadd(nb, nc)); + setnvalue(ra, luai_numadd(L, nb, nc)); } else Protect(Arith(L, ra, rb, rc, TM_ADD)); @@ -473,7 +470,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numsub(nb, nc)); + setnvalue(ra, luai_numsub(L, nb, nc)); } else Protect(Arith(L, ra, rb, rc, TM_SUB)); @@ -484,7 +481,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_nummul(nb, nc)); + setnvalue(ra, luai_nummul(L, nb, nc)); } else Protect(Arith(L, ra, rb, rc, TM_MUL)); @@ -495,7 +492,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numdiv(nb, nc)); + setnvalue(ra, luai_numdiv(L, nb, nc)); } else Protect(Arith(L, ra, rb, rc, TM_DIV)); @@ -506,7 +503,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_nummod(nb, nc)); + setnvalue(ra, luai_nummod(L, nb, nc)); } else Protect(Arith(L, ra, rb, rc, TM_MOD)); @@ -517,25 +514,20 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numpow(nb, nc)); + setnvalue(ra, luai_numpow(L, nb, nc)); } else Protect(Arith(L, ra, rb, rc, TM_POW)); continue; } case OP_UNM: { - const TValue *rb = RB(i); - TValue temp; - if (tonumber(rb, &temp)) { + TValue *rb = RB(i); + if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); - setnvalue(ra, luai_numunm(nb)); + setnvalue(ra, luai_numunm(L, nb)); } else { - rb = RB(i); /* `tonumber' erased `rb' */ - Protect( - if (!call_binTM(L, rb, &luaO_nilobject, ra, TM_UNM)) - luaG_aritherror(L, rb, &luaO_nilobject); - ) + Protect(Arith(L, ra, rb, rb, TM_UNM)); } continue; } @@ -544,16 +536,23 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { setbvalue(ra, res); continue; } - case OP_SIZ: { + case OP_LEN: { const TValue *rb = RB(i); - if (ttype(rb) == LUA_TTABLE) { - setnvalue(ra, cast(lua_Number, luaH_getn(hvalue(rb)))); - } - else { /* try metamethod */ - Protect( - if (!call_binTM(L, rb, &luaO_nilobject, ra, TM_SIZ)) - luaG_typeerror(L, rb, "get size of"); - ) + switch (ttype(rb)) { + case LUA_TTABLE: { + setnvalue(ra, cast(lua_Number, luaH_getn(hvalue(rb)))); + break; + } + case LUA_TSTRING: { + setnvalue(ra, cast(lua_Number, tsvalue(rb)->len)); + break; + } + default: { /* try metamethod */ + Protect( + if (!call_binTM(L, rb, &luaO_nilobject, ra, TM_LEN)) + luaG_typeerror(L, rb, "get length of"); + ) + } } continue; } @@ -569,8 +568,10 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_EQ: { + TValue *rb = RKB(i); + TValue *rc = RKC(i); Protect( - if (equalobj(L, RKB(i), RKC(i)) == GETARG_A(i)) + if (equalobj(L, rb, rc) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; @@ -593,6 +594,12 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_TEST: { + if (l_isfalse(ra) == GETARG_C(i)) pc++; + else + dojump(L, pc, GETARG_sBx(*pc) + 1); + continue; + } + case OP_TESTSET: { TValue *rb = RB(i); if (l_isfalse(rb) == GETARG_C(i)) pc++; else { @@ -609,7 +616,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { switch (luaD_precall(L, ra, nresults)) { case PCRLUA: { nexeccalls++; - goto callentry; /* restart luaV_execute over new Lua function */ + goto reentry; /* restart luaV_execute over new Lua function */ } case PCRC: { /* it was a C function (`precall' called it); adjust results */ @@ -618,7 +625,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { continue; } default: { - return NULL; + return; /* yield */ } } } @@ -643,15 +650,14 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { ci->savedpc = L->savedpc; ci->tailcalls++; /* one more call lost */ L->ci--; /* remove new frame */ - goto callentry; + goto reentry; } - case PCRC: { - /* it was a C function (`precall' called it) */ + case PCRC: { /* it was a C function (`precall' called it) */ base = L->base; continue; } default: { - return NULL; + return; /* yield */ } } } @@ -660,22 +666,21 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); L->savedpc = pc; + b = luaD_poscall(L, ra); if (--nexeccalls == 0) /* was previous function running `here'? */ - return ra; /* no: return */ + return; /* no: return */ else { /* yes: continue its execution */ - int nresults = L->ci->nresults; - lua_assert(isLua(L->ci - 1)); - lua_assert(GET_OPCODE(*((L->ci - 1)->savedpc - 1)) == OP_CALL); - luaD_poscall(L, nresults, ra); - if (nresults >= 0) L->top = L->ci->top; - goto retentry; + if (b) L->top = L->ci->top; + lua_assert(isLua(L->ci)); + lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); + goto reentry; } } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); - lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ + lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); - if (step > 0 ? luai_numle(idx, limit) : luai_numle(limit, idx)) { + if (step > 0 ? luai_numle(L, idx, limit) : luai_numle(L, limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ @@ -693,7 +698,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); - setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); + setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); dojump(L, pc, GETARG_sBx(i)); continue; } @@ -720,7 +725,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { int last; Table *h; if (n == 0) { - n = L->top - ra - 1; + n = cast(int, L->top - ra) - 1; L->top = L->ci->top; } if (c == 0) c = cast(int, *pc++); @@ -764,15 +769,21 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { int b = GETARG_B(i) - 1; int j; CallInfo *ci = L->ci; - int n = ci->base - ci->func - cl->p->numparams - 1; + int n = cast(int, ci->base - ci->func) - cl->p->numparams - 1; if (b == LUA_MULTRET) { + Protect(luaD_checkstack(L, n)); + ra = RA(i); /* previous call may change the stack */ b = n; L->top = ra + n; } - for (j=0; jbase - n + j); - for (; jbase - n + j); + } + else { + setnilvalue(ra + j); + } + } continue; } } diff --git a/src/lvm.h b/src/lvm.h index b00cb8f20b..788423f8e3 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ +** $Id: lvm.h,v 2.5 2005/08/22 18:54:49 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -30,7 +30,7 @@ LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); -LUAI_FUNC StkId luaV_execute (lua_State *L, int nexeccalls); +LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); #endif diff --git a/src/lzio.c b/src/lzio.c index abe086b429..5121ada846 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.30 2005/05/17 19:49:15 roberto Exp $ +** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -34,10 +34,12 @@ int luaZ_fill (ZIO *z) { int luaZ_lookahead (ZIO *z) { if (z->n == 0) { - int c = luaZ_fill(z); - if (c == EOZ) return c; - z->n++; - z->p--; + if (luaZ_fill(z) == EOZ) + return EOZ; + else { + z->n++; /* luaZ_fill removed first byte; put back it */ + z->p--; + } } return char2int(*z->p); } @@ -56,14 +58,8 @@ void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; - if (z->n == 0) { - if (luaZ_fill(z) == EOZ) - return n; /* return number of missing bytes */ - else { - ++z->n; /* filbuf removed first byte; put back it */ - --z->p; - } - } + if (luaZ_lookahead(z) == EOZ) + return n; /* return number of missing bytes */ m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; diff --git a/src/print.c b/src/print.c index 8530870540..8090a2d5d2 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.50 2005/05/12 00:26:50 lhf Exp $ +** $Id: print.c,v 1.52 2005/06/08 14:40:44 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -135,6 +135,10 @@ static void PrintCode(const Proto* f) case OP_CLOSURE: printf("\t; %p",VOID(f->p[bx])); break; + case OP_SETLIST: + if (c==0) printf("\t; %d",(int)code[++pc]); + else printf("\t; %d",c); + break; default: break; } @@ -158,7 +162,7 @@ static void PrintHeader(const Proto* f) (f->linedefined==0)?"main":"function",s, f->linedefined,f->lastlinedefined, S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); - printf("%d%s param%s, %d stack%s, %d upvalue%s, ", + printf("%d%s param%s, %d slot%s, %d upvalue%s, ", f->numparams,f->is_vararg?"+":"",SS(f->numparams), S(f->maxstacksize),S(f->nups)); printf("%d local%s, %d constant%s, %d function%s\n", diff --git a/test/luac.lua b/test/luac.lua index adae1b29bb..96a0a97ce7 100644 --- a/test/luac.lua +++ b/test/luac.lua @@ -4,4 +4,4 @@ assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") f=assert(io.open("luac.out","wb")) assert(f:write(string.dump(assert(loadfile(arg[1]))))) -assert(io.close(f)) +assert(f:close()) diff --git a/test/trace-calls.lua b/test/trace-calls.lua index 5613c2cbfc..6d7a7b3b43 100644 --- a/test/trace-calls.lua +++ b/test/trace-calls.lua @@ -1,5 +1,5 @@ -- trace calls --- example: lua -ltrace-calls.lua bisect.lua +-- example: lua -ltrace-calls bisect.lua local level=0 From b3196343ba1a5dfe10e68eb9c61dc0ad5bb961a8 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 18 Nov 2005 12:00:00 +0000 Subject: [PATCH 25/97] Lua 5.1-beta --- HISTORY | 2 +- INSTALL | 4 +- MANIFEST | 214 ++++---- Makefile | 12 +- README | 2 +- doc/contents.html | 273 +++++++++- doc/manual.html | 1285 ++++++++++++++++++++++++--------------------- src/lapi.c | 22 +- src/lauxlib.c | 19 +- src/lauxlib.h | 3 +- src/lbaselib.c | 48 +- src/lcode.c | 279 +++++----- src/lcode.h | 8 +- src/ldblib.c | 11 +- src/ldebug.c | 55 +- src/ldo.c | 16 +- src/ldump.c | 53 +- src/liolib.c | 6 +- src/llex.c | 40 +- src/loadlib.c | 25 +- src/lobject.c | 4 +- src/lobject.h | 4 +- src/lopcodes.c | 6 +- src/lopcodes.h | 10 +- src/loslib.c | 6 +- src/lparser.c | 43 +- src/lparser.h | 8 +- src/lstate.c | 10 +- src/lstrlib.c | 133 +++-- src/ltable.c | 10 +- src/ltablib.c | 58 +- src/lua.c | 186 +++---- src/lua.h | 12 +- src/luac.c | 19 +- src/luaconf.h | 168 +++--- src/lundump.c | 149 ++---- src/lundump.h | 34 +- src/lvm.c | 118 ++--- src/print.c | 9 +- 39 files changed, 1862 insertions(+), 1502 deletions(-) diff --git a/HISTORY b/HISTORY index 4497c06989..8cf6bfbb03 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,4 @@ -This is Lua 5.1 (alpha). +This is Lua 5.1 (beta). * Changes from version 5.0 to 5.1 ------------------------------- diff --git a/INSTALL b/INSTALL index 4f17a9e9a3..aa881bd74e 100644 --- a/INSTALL +++ b/INSTALL @@ -1,10 +1,12 @@ -This is Lua 5.1 (alpha). +This is Lua 5.1 (beta). * Installation ------------ Building Lua on a Unix system should be very easy: simply doing "make" should work. This will build Lua in the src directory. + There are also special make targets for ansi, linux, bsd, mingw. + See below for customization instructions. If you want to install Lua in an official place in your system, then diff --git a/MANIFEST b/MANIFEST index 5731f184ef..964437ee87 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,108 +1,108 @@ -MANIFEST contents of Lua 5.1 (alpha) distribution on Fri Sep 9 16:55:12 BRST 2005 -lua-5.1-alpha -lua-5.1-alpha/COPYRIGHT -lua-5.1-alpha/HISTORY -lua-5.1-alpha/INSTALL -lua-5.1-alpha/MANIFEST -lua-5.1-alpha/Makefile -lua-5.1-alpha/README -lua-5.1-alpha/doc -lua-5.1-alpha/doc/contents.html -lua-5.1-alpha/doc/logo.gif -lua-5.1-alpha/doc/lua.1 -lua-5.1-alpha/doc/lua.css -lua-5.1-alpha/doc/lua.html -lua-5.1-alpha/doc/luac.1 -lua-5.1-alpha/doc/luac.html -lua-5.1-alpha/doc/manual.html -lua-5.1-alpha/doc/readme.html -lua-5.1-alpha/etc -lua-5.1-alpha/etc/Makefile -lua-5.1-alpha/etc/README -lua-5.1-alpha/etc/all.c -lua-5.1-alpha/etc/lua.hpp -lua-5.1-alpha/etc/lua.ico -lua-5.1-alpha/etc/lua.pc -lua-5.1-alpha/etc/luavs.bat -lua-5.1-alpha/etc/min.c -lua-5.1-alpha/etc/noparser.c -lua-5.1-alpha/etc/strict.lua -lua-5.1-alpha/src -lua-5.1-alpha/src/Makefile -lua-5.1-alpha/src/lapi.c -lua-5.1-alpha/src/lapi.h -lua-5.1-alpha/src/lauxlib.c -lua-5.1-alpha/src/lauxlib.h -lua-5.1-alpha/src/lbaselib.c -lua-5.1-alpha/src/lcode.c -lua-5.1-alpha/src/lcode.h -lua-5.1-alpha/src/ldblib.c -lua-5.1-alpha/src/ldebug.c -lua-5.1-alpha/src/ldebug.h -lua-5.1-alpha/src/ldo.c -lua-5.1-alpha/src/ldo.h -lua-5.1-alpha/src/ldump.c -lua-5.1-alpha/src/lfunc.c -lua-5.1-alpha/src/lfunc.h -lua-5.1-alpha/src/lgc.c -lua-5.1-alpha/src/lgc.h -lua-5.1-alpha/src/linit.c -lua-5.1-alpha/src/liolib.c -lua-5.1-alpha/src/llex.c -lua-5.1-alpha/src/llex.h -lua-5.1-alpha/src/llimits.h -lua-5.1-alpha/src/lmathlib.c -lua-5.1-alpha/src/lmem.c -lua-5.1-alpha/src/lmem.h -lua-5.1-alpha/src/loadlib.c -lua-5.1-alpha/src/lobject.c -lua-5.1-alpha/src/lobject.h -lua-5.1-alpha/src/lopcodes.c -lua-5.1-alpha/src/lopcodes.h -lua-5.1-alpha/src/loslib.c -lua-5.1-alpha/src/lparser.c -lua-5.1-alpha/src/lparser.h -lua-5.1-alpha/src/lstate.c -lua-5.1-alpha/src/lstate.h -lua-5.1-alpha/src/lstring.c -lua-5.1-alpha/src/lstring.h -lua-5.1-alpha/src/lstrlib.c -lua-5.1-alpha/src/ltable.c -lua-5.1-alpha/src/ltable.h -lua-5.1-alpha/src/ltablib.c -lua-5.1-alpha/src/ltm.c -lua-5.1-alpha/src/ltm.h -lua-5.1-alpha/src/lua.c -lua-5.1-alpha/src/lua.h -lua-5.1-alpha/src/luac.c -lua-5.1-alpha/src/luaconf.h -lua-5.1-alpha/src/lualib.h -lua-5.1-alpha/src/lundump.c -lua-5.1-alpha/src/lundump.h -lua-5.1-alpha/src/lvm.c -lua-5.1-alpha/src/lvm.h -lua-5.1-alpha/src/lzio.c -lua-5.1-alpha/src/lzio.h -lua-5.1-alpha/src/print.c -lua-5.1-alpha/test -lua-5.1-alpha/test/README -lua-5.1-alpha/test/bisect.lua -lua-5.1-alpha/test/cf.lua -lua-5.1-alpha/test/echo.lua -lua-5.1-alpha/test/env.lua -lua-5.1-alpha/test/factorial.lua -lua-5.1-alpha/test/fib.lua -lua-5.1-alpha/test/fibfor.lua -lua-5.1-alpha/test/globals.lua -lua-5.1-alpha/test/hello.lua -lua-5.1-alpha/test/life.lua -lua-5.1-alpha/test/luac.lua -lua-5.1-alpha/test/printf.lua -lua-5.1-alpha/test/readonly.lua -lua-5.1-alpha/test/sieve.lua -lua-5.1-alpha/test/sort.lua -lua-5.1-alpha/test/table.lua -lua-5.1-alpha/test/trace-calls.lua -lua-5.1-alpha/test/trace-globals.lua -lua-5.1-alpha/test/xd.lua +MANIFEST contents of Lua 5.1 (beta) distribution on Fri Nov 18 07:42:23 BRST 2005 +lua-5.1-beta +lua-5.1-beta/COPYRIGHT +lua-5.1-beta/HISTORY +lua-5.1-beta/INSTALL +lua-5.1-beta/MANIFEST +lua-5.1-beta/Makefile +lua-5.1-beta/README +lua-5.1-beta/doc +lua-5.1-beta/doc/contents.html +lua-5.1-beta/doc/logo.gif +lua-5.1-beta/doc/lua.1 +lua-5.1-beta/doc/lua.css +lua-5.1-beta/doc/lua.html +lua-5.1-beta/doc/luac.1 +lua-5.1-beta/doc/luac.html +lua-5.1-beta/doc/manual.html +lua-5.1-beta/doc/readme.html +lua-5.1-beta/etc +lua-5.1-beta/etc/Makefile +lua-5.1-beta/etc/README +lua-5.1-beta/etc/all.c +lua-5.1-beta/etc/lua.hpp +lua-5.1-beta/etc/lua.ico +lua-5.1-beta/etc/lua.pc +lua-5.1-beta/etc/luavs.bat +lua-5.1-beta/etc/min.c +lua-5.1-beta/etc/noparser.c +lua-5.1-beta/etc/strict.lua +lua-5.1-beta/src +lua-5.1-beta/src/Makefile +lua-5.1-beta/src/lapi.c +lua-5.1-beta/src/lapi.h +lua-5.1-beta/src/lauxlib.c +lua-5.1-beta/src/lauxlib.h +lua-5.1-beta/src/lbaselib.c +lua-5.1-beta/src/lcode.c +lua-5.1-beta/src/lcode.h +lua-5.1-beta/src/ldblib.c +lua-5.1-beta/src/ldebug.c +lua-5.1-beta/src/ldebug.h +lua-5.1-beta/src/ldo.c +lua-5.1-beta/src/ldo.h +lua-5.1-beta/src/ldump.c +lua-5.1-beta/src/lfunc.c +lua-5.1-beta/src/lfunc.h +lua-5.1-beta/src/lgc.c +lua-5.1-beta/src/lgc.h +lua-5.1-beta/src/linit.c +lua-5.1-beta/src/liolib.c +lua-5.1-beta/src/llex.c +lua-5.1-beta/src/llex.h +lua-5.1-beta/src/llimits.h +lua-5.1-beta/src/lmathlib.c +lua-5.1-beta/src/lmem.c +lua-5.1-beta/src/lmem.h +lua-5.1-beta/src/loadlib.c +lua-5.1-beta/src/lobject.c +lua-5.1-beta/src/lobject.h +lua-5.1-beta/src/lopcodes.c +lua-5.1-beta/src/lopcodes.h +lua-5.1-beta/src/loslib.c +lua-5.1-beta/src/lparser.c +lua-5.1-beta/src/lparser.h +lua-5.1-beta/src/lstate.c +lua-5.1-beta/src/lstate.h +lua-5.1-beta/src/lstring.c +lua-5.1-beta/src/lstring.h +lua-5.1-beta/src/lstrlib.c +lua-5.1-beta/src/ltable.c +lua-5.1-beta/src/ltable.h +lua-5.1-beta/src/ltablib.c +lua-5.1-beta/src/ltm.c +lua-5.1-beta/src/ltm.h +lua-5.1-beta/src/lua.c +lua-5.1-beta/src/lua.h +lua-5.1-beta/src/luac.c +lua-5.1-beta/src/luaconf.h +lua-5.1-beta/src/lualib.h +lua-5.1-beta/src/lundump.c +lua-5.1-beta/src/lundump.h +lua-5.1-beta/src/lvm.c +lua-5.1-beta/src/lvm.h +lua-5.1-beta/src/lzio.c +lua-5.1-beta/src/lzio.h +lua-5.1-beta/src/print.c +lua-5.1-beta/test +lua-5.1-beta/test/README +lua-5.1-beta/test/bisect.lua +lua-5.1-beta/test/cf.lua +lua-5.1-beta/test/echo.lua +lua-5.1-beta/test/env.lua +lua-5.1-beta/test/factorial.lua +lua-5.1-beta/test/fib.lua +lua-5.1-beta/test/fibfor.lua +lua-5.1-beta/test/globals.lua +lua-5.1-beta/test/hello.lua +lua-5.1-beta/test/life.lua +lua-5.1-beta/test/luac.lua +lua-5.1-beta/test/printf.lua +lua-5.1-beta/test/readonly.lua +lua-5.1-beta/test/sieve.lua +lua-5.1-beta/test/sort.lua +lua-5.1-beta/test/table.lua +lua-5.1-beta/test/trace-calls.lua +lua-5.1-beta/test/trace-globals.lua +lua-5.1-beta/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index 58cbcca47f..e554e18971 100644 --- a/Makefile +++ b/Makefile @@ -55,15 +55,21 @@ ansi: cd src; $(MAKE) MYCFLAGS=-DLUA_ANSI linux: - cd src; $(MAKE) MYCFLAGS=-DLUA_USE_DLOPEN MYLIBS="-Wl,-E -ldl" + cd src; $(MAKE) MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" + +macosx: + cd src; $(MAKE) MYCFLAGS=-DLUA_USE_MACOSX + +posix: + cd src; $(MAKE) MYCFLAGS=-DLUA_USE_POSIX bsd: - cd src; $(MAKE) MYCFLAGS=-DLUA_USE_DLOPEN MYLIBS="-Wl,-E" + cd src; $(MAKE) MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" mingw: cd src; $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ "AR=gcc -shared -o" "RANLIB=strip --strip-unneeded" \ - "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" MYLDFLAGS=-s" lua.exe + "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe # echo config parameters echo: diff --git a/README b/README index 668f569d08..5f950281fd 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Lua 5.1 (alpha). +This is Lua 5.1 (beta). See HISTORY for a summary of changes since the last released version. * What is Lua? diff --git a/doc/contents.html b/doc/contents.html index 9db0cafa11..25dd0c5a0f 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -19,6 +19,7 @@


        +

        Word index

        + +_G
        +_VERSION
        +assert
        +collectgarbage
        +coroutine.create
        +coroutine.resume
        +coroutine.running
        +coroutine.status
        +coroutine.wrap
        +coroutine.yield
        +debug.debug
        +debug.getfenv
        +debug.gethook
        +debug.getinfo
        +debug.getlocal
        +debug.getmetatable
        +debug.getregistry
        +debug.getupvalue
        +debug.setfenv
        +debug.sethook
        +debug.setlocal
        +debug.setmetatable
        +debug.setupvalue
        +debug.traceback
        +dofile
        +error
        +file:close
        +file:flush
        +file:lines
        +file:read
        +file:seek
        +file:setvbuf
        +file:write
        +getfenv
        +getmetatable
        +io.close
        +io.flush
        +io.input
        +io.lines
        +io.open
        +io.output
        +io.popen
        +io.read
        +io.tmpfile
        +io.type
        +io.write
        +ipairs
        +load
        +loadfile
        +loadstring
        + +luaL_Buffer
        +luaL_Reg
        +luaL_addchar
        +luaL_addlstring
        +luaL_addsize
        +luaL_addstring
        +luaL_addvalue
        +luaL_argcheck
        +luaL_argerror
        +luaL_buffinit
        +luaL_callmeta
        +luaL_checkany
        +luaL_checkint
        +luaL_checkinteger
        +luaL_checklong
        +luaL_checklstring
        +luaL_checknumber
        +luaL_checkoption
        +luaL_checkstack
        +luaL_checkstring
        +luaL_checktype
        +luaL_checkudata
        +luaL_error
        +luaL_getmetafield
        +luaL_getmetatable
        +luaL_gsub
        +luaL_loadbuffer
        +luaL_loadfile
        +luaL_loadstring
        +luaL_newmetatable
        +luaL_newstate
        +luaL_optint
        +luaL_optinteger
        +luaL_optlong
        +luaL_optlstring
        +luaL_optnumber
        +luaL_optstring
        +luaL_prepbuffer
        +luaL_pushresult
        +luaL_ref
        +luaL_register
        +luaL_typename
        +luaL_typerror
        +luaL_unref
        +luaL_where
        +lua_Alloc
        +lua_CFunction
        +lua_Debug
        +lua_Hook
        +lua_Integer
        +lua_Number
        +lua_Reader
        +lua_State
        +lua_Writer
        +lua_atpanic
        +lua_call
        +lua_checkstack
        +lua_close
        +lua_concat
        +lua_cpcall
        +lua_createtable
        +lua_dump
        +lua_equal
        +lua_error
        +lua_gc
        +lua_getallocf
        +lua_getfenv
        +lua_getfield
        +lua_gethook
        +lua_gethookcount
        +lua_gethookmask
        +lua_getinfo
        +lua_getlocal
        +lua_getmetatable
        +lua_getstack
        +lua_gettable
        +lua_gettop
        +lua_getupvalue
        +lua_insert
        +lua_isboolean
        +lua_iscfunction
        +lua_isfunction
        +lua_islightuserdata
        +lua_isnil
        +lua_isnumber
        +lua_isstring
        +lua_istable
        +lua_isthread
        +lua_isuserdata
        +lua_lessthan
        +lua_load
        +lua_newstate
        +lua_newtable
        +lua_newthread
        +lua_newuserdata
        +lua_next
        +lua_objlen
        +lua_pcall
        +lua_pop
        +lua_pushboolean
        +lua_pushcclosure
        +lua_pushcfunction
        +lua_pushfstring
        +lua_pushinteger
        +lua_pushlightuserdata
        +lua_pushlstring
        +lua_pushnil
        +lua_pushnumber
        +lua_pushstring
        +lua_pushvalue
        +lua_pushvfstring
        +lua_rawequal
        +lua_rawget
        +lua_rawgeti
        +lua_rawset
        +lua_rawseti
        +lua_remove
        +lua_replace
        +lua_resume
        +lua_setallocf
        +lua_setfenv
        +lua_setfield
        +lua_sethook
        +lua_setlocal
        +lua_setmetatable
        +lua_settable
        +lua_settop
        +lua_setupvalue
        +lua_toboolean
        +lua_tocfunction
        +lua_tointeger
        +lua_tolstring
        +lua_tonumber
        +lua_topointer
        +lua_tostring
        +lua_tothread
        +lua_touserdata
        +lua_type
        +lua_xmove
        +lua_yield
        + +math.abs
        +math.acos
        +math.asin
        +math.atan
        +math.atan2
        +math.ceil
        +math.cos
        +math.cosh
        +math.def
        +math.exp
        +math.floor
        +math.fmod
        +math.ldexp
        +math.log
        +math.log10
        +math.pow
        +math.sin
        +math.sinh
        +math.sqrt
        +math.tan
        +math.tanh
        +module
        +next
        +os.clock
        +os.date
        +os.difftime
        +os.execute
        +os.exit
        +os.getenv
        +os.remove
        +os.rename
        +os.setlocale
        +os.time
        +os.tmpname
        +package.cpath
        +package.loaded
        +package.loadlib
        +package.path
        +package.preload
        +package.seeall
        +pairs
        +pcall
        +print
        +rawequal
        +rawget
        +rawset
        +require
        +select
        +setfenv
        +setmetatable
        +string.byte
        +string.char
        +string.dump
        +string.find
        +string.format
        +string.gmatch
        +string.gsub
        +string.len
        +string.lower
        +string.match
        +string.rep
        +string.reverse
        +string.sub
        +string.upper
        +table.concat
        +table.insert
        +table.maxn(table)
        +table.remove
        +table.sort
        +tonumber
        +tostring
        +type
        +unpack
        +xpcall
        +

        +


        Last update: -Fri Sep 9 14:44:10 BRST 2005 +Tue Nov 1 15:40:46 BRST 2005 diff --git a/doc/manual.html b/doc/manual.html index b55232bd42..293532f1e6 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,16 +1,16 @@ - + Lua 5.1 Reference Manual - + - + -
        +

        -[Lua logo] +[Lua logo] Lua 5.1 Reference Manual

        @@ -20,7 +20,7 @@

        Copyright © 2005 Lua.org, PUC-Rio. All rights reserved. -
        +

        @@ -28,7 +28,6 @@

        -

        1 - Introduction

        Lua is an extension programming language designed to support @@ -68,21 +67,21 @@

        • R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. -Lua—an extensible extension language. -Software: Practice & Experience 26:6 (1996) 635–652. +Lua---an extensible extension language. +Software: Practice & Experience 26:6 (1996) 635--652.
        • L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. The design and implementation of a language for extending applications. Proceedings of XXI Brazilian Seminar on Software and Hardware -(1994) 273–283. +(1994) 273--283.
        • L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. Lua: an extensible embedded language. -Dr. Dobb's Journal 21:12 (Dec 1996) 26–33. +Dr. Dobb's Journal 21:12 (Dec 1996) 26--33.
        • R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. The evolution of an extension language: a history of Lua, -Proceedings of V Brazilian Symposium on Programming Languages (2001) B-14–B-28. +Proceedings of V Brazilian Symposium on Programming Languages (2001) B-14--B-28.

        Lua means "moon" in Portuguese and is pronounced LOO-ah. @@ -119,12 +118,12 @@

        The following keywords are reserved and cannot be used as names: -

        +
                and       break     do        else      elseif
                end       false     for       function  if
                in        local     nil       not       or
                repeat    return    then      true      until     while
        -
        +

        Lua is a case-sensitive language: and is a reserved word, but And and AND @@ -134,27 +133,27 @@

        are reserved for internal variables used by Lua.

        The following strings denote other tokens: -

        +
                +     -     *     /     %     ^     #
                ==    ~=    <=    >=    <     >     =
                (     )     {     }     [     ]
                ;     :     ,     .     ..    ...
        -
        +

        Literal strings can be delimited by matching single or double quotes, and can contain the following C-like escape sequences:

          -
        • \a — bell -
        • \b — backspace -
        • \f — form feed -
        • \n — newline -
        • \r — carriage return -
        • \t — horizontal tab -
        • \v — vertical tab -
        • \\ — backslash -
        • \" — quotation mark -
        • \' — apostrophe +
        • \a --- bell +
        • \b --- backspace +
        • \f --- form feed +
        • \n --- newline +
        • \r --- carriage return +
        • \t --- horizontal tab +
        • \v --- vertical tab +
        • \\ --- backslash +
        • \" --- quotation mark +
        • \' --- apostrophe
        Moreover, a `\newline´ (that is, a backslash followed by a real newline) @@ -188,7 +187,7 @@

        (in which `a´ is coded as 97, newline is coded as 10, and `1´ is coded as 49), the four literals below denote the same string: -
        +
               (1)   "alo\n123\""
               (2)   '\97lo\10\04923"'
               (3)   [[alo
        @@ -196,14 +195,14 @@ 

        (4) [==[ alo 123"]==] -

        +

        Numerical constants may be written with an optional decimal part and an optional decimal exponent. Examples of valid numerical constants are -

        +
                3     3.0     3.1416  314.16e-2   0.31416E1
        -
        +

        Comments start anywhere outside a string with a double hyphen (--). @@ -225,11 +224,11 @@

        nil, boolean, number, string, function, userdata, thread, and table. -Nil is the type of the value nil, +Nil is the type of the value nil, whose main property is to be different from any other value; usually it represents the absence of a useful value. -Boolean is the type of the values false and true. -In Lua, both nil and false make a condition false; +Boolean is the type of the values false and true. +In Lua, both nil and false make a condition false; any other value makes it true. Number represents real (double-precision floating-point) numbers. (It is easy to build Lua interpreters that use other @@ -266,10 +265,10 @@

        The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, -but with any value (except nil). +but with any value (except nil). Moreover, tables can be heterogeneous, -that is, they can contain values of all types (except nil). +that is, they can contain values of all types (except nil). Tables are the sole data structuring mechanism in Lua; they may be used to represent ordinary arrays, symbol tables, sets, records, graphs, trees, etc. @@ -280,7 +279,7 @@

        (see 2.5.7).

        Like indices, -the value of a table field can be of any type (except nil). +the value of a table field can be of any type (except nil). In particular, because functions are first class values, table fields may contain functions. @@ -327,7 +326,7 @@

        Local variables can be freely accessed by functions defined inside their scope (see 2.6). -

        Before the first assignment to a variable, its value is nil. +

        Before the first assignment to a variable, its value is nil.

        Square brackets are used to index a table:

        @@ -370,9 +369,9 @@ 

        An access to a global variable x is equivalent to _env.x, which in turn is equivalent to -

        +
                gettable_event(_env, "x")
        -
        +
        where _env is the environment of the running function. (See 2.8 for a complete description of the gettable_event function. @@ -454,7 +453,7 @@

        If there are more values than needed, the excess values are thrown away. If there are fewer values than needed, -the list is extended with as many nil's as needed. +the list is extended with as many nil's as needed. If the list of expressions ends with a function call, then all values returned by that function call enter in the list of values, before the adjustment @@ -463,17 +462,17 @@

        The assignment statement first evaluates all its expressions and only then are the assignments performed. Thus the code -

        +
                i = 3
                i, a[i] = i+1, 20
        -
        +
        sets a[3] to 20, without affecting a[4] because the i in a[i] is evaluated (to 3) before it is assigned 4. Similarly, the line -
        +
                x, y = y, x
        -
        +
        exchanges the values of x and y.

        The meaning of assignments to global variables @@ -489,9 +488,9 @@

        is equivalent to the assignment _env.x = val, which in turn is equivalent to -
        +
                settable_event(_env, "x", val)
        -
        +
        where _env is the environment of the running function. (The _env variable is not defined in Lua. We use it here only for explanatory purposes.) @@ -512,11 +511,11 @@

        The condition expression exp of a control structure may return any value. -Both false and nil are considered false. -All values different from nil and false are considered true +Both false and nil are considered false. +All values different from nil and false are considered true (in particular, the number 0 and the empty string are also true). -

        In the repeatuntil loop, +

        In the repeat--until loop, the inner block does not end at the until keyword, but only after the condition. That means the condition can refer to local variables @@ -567,11 +566,11 @@

        the first exp, until it passes the second exp by steps of the third exp. More precisely, a for statement like -
        +
                for var = e1, e2, e3 do block end
        -
        +
        is equivalent to the code: -
        +
                do
                  local _var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
                  if not (_var and _limit and _step) then error() end
        @@ -581,7 +580,7 @@ 

        _var = _var + _step end end -

        +
        Note the following:
        • All three control expressions are evaluated only once, @@ -601,17 +600,17 @@

          The generic for statement works over functions, called iterators. For each iteration, it calls its iterator function to produce a new value, -stopping when the new value is nil. +stopping when the new value is nil. The generic for loop has the following syntax:

           	stat ::= for Name {`,´ Name} in explist1 do block end
           
          A for statement like -
          +
                  for var_1, ..., var_n in explist do block end
          -
          +
          is equivalent to the code: -
          +
                  do
                    local _f, _s, _var = explist
                    while true do
          @@ -621,7 +620,7 @@ 

          block end end -

          +
          Note the following:
          • explist is evaluated only once. @@ -654,7 +653,7 @@

        If present, an initial assignment has the same semantics of a multiple assignment (see 2.4.3). -Otherwise, all variables are initialized with nil. +Otherwise, all variables are initialized with nil.

        A chunk is also a block (see 2.4.1), so local variables can be declared in a chunk outside any explicit block. @@ -668,7 +667,7 @@

        The basic expressions in Lua are the following:
         	exp ::= prefixexp
        -	exp ::= nil | false | true
        +	exp ::= nil  |  false  |  true
         	exp ::= Number
         	exp ::= Literal
         	exp ::= function
        @@ -676,7 +675,7 @@ 

        exp ::= `...´ exp ::= exp binop exp exp ::= unop exp - prefixexp ::= var | functioncall | `(´ exp `)´ + prefixexp ::= var | functioncall | `(´ exp `)´

        Numbers and literal strings are explained in 2.1; @@ -710,7 +709,7 @@

        unless the call is enclosed in parentheses.

        Here are some examples: -

        +
                f()                -- adjusted to 0 results
                g(f(), x)          -- f() is adjusted to 1 result
                g(x, f())          -- g gets x plus all values returned by f()
        @@ -726,14 +725,14 @@ 

        {f()} -- creates a list with all values returned by f() {...} -- creates a list with all vararg parameters {f(), nil} -- f() is adjusted to 1 result -

        +

        An expression enclosed in parentheses always results in only one value. Thus, (f(x,y,z)) is always a single value, even if f returns several values. (The value of (f(x,y,z)) is the first value returned by f -or nil if f does not return any values.) +or nil if f does not return any values.)

        2.5.1 - Arithmetic Operators

        Lua supports the usual arithmetic operators: @@ -747,21 +746,21 @@

        Exponentiation works for any exponent. For instance, x^-0.5 computes the inverse of the square root of x. Modulus is defined as -
        +
           a % b == a - math.floor(a/b)*b
        -
        +
        That is, it is the remaining of a division that rounds the quotient towards minus infinity.

        2.5.2 - Relational Operators

        The relational operators in Lua are -
        +
                ==    ~=    <     >     <=    >=
        -
        -These operators always result in false or true. +
        +These operators always result in false or true.

        Equality (==) first compares the type of its operands. -If the types are different, then the result is false. +If the types are different, then the result is false. Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. Objects (tables, userdata, threads, and functions) @@ -775,7 +774,7 @@

        The conversion rules of 2.2.1 do not apply to equality comparisons. -Thus, "0"==0 evaluates to false, +Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table. @@ -792,27 +791,27 @@

        2.5.3 - Logical Operators

        The logical operators in Lua are -
        +
                and   or    not
        -
        +
        Like the control structures (see 2.4.4), -all logical operators consider both false and nil as false +all logical operators consider both false and nil as false and anything else as true. -

        The operator not always returns false or true. +

        The operator not always returns false or true.

        The conjunction operator and returns its first argument -if this value is false or nil; +if this value is false or nil; otherwise, and returns its second argument. The disjunction operator or returns its first argument -if this value is different from nil and false; +if this value is different from nil and false; otherwise, or returns its second argument. Both and and or use short-cut evaluation, that is, the second operand is evaluated only if necessary. For example, -

        +
                10 or error()       -> 10
                nil or "a"          -> "a"
                nil and 10          -> nil
        @@ -820,7 +819,7 @@ 

        false and nil -> false false or nil -> nil 10 and 20 -> 20 -

        +

        2.5.4 - Concatenation

        The string concatenation operator in Lua is @@ -837,22 +836,22 @@

        character is one byte). The length of a table t is defined to be any integer index n -such that t[n] is not nil and t[n+1] is nil; -moreover, if t[1] is nil, n may be zero. +such that t[n] is not nil and t[n+1] is nil; +moreover, if t[1] is nil, n may be zero.

        For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" -(that is, nil values between other non-nil values), -then #t may be any of the indices that precede a nil value -(that is, it may consider any such nil value as the end of +(that is, nil values between other non-nil values), +then #t may be any of the indices that precede a nil value +(that is, it may consider any such nil value as the end of the array).

        2.5.6 - Precedence

        Operator precedence in Lua follows the table below, from lower to higher priority: -
        +
                or
                and
                <     >     <=    >=    ~=    ==
        @@ -861,7 +860,7 @@ 

        * / % not # - (unary) ^ -

        +
        You can use parentheses to change the precedences of an expression. The concatenation (`..´) and exponentiation (`^´) operators are right associative. @@ -876,8 +875,8 @@

         	tableconstructor ::= `{´ [fieldlist] `}´
         	fieldlist ::= field {fieldsep field} [fieldsep]
        -	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
        -	fieldsep ::= `,´ | `;´
        +	field ::= `[´ exp `]´ `=´ exp  |  Name `=´ exp  |  exp
        +	fieldsep ::= `,´  |  `;´
         

        Each field of the form [exp1] = exp2 adds to the new table an entry @@ -889,11 +888,11 @@

        starting with 1. Fields in the other formats do not affect this counting. For example, -
        +
                a = {[f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45}
        -
        +
        is equivalent to -
        +
                do
                  local temp = {}
                  temp[f(1)] = g
        @@ -905,7 +904,7 @@ 

        temp[4] = 45 -- 4th exp a = temp end -

        +

        If the last field in the list has the form exp and the expression is a function call or a vararg expression, @@ -961,10 +960,10 @@

        you cannot put a line break before the `(´ in a function call. That restriction avoids some ambiguities in the language. If you write -
        +
                a = f
                (g).x(a)
        -
        +
        Lua would read that as a = f(g).x(a). So, if you want two statements, you must add a semi-colon between them. If you actually want to call f, @@ -985,13 +984,13 @@

        this syntax makes the calling function returns exactly the returns of the called function. So, all the following examples are not tail calls: -
        +
           return (f(x))        -- results adjusted to 1
           return 2 * f(x)
           return x, f(x)       -- additional results
           f(x); return         -- results discarded
           return x or f(x)     -- results adjusted to 1
        -
        +

        2.5.9 - Function Definitions

        @@ -1008,29 +1007,29 @@

        funcname ::= Name {`.´ Name} [`:´ Name]

    The statement -
    +
            function f () ... end
    -
    +
    translates to -
    +
            f = function () ... end
    -
    +
    The statement -
    +
            function t.a.b.c.f () ... end
    -
    +
    translates to -
    +
            t.a.b.c.f = function () ... end
    -
    +
    The statement -
    +
            local function f () ... end
    -
    +
    translates to -
    +
            local f; f = function () ... end
    -
    +

    A function definition is an executable expression, whose value has type function. @@ -1047,7 +1046,7 @@

    Parameters act as local variables that are initialized with the argument values:

    -	parlist1 ::= namelist [`,´ `...´] | `...´
    +	parlist1 ::= namelist [`,´ `...´]  |  `...´
     
    When a function is called, the list of arguments is adjusted to @@ -1069,14 +1068,14 @@

    (unless the call is enclosed in parentheses).

    As an example, consider the following definitions: -

    +
            function f(a, b) end
            function g(a, b, ...) end
            function r() return 1,2,3 end
    -
    +
    Then, we have the following mapping from arguments to parameters and to the vararg expression: -
    +
            CALL            PARAMETERS
     
            f(3)             a=3, b=nil
    @@ -1089,7 +1088,7 @@ 

    g(3, 4) a=3, b=4, ... -> (nothing) g(3, 4, 5, 8) a=3, b=4, ... -> 5 8 g(5, r()) a=5, b=1, ... -> 2 3 -

    +

    Results are returned using the return statement (see 2.4.4). If control reaches the end of a function @@ -1100,13 +1099,13 @@

    is used for defining methods, that is, functions that have an implicit extra parameter self. Thus, the statement -
    +
            function t.a.b.c:f (...) ... end
    -
    +
    is syntactic sugar for -
    +
            t.a.b.c.f = function (self, ...) ... end
    -
    +

    2.6 - Visibility Rules

    @@ -1116,7 +1115,7 @@

    their declaration and lasts until the end of the innermost block that includes the declaration. For instance: -
    +
       x = 10                -- global variable
       do                    -- new block
         local x = x         -- new `x', with value 10
    @@ -1129,7 +1128,7 @@ 

    print(x) --> 11 end print(x) --> 10 (the global one) -

    +
    Notice that, in a declaration like local x = x, the new x being declared is not in scope yet, and so the second x refers to the outside variable. @@ -1138,13 +1137,13 @@

    local variables can be freely accessed by functions defined inside their scope. For instance: -
    +
       local counter = 0
       function inc (x)
         counter = counter + x
         return counter
       end
    -
    +
    A local variable used by an inner function is called an upvalue, or external local variable, inside the inner function. @@ -1152,14 +1151,14 @@

    Notice that each execution of a local statement defines new local variables. Consider the following example: -

    +
       a = {}
       local x = 20
       for i=1,10 do
         local y = 0
         a[i] = function () y=y+1; return x+y end
       end
    -
    +
    The loop creates ten closures (that is, ten instances of the anonymous function). Each of these closures uses a different y variable, @@ -1243,16 +1242,16 @@

    are described in 5.1. In particular, to retrieve the metamethod of a given object, we use the expression -
    +
       metatable(obj)[event]
    -
    +
    This should be read as -
    +
       rawget(metatable(obj) or {}, event)
    -
    +
    That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail -(it simply results in nil). +(it simply results in nil).

    • "add": @@ -1263,14 +1262,14 @@

      First, Lua tries the first operand. If its type does not define a handler for the operation, then Lua tries the second operand. -
      +
        function getbinhandler (op1, op2, event)
          return metatable(op1)[event] or metatable(op2)[event]
        end
      -
      +
      Using that function, the behavior of the op1 + op2 is -
      +
        function add_event (op1, op2)
          local o1, o2 = tonumber(op1), tonumber(op2)
          if o1 and o2 then  -- both operands are numeric?
      @@ -1285,7 +1284,7 @@ 

      end end end -

      +

    • "sub": the - operation. @@ -1313,7 +1312,7 @@

    • "unm": the unary - operation. -
      +
        function unm_event (op)
          local o = tonumber(op)
          if o then  -- operand is numeric?
      @@ -1329,11 +1328,11 @@ 

      end end end -

      +

    • "concat": the .. (concatenation) operation. -
      +
        function concat_event (op1, op2)
          if (type(op1) == "string" or type(op1) == "number") and
             (type(op2) == "string" or type(op2) == "number") then
      @@ -1347,11 +1346,11 @@ 

      end end end -

      +

    • "len": the # operation. -
      +
        function len_event (op)
          if type(op) == "string" then
            return strlen(op)         -- primitive string length
      @@ -1367,7 +1366,7 @@ 

      end end end -

      +
      See 2.5.5 for a description of the length of a table.

    • "eq": @@ -1377,16 +1376,16 @@

      A metamethod only is selected when both objects being compared have the same type and the same metamethod for the selected operation. -
      +
        function getcomphandler (op1, op2, event)
          if type(op1) ~= type(op2) then return nil end
          local mm1 = metatable(op1)[event]
          local mm2 = metatable(op2)[event]
          if mm1 == mm2 then return mm1 else return nil end
        end
      -
      +
      The "eq" event is defined as follows: -
      +
        function eq_event (op1, op2)
          if type(op1) ~= type(op2) then  -- different types?
            return false   -- different objects
      @@ -1402,12 +1401,12 @@ 

      return false end end -

      +
      a ~= b is equivalent to not (a == b).

    • "lt": the < operation. -
      +
        function lt_event (op1, op2)
          if type(op1) == "number" and type(op2) == "number" then
            return op1 < op2   -- numeric comparison
      @@ -1422,12 +1421,12 @@ 

      end end end -

      +
      a > b is equivalent to b < a.

    • "le": the <= operation. -
      +
        function le_event (op1, op2)
          if type(op1) == "number" and type(op2) == "number" then
            return op1 <= op2   -- numeric comparison
      @@ -1447,7 +1446,7 @@ 

      end end end -

      +
      a >= b is equivalent to b <= a. Note that, in the absence of a "le" metamethod, Lua tries the "lt", assuming that a <= b is @@ -1455,7 +1454,7 @@

    • "index": The indexing access table[key]. -
      +
        function gettable_event (table, key)
          local h
          if type(table) == "table" then
      @@ -1474,11 +1473,11 @@ 

      else return h[key] -- or repeat operation on it end end -

      +

    • "newindex": The indexing assignment table[key] = value. -
      +
        function settable_event (table, key, value)
          local h
          if type(table) == "table" then
      @@ -1497,11 +1496,11 @@ 

      else h[key] = value -- or repeat operation on it end end -

      +

    • "call": called when Lua calls a value. -
      +
        function function_event (func, ...)
          if type(func) == "function" then
            return func(unpack(arg))   -- primitive call
      @@ -1514,7 +1513,7 @@ 

      end end end -

      +

    @@ -1612,14 +1611,14 @@

    After the collection, Lua does the equivalent of the following function for each userdata in that list: -
    +
      function gc_event (udata)
        local h = metatable(udata).__gc
        if h then
          h(udata)
        end
      end
    -
    +

    At the end of each garbage-collection cycle, the finalizers for userdata are called in reverse @@ -1686,9 +1685,9 @@

    Normally, when its main function returns (explicitly or implicitly, after the last instruction); and abnormally, if there is an unprotected error. -In the first case, coroutine.resume returns true, +In the first case, coroutine.resume returns true, plus any values returned by the coroutine main function. -In case of errors, coroutine.resume returns false +In case of errors, coroutine.resume returns false plus an error message.

    A coroutine yields by calling coroutine.yield. @@ -1697,7 +1696,7 @@

    even if the yield happens inside nested function calls (that is, not in the main function, but in a function directly or indirectly called by the main function). -In the case of a yield, coroutine.resume also returns true, +In the case of a yield, coroutine.resume also returns true, plus any values passed to coroutine.yield. The next time you resume the same coroutine, it continues its execution from the point where it yielded, @@ -1718,7 +1717,7 @@

    As an example, consider the next code: -

    +
     function foo1 (a)
       print("foo", a)
       return coroutine.yield(2*a)
    @@ -1741,9 +1740,9 @@ 

    print("main", a, b, c) a, b = coroutine.resume(co, "x", "y") print("main", a, b) -

    +
    When you run it, it produces the following output: -
    +
     co-body 1       10
     foo     2
     main    true    4
    @@ -1752,7 +1751,7 @@ 

    co-body x y main true 10 end main false cannot resume dead coroutine -

    +

    3 - The Application Program Interface

    @@ -1780,7 +1779,7 @@

    Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value -(nil, number, string, etc.). +(nil, number, string, etc.).

    Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of @@ -1828,9 +1827,9 @@

    Such indices are called acceptable indices. More formally, we define an acceptable index as follows: -
    +
          (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
    -
    +
    Note that 0 is never an acceptable index.

    3.3 - Pseudo-Indices

    @@ -1853,9 +1852,9 @@

    To access and change the value of global variables, you can use regular table operations over an environment table. For instance, to access the value of a global variable, do -

    +
            lua_getfield(L, LUA_GLOBALSINDEX, varname);
    -
    +

    3.4 - C Closures

    @@ -1918,7 +1917,7 @@

    alphabetical order.

    -


    lua_Alloc

    +

    lua_Alloc

               typedef void * (*lua_Alloc) (void *ud,
                                            void *ptr,
    @@ -1950,8 +1949,9 @@ 

    Lua assumes that the allocator never fails when osize >= nsize. -

    A simple implementation for the allocator function could be like this: -

    +

    A simple implementation for the allocator function +could be like this: +

     static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
       (void)ud;     /* not used */
       (void)osize;  /* not used */
    @@ -1963,10 +1963,10 @@ 

    /* ANSI ensures that realloc(NULL, size) == malloc(size) */ return realloc(ptr, nsize); } -

    +

    -


    lua_atpanic

    +

    lua_atpanic

               lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
     
    @@ -1983,7 +1983,7 @@

    The panic function can access the error message at the top of the stack.

    -


    lua_call

    +

    lua_call

               void lua_call (lua_State *L, int nargs, int nresults);
     
    @@ -2012,11 +2012,11 @@

    The following example shows how the host program may do the equivalent to this Lua code: -

    +
            a = f("how", t.x, 14)
    -
    +
    Here it is in C: -
    +
         lua_getfield(L, LUA_GLOBALSINDEX, "t");     /* global `t' (for later use) */
         lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* function to be called */
         lua_pushstring(L, "how");                                 /* 1st argument */
    @@ -2025,13 +2025,13 @@ 

    lua_call(L, 3, 1); /* call function with 3 arguments and 1 result */ lua_setfield(L, LUA_GLOBALSINDEX, "a"); /* set global variable `a' */ lua_pop(L, 1); /* remove `t' from the stack */ -

    +
    Note that the code above is "balanced": at its end, the stack is back to its original configuration. This is considered good programming practice.

    -


    lua_CFunction

    +

    lua_CFunction

               typedef int (*lua_CFunction) (lua_State *L);
     
    @@ -2056,7 +2056,7 @@

    As an example, the following function receives a variable number of numerical arguments and returns their average and sum: -

    +
            static int foo (lua_State *L) {
              int n = lua_gettop(L);    /* number of arguments */
              lua_Number sum = 0;
    @@ -2072,10 +2072,10 @@ 

    lua_pushnumber(L, sum); /* second result */ return 2; /* number of results */ } -

    +

    -


    lua_checkstack

    +

    lua_checkstack

               int lua_checkstack (lua_State *L, int extra);
     
    @@ -2088,7 +2088,7 @@

    it is left unchanged.

    -


    lua_close

    +

    lua_close

               void lua_close (lua_State *L);
     
    @@ -2105,7 +2105,7 @@

    to avoid growing too large.

    -


    lua_concat

    +

    lua_concat

               void lua_concat (lua_State *L, int n);
     
    @@ -2120,7 +2120,7 @@

    (see 2.5.4).

    -


    lua_cpcall

    +

    lua_cpcall

               int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
     
    @@ -2136,7 +2136,7 @@

    Any value returned by func is discarded.

    -


    lua_createtable

    +

    lua_createtable

               void lua_createtable (lua_State *L, int narr, int nrec);
     
    @@ -2150,7 +2150,7 @@

    Otherwise you can use the function lua_newtable.

    -


    lua_dump

    +

    lua_dump

               int lua_dump (lua_State *L, lua_Writer writer, void *data);
     
    @@ -2172,7 +2172,7 @@

    This function does not pop the function from the stack.

    -


    lua_equal

    +

    lua_equal

               int lua_equal (lua_State *L, int index1, int index2);
     
    @@ -2180,13 +2180,13 @@

    Returns 1 if the two values in acceptable indices index1 and index2 are equal, -following the semantics of the Lua = operator +following the semantics of the Lua == operator (that is, may call metamethods). Otherwise returns 0. Also returns 0 if any of the indices are non valid.

    -


    lua_error

    +

    lua_error

               int lua_error (lua_State *L);
     
    @@ -2199,7 +2199,7 @@

    and therefore never returns.

    -


    lua_gc

    +

    lua_gc

               int lua_gc (lua_State *L, int what, int data);
     
    @@ -2210,12 +2210,15 @@

    This function performs several tasks, according to the value of the parameter what:

      -
    • LUA_GCSTOP— stops the garbage collector. -
    • LUA_GCRESTART— restarts the garbage collector. -
    • LUA_GCCOLLECT— performs a full garbage-collection cycle. -
    • LUA_GCCOUNT— returns the current +
    • LUA_GCSTOP--- stops the garbage collector. +
    • LUA_GCRESTART--- restarts the garbage collector. +
    • LUA_GCCOLLECT--- performs a full garbage-collection cycle. +
    • LUA_GCCOUNT--- returns the current amount of memory (in Kbytes) in use by Lua. -
    • LUA_GCSTEP— performs an incremental step of +
    • LUA_GCCOUNTB--- returns the remainder of +dividing the current amount of bytes of memory in use by Lua +by 1024. +
    • LUA_GCSTEP--- performs an incremental step of garbage collection. The step "size" is controlled by data (larger values mean more steps) in a non-specified way. @@ -2223,16 +2226,18 @@

      you must tune experimentally the value of data. The function returns 1 if that step finished a garbage-collection cycle. -
    • LUA_GCSETPAUSE— +
    • LUA_GCSETPAUSE--- sets data/100 as the new value for the pause of the collector (see 2.10). -
    • LUA_GCSETSTEPMUL— +The function returns the previous value of the pause. +
    • LUA_GCSETSTEPMUL--- sets arg/100 as the new value for the step multiplier of the collector (see 2.10). +The function returns the previous value of the step multiplier.

    -


    lua_getallocf

    +

    lua_getallocf

               lua_Alloc lua_getallocf (lua_State *L, void **ud);
     
    @@ -2243,7 +2248,7 @@

    opaque pointer passed to lua_newstate.

    -


    lua_getfenv

    +

    lua_getfenv

               void lua_getfenv (lua_State *L, int index);
     
    @@ -2253,7 +2258,7 @@

    the value at the given index.

    -


    lua_getfield

    +

    lua_getfield

               void lua_getfield (lua_State *L, int index, const char *k);
     
    @@ -2265,7 +2270,7 @@

    for the "index" event (see 2.8).

    -


    lua_getmetatable

    +

    lua_getmetatable

               int lua_getmetatable (lua_State *L, int index);
     
    @@ -2278,7 +2283,7 @@

    returns 0 and pushes nothing on the stack.

    -


    lua_gettable

    +

    lua_gettable

               void lua_gettable (lua_State *L, int index);
     
    @@ -2294,7 +2299,7 @@

    for the "index" event (see 2.8).

    -


    lua_gettop

    +

    lua_gettop

               int lua_gettop (lua_State *L);
     
    @@ -2306,7 +2311,7 @@

    (and so 0 means an empty stack).

    -


    lua_insert

    +

    lua_insert

               void lua_insert (lua_State *L, int index);
     
    @@ -2318,7 +2323,7 @@

    because a pseudo-index is not an actual stack position.

    -


    lua_Integer

    +

    lua_Integer

               typedef ptrdiff_t lua_Integer;
     
    @@ -2331,7 +2336,7 @@

    "comfortably".

    -


    lua_isboolean

    +

    lua_isboolean

               int lua_isboolean (lua_State *L, int index);
     
    @@ -2341,7 +2346,7 @@

    and 0 otherwise.

    -


    lua_iscfunction

    +

    lua_iscfunction

               int lua_iscfunction (lua_State *L, int index);
     
    @@ -2351,7 +2356,7 @@

    and 0 otherwise.

    -


    lua_isfunction

    +

    lua_isfunction

               int lua_isfunction (lua_State *L, int index);
     
    @@ -2361,7 +2366,7 @@

    (either C or Lua), and 0 otherwise.

    -


    lua_islightuserdata

    +

    lua_islightuserdata

               int lua_islightuserdata (lua_State *L, int index);
     
    @@ -2371,17 +2376,17 @@

    and 0 otherwise.

    -


    lua_isnil

    +

    lua_isnil

               int lua_isnil (lua_State *L, int index);
     
    -

    Returns 1 if the value at the given acceptable index is nil, +

    Returns 1 if the value at the given acceptable index is nil, and 0 otherwise.

    -


    lua_isnumber

    +

    lua_isnumber

               int lua_isnumber (lua_State *L, int index);
     
    @@ -2392,7 +2397,7 @@

    and 0 otherwise.

    -


    lua_isstring

    +

    lua_isstring

               int lua_isstring (lua_State *L, int index);
     
    @@ -2403,7 +2408,7 @@

    and 0 otherwise.

    -


    lua_istable

    +

    lua_istable

               int lua_istable (lua_State *L, int index);
     
    @@ -2413,7 +2418,7 @@

    and 0 otherwise.

    -


    lua_isthread

    +

    lua_isthread

               int lua_isthread (lua_State *L, int index);
     
    @@ -2423,7 +2428,7 @@

    and 0 otherwise.

    -


    lua_isuserdata

    +

    lua_isuserdata

               int lua_isuserdata (lua_State *L, int index);
     
    @@ -2433,7 +2438,7 @@

    (either full or light), and 0 otherwise.

    -


    lua_lessthan

    +

    lua_lessthan

               int lua_lessthan (lua_State *L, int index1, int index2);
     
    @@ -2447,7 +2452,7 @@

    Also returns 0 if any of the indices are non valid.

    -


    lua_load

    +

    lua_load

               int lua_load (lua_State *L, lua_Reader reader, void *data,
                                           const char *chunkname);
    @@ -2462,10 +2467,10 @@ 

    Otherwise, it pushes an error message. The return values of lua_load are:
      -
    • 0 — no errors; -
    • LUA_ERRSYNTAX — +
    • 0 --- no errors; +
    • LUA_ERRSYNTAX --- syntax error during pre-compilation. -
    • LUA_ERRMEM — +
    • LUA_ERRMEM --- memory allocation error.
    @@ -2480,7 +2485,7 @@

    It is used for error messages and debug information (see 3.8).

    -


    lua_newstate

    +

    lua_newstate

               lua_State *lua_newstate (lua_Alloc f, void *ud);
     
    @@ -2495,7 +2500,7 @@

    simply passes to the allocator in every call.

    -


    lua_newtable

    +

    lua_newtable

               void lua_newtable (lua_State *L);
     
    @@ -2505,7 +2510,7 @@

    Equivalent to lua_createtable(L, 0, 0).

    -


    lua_newthread

    +

    lua_newthread

               lua_State *lua_newthread (lua_State *L);
     
    @@ -2522,7 +2527,7 @@

    like any Lua object.

    -


    lua_newuserdata

    +

    lua_newuserdata

               void *lua_newuserdata (lua_State *L, size_t size);
     
    @@ -2544,7 +2549,7 @@

    and then it frees the userdata's corresponding memory.

    -


    lua_next

    +

    lua_next

               int lua_next (lua_State *L, int index);
     
    @@ -2557,7 +2562,7 @@

    then lua_next returns 0 (and pushes nothing).

    A typical traversal looks like this: -

    +
            /* table is in the stack at index `t' */
            lua_pushnil(L);  /* first key */
            while (lua_next(L, t) != 0) {
    @@ -2566,7 +2571,7 @@ 

    lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1))); lua_pop(L, 1); /* removes `value'; keeps `key' for next iteration */ } -

    +

    While traversing a table, do not call lua_tolstring directly on a key, @@ -2576,7 +2581,7 @@

    this confuses the next call to lua_next.

    -


    lua_Number

    +

    lua_Number

               typedef double lua_Number;
     
    @@ -2588,7 +2593,7 @@

    Lua to operate with other type for numbers (e.g., float or long).

    -


    lua_objlen

    +

    lua_objlen

               size_t lua_objlen (lua_State *L, int index);
     
    @@ -2602,7 +2607,7 @@

    For other values, returns 0.

    -


    lua_pcall

    +

    lua_pcall

               lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
     
    @@ -2640,15 +2645,15 @@

    or one of the following error codes (defined in lua.h):
      -
    • LUA_ERRRUN — a runtime error. -
    • LUA_ERRMEM — memory allocation error. +
    • LUA_ERRRUN --- a runtime error. +
    • LUA_ERRMEM --- memory allocation error. For such errors, Lua does not call the error handler function. -
    • LUA_ERRERR — +
    • LUA_ERRERR --- error while running the error handler function.

    -


    lua_pop

    +

    lua_pop

               void lua_pop (lua_State *L, int n);
     
    @@ -2657,7 +2662,7 @@

    Pops n elements from the stack.

    -


    lua_pushboolean

    +

    lua_pushboolean

               void lua_pushboolean (lua_State *L, int b);
     
    @@ -2666,7 +2671,7 @@

    Pushes a boolean value with value b onto the stack.

    -


    lua_pushcclosure

    +

    lua_pushcclosure

               void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
     
    @@ -2688,7 +2693,7 @@

    lua_pushcclosure also pops these values from the stack.

    -


    lua_pushcfunction

    +

    lua_pushcfunction

               void lua_pushcfunction (lua_State *L, lua_CFunction f);
     
    @@ -2698,7 +2703,7 @@

    This function is equivalent to lua_pushcclosure(L, f, 0);.

    -


    lua_pushfstring

    +

    lua_pushfstring

               const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
     
    @@ -2724,7 +2729,7 @@

    -


    lua_pushinteger

    +

    lua_pushinteger

               void lua_pushinteger (lua_State *L, lua_Integer n);
     
    @@ -2733,7 +2738,7 @@

    Pushes a number with value n onto the stack.

    -


    lua_pushlightuserdata

    +

    lua_pushlightuserdata

               void lua_pushlightuserdata (lua_State *L, void *p);
     
    @@ -2750,7 +2755,7 @@

    light userdata with the same C address.

    -


    lua_pushlstring

    +

    lua_pushlstring

               void lua_pushlstring (lua_State *L, const char *s, size_t len);
     
    @@ -2763,7 +2768,7 @@

    the function returns.

    -


    lua_pushnil

    +

    lua_pushnil

               void lua_pushnil (lua_State *L);
     
    @@ -2772,7 +2777,7 @@

    Pushes a nil value onto the stack.

    -


    lua_pushnumber

    +

    lua_pushnumber

               void lua_pushnumber (lua_State *L, lua_Number n);
     
    @@ -2781,7 +2786,7 @@

    Pushes a number with value n onto the stack.

    -


    lua_pushstring

    +

    lua_pushstring

               void lua_pushstring (lua_State *L, const char *s);
     
    @@ -2794,7 +2799,7 @@

    the function returns.

    -


    lua_pushvalue

    +

    lua_pushvalue

               void lua_pushvalue (lua_State *L, int index);
     
    @@ -2804,7 +2809,7 @@

    onto the stack.

    -


    lua_pushvfstring

    +

    lua_pushvfstring

               const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
     
    @@ -2814,7 +2819,7 @@

    instead of a variable number of arguments.

    -


    lua_rawequal

    +

    lua_rawequal

               int lua_rawequal (lua_State *L, int index1, int index2);
     
    @@ -2827,7 +2832,7 @@

    Also returns 0 if any of the indices are non valid.

    -


    lua_rawget

    +

    lua_rawget

               void lua_rawget (lua_State *L, int index);
     
    @@ -2837,7 +2842,7 @@

    (i.e., without metamethods).

    -


    lua_rawgeti

    +

    lua_rawgeti

               void lua_rawgeti (lua_State *L, int index, int n);
     
    @@ -2849,7 +2854,7 @@

    that is, it does not invoke metamethods.

    -


    lua_rawset

    +

    lua_rawset

               void lua_rawset (lua_State *L, int index);
     
    @@ -2859,7 +2864,7 @@

    (i.e., without metamethods).

    -


    lua_rawseti

    +

    lua_rawseti

               void lua_rawseti (lua_State *L, int index, int n);
     
    @@ -2874,7 +2879,7 @@

    that is, it does not invoke metamethods.

    -


    lua_Reader

    +

    lua_Reader

               typedef const char * (*lua_Reader)
                                    (lua_State *L, void *data, size_t *size);
    @@ -2893,7 +2898,7 @@ 

    The reader function may return pieces of any size greater than zero.

    -


    lua_remove

    +

    lua_remove

               void lua_remove (lua_State *L, int index);
     
    @@ -2905,7 +2910,7 @@

    because a pseudo-index is not an actual stack position.

    -


    lua_replace

    +

    lua_replace

               void lua_replace (lua_State *L, int index);
     
    @@ -2916,7 +2921,7 @@

    (therefore replacing the value at the given position).

    -


    lua_resume

    +

    lua_resume

               int lua_resume (lua_State *L, int narg);
     
    @@ -2932,8 +2937,11 @@

    This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. -lua_resume returns 0 if there are no errors running the coroutine, -or an error code (see lua_pcall). +lua_resume returns +LUA_YIELD if the coroutine yields, +0 if the coroutine finishes its execution +without errors, +or an error code in case of errors (see lua_pcall). In case of errors, the stack is not unwound, so you can use the debug API over it; @@ -2942,8 +2950,18 @@

    be passed as results from yield, and then call lua_resume. +

    +


    lua_setallocf

    +
    +          void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
    +
    + + +

    Changes the allocator function of a given state to f +with user data ud. +

    -


    lua_setfenv

    +

    lua_setfenv

               int lua_setfenv (lua_State *L, int index);
     
    @@ -2956,7 +2974,7 @@

    lua_setfenv returns 0 (false).

    -


    lua_setfield

    +

    lua_setfield

               void lua_setfield (lua_State *L, int index, const char *k);
     
    @@ -2971,7 +2989,7 @@

    for the "newindex" event (see 2.8).

    -


    lua_setmetatable

    +

    lua_setmetatable

               int lua_setmetatable (lua_State *L, int index);
     
    @@ -2982,7 +3000,7 @@

    acceptable index.

    -


    lua_settable

    +

    lua_settable

               void lua_settable (lua_State *L, int index);
     
    @@ -2998,7 +3016,7 @@

    for the "newindex" event (see 2.8).

    -


    lua_settop

    +

    lua_settop

               void lua_settop (lua_State *L, int index);
     
    @@ -3007,11 +3025,11 @@

    Accepts any acceptable index, or 0, and sets the stack top to that index. If the new top is larger than the old one, -then the new elements are filled with nil. +then the new elements are filled with nil. If index is 0, then all stack elements are removed.

    -


    lua_State

    +

    lua_State

               typedef struct lua_State lua_State;
     
    @@ -3027,7 +3045,7 @@

    which creates a Lua state from scratch.

    -


    lua_toboolean

    +

    lua_toboolean

               int lua_toboolean (lua_State *L, int index);
     
    @@ -3037,14 +3055,14 @@

    value ((0 or 1). Like all tests in Lua, lua_toboolean returns 1 for any Lua value -different from false and nil; +different from false and nil; otherwise it returns 0. It also returns 0 when called with a non-valid index. (If you want to accept only real boolean values, use lua_isboolean to test the value's type.)

    -


    lua_tocfunction

    +

    lua_tocfunction

               lua_CFunction lua_tocfunction (lua_State *L, int index);
     
    @@ -3055,7 +3073,7 @@

    otherwise, returns NULL.

    -


    lua_tointeger

    +

    lua_tointeger

               lua_Integer lua_tointeger (lua_State *L, int idx);
     
    @@ -3071,7 +3089,7 @@

    it is truncated in some non-specified way.

    -


    lua_tolstring

    +

    lua_tolstring

               const char *lua_tolstring (lua_State *L, int index, size_t *len);
     
    @@ -3099,7 +3117,7 @@

    will be valid after the corresponding value is removed from the stack.

    -


    lua_tonumber

    +

    lua_tonumber

               lua_Number lua_tonumber (lua_State *L, int index);
     
    @@ -3112,7 +3130,7 @@

    otherwise, lua_tonumber returns 0.

    -


    lua_topointer

    +

    lua_topointer

               const void *lua_topointer (lua_State *L, int index);
     
    @@ -3128,7 +3146,7 @@

    Typically this function is used for debug information.

    -


    lua_tostring

    +

    lua_tostring

               const char *lua_tostring (lua_State *L, int index);
     
    @@ -3137,7 +3155,7 @@

    Equivalent to lua_tolstring with len equal to NULL.

    -


    lua_tothread

    +

    lua_tothread

               lua_State *lua_tothread (lua_State *L, int index);
     
    @@ -3149,7 +3167,7 @@

    otherwise, the function returns NULL.

    -


    lua_touserdata

    +

    lua_touserdata

               void *lua_touserdata (lua_State *L, int index);
     
    @@ -3162,7 +3180,7 @@

    Otherwise, returns NULL.

    -


    lua_type

    +

    lua_type

               int lua_type (lua_State *L, int index);
     
    @@ -3184,7 +3202,7 @@

    LUA_TLIGHTUSERDATA.

    -


    lua_Writer

    +

    lua_Writer

               typedef int (*lua_Writer)
                               (lua_State *L, const void* p, size_t sz, void* ud);
    @@ -3205,7 +3223,7 @@ 

    calling the writer again.

    -


    lua_xmove

    +

    lua_xmove

               void lua_xmove (lua_State *from, lua_State *to, int n);
     
    @@ -3217,7 +3235,7 @@

    and pushes them into the stack to.

    -


    lua_yield

    +

    lua_yield

               int lua_yield  (lua_State *L, int nresults);
     
    @@ -3227,9 +3245,9 @@

    This function can only be called as the return expression of a C function, as follows: -

    +
            return lua_yield (L, nresults);
    -
    +
    When a C function calls lua_yield in that way, the running coroutine suspends its execution, and the call to lua_resume that started this coroutine returns. @@ -3247,7 +3265,7 @@

    that need "inside information" from the interpreter.

    -


    lua_Debug

    +

    lua_Debug

               typedef struct lua_Debug {
                 int event;
    @@ -3260,8 +3278,8 @@ 

    int linedefined; /* (S) */ int lastlinedefined; /* (S) */ char short_src[LUA_IDSIZE]; /* (S) */ - -

    /* private part */ + + /* private part */ ... } lua_Debug; @@ -3329,7 +3347,7 @@

    -


    lua_gethook

    +

    lua_gethook

               lua_Hook lua_gethook (lua_State *L);
     
    @@ -3338,7 +3356,7 @@

    Returns the current hook function.

    -


    lua_gethookcount

    +

    lua_gethookcount

               int lua_gethookcount (lua_State *L);
     
    @@ -3347,7 +3365,7 @@

    Returns the current hook count.

    -


    lua_gethookmask

    +

    lua_gethookmask

               int lua_gethookmask (lua_State *L);
     
    @@ -3356,7 +3374,7 @@

    Returns the current hook mask.

    -


    lua_getinfo

    +

    lua_getinfo

               int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
     
    @@ -3382,15 +3400,15 @@

    and start the what string with the character `>´. For instance, to know in which line a function f was defined, you can write the following code: -
    +
            lua_Debug ar;
            lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* get global `f' */
            lua_getinfo(L, ">S", &ar);
            printf("%d\n", ar.linedefined);
    -
    +

    -


    lua_getlocal

    +

    lua_getlocal

               const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
     
    @@ -3406,12 +3424,16 @@

    lua_getlocal pushes the variable's value onto the stack, and returns its name. +

    Variable names starting with `(´ (open parentheses) +represent internal variables +(loop control variables, temporaries, and C function locals). +

    Returns NULL (and pushes nothing) when the index is greater than the number of active local variables.

    -


    lua_getstack

    +

    lua_getstack

               int lua_getstack (lua_State *L, int level, lua_Debug *ar);
     
    @@ -3429,7 +3451,7 @@

    it returns 0.

    -


    lua_getupvalue

    +

    lua_getupvalue

               const char *lua_getupvalue (lua_State *L, int funcindex, int n);
     
    @@ -3452,7 +3474,7 @@

    as a name for all upvalues.

    -


    lua_Hook

    +

    lua_Hook

               typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
     
    @@ -3480,7 +3502,7 @@

    that execution occurs without any calls to hooks.

    -


    lua_sethook

    +

    lua_sethook

               int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
     
    @@ -3515,7 +3537,7 @@

    A hook is disabled by setting mask to zero.

    -


    lua_setlocal

    +

    lua_setlocal

               const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
     
    @@ -3533,7 +3555,7 @@

    the number of active local variables.

    -


    lua_setupvalue

    +

    lua_setupvalue

               const char *lua_setupvalue (lua_State *L, int funcindex, int n);
     
    @@ -3582,7 +3604,7 @@

    in alphabetical order.

    -


    luaL_addchar

    +

    luaL_addchar

               void luaL_addchar (luaL_Buffer B, char c);
     
    @@ -3592,7 +3614,7 @@

    (see luaL_Buffer).

    -


    luaL_addlstring

    +

    luaL_addlstring

               void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
     
    @@ -3603,7 +3625,7 @@

    (see luaL_Buffer).

    -


    luaL_addsize

    +

    luaL_addsize

               void luaL_addsize (luaL_Buffer B, size_t n);
     
    @@ -3614,7 +3636,7 @@

    (see luaL_Buffer).

    -


    luaL_addstring

    +

    luaL_addstring

               void luaL_addstring (luaL_Buffer *B, const char *s);
     
    @@ -3625,7 +3647,7 @@

    (see luaL_Buffer).

    -


    luaL_addvalue

    +

    luaL_addvalue

               void luaL_addvalue (luaL_Buffer *B);
     
    @@ -3641,7 +3663,7 @@

    which is the value to be added to the buffer.

    -


    luaL_argcheck

    +

    luaL_argcheck

               void luaL_argcheck (lua_State *L, int cond, int numarg,
                                   const char *extramsg);
    @@ -3654,7 +3676,7 @@ 

    where func is retrieved from the call stack.

    -


    luaL_argerror

    +

    luaL_argerror

               int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
     
    @@ -3667,7 +3689,7 @@

    This function never returns.

    -


    luaL_Buffer

    +

    luaL_Buffer

               typedef struct luaL_Buffer luaL_Buffer;
     
    @@ -3700,7 +3722,7 @@

    plus the final string on its top.

    -


    luaL_buffinit

    +

    luaL_buffinit

               void luaL_buffinit (lua_State *L, luaL_Buffer *B);
     
    @@ -3712,7 +3734,7 @@

    (see luaL_Buffer).

    -


    luaL_callmeta

    +

    luaL_callmeta

               int luaL_callmeta (lua_State *L, int obj, const char *e);
     
    @@ -3729,7 +3751,7 @@

    (without pushing any value on the stack).

    -


    luaL_checkany

    +

    luaL_checkany

               void luaL_checkany (lua_State *L, int narg);
     
    @@ -3738,7 +3760,7 @@

    Checks whether the function has an argument narg.

    -


    luaL_checkint

    +

    luaL_checkint

               int luaL_checkint (lua_State *L, int narg);
     
    @@ -3748,7 +3770,7 @@

    and returns that number casted to an int.

    -


    luaL_checkinteger

    +

    luaL_checkinteger

               lua_Integer luaL_checkinteger (lua_State *L, int numArg);
     
    @@ -3758,7 +3780,7 @@

    and returns that number casted to a lua_Integer.

    -


    luaL_checklong

    +

    luaL_checklong

               long luaL_checklong (lua_State *L, int narg);
     
    @@ -3768,7 +3790,7 @@

    and returns that number casted to a long.

    -


    luaL_checklstring

    +

    luaL_checklstring

               const char *luaL_checklstring (lua_State *L, int numArg, size_t *l);
     
    @@ -3780,7 +3802,7 @@

    with the string's length.

    -


    luaL_checknumber

    +

    luaL_checknumber

               lua_Number luaL_checknumber (lua_State *L, int numArg);
     
    @@ -3790,7 +3812,7 @@

    and returns that number.

    -


    luaL_checkoption

    +

    luaL_checkoption

               int luaL_checkoption (lua_State *L, int narg, const char *def,
                                     const char *const lst[]);
    @@ -3802,14 +3824,14 @@ 

    (which must be NULL-terminated). If def is not NULL, uses def as a default value when -the function has no argument narg or if that argument is nil. +the function has no argument narg or if that argument is nil.

    Returns the index in the array where the string was found. Raises an error if the argument is not a string or if the string cannot be found.

    -


    luaL_checkstack

    +

    luaL_checkstack

               void luaL_checkstack (lua_State *L, int sz, const char *msg);
     
    @@ -3820,7 +3842,7 @@

    msg is an additional text to go into the error message.

    -


    luaL_checkstring

    +

    luaL_checkstring

               const char *luaL_checkstring (lua_State *L, int narg);
     
    @@ -3830,7 +3852,7 @@

    and returns that string.

    -


    luaL_checktype

    +

    luaL_checktype

               void luaL_checktype (lua_State *L, int narg, int t);
     
    @@ -3839,7 +3861,7 @@

    Checks whether the function argument narg has type t.

    -


    luaL_checkudata

    +

    luaL_checkudata

               void *luaL_checkudata (lua_State *L, int ud, const char *tname);
     
    @@ -3849,7 +3871,7 @@

    of the type tname (see luaL_newmetatable).

    -


    luaL_error

    +

    luaL_error

               int luaL_error (lua_State *L, const char *fmt, ...);
     
    @@ -3866,7 +3888,7 @@

    This function never returns.

    -


    luaL_getmetafield

    +

    luaL_getmetafield

               int luaL_getmetafield (lua_State *L, int obj, const char *e);
     
    @@ -3879,7 +3901,7 @@

    returns 0 (false) and pushes nothing.

    -


    luaL_getmetatable

    +

    luaL_getmetatable

               void luaL_getmetatable (lua_State *L, const char *tname);
     
    @@ -3889,7 +3911,7 @@

    in the registry (see luaL_newmetatable).

    -


    luaL_gsub

    +

    luaL_gsub

               const char *luaL_gsub (lua_State *L, const char *s,
                                      const char *p, const char *r);
    @@ -3901,7 +3923,7 @@ 

    Pushes the resulting string on the stack and returns it.

    -


    luaL_loadbuffer

    +

    luaL_loadbuffer

               int luaL_loadbuffer (lua_State *L, const char *buff,
                                    size_t sz, const char *name);
    @@ -3917,7 +3939,7 @@ 

    used for debug information and error messages.

    -


    luaL_loadfile

    +

    luaL_loadfile

               int luaL_loadfile (lua_State *L, const char *filename);
     
    @@ -3933,7 +3955,7 @@

    if it cannot open the file.

    -


    luaL_loadstring

    +

    luaL_loadstring

               int luaL_loadstring (lua_State *L, const char *s);
     
    @@ -3946,7 +3968,7 @@

    This function returns the same results as lua_load.

    -


    luaL_newmetatable

    +

    luaL_newmetatable

               int luaL_newmetatable (lua_State *L, const char *tname);
     
    @@ -3963,7 +3985,7 @@

    with "tname" in the registry.

    -


    luaL_newstate

    +

    luaL_newstate

               lua_State *luaL_newstate (void);
     
    @@ -3979,7 +4001,7 @@

    or NULL if there is a memory allocation error.

    -


    luaL_optint

    +

    luaL_optint

               int luaL_optint (lua_State *L, int narg, int d);
     
    @@ -3987,12 +4009,12 @@

    If the function argument narg is a number, returns that number casted to an int. -If that argument is absent or is nil, +If that argument is absent or is nil, returns d. Otherwise, raise an error.

    -


    luaL_optinteger

    +

    luaL_optinteger

               lua_Integer luaL_optinteger (lua_State *L, int nArg, lua_Integer d);
     
    @@ -4000,12 +4022,12 @@

    If the function argument narg is a number, returns that number casted to a lua_Integer. -If that argument is absent or is nil, +If that argument is absent or is nil, returns d. Otherwise, raise an error.

    -


    luaL_optlong

    +

    luaL_optlong

               long luaL_optlong (lua_State *L, int narg, long d);
     
    @@ -4013,12 +4035,12 @@

    If the function argument narg is a number, returns that number casted to a long. -If that argument is absent or is nil, +If that argument is absent or is nil, returns d. Otherwise, raise an error.

    -


    luaL_optlstring

    +

    luaL_optlstring

               const char *luaL_optlstring (lua_State *L, int numArg,
                                            const char *d, size_t *l);
    @@ -4027,7 +4049,7 @@ 

    If the function argument narg is a string, returns that string. -If that argument is absent or is nil, +If that argument is absent or is nil, returns d. Otherwise, raise an error. @@ -4035,7 +4057,7 @@

    with the results's length.

    -


    luaL_optnumber

    +

    luaL_optnumber

               lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number d);
     
    @@ -4043,12 +4065,12 @@

    If the function argument narg is a number, returns that number. -If that argument is absent or is nil, +If that argument is absent or is nil, returns d. Otherwise, raise an error.

    -


    luaL_optstring

    +

    luaL_optstring

               const char *luaL_optstring (lua_State *L, int narg, const char *d);
     
    @@ -4056,12 +4078,12 @@

    If the function argument narg is a string, returns that string. -If that argument is absent or is nil, +If that argument is absent or is nil, returns d. Otherwise, raise an error.

    -


    luaL_prepbuffer

    +

    luaL_prepbuffer

               char *luaL_prepbuffer (luaL_Buffer *B);
     
    @@ -4075,7 +4097,7 @@

    it to the buffer.

    -


    luaL_pushresult

    +

    luaL_pushresult

               void luaL_pushresult (luaL_Buffer *B);
     
    @@ -4085,7 +4107,7 @@

    the top of the stack.

    -


    luaL_ref

    +

    luaL_ref

               int luaL_ref (lua_State *L, int t);
     
    @@ -4102,13 +4124,13 @@

    calling lua_rawgeti(L, t, r). Function luaL_unref frees a reference and its associated object. -

    Whenever the object at the top of the stack is nil, +

    Whenever the object at the top of the stack is nil, luaL_ref returns the same reference LUA_REFNIL. The constant LUA_NOREF is garanteed to be different from any reference returned by luaL_ref.

    -


    luaL_Reg

    +

    luaL_Reg

               typedef struct luaL_Reg {
                 const char *name;
    @@ -4126,7 +4148,7 @@ 

    wherein both name and func are NULL.

    -


    luaL_register

    +

    luaL_register

               void luaL_register (lua_State *L, const char *libname,
                                   const luaL_Reg *l);
    @@ -4152,7 +4174,7 @@ 

    on the top of the stack.

    -


    luaL_typename

    +

    luaL_typename

               const char *luaL_typename (lua_State *L, int idx);
     
    @@ -4161,22 +4183,22 @@

    Returns the name of the type of the value at index idx.

    -


    luaL_typerror

    +

    luaL_typerror

               int luaL_typerror (lua_State *L, int narg, const char *tname);
     

    Generates an error with a message like -

    +
     <location>: bad argument <narg> to <function> (<tname> expected, got <realt>)
    -
    +
    where <location> is produced by luaL_where, <function> is the name of the current function, and <realt> is the type name of the actual argument.

    -


    luaL_unref

    +

    luaL_unref

               void luaL_unref (lua_State *L, int t, int ref);
     
    @@ -4192,7 +4214,7 @@

    luaL_unref does nothing.

    -


    luaL_where

    +

    luaL_where

               void luaL_where (lua_State *L, int lvl);
     
    @@ -4255,14 +4277,14 @@

    you should check carefully whether you need to provide some alternative implementation for some of its facilities. -


    assert (v [, message])

    +


    assert (v [, message])

    Issues an error when -the value of its argument v is nil or false; +the value of its argument v is nil or false; otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!" -


    collectgarbage (opt [, arg])

    +


    collectgarbage (opt [, arg])

    This function is a generic interface to the garbage collector. It performs different functions according to its first argument, opt: @@ -4276,6 +4298,7 @@

    (larger values mean more steps) in a non-specified way. If you want to control the step size you must tune experimentally the value of arg. +Returns true if that step finished a collection cycle.
  • "steppause" sets arg/100 as the new value for the pause of the collector (see 2.10). @@ -4284,7 +4307,7 @@

    the collector (see 2.10). -


    dofile (filename)

    +


    dofile (filename)

    Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). @@ -4292,7 +4315,7 @@

    In case of errors, dofile propagates the error to its caller (that is, it does not run in protected mode). -


    error (message [, level])

    +


    error (message [, level])

    Terminates the last protected function called and returns message as the error message. Function error never returns. @@ -4307,14 +4330,14 @@

    Passing a level 0 avoids the addition of error position information to the message. -


    _G

    +


    _G

    A global variable (not a function) that holds the global environment (that is, _G._G = _G). Lua itself does not use this variable; changing its value does not affect any environment. (Use setfenv to change environments.) -


    getfenv (f)

    +


    getfenv (f)

    Returns the current environment in use by the function. f can be a Lua function or a number, which specifies the function at that stack level: @@ -4324,73 +4347,73 @@

    getfenv returns the global environment. The default for f is 1. -


    getmetatable (object)

    +


    getmetatable (object)

    -

    If object does not have a metatable, returns nil. +

    If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a "__metatable" field, returns the associated value. Otherwise, returns the metatable of the given object. -


    ipairs (t)

    +


    ipairs (t)

    Returns an iterator function, the table t, and 0, so that the construction -

    +
            for i,v in ipairs(t) do ... end
    -
    +
    will iterate over the pairs (1,t[1]), (2,t[2]), ..., up to the first integer key with a nil value in the table. -


    load (func [, chunkname])

    +


    load (func [, chunkname])

    Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates with previous results. -A return of nil (or no value) signals the end of the chunk. +A return of nil (or no value) signals the end of the chunk.

    If there are no errors, returns the compiled chunk as a function; -otherwise, returns nil plus the error message. +otherwise, returns nil plus the error message. The environment of the returned function is the global environment.

    chunkname is used as the chunk name for error messages and debug information. -


    loadfile (filename)

    +


    loadfile (filename)

    Similar to load, but gets the chunk from file filename. -


    loadstring (string [, chunkname])

    +


    loadstring (string [, chunkname])

    Similar to load, but gets the chunk from the given string.

    To load and run a given string, use the idiom -

    +
           assert(loadstring(s))()
    -
    +
    -


    next (table [, index])

    +


    next (table [, index])

    Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. next returns the next index of the table and the value associated with the index. -When called with nil as its second argument, +When called with nil as its second argument, next returns the first index of the table and its associated value. When called with the last index, -or with nil in an empty table, -next returns nil. -If the second argument is absent, then it is interpreted as nil. +or with nil in an empty table, +next returns nil. +If the second argument is absent, then it is interpreted as nil.

    Lua has no declaration of fields; There is no difference between a -field not present in a table or a field with value nil. -Therefore, next only considers fields with non-nil values. +field not present in a table or a field with value nil. +Therefore, next only considers fields with non-nil values. The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, @@ -4400,16 +4423,16 @@

    during the traversal, you assign any value to a non-existent field in the table. -


    pairs (t)

    +


    pairs (t)

    -

    Returns the next function and the table t (plus a nil), +

    Returns the next function and the table t (plus a nil), so that the construction -

    +
            for k,v in pairs(t) do ... end
    -
    -will iterate over all key–value pairs of table t. +
    +will iterate over all key--value pairs of table t. -


    pcall (f, arg1, arg2, ...)

    +


    pcall (f, arg1, arg2, ...)

    Calls function f with the given arguments in protected mode. @@ -4420,9 +4443,9 @@

    which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. -In case of any error, pcall returns false plus the error message. +In case of any error, pcall returns false plus the error message. -


    print (e1, e2, ...)

    +


    print (e1, e2, ...)

    Receives any number of arguments, and prints their values in stdout, using the tostring function to convert them to strings. @@ -4431,32 +4454,32 @@

    typically for debugging. For formatted output, use format (see 5.4). -


    rawequal (v1, v2)

    +


    rawequal (v1, v2)

    Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean. -


    rawget (table, index)

    +


    rawget (table, index)

    Gets the real value of table[index], without invoking any metamethod. table must be a table; -index is any value different from nil. +index is any value different from nil. -


    rawset (table, index, value)

    +


    rawset (table, index, value)

    Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, -index is any value different from nil, +index is any value different from nil, and value is any Lua value. -


    select (index, ...)

    +


    select (index, ...)

    If index is a number, returns all argument after argument number index. Otherwise, index must be the string "#", and select returns the total number of extra arguments it received. -


    setfenv (f, table)

    +


    setfenv (f, table)

    Sets the environment to be used by the given function. f can be a Lua function or a number, @@ -4468,22 +4491,22 @@

    the environment of the running thread. In this case, setfenv returns no values. -


    setmetatable (table, metatable)

    +


    setmetatable (table, metatable)

    Sets the metatable for the given table. (You cannot change the metatable of other types from Lua.) -If metatable is nil, +If metatable is nil, removes the metatable of the given table. If the original metatable has a "__metatable" field, raises an error.

    This function returns table. -


    tonumber (e [, base])

    +


    tonumber (e [, base])

    Tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns that number; -otherwise, it returns nil. +otherwise, it returns nil.

    An optional argument specifies the base to interpret the numeral. The base may be any integer between 2 and 36, inclusive. @@ -4494,7 +4517,7 @@

    as well as an optional exponent part (see 2.2.1). In other bases, only unsigned integers are accepted. -


    tostring (e)

    +


    tostring (e)

    Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, @@ -4505,10 +4528,10 @@

    with e as argument, and uses the result of the call as its result. -


    type (v)

    +


    type (v)

    Returns the type of its only argument, coded as a string. The possible results of this function are -"nil" (a string, not the value nil), +"nil" (a string, not the value nil), "number", "string", "boolean, @@ -4517,23 +4540,23 @@

    "thread", and "userdata". -


    unpack (list [, i [, j]])

    +


    unpack (list [, i [, j]])

    Returns the elements from the given list. This function is equivalent to -
    +
       return list[i], list[i+1], ..., list[j]
    -
    +
    except that the above code can be written only for a fixed number of elements. By default, i is 1 and j is the length of the list, as defined by the length operator. -


    _VERSION

    +


    _VERSION

    A global variable (not a function) that holds a string containing the current interpreter version. The current contents of this variable is "Lua 5.1". -


    xpcall (f, err)

    +


    xpcall (f, err)

    This function is similar to pcall, except that you can set a new error handler. @@ -4557,14 +4580,14 @@

    the basic library and come inside the table coroutine. See 2.11 for a general description of coroutines. -


    coroutine.create (f)

    +


    coroutine.create (f)

    Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". -


    coroutine.resume (co, val1, ...)

    +


    coroutine.resume (co, val1, ...)

    Starts or continues the execution of coroutine co. The first time you resume a coroutine, @@ -4575,18 +4598,18 @@

    the arguments val1, ... go as the results from the yield.

    If the coroutine runs without any errors, -resume returns true plus any values passed to yield +resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, -resume returns false plus the error message. +resume returns false plus the error message. -


    coroutine.running ()

    +


    coroutine.running ()

    Returns the running coroutine, -or nil when called by the main thread. +or nil when called by the main thread. -


    coroutine.status (co)

    +


    coroutine.status (co)

    Returns the status of coroutine co, as a string: "running", @@ -4598,7 +4621,7 @@

    and "dead" if the coroutine has finished its body function, or if it has stopped with an error. -


    coroutine.wrap (f)

    +


    coroutine.wrap (f)

    Creates a new coroutine, with body f. f must be a Lua function. @@ -4609,7 +4632,7 @@

    except the first boolean. In case of error, propagates the error. -


    coroutine.yield (val1, ...)

    +


    coroutine.yield (val1, ...)

    Suspends the execution of the calling coroutine. The coroutine cannot be running neither a C function, @@ -4624,7 +4647,7 @@

    require and module. Everything else is exported in a table package. -


    module (name [, ...])

    +


    module (name [, ...])

    Creates a module. If there is a table in package.loaded[name], @@ -4654,7 +4677,7 @@

    the module name, where each option is a function to be applied over the module. -


    require (modname)

    +


    require (modname)

    Loads the given module. The function starts by looking into the table package.loaded @@ -4682,9 +4705,9 @@

    The name of that C function is the string "luaopen_" concatenated with a copy of the module name wherein each dot is replaced by an underscore. -Moreover, if the module name has a colon, -its prefix up to (and including) the first colon is removed. -For instance, if the module name is a.v1:b.c, +Moreover, if the module name has a hyphen, +its prefix up to (and including) the first hyphen is removed. +For instance, if the module name is a.v1-b.c, the function name will be luaopen_b_c.

    If require finds neither a Lua library nor a @@ -4715,7 +4738,7 @@

    or if it cannot find any loader for that module, then require signals an error. -


    package.cpath

    +


    package.cpath

    The path used by require to search for a C loader. @@ -4724,7 +4747,7 @@

    using the environment variable LUA_CPATH (plus another compiled-defined default path). -


    package.loaded

    +


    package.loaded

    A table used by require to control which modules are already loaded. @@ -4732,7 +4755,7 @@

    package.loaded[modname] is not false, require simply returns the value stored there. -


    package.loadlib (libname, funcname)

    +


    package.loadlib (libname, funcname)

    Links the program with the dynamic C library libname. Inside this library, looks for a function funcname @@ -4746,7 +4769,7 @@

    (Windows, Linux, Solaris, BSD, plus other Unix systems that support the dlfcn standard). -


    package.path

    +


    package.path

    The path used by require to search for a Lua loader. @@ -4764,20 +4787,20 @@

    "directory separator" (such as "/" in Unix); then it will try to load the resulting file name. So, for instance, if the Lua path is -
    +
       "./?.lua;./?.lc;/usr/local/?/init.lua"
    -
    +
    the search for a Lua loader for module mod will try to load the files ./mod.lua, ./mod.lc, and /usr/local/mod/init.lua, in that order. -


    package.preload

    +


    package.preload

    A table to store loaders for specific modules (see require). -


    package.seeall (module)

    +


    package.seeall (module)

    Sets a metatable for module with its __index field refering to the global environment, @@ -4803,7 +4826,7 @@

    For instance, string.byte(s, i) can be written as s:byte(i). -


    string.byte (s [, i [, j]])

    +


    string.byte (s [, i [, j]])

    Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; @@ -4811,7 +4834,7 @@

    Note that numerical codes are not necessarily portable across platforms. -


    string.char (i1, i2, ...)

    +


    string.char (i1, i2, ...)

    Receives 0 or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal @@ -4819,29 +4842,34 @@

    Note that numerical codes are not necessarily portable across platforms. -


    string.dump (function)

    +


    string.dump (function)

    Returns a binary representation of the given function, so that a later loadstring on that string returns a copy of the function. function must be a Lua function. -


    string.find (s, pattern [, init [, plain]])

    +


    string.find (s, pattern [, init [, plain]])

    Looks for the first match of pattern in the string s. If it finds one, then find returns the indices of s where this occurrence starts and ends; -otherwise, it returns nil. +otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. -A value of true as a fourth, optional argument plain +A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then init must be given too. -


    string.format (formatstring, e1, e2, ...)

    +

    If the pattern has captures, +then in a successful match +the captured values are also returned, +after the two indices. + +


    string.format (formatstring, e1, e2, ...)

    Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of @@ -4856,14 +4884,14 @@

    and all double quotes, newlines, and backslashes in the string are correctly escaped when written. For instance, the call -
    +
            string.format('%q', 'a string with "quotes" and \n new line')
    -
    +
    will produce the string: -
    +
     "a string with \"quotes\" and \
      new line"
    -
    +

    The options c, d, E, e, f, g, G, i, o, u, X, and x all @@ -4873,7 +4901,7 @@

    This function does not accept string values containing embedded zeros. -


    string.gmatch (s, pat)

    +


    string.gmatch (s, pat)

    Returns an iterator function that, each time it is called, returns the next captures from pattern pat over string s. @@ -4882,25 +4910,25 @@

    then the whole match is produced in each call.

    As an example, the following loop -

    +
       s = "hello world from Lua"
       for w in string.gmatch(s, "%a+") do
         print(w)
       end
    -
    +
    will iterate over all the words from string s, printing one per line. The next example collects all pairs key=value from the given string into a table: -
    +
       t = {}
       s = "from=world, to=Lua"
       for k, v in string.gmatch(s, "(%w+)=(%w+)") do
         t[k] = v
       end
    -
    +
    -


    string.gsub (s, pat, repl [, n])

    +


    string.gsub (s, pat, repl [, n])

    Returns a copy of s in which all occurrences of the pattern pat have been replaced by a replacement string specified by repl. @@ -4920,9 +4948,16 @@

    in order; if the pattern specifies no captures, then the whole match is passed as a sole argument. -If the value returned by this function is a string, +If repl is a table, then this table is queried with the +value of the first capture or of the whole match, +if the pattern specifies no captures. +In both cases, +if the value returned by the function or resulted by the query +is a string, then it is used as the replacement string; -otherwise, the replacement string is the empty string. +otherwise, if it is false or nil, +then there is no replacement +(that is, the original match is kept in the string).

    The optional last parameter n limits the maximum number of substitutions to occur. @@ -4930,7 +4965,7 @@

    pat is replaced.

    Here are some examples: -

    +
        x = string.gsub("hello world", "(%w+)", "%1 %1")
        --> x="hello hello world world"
     
    @@ -4949,44 +4984,42 @@ 

    --> x="4+5 = 9" local t = {name="lua", version="5.0"} - x = string.gsub("$name_$version.tar.gz", "%$(%w+)", function (v) - return t[v] - end) + x = string.gsub("$name_$version.tar.gz", "%$(%w+)", t) --> x="lua_5.0.tar.gz" -

    +
    -


    string.len (s)

    +


    string.len (s)

    Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5. -


    string.lower (s)

    +


    string.lower (s)

    Receives a string and returns a copy of that string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what is an uppercase letter depends on the current locale. -


    string.match (s, pattern [, init])

    +


    string.match (s, pattern [, init])

    Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; -otherwise it returns nil. +otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. -


    string.rep (s, n)

    +


    string.rep (s, n)

    Returns a string that is the concatenation of n copies of the string s. -


    string.reverse (s)

    +


    string.reverse (s)

    Returns a string that is the string s reversed. -


    string.sub (s, i [, j])

    +


    string.sub (s, i [, j])

    Returns the substring of s that starts at i and continues until j; i and j may be negative. @@ -4998,7 +5031,7 @@

    and string.sub(s, -i) returns a suffix of s with length i. -


    string.upper (s)

    +


    string.upper (s)

    Receives a string and returns a copy of that string with all lowercase letters changed to uppercase. All other characters are left unchanged. @@ -5012,26 +5045,26 @@

    • x (where x is not one of the magic characters ^$()%.[]*+-?) -— represents the character x itself. -
    • . — (a dot) represents all characters. -
    • %a — represents all letters. -
    • %c — represents all control characters. -
    • %d — represents all digits. -
    • %l — represents all lowercase letters. -
    • %p — represents all punctuation characters. -
    • %s — represents all space characters. -
    • %u — represents all uppercase letters. -
    • %w — represents all alphanumeric characters. -
    • %x — represents all hexadecimal digits. -
    • %z — represents the character with representation 0. -
    • %x (where x is any non-alphanumeric character) — +--- represents the character x itself. +
    • . --- (a dot) represents all characters. +
    • %a --- represents all letters. +
    • %c --- represents all control characters. +
    • %d --- represents all digits. +
    • %l --- represents all lowercase letters. +
    • %p --- represents all punctuation characters. +
    • %s --- represents all space characters. +
    • %u --- represents all uppercase letters. +
    • %w --- represents all alphanumeric characters. +
    • %x --- represents all hexadecimal digits. +
    • %z --- represents the character with representation 0. +
    • %x (where x is any non-alphanumeric character) --- represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic) can be preceded by a `%´ when used to represent itself in a pattern. -

    • [set] — +

    • [set] --- represents the class which is the union of all characters in set. A range of characters may be specified by @@ -5049,7 +5082,7 @@

      Therefore, patterns like [%a-z] or [a-%%] have no meaning. -

    • [^set] — +

    • [^set] --- represents the complement of set, where set is interpreted as above.
    @@ -5135,30 +5168,14 @@

    For those functions, when we talk about "the length" of a table we mean the result of the length operator. -


    table.concat (table [, sep [, i [, j]]])

    +


    table.concat (table [, sep [, i [, j]]])

    Returns table[i]..sep..table[i+1] ... sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string. -


    table.sort (table [, comp])

    -Sorts table elements in a given order, in-place, -from table[1] to table[n], -where n is the length of the table. -If comp is given, -then it must be a function that receives two table elements, -and returns true -when the first is less than the second -(so that not comp(a[i+1],a[i]) will be true after the sort). -If comp is not given, -then the standard Lua operator < is used instead. - -

    The sort algorithm is not stable, -that is, elements considered equal by the given order -may have their relative positions changed by the sort. - -


    table.insert (table, [pos,] value)

    +


    table.insert (table, [pos,] value)

    Inserts element value at position pos in table, shifting up other elements to open space, if necessary. @@ -5167,7 +5184,12 @@

    so that a call table.insert(t,x) inserts x at the end of table t. -


    table.remove (table [, pos])

    +


    table.maxn(table)

    + +

    Returns the largest positive numerical index of the given table, +or zero if the table has no positive numerical indices. + +


    table.remove (table [, pos])

    Removes from table the element at position pos, shifting down other elements to close the space, if necessary. @@ -5177,26 +5199,42 @@

    so that a call table.remove(t) removes the last element of table t. +


    table.sort (table [, comp])

    +Sorts table elements in a given order, in-place, +from table[1] to table[n], +where n is the length of the table. +If comp is given, +then it must be a function that receives two table elements, +and returns true +when the first is less than the second +(so that not comp(a[i+1],a[i]) will be true after the sort). +If comp is not given, +then the standard Lua operator < is used instead. + +

    The sort algorithm is not stable, +that is, elements considered equal by the given order +may have their relative positions changed by the sort. +

    5.6 - Mathematical Functions

    This library is an interface to the standard C math library. It provides all its functions inside the table math. The library provides the following functions: - - - - - - - -

    +
    +
    +
    +
    +
    +
    +
    +
            math.abs     math.acos    math.asin    math.atan    math.atan2
            math.ceil    math.cosh    math.cos     math.deg     math.exp
            math.floor   math.fmod    math.frexp   math.ldexp   math.log
            math.log10   math.max     math.min     math.modf    math.pow
            math.rad     math.random  math.randomseed           math.sin
            math.sinh    math.sqrt    math.tan     math.tanh
    -
    +
    plus a variable math.pi and a variable math.huge, with the value HUGE_VAL. @@ -5255,20 +5293,20 @@

    io.stdin, io.stdout, and io.stderr.

    Unless otherwise stated, -all I/O functions return nil on failure +all I/O functions return nil on failure (plus an error message as a second result) -and some value different from nil on success. +and some value different from nil on success. -


    io.close ([file])

    +


    io.close ([file])

    Equivalent to file:close(). Without a file, closes the default output file. -


    io.flush ()

    +


    io.flush ()

    Equivalent to file:flush over the default output file. -


    io.input ([file])

    +


    io.input ([file])

    When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. @@ -5280,31 +5318,31 @@

    In case of errors this function raises the error, instead of returning an error code. -


    io.lines ([filename])

    +


    io.lines ([filename])

    Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction -

    +
            for line in io.lines(filename) do ... end
    -
    +
    will iterate over all lines of the file. When the iterator function detects the end of file, -it returns nil (to finish the loop) and automatically closes the file. +it returns nil (to finish the loop) and automatically closes the file.

    The call io.lines() (without a file name) is equivalent to io.input():lines(), that is, it iterates over the lines of the default input file. In that case it does not close the file when the loop ends. -


    io.open (filename [, mode])

    +


    io.open (filename [, mode])

    This function opens a file, in the mode specified in the string mode. It returns a new file handle, -or, in case of errors, nil plus an error message. +or, in case of errors, nil plus an error message.

    The mode string can be any of the following:

      @@ -5321,11 +5359,11 @@

      This string is exactly what is used in the standard C function fopen. -


      io.output ([file])

      +


      io.output ([file])

      Similar to io.input, but operates over the default output file. -


      io.popen ([prog [, mode]])

      +


      io.popen ([prog [, mode]])

      Starts program prog in a separated process and returns a file handle that you can use to read data from that program @@ -5336,57 +5374,57 @@

      This function is system dependent and is not available in all platforms. -


      io.read (format1, ...)

      +


      io.read (format1, ...)

      Equivalent to io.input():read. -


      io.tmpfile ()

      +


      io.tmpfile ()

      Returns a handle for a temporary file. This file is open in update mode and it is automatically removed when the program ends. -


      io.type (obj)

      +


      io.type (obj)

      Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, -and nil if obj is not a file handle. +and nil if obj is not a file handle. -


      io.write (value1, ...)

      +


      io.write (value1, ...)

      Equivalent to io.output():write. -


      file:close ()

      +


      file:close ()

      Closes file. Note that files are automatically closed when garbage collected, but that takes an unpredictable time to happen. -


      file:flush ()

      +


      file:flush ()

      Saves any written data to file. -


      file:lines ()

      +


      file:lines ()

      Returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction -

      +
              for line in file:lines() do ... end
      -
      +
      will iterate over all lines of the file. (Unlike io.lines, this function does not close the file when the loop ends.) -


      file:read (format1, ...)

      +


      file:read (format1, ...)

      Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, -or nil if it cannot read data with the specified format. +or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below). @@ -5398,16 +5436,16 @@

    • "*a" reads the whole file, starting at the current position. On end of file, it returns the empty string.
    • "*l" reads the next line (skipping the end of line), -returning nil on end of file. +returning nil on end of file. This is the default format.
    • number reads a string with up to that number of characters, -returning nil on end of file. +returning nil on end of file. If number is zero, it reads nothing and returns an empty string, -or nil on end of file. +or nil on end of file.
    -


    file:seek ([whence] [, offset])

    +


    file:seek ([whence] [, offset])

    Sets and gets the file position, measured from the beginning of the file, @@ -5420,7 +5458,7 @@

    In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. -If this function fails, it returns nil, +If this function fails, it returns nil, plus a string describing the error.

    The default value for whence is "cur", @@ -5432,7 +5470,7 @@

    and the call file:seek("end") sets the position to the end of the file, and returns its size. -


    file:setvbuf (mode [, size])

    +


    file:setvbuf (mode [, size])

    Sets the buffering mode for an output file. There are three available modes: @@ -5448,7 +5486,7 @@

    specifies the size of the buffer, in bytes. The default is an appropriate size. -


    file:write (value1, ...)

    +


    file:write (value1, ...)

    Writes the value of each of its arguments to the filehandle file. @@ -5460,12 +5498,12 @@

    This library is implemented through table os. -


    os.clock ()

    +


    os.clock ()

    Returns an approximation of the amount of CPU time used by the program, in seconds. -


    os.date ([format [, time]])

    +


    os.date ([format [, time]])

    Returns a string or a table containing date and time, formatted according to the given string format. @@ -5495,43 +5533,43 @@

    the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")). -


    os.difftime (t2, t1)

    +


    os.difftime (t2, t1)

    Returns the number of seconds from time t1 to time t2. In Posix, Windows, and some other systems, this value is exactly t2-t1. -


    os.execute (command)

    +


    os.execute (command)

    This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. -


    os.exit ([code])

    +


    os.exit ([code])

    Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. -


    os.getenv (varname)

    +


    os.getenv (varname)

    Returns the value of the process environment variable varname, -or nil if the variable is not defined. +or nil if the variable is not defined. -


    os.remove (filename)

    +


    os.remove (filename)

    Deletes the file with the given name. -If this function fails, it returns nil, +If this function fails, it returns nil, plus a string describing the error. -


    os.rename (oldname, newname)

    +


    os.rename (oldname, newname)

    Renames file named oldname to newname. -If this function fails, it returns nil, +If this function fails, it returns nil, plus a string describing the error. -


    os.setlocale (locale [, category])

    +


    os.setlocale (locale [, category])

    Sets the current locale of the program. locale is a string specifying a locale; @@ -5540,9 +5578,9 @@

    "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, -or nil if the request cannot be honored. +or nil if the request cannot be honored. -


    os.time ([table])

    +


    os.time ([table])

    Returns the current time when called without arguments, or a time representing the date and time specified by the given table. @@ -5557,7 +5595,7 @@

    and the number returned by time can be used only as an argument to date and difftime. -


    os.tmpname ()

    +


    os.tmpname ()

    Returns a string with a file name that can be used for a temporary file. @@ -5583,7 +5621,7 @@

    All functions in this library are provided inside a debug table. -


    debug.debug ()

    +


    debug.debug ()

    Enters an interactive mode with the user, running each string that the user enters. @@ -5596,17 +5634,17 @@

    Note that commands for debug.debug are not lexically nested with any function, so they have no direct access to local variables. -


    debug.getfenv (o)

    +


    debug.getfenv (o)

    Returns the environment of object o. -


    debug.gethook ()

    +


    debug.gethook ()

    Returns the current hook settings, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function). -


    debug.getinfo (function [, what])

    +


    debug.getinfo (function [, what])

    This function returns a table with information about a function. You can give the function directly, @@ -5616,7 +5654,7 @@

    level 1 is the function that called getinfo; and so on. If function is a number larger than the number of active functions, -then getinfo returns nil. +then getinfo returns nil.

    The returned table contains all the fields returned by lua_getinfo, with the string what describing which fields to fill in. @@ -5630,33 +5668,41 @@

    and debug.getinfo(print) returns a table with all available information about the print function. -


    debug.getlocal (level, local)

    +


    debug.getlocal (level, local)

    This function returns the name and the value of the local variable with index local of the function at level level of the stack. (The first parameter or local variable has index 1, and so on, until the last active local variable.) -The function returns nil if there is no local +The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.) -


    debug.getmetatable (object)

    +

    Variable names starting with `(´ (open parentheses) +represent internal variables +(loop control variables, temporaries, and C function locals). -

    If object does not have a metatable, returns nil. +


    debug.getmetatable (object)

    + +

    If object does not have a metatable, returns nil. Otherwise, returns the metatable of the given object. -


    debug.getupvalue (func, up)

    +


    debug.getregistry ()

    + +

    Returns the registry table (see 3.5). + +


    debug.getupvalue (func, up)

    This function returns the name and the value of the upvalue with index up of the function func. -The function returns nil if there is no upvalue with the given index. +The function returns nil if there is no upvalue with the given index. -


    debug.setfenv (o, table)

    +


    debug.setfenv (o, table)

    Sets the environment of the given object. -


    debug.sethook (hook, mask [, count])

    +


    debug.sethook (hook, mask [, count])

    Sets the given function as a hook. The string mask and the number count describe @@ -5689,29 +5735,29 @@

    In this case, Lua is only simulating the return, and a call to getinfo will return invalid data. -


    debug.setlocal (level, local, value)

    +


    debug.setlocal (level, local, value)

    This function assigns the value value to the local variable with index local of the function at level level of the stack. -The function returns nil if there is no local +The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable. -


    debug.setmetatable (o, metatable)

    +


    debug.setmetatable (o, metatable)

    Sets the metatable for the given object. -


    debug.setupvalue (func, up, value)

    +


    debug.setupvalue (func, up, value)

    This function assigns the value value to the upvalue with index up of the function func. -The function returns nil if there is no upvalue +The function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue. -


    debug.traceback ([message])

    +


    debug.traceback ([message])

    Returns a string with a traceback of the call stack. An optional message string is appended @@ -5731,17 +5777,17 @@

    The stand-alone interpreter includes all standard libraries plus the reflexive debug interface. Its usage is: -
    +
           lua [options] [script [args]]
    -
    +
    The options are:
      -
    • - executes stdin as a file;
    • -e stat executes string stat;
    • -l mod "requires" mod;
    • -i enters interactive mode after running script;
    • -v prints version information; -
    • -- stop handling options. +
    • -- stops handling options; +
    • - executes stdin as a file and stops handling options.
    After handling its options, lua runs the given script, passing to it the given args. @@ -5757,9 +5803,9 @@

    All options are handled in order, except -i. For instance, an invocation like -

    +
            $ lua -e'a=1' -e 'print(a)' script.lua
    -
    +
    will first set a to 1, then print a, and finally run the file script.lua. (Here $ is the shell prompt. Your prompt may be different.) @@ -5774,15 +5820,15 @@

    (that is, the interpreter name plus the options) go to negative indices. For instance, in the call -
    +
            $ lua -la.lua b.lua t1 t2
    -
    +
    the interpreter first runs the file a.lua, then creates a table -
    +
            arg = { [-2] = "lua", [-1] = "-la.lua", [0] = "b.lua",
                    [1] = "t1", [2] = "t2" }
    -
    +
    and finally runs the file b.lua. The script is called with arg[1], arg[2], ... as arguments; @@ -5795,9 +5841,9 @@

    If the global variable _PROMPT is defined as a string, then its value is used as the prompt. Therefore, the prompt can be changed directly on the command line: -

    +
            $ lua -e"_PROMPT='myprompt> '" -i
    -
    +
    (the outer pair of quotes is for the shell, the inner is for Lua), or in any Lua programs by assigning to _PROMPT. @@ -5811,19 +5857,19 @@

    Therefore, Lua scripts can be made into executable programs by using chmod +x and the #! form, as in -
    +
     #!/usr/local/bin/lua
    -
    +
    (Of course, the location of the Lua interpreter may be different in your machine. If lua is in your PATH, then -
    +
     #!/usr/bin/env lua
    -
    +
    is a more portable solution.) -


    +


    Incompatibilities with Previous Version

    @@ -5866,6 +5912,13 @@

    Function string.gfind was renamed string.gmatch. (Option LUA_COMPAT_GFIND) +

  • +When string.gsub is called with a function as its +third argument, +whenever that function returns nil or false the +replacement string is the whole match, +instead of the empty string. +

  • Function table.setn was deprecated. Function table.getn corresponds @@ -5924,48 +5977,66 @@

     
    -

    chunk ::= {stat [`;´]} + chunk ::= {stat [`;´]} [laststat[`;´]] + + block ::= chunk -

    block ::= chunk + stat ::= varlist1 `=´ explist1 | + functioncall | + do block end | + while exp do block end | + repeat block until exp | + if exp then block {elseif exp then block} [else block] end | + for Name `=´ exp `,´ exp [`,´ exp] do block end | + for namelist in explist1 do block end | + function funcname funcbody | + local function Name funcbody | + local namelist [init] -

    stat ::= varlist1 `=´ explist1 | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | return [explist1] | break | for Name `=´ exp `,´ exp [`,´ exp] do block end | for namelist in explist1 do block end | function funcname funcbody | local function Name funcbody | local namelist [init] + laststat ::= return [explist1] | break -

    funcname ::= Name {`.´ Name} [`:´ Name] + funcname ::= Name {`.´ Name} [`:´ Name] + + varlist1 ::= var {`,´ var} -

    varlist1 ::= var {`,´ var} + var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name -

    var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name + namelist ::= Name {`,´ Name} -

    namelist ::= Name {`,´ Name} + init ::= `=´ explist1 -

    init ::= `=´ explist1 + explist1 ::= {exp `,´} exp -

    explist1 ::= {exp `,´} exp + exp ::= nil | false | true | Number | Literal | `...´ | + function | prefixexp | tableconstructor | exp binop exp | unop exp -

    exp ::= nil | false | true | Number | Literal | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp + prefixexp ::= var | functioncall | `(´ exp `)´ -

    prefixexp ::= var | functioncall | `(´ exp `)´ + functioncall ::= prefixexp args | prefixexp `:´ Name args -

    functioncall ::= prefixexp args | prefixexp `:´ Name args + args ::= `(´ [explist1] `)´ | tableconstructor | Literal -

    args ::= `(´ [explist1] `)´ | tableconstructor | Literal + function ::= function funcbody -

    function ::= function funcbody + funcbody ::= `(´ [parlist1] `)´ block end -

    funcbody ::= `(´ [parlist1] `)´ block end + parlist1 ::= namelist [`,´ `...´] | `...´ -

    parlist1 ::= namelist [`,´ `...´] | `...´ + tableconstructor ::= `{´ [fieldlist] `}´ -

    tableconstructor ::= `{´ [fieldlist] `}´ fieldlist ::= field {fieldsep field} [fieldsep] - field ::= `[´ exp `]´ `=´ exp | name `=´ exp | exp - fieldsep ::= `,´ | `;´ -

    binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | and | or + field ::= `[´ exp `]´ `=´ exp | name `=´ exp | exp -

    unop ::= `-´ | not | `#´ + fieldsep ::= `,´ | `;´ -

    + binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | + `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | + and | or + + unop ::= `-´ | not | `#´ + +

  • @@ -5974,7 +6045,7 @@


    Last update: -Wed Sep 7 13:53:49 BRT 2005 +Tue Nov 1 15:20:21 BRST 2005 diff --git a/src/lapi.c b/src/lapi.c index b85e1dc54b..71daabdae8 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.48 2005/09/01 17:42:22 roberto Exp $ +** $Id: lapi.c,v 2.51 2005/10/20 11:35:50 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -141,7 +141,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { setthvalue(L, L->top, L1); api_incr_top(L); lua_unlock(L); - luai_userstateopen(L1); + luai_userstatethread(L, L1); return L1; } @@ -913,6 +913,10 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { res = cast(int, g->totalbytes >> 10); break; } + case LUA_GCCOUNTB: { + res = cast(int, g->totalbytes & 0x3ff); + break; + } case LUA_GCSTEP: { lu_mem a = (cast(lu_mem, data) << 10); if (a <= g->totalbytes) @@ -992,8 +996,20 @@ LUA_API void lua_concat (lua_State *L, int n) { LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { + lua_Alloc f; + lua_lock(L); if (ud) *ud = G(L)->ud; - return G(L)->frealloc; + f = G(L)->frealloc; + lua_unlock(L); + return f; +} + + +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { + lua_lock(L); + G(L)->ud = ud; + G(L)->frealloc = f; + lua_unlock(L); } diff --git a/src/lauxlib.c b/src/lauxlib.c index b643d6c3ff..0462097975 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.152 2005/09/06 17:20:11 roberto Exp $ +** $Id: lauxlib.c,v 1.156 2005/10/21 13:47:42 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -176,8 +176,7 @@ LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { - if (lua_isnoneornil(L, narg)) return def; - else return luaL_checknumber(L, narg); + return luaL_opt(L, luaL_checknumber, narg, def); } @@ -190,16 +189,16 @@ LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, - lua_Integer def) { - if (lua_isnoneornil(L, narg)) return def; - else return luaL_checkinteger(L, narg); + lua_Integer def) { + return luaL_opt(L, luaL_checkinteger, narg, def); } LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; - lua_getfield(L, -1, event); + lua_pushstring(L, event); + lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 2); /* remove metatable and metafield */ return 0; @@ -231,7 +230,7 @@ LUALIB_API void luaI_openlib (lua_State *L, const char *libname, const luaL_Reg *l, int nup) { if (libname) { /* check whether lib already exists */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, -1, libname); /* get _LOADED[libname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ @@ -305,7 +304,7 @@ LUALIB_API int luaL_getn (lua_State *L, int t) { if ((n = checkint(L, 2)) >= 0) return n; lua_getfield(L, t, "n"); /* else try t.n */ if ((n = checkint(L, 1)) >= 0) return n; - return lua_objlen(L, t); + return (int)lua_objlen(L, t); } #endif @@ -470,7 +469,7 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ - ref = lua_objlen(L, t); + ref = (int)lua_objlen(L, t); ref++; /* create new reference */ } lua_rawseti(L, t, ref); diff --git a/src/lauxlib.h b/src/lauxlib.h index aa07cb2b00..ee503cc84a 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.85 2005/09/06 17:19:51 roberto Exp $ +** $Id: lauxlib.h,v 1.86 2005/10/21 13:47:42 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -114,6 +114,7 @@ LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) /* ** {====================================================== diff --git a/src/lbaselib.c b/src/lbaselib.c index fb21da4b19..7d8724a563 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.182 2005/08/26 17:36:32 roberto Exp $ +** $Id: lbaselib.c,v 1.186 2005/10/21 13:47:42 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -196,9 +196,23 @@ static int luaB_collectgarbage (lua_State *L) { static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; int o = luaL_checkoption(L, 1, "collect", opts); - int ex = luaL_optinteger(L, 2, 0); - lua_pushinteger(L, lua_gc(L, optsnum[o], ex)); - return 1; + int ex = luaL_optint(L, 2, 0); + int res = lua_gc(L, optsnum[o], ex); + switch (optsnum[o]) { + case LUA_GCCOUNT: { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, ((lua_Number)res*1024 + b)/1000); + return 1; + } + case LUA_GCSTEP: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushnumber(L, res); + return 1; + } + } } @@ -326,12 +340,10 @@ static int luaB_assert (lua_State *L) { static int luaB_unpack (lua_State *L) { - int i = luaL_optint(L, 2, 1); - int e = luaL_optint(L, 3, -1); - int n; + int i, e, n; luaL_checktype(L, 1, LUA_TTABLE); - if (e == -1) - e = luaL_getn(L, 1); + i = luaL_optint(L, 2, 1); + e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); n = e - i + 1; /* number of elements */ if (n <= 0) return 0; /* empty range */ luaL_checkstack(L, n, "table too big to unpack"); @@ -349,8 +361,9 @@ static int luaB_select (lua_State *L) { } else { int i = luaL_checkint(L, 1); - if (i <= 0) i = 1; - else if (i >= n) i = n; + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); return n - i; } } @@ -560,7 +573,7 @@ static int luaB_costatus (lua_State *L) { lua_pushliteral(L, "dead"); else lua_pushliteral(L, "suspended"); /* initial state */ - break; + break; } default: /* some error occured */ lua_pushliteral(L, "dead"); @@ -601,8 +614,11 @@ static void auxopen (lua_State *L, const char *name, static void base_open (lua_State *L) { + /* set global _G */ lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_register(L, NULL, base_funcs); /* open lib into global table */ + lua_setglobal(L, "_G"); + /* open lib into global table */ + luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); lua_setglobal(L, "_VERSION"); /* set global _VERSION */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */ @@ -616,12 +632,6 @@ static void base_open (lua_State *L) { lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); lua_setglobal(L, "newproxy"); /* set global `newproxy' */ - /* create register._LOADED to track loaded modules */ - lua_newtable(L); - lua_setfield(L, LUA_REGISTRYINDEX, "_LOADED"); - /* set global _G */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setglobal(L, "_G"); } diff --git a/src/lcode.c b/src/lcode.c index 04838f331e..ecda5cbfe2 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.16 2005/08/29 20:49:21 roberto Exp $ +** $Id: lcode.c,v 2.22 2005/11/16 11:55:27 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -27,16 +27,24 @@ #define hasjumps(e) ((e)->t != (e)->f) +static int isnumeral(expdesc *e) { + return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +} + + void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; - if (fs->pc > fs->lasttarget && /* no jumps to current position? */ - GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pto = GETARG_B(*previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(*previous, from+n-1); - return; + if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ + if (fs->pc == 0) /* function start? */ + return; /* positions are already clean */ + if (GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; + } } } luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ @@ -115,20 +123,22 @@ static int need_value (FuncState *fs, int list) { } -static void patchtestreg (Instruction *i, int reg) { - if (reg != NO_REG) +static int patchtestreg (FuncState *fs, int node, int reg) { + Instruction *i = getjumpcontrol(fs, node); + if (GET_OPCODE(*i) != OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(*i)) SETARG_A(*i, reg); - else /* no register to put value; change TESTSET to TEST */ + else /* no register to put value or register already has the value */ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); + + return 1; } static void removevalues (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) == OP_TESTSET) - patchtestreg(i, NO_REG); - } + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); } @@ -136,11 +146,8 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { int next = getjump(fs, list); - Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) == OP_TESTSET) { - patchtestreg(i, reg); + if (patchtestreg(fs, list, reg)) fixjump(fs, list, vtarget); - } else fixjump(fs, list, dtarget); /* jump to default target */ list = next; @@ -210,7 +217,7 @@ static void freereg (FuncState *fs, int reg) { static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) - freereg(fs, e->info); + freereg(fs, e->u.s.info); } @@ -280,7 +287,7 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ e->k = VNONRELOC; - e->info = GETARG_A(getcode(fs, e)); + e->u.s.info = GETARG_A(getcode(fs, e)); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), 2); @@ -296,19 +303,19 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VUPVAL: { - e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0); + e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } case VGLOBAL: { - e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info); + e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); e->k = VRELOCABLE; break; } case VINDEXED: { - freereg(fs, e->aux); - freereg(fs, e->info); - e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux); + freereg(fs, e->u.s.aux); + freereg(fs, e->u.s.info); + e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); e->k = VRELOCABLE; break; } @@ -340,7 +347,11 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VK: { - luaK_codeABx(fs, OP_LOADK, reg, e->info); + luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); + break; + } + case VKNUM: { + luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { @@ -349,8 +360,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VNONRELOC: { - if (reg != e->info) - luaK_codeABC(fs, OP_MOVE, reg, e->info, 0); + if (reg != e->u.s.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); break; } default: { @@ -358,7 +369,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { return; /* nothing to do... */ } } - e->info = reg; + e->u.s.info = reg; e->k = VNONRELOC; } @@ -374,15 +385,13 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) { static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) - luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */ + luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { - int fj = NO_JUMP; /* first jump (over LOAD ops.) */ - if (e->k != VJMP) - fj = luaK_jump(fs); + int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_label(fs, reg, 0, 1); p_t = code_label(fs, reg, 1, 0); luaK_patchtohere(fs, fj); @@ -392,7 +401,7 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; - e->info = reg; + e->u.s.info = reg; e->k = VNONRELOC; } @@ -408,14 +417,14 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); if (e->k == VNONRELOC) { - if (!hasjumps(e)) return e->info; /* exp is already in a register */ - if (e->info >= fs->nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e->info); /* put value on it */ - return e->info; + if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ + if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.s.info); /* put value on it */ + return e->u.s.info; } } luaK_exp2nextreg(fs, e); /* default */ - return e->info; + return e->u.s.info; } @@ -430,19 +439,22 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { + case VKNUM: case VTRUE: case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ - e->info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); + e->u.s.info = (e->k == VNIL) ? nilK(fs) : + (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : + boolK(fs, (e->k == VTRUE)); e->k = VK; - return RKASK(e->info); + return RKASK(e->u.s.info); } else break; } case VK: { - if (e->info <= MAXINDEXRK) /* constant fit in argC? */ - return RKASK(e->info); + if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ + return RKASK(e->u.s.info); else break; } default: break; @@ -456,22 +468,22 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); - exp2reg(fs, ex, var->info); + exp2reg(fs, ex, var->u.s.info); return; } case VUPVAL: { int e = luaK_exp2anyreg(fs, ex); - luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); break; } case VGLOBAL: { int e = luaK_exp2anyreg(fs, ex); - luaK_codeABx(fs, OP_SETGLOBAL, e, var->info); + luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); break; } case VINDEXED: { int e = luaK_exp2RK(fs, ex); - luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e); + luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); break; } default: { @@ -489,15 +501,15 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { freeexp(fs, e); func = fs->freereg; luaK_reserveregs(fs, 2); - luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key)); + luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); freeexp(fs, key); - e->info = func; + e->u.s.info = func; e->k = VNONRELOC; } static void invertjump (FuncState *fs, expdesc *e) { - Instruction *pc = getjumpcontrol(fs, e->info); + Instruction *pc = getjumpcontrol(fs, e->u.s.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); @@ -515,7 +527,7 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { } discharge2anyreg(fs, e); freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->info, cond); + return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); } @@ -523,7 +535,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { - case VK: case VTRUE: { + case VK: case VKNUM: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } @@ -533,7 +545,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } case VJMP: { invertjump(fs, e); - pc = e->info; + pc = e->u.s.info; break; } default: { @@ -547,7 +559,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } -void luaK_goiffalse (FuncState *fs, expdesc *e) { +static void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { @@ -560,7 +572,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { break; } case VJMP: { - pc = e->info; + pc = e->u.s.info; break; } default: { @@ -581,7 +593,7 @@ static void codenot (FuncState *fs, expdesc *e) { e->k = VTRUE; break; } - case VK: case VTRUE: { + case VK: case VKNUM: case VTRUE: { e->k = VFALSE; break; } @@ -593,7 +605,7 @@ static void codenot (FuncState *fs, expdesc *e) { case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0); + e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } @@ -610,34 +622,81 @@ static void codenot (FuncState *fs, expdesc *e) { void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - t->aux = luaK_exp2RK(fs, k); + t->u.s.aux = luaK_exp2RK(fs, k); t->k = VINDEXED; } +static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { + lua_Number v1, v2, r; + if (!isnumeral(e1) || !isnumeral(e2)) return 0; + v1 = e1->u.nval; + v2 = e2->u.nval; + switch (op) { + case OP_ADD: r = luai_numadd(v1, v2); break; + case OP_SUB: r = luai_numsub(v1, v2); break; + case OP_MUL: r = luai_nummul(v1, v2); break; + case OP_DIV: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_numdiv(v1, v2); break; + case OP_MOD: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_nummod(v1, v2); break; + case OP_POW: r = luai_numpow(v1, v2); break; + case OP_UNM: r = luai_numunm(v1); break; + case OP_LEN: return 0; /* no constant folding for 'len' */ + default: lua_assert(0); r = 0; break; + } + if (r != r) return 0; /* do not attempt to produce NaN */ + e1->u.nval = r; + return 1; +} + + +static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { + if (constfolding(op, e1, e2)) + return; + else { + int o1 = luaK_exp2RK(fs, e1); + int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; + freeexp(fs, e2); + freeexp(fs, e1); + e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); + e1->k = VRELOCABLE; + } +} + + +static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, + expdesc *e2) { + int o1 = luaK_exp2RK(fs, e1); + int o2 = luaK_exp2RK(fs, e2); + freeexp(fs, e2); + freeexp(fs, e1); + if (cond == 0 && op != OP_EQ) { + int temp; /* exchange args to replace by `<' or `<=' */ + temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ + cond = 1; + } + e1->u.s.info = condjump(fs, op, cond, o1, o2); + e1->k = VJMP; +} + + void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { + expdesc e2; + e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { case OPR_MINUS: { - luaK_exp2val(fs, e); - if (e->k == VK && ttisnumber(&fs->f->k[e->info])) - e->info = luaK_numberK(fs, luai_numunm(L, nvalue(&fs->f->k[e->info]))); - else { - luaK_exp2anyreg(fs, e); - freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0); - e->k = VRELOCABLE; - } - break; - } - case OPR_NOT: { - codenot(fs, e); + if (e->k == VK) + luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ + codearith(fs, OP_UNM, e, &e2); break; } + case OPR_NOT: codenot(fs, e); break; case OPR_LEN: { - luaK_exp2anyreg(fs, e); - freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_LEN, 0, e->info, 0); - e->k = VRELOCABLE; + luaK_exp2anyreg(fs, e); /* cannot operate on constants */ + codearith(fs, OP_LEN, e, &e2); break; } default: lua_assert(0); @@ -660,74 +719,58 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { break; } default: { - luaK_exp2RK(fs, v); + if (!isnumeral(v)) luaK_exp2RK(fs, v); break; } } } -static void codebinop (FuncState *fs, expdesc *res, BinOpr op, - int o1, int o2) { - if (op <= OPR_POW) { /* arithmetic operator? */ - OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD); /* ORDER OP */ - res->info = luaK_codeABC(fs, opc, 0, o1, o2); - res->k = VRELOCABLE; - } - else { /* test operator */ - static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE}; - int cond = 1; - if (op >= OPR_GT) { /* `>' or `>='? */ - int temp; /* exchange args and replace by `<' or `<=' */ - temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ - } - else if (op == OPR_NE) cond = 0; - res->info = condjump(fs, ops[op - OPR_NE], cond, o1, o2); - res->k = VJMP; - } -} - - void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e1->f, e2->f); - e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t; + e1->k = e2->k; e1->u.s.info = e2->u.s.info; + e1->u.s.aux = e2->u.s.aux; e1->t = e2->t; break; } case OPR_OR: { lua_assert(e1->f == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e1->t, e2->t); - e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f; + e1->k = e2->k; e1->u.s.info = e2->u.s.info; + e1->u.s.aux = e2->u.s.aux; e1->f = e2->f; break; } case OPR_CONCAT: { luaK_exp2val(fs, e2); if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1); + lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1->info); - e1->k = e2->k; e1->info = e2->info; + SETARG_B(getcode(fs, e2), e1->u.s.info); + e1->k = e2->k; e1->u.s.info = e2->u.s.info; } else { - luaK_exp2nextreg(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info); - e1->k = VRELOCABLE; + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codearith(fs, OP_CONCAT, e1, e2); } break; } - default: { - int o1 = luaK_exp2RK(fs, e1); - int o2 = luaK_exp2RK(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - codebinop(fs, e1, op, o1, o2); - } + case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; + case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; + case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; + case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; + case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; + case OPR_POW: codearith(fs, OP_POW, e1, e2); break; + case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; + case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; + case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; + case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; + case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; + case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; + default: lua_assert(0); } } @@ -737,7 +780,7 @@ void luaK_fixline (FuncState *fs, int line) { } -int luaK_code (FuncState *fs, Instruction i, int line) { +static int luaK_code (FuncState *fs, Instruction i, int line) { Proto *f = fs->f; dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ diff --git a/src/lcode.h b/src/lcode.h index ed1a95bc98..b5668f22a6 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.45 2005/08/29 20:49:21 roberto Exp $ +** $Id: lcode.h,v 1.47 2005/11/08 19:44:31 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ ** grep "ORDER OPR" if you change these enums */ typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_MOD, OPR_POW, + OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE, @@ -37,13 +37,12 @@ typedef enum BinOpr { typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; -#define getcode(fs,e) ((fs)->f->code[(e)->info]) +#define getcode(fs,e) ((fs)->f->code[(e)->u.s.info]) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) -LUAI_FUNC int luaK_code (FuncState *fs, Instruction i, int line); LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); @@ -60,7 +59,6 @@ LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); -LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); diff --git a/src/ldblib.c b/src/ldblib.c index e7458634ab..5da6e1da9a 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.101 2005/08/26 17:36:32 roberto Exp $ +** $Id: ldblib.c,v 1.103 2005/11/01 16:08:32 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -19,6 +19,12 @@ +static int db_getregistry (lua_State *L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + + static int db_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { @@ -319,7 +325,7 @@ static int db_errorfb (lua_State *L) { lua_State *L1 = getthread(L, &arg); lua_Debug ar; if (lua_isnumber(L, arg+2)) { - level = lua_tointeger(L, arg+2); + level = (int)lua_tointeger(L, arg+2); lua_pop(L, 1); } else @@ -371,6 +377,7 @@ static const luaL_Reg dblib[] = { {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, + {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, {"setfenv", db_setfenv}, diff --git a/src/ldebug.c b/src/ldebug.c index 11166c0a69..5fb11ce11f 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.26 2005/08/04 13:37:38 roberto Exp $ +** $Id: ldebug.c,v 2.28 2005/11/01 16:08:52 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -109,40 +109,39 @@ static Proto *getluaproto (CallInfo *ci) { } -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { +static const char *findlocal (lua_State *L, CallInfo *ci, int n) { const char *name; - CallInfo *ci; - Proto *fp; - lua_lock(L); - name = NULL; - ci = L->base_ci + ar->i_ci; - fp = getluaproto(ci); - if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(L, ci)); - if (name) - luaA_pushobject(L, ci->base+(n-1)); /* push value */ + Proto *fp = getluaproto(ci); + if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) + return name; /* is a local variable in a Lua function */ + else { + StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; + if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + return "(*temporary)"; + else + return NULL; } +} + + +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); + lua_lock(L); + if (name) + luaA_pushobject(L, ci->base + (n - 1)); lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - const char *name; - CallInfo *ci; - Proto *fp; + CallInfo *ci = L->base_ci + ar->i_ci; + const char *name = findlocal(L, ci, n); lua_lock(L); - name = NULL; - ci = L->base_ci + ar->i_ci; - fp = getluaproto(ci); - L->top--; /* pop new value */ - if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(L, ci)); - if (!name || name[0] == '(') /* `(' starts private locals */ - name = NULL; - else - setobjs2s(L, ci->base+(n-1), L->top); - } + if (name) + setobjs2s(L, ci->base + (n - 1), L->top - 1); + L->top--; /* pop value */ lua_unlock(L); return name; } @@ -321,7 +320,7 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ check(precheck(pt)); for (pc = 0; pc < lastpc; pc++) { - const Instruction i = pt->code[pc]; + Instruction i = pt->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); int b = 0; @@ -348,7 +347,7 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { check(0 <= dest && dest < pt->sizecode); if (dest > 0) { /* cannot jump to a setlist count */ - const Instruction d = pt->code[dest-1]; + Instruction d = pt->code[dest-1]; check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); } } diff --git a/src/ldo.c b/src/ldo.c index d7645835d4..cb510dd84b 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.33 2005/09/09 18:16:28 roberto Exp $ +** $Id: ldo.c,v 2.36 2005/10/23 17:52:42 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -276,8 +276,11 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { Proto *p = cl->p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); - if (!p->is_vararg) /* no varargs? */ + if (!p->is_vararg) { /* no varargs? */ base = func + 1; + if (L->top > base + p->numparams) + L->top = base + p->numparams; + } else { /* vararg function */ int nargs = cast(int, L->top - func) - 1; base = adjust_varargs(L, p, nargs); @@ -316,14 +319,12 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); - if (n >= 0) { /* no yielding? */ + if (n < 0) /* yielding? */ + return PCRYIELD; + else { luaD_poscall(L, L->top - n); return PCRC; } - else { - ci->nresults = nresults; - return PCRYIELD; - } } } @@ -428,6 +429,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { if (status != 0) { /* error? */ L->status = cast(lu_byte, status); /* mark thread as `dead' */ luaD_seterrorobj(L, status, L->top); + L->ci->top = L->top; } else status = L->status; diff --git a/src/ldump.c b/src/ldump.c index e580047bd2..7346341010 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,6 +1,6 @@ /* -** $Id: ldump.c,v 1.12 2005/06/08 14:40:44 lhf Exp $ -** save pre-compiled Lua chunks +** $Id: ldump.c,v 1.14 2005/11/11 14:03:13 lhf Exp $ +** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -12,7 +12,6 @@ #include "lua.h" #include "lobject.h" -#include "lopcodes.h" #include "lstate.h" #include "lundump.h" @@ -24,11 +23,8 @@ typedef struct { int status; } DumpState; -#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) -#define DumpLines(f,D) DumpVector(f->lineinfo,f->sizelineinfo,sizeof(int),D) -#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D) -#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) #define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) +#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) static void DumpBlock(const void* b, size_t size, DumpState* D) { @@ -77,24 +73,7 @@ static void DumpString(const TString* s, DumpState* D) } } -static void DumpLocals(const Proto* f, DumpState* D) -{ - int i,n=f->sizelocvars; - DumpInt(n,D); - for (i=0; ilocvars[i].varname,D); - DumpInt(f->locvars[i].startpc,D); - DumpInt(f->locvars[i].endpc,D); - } -} - -static void DumpUpvalues(const Proto* f, DumpState* D) -{ - int i,n=f->sizeupvalues; - DumpInt(n,D); - for (i=0; iupvalues[i],D); -} +#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) static void DumpFunction(const Proto* f, const TString* p, DumpState* D); @@ -129,6 +108,24 @@ static void DumpConstants(const Proto* f, DumpState* D) for (i=0; ip[i],f->source,D); } +static void DumpDebug(const Proto* f, DumpState* D) +{ + int i,n; + n= (D->strip) ? 0 : f->sizelineinfo; + DumpVector(f->lineinfo,n,sizeof(int),D); + n= (D->strip) ? 0 : f->sizelocvars; + DumpInt(n,D); + for (i=0; ilocvars[i].varname,D); + DumpInt(f->locvars[i].startpc,D); + DumpInt(f->locvars[i].endpc,D); + } + n= (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n,D); + for (i=0; iupvalues[i],D); +} + static void DumpFunction(const Proto* f, const TString* p, DumpState* D) { DumpString((f->source==p) ? NULL : f->source,D); @@ -138,11 +135,9 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); - if (D->strip) DumpInt(0,D); else DumpLines(f,D); - if (D->strip) DumpInt(0,D); else DumpLocals(f,D); - if (D->strip) DumpInt(0,D); else DumpUpvalues(f,D); - DumpConstants(f,D); DumpCode(f,D); + DumpConstants(f,D); + DumpDebug(f,D); } static void DumpHeader(DumpState* D) diff --git a/src/liolib.c b/src/liolib.c index a7f8743fa4..cc493aff82 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.67 2005/08/26 17:36:32 roberto Exp $ +** $Id: liolib.c,v 2.69 2005/10/19 13:05:11 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -424,7 +424,7 @@ static int f_seek (lua_State *L) { static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Integer offset = luaL_optinteger(L, 3, 0); + long offset = luaL_optlong(L, 3, 0); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ @@ -440,7 +440,7 @@ static int f_setvbuf (lua_State *L) { static const char *const modenames[] = {"no", "full", "line", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); - lua_Integer sz = luaL_optinteger(L, 3, BUFSIZ); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); int res = setvbuf(f, NULL, mode[op], sz); return pushresult(L, res == 0, NULL); } diff --git a/src/llex.c b/src/llex.c index b663b43299..d7753394a0 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.12 2005/05/17 19:49:15 roberto Exp $ +** $Id: llex.c,v 2.13 2005/11/08 19:45:14 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -155,28 +155,23 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { +static int check_next (LexState *ls, const char *set) { + if (!strchr(set, ls->current)) + return 0; + save_and_next(ls); + return 1; +} + + /* LUA_NUMBER */ static void read_numeral (LexState *ls, SemInfo *seminfo) { - while (isdigit(ls->current)) { + lua_assert(isdigit(ls->current)); + do { save_and_next(ls); - } - if (ls->current == '.') { - save_and_next(ls); - if (ls->current == '.') { - save_and_next(ls); - luaX_lexerror(ls, - "ambiguous syntax (decimal point x string concatenation)", - TK_NUMBER); - } - } - while (isdigit(ls->current)) { - save_and_next(ls); - } - if (ls->current == 'e' || ls->current == 'E') { - save_and_next(ls); /* read `E' */ - if (ls->current == '+' || ls->current == '-') - save_and_next(ls); /* optional exponent sign */ + } while (isdigit(ls->current) || ls->current == '.'); + if (check_next(ls, "Ee")) { /* `E'? */ + check_next(ls, "+-"); /* optional exponent sign */ while (isdigit(ls->current)) { save_and_next(ls); } @@ -375,12 +370,9 @@ int luaX_lex (LexState *ls, SemInfo *seminfo) { } case '.': { save_and_next(ls); - if (ls->current == '.') { - next(ls); - if (ls->current == '.') { - next(ls); + if (check_next(ls, ".")) { + if (check_next(ls, ".")) return TK_DOTS; /* ... */ - } else return TK_CONCAT; /* .. */ } else if (!isdigit(ls->current)) return '.'; diff --git a/src/loadlib.c b/src/loadlib.c index 767fdb8e84..9f992086b6 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.44 2005/09/06 17:20:25 roberto Exp $ +** $Id: loadlib.c,v 1.48 2005/10/17 18:01:51 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -97,16 +97,18 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #undef setprogdir -void setprogdir (lua_State *L) { +static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; DWORD nsize = sizeof(buff)/sizeof(char); DWORD n = GetModuleFileName(NULL, buff, nsize); if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) luaL_error(L, "unable to get ModuleFileName"); - *lb = '\0'; - luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); - lua_remove(L, -2); /* remove original string */ + else { + *lb = '\0'; + luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + lua_remove(L, -2); /* remove original string */ + } } @@ -440,7 +442,8 @@ static int loader_preload (lua_State *L) { } -static const int sentinel = 0; +static const int sentinel_ = 0; +#define sentinel ((void *)&sentinel_) static int ll_require (lua_State *L) { @@ -450,7 +453,7 @@ static int ll_require (lua_State *L) { lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); if (lua_toboolean(L, -1)) { /* is it there? */ - if (lua_touserdata(L, -1) == &sentinel) /* check loops */ + if (lua_touserdata(L, -1) == sentinel) /* check loops */ luaL_error(L, "loop or previous error loading module " LUA_QS, name); return 1; /* package is already loaded */ } @@ -467,14 +470,14 @@ static int ll_require (lua_State *L) { if (lua_isnil(L, -1)) lua_pop(L, 1); /* did not found module */ else break; /* module loaded successfully */ } - lua_pushlightuserdata(L, (void *)&sentinel); + lua_pushlightuserdata(L, sentinel); lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ lua_pushstring(L, name); /* pass name as argument to module */ lua_call(L, 1, 1); /* run loaded module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_getfield(L, 2, name); - if (lua_touserdata(L, -1) == &sentinel) { /* module did not set a value? */ + if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ @@ -623,8 +626,6 @@ LUALIB_API int luaopen_package (lua_State *L) { lua_getfield(L, -1, "loadlib"); lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); #endif - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, "_PACKAGE"); lua_pushvalue(L, -1); lua_replace(L, LUA_ENVIRONINDEX); /* create `loaders' table */ @@ -642,7 +643,7 @@ LUALIB_API int luaopen_package (lua_State *L) { LUA_EXECDIR "\n" LUA_IGMARK); lua_setfield(L, -2, "config"); /* set field `loaded' */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); /* set field `preload' */ lua_newtable(L); diff --git a/src/lobject.c b/src/lobject.c index 9aa9760f75..3974c68311 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.18 2005/08/01 04:22:23 roberto Exp $ +** $Id: lobject.c,v 2.19 2005/10/24 17:37:52 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -75,7 +75,7 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { case LUA_TNIL: return 1; case LUA_TNUMBER: - return luai_numeq(L, nvalue(t1), nvalue(t2)); + return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: diff --git a/src/lobject.h b/src/lobject.h index 1709fa3ca1..1416e360ee 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.17 2005/06/13 14:19:00 roberto Exp $ +** $Id: lobject.h,v 2.18 2005/10/24 17:37:33 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -353,7 +353,7 @@ typedef struct Table { ** `module' operation for hashing (size is always a power of 2) */ #define lmod(s,size) \ - check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))) + (check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1))))) #define twoto(x) (1<<(x)) diff --git a/src/lopcodes.c b/src/lopcodes.c index 5e3bc5f775..bf9cd522c2 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.35 2005/08/29 20:49:21 roberto Exp $ +** $Id: lopcodes.c,v 1.37 2005/11/08 19:45:36 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -7,9 +7,7 @@ #define lopcodes_c #define LUA_CORE -#include "lua.h" -#include "lobject.h" #include "lopcodes.h" @@ -88,7 +86,7 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ - ,opmode(1, 0, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ diff --git a/src/lopcodes.h b/src/lopcodes.h index b08b679874..88e7e65ccc 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.122 2005/08/29 20:49:21 roberto Exp $ +** $Id: lopcodes.h,v 1.123 2005/10/23 17:37:55 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -193,12 +193,12 @@ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ -OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) =) R(A)*/ diff --git a/src/loslib.c b/src/loslib.c index 4cee7ba5c5..01458b90ef 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.13 2005/09/09 18:22:46 roberto Exp $ +** $Id: loslib.c,v 1.14 2005/10/21 13:47:42 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -125,8 +125,8 @@ static int getfield (lua_State *L, const char *key, int d) { static int io_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - lua_Number n = luaL_optnumber(L, 2, -1); - time_t t = (n == -1) ? time(NULL) : (time_t)n; + time_t t = lua_isnoneornil(L, 2) ? time(NULL) : + (time_t)luaL_checknumber(L, 2); struct tm *stm; if (*s == '!') { /* UTC? */ stm = gmtime(&t); diff --git a/src/lparser.c b/src/lparser.c index 91dc4fff19..dd4715d0f2 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.35 2005/08/29 20:49:21 roberto Exp $ +** $Id: lparser.c,v 2.38 2005/10/24 17:38:47 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -144,7 +144,7 @@ static TString *str_checkname (LexState *ls) { static void init_exp (expdesc *e, expkind k, int i) { e->f = e->t = NO_JUMP; e->k = k; - e->info = i; + e->u.s.info = i; } @@ -184,7 +184,7 @@ static void new_localvar (LexState *ls, TString *name, int n) { static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - fs->nactvar += nvars; + fs->nactvar = cast(lu_byte, fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; } @@ -203,7 +203,7 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; for (i=0; inups; i++) { - if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) { + if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { lua_assert(f->upvalues[i] == name); return i; } @@ -217,7 +217,7 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { luaC_objbarrier(fs->L, f, name); lua_assert(v->k == VLOCAL || v->k == VUPVAL); fs->upvalues[f->nups].k = cast(lu_byte, v->k); - fs->upvalues[f->nups].info = cast(lu_byte, v->info); + fs->upvalues[f->nups].info = cast(lu_byte, v->u.s.info); return f->nups++; } @@ -255,7 +255,7 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { else { /* not found at current level; try upper one */ if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) return VGLOBAL; - var->info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ + var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ var->k = VUPVAL; /* upvalue in this level */ return VUPVAL; } @@ -267,7 +267,7 @@ static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VGLOBAL) - var->info = luaK_stringK(fs, varname); /* info points to global name */ + var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ } @@ -351,7 +351,7 @@ static void open_func (LexState *ls, FuncState *fs) { fs->L = L; ls->fs = fs; fs->pc = 0; - fs->lasttarget = 0; + fs->lasttarget = -1; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; @@ -472,8 +472,8 @@ static void recfield (LexState *ls, struct ConsControl *cc) { checknext(ls, '='); luaK_exp2RK(fs, &key); expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->info, luaK_exp2RK(fs, &key), - luaK_exp2RK(fs, &val)); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, luaK_exp2RK(fs, &key), + luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } @@ -483,7 +483,7 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) { luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { - luaK_setlist(fs, cc->t->info, cc->na, cc->tostore); /* flush */ + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ } } @@ -493,13 +493,13 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); - luaK_setlist(fs, cc->t->info, cc->na, LUA_MULTRET); + luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); - luaK_setlist(fs, cc->t->info, cc->na, cc->tostore); + luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); } } @@ -657,7 +657,7 @@ static void funcargs (LexState *ls, expdesc *f) { } } lua_assert(f->k == VNONRELOC); - base = f->info; /* base register for call */ + base = f->u.s.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { @@ -746,7 +746,8 @@ static void simpleexp (LexState *ls, expdesc *v) { constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { - init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r)); + init_exp(v, VKNUM, 0); + v->u.nval = ls->t.seminfo.r; break; } case TK_STRING: { @@ -805,7 +806,7 @@ static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; - case '*': return OPR_MULT; + case '*': return OPR_MUL; case '/': return OPR_DIV; case '%': return OPR_MOD; case '^': return OPR_POW; @@ -927,18 +928,18 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { int conflict = 0; for (; lh; lh = lh->prev) { if (lh->v.k == VINDEXED) { - if (lh->v.info == v->info) { /* conflict? */ + if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ conflict = 1; - lh->v.info = extra; /* previous assignment will use safe copy */ + lh->v.u.s.info = extra; /* previous assignment will use safe copy */ } - if (lh->v.aux == v->info) { /* conflict? */ + if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ conflict = 1; - lh->v.aux = extra; /* previous assignment will use safe copy */ + lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ } } } if (conflict) { - luaK_codeABC(fs, OP_MOVE, fs->freereg, v->info, 0); /* make copy */ + luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ luaK_reserveregs(fs, 1); } } diff --git a/src/lparser.h b/src/lparser.h index d8542f9c9b..d5e6e81d0d 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.55 2005/04/25 19:24:10 roberto Exp $ +** $Id: lparser.h,v 1.56 2005/10/03 14:02:40 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,6 +23,7 @@ typedef enum { VTRUE, VFALSE, VK, /* info = index of constant in `k' */ + VKNUM, /* nval = numerical value */ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in `upvalues' */ VGLOBAL, /* info = index of table; aux = index of global name in `k' */ @@ -36,7 +37,10 @@ typedef enum { typedef struct expdesc { expkind k; - int info, aux; + union { + struct { int info, aux; } s; + lua_Number nval; + } u; int t; /* patch list of `exit when true' */ int f; /* patch list of `exit when false' */ } expdesc; diff --git a/src/lstate.c b/src/lstate.c index 2a4ace1284..77e93fbdfa 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.33 2005/08/25 15:39:16 roberto Exp $ +** $Id: lstate.c,v 2.35 2005/10/06 20:46:25 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -71,8 +71,8 @@ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ - sethvalue(L, gt(L), luaH_new(L, 0, 20)); /* table of globals */ - sethvalue(L, registry(L), luaH_new(L, 6, 20)); /* registry */ + sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ + sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); @@ -134,6 +134,7 @@ lua_State *luaE_newthread (lua_State *L) { void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); + luai_userstatefree(L1); freestack(L, L1); luaM_freemem(L, fromstate(L1), state_size(lua_State)); } @@ -196,8 +197,9 @@ static void callallgcTM (lua_State *L, void *ud) { LUA_API void lua_close (lua_State *L) { - lua_lock(L); L = G(L)->mainthread; /* only the main thread can be closed */ + luai_userstateclose(L); + lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ L->errfunc = 0; /* no error function during GC metamethods */ diff --git a/src/lstrlib.c b/src/lstrlib.c index 4cf5836aae..25258bfe03 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.123 2005/08/26 17:36:32 roberto Exp $ +** $Id: lstrlib.c,v 1.127 2005/10/26 13:28:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -111,7 +111,9 @@ static int str_byte (lua_State *L) { if (posi <= 0) posi = 1; if ((size_t)pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ - n = pose - posi + 1; + n = (int)(pose - posi + 1); + if (posi + n <= pose) /* overflow? */ + luaL_error(L, "string slice too long"); luaL_checkstack(L, n, "string slice too long"); for (i=0; icapture[i].len; - if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); - if (l == CAP_POSITION) - lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); - else - lua_pushlstring(ms->L, ms->capture[i].init, l); +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + if (i >= ms->level) { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index"); + } + else { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; - luaL_checkstack(ms->L, ms->level, "too many captures"); - if (ms->level == 0 && s) { /* no explicit captures? */ - lua_pushlstring(ms->L, s, e-s); /* return whole match */ - return 1; - } - else { /* return all captures */ - for (i=0; ilevel; i++) - push_onecapture(ms, i); - return ms->level; /* number of strings pushed */ - } + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ } @@ -516,12 +522,7 @@ static int str_find_aux (lua_State *L, int find) { if (find) { lua_pushinteger(L, s1-s+1); /* start */ lua_pushinteger(L, res-s); /* end */ -#if defined(LUA_COMPAT_FIND) return push_captures(&ms, NULL, 0) + 2; -#else - return 2; -#endif - } else return push_captures(&ms, s1, res); @@ -585,42 +586,61 @@ static int gfind_nodef (lua_State *L) { } -static void add_s (MatchState *ms, luaL_Buffer *b, - const char *s, const char *e) { - lua_State *L = ms->L; - if (lua_isstring(L, 3)) { - size_t l; - const char *news = lua_tolstring(L, 3, &l); - size_t i; - for (i=0; iL, 3, &l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) luaL_addchar(b, news[i]); + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); else { - i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) - luaL_addchar(b, news[i]); - else { - if (news[i] == '0') - lua_pushlstring(L, s, e - s); /* add whole match */ - else { - int level = check_capture(ms, news[i]); - push_onecapture(ms, level); - } - luaL_addvalue(b); /* add capture to accumulated result */ - } + push_onecapture(ms, news[i] - '1', s, e); + luaL_addvalue(b); /* add capture to accumulated result */ } } } - else { /* is a function */ - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - if (lua_isstring(L, -1)) - luaL_addvalue(b); /* add return to accumulated result */ - else - lua_pop(L, 1); /* function result is not a string: pop it */ +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + lua_State *L = ms->L; + switch (lua_type(L, 3)) { + case LUA_TNUMBER: + case LUA_TSTRING: { + add_s(ms, b, s, e); + return; + } + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + default: { + luaL_argerror(L, 3, "string/function/table expected"); + return; + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ } @@ -633,9 +653,6 @@ static int str_gsub (lua_State *L) { int n = 0; MatchState ms; luaL_Buffer b; - luaL_argcheck(L, - lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), - 3, "string or function expected"); luaL_buffinit(L, &b); ms.L = L; ms.src_init = src; @@ -646,7 +663,7 @@ static int str_gsub (lua_State *L) { e = match(&ms, src, p); if (e) { n++; - add_s(&ms, &b, src, e); + add_value(&ms, &b, src, e); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ diff --git a/src/ltable.c b/src/ltable.c index 979cc5ca97..5d4a828a4f 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.26 2005/07/11 14:01:37 roberto Exp $ +** $Id: ltable.c,v 2.27 2005/10/24 17:37:52 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -120,7 +120,7 @@ static int arrayindex (const TValue *key) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); - if (luai_numeq(L, cast(lua_Number, k), nvalue(key))) + if (luai_numeq(cast(lua_Number, k), nvalue(key))) return k; } return -1; /* `key' did not match some condition */ @@ -437,7 +437,7 @@ const TValue *luaH_getnum (Table *t, int key) { lua_Number nk = cast(lua_Number, key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && luai_numeq(L, nvalue(gkey(n)), nk)) + if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); @@ -471,7 +471,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { int k; lua_Number n = nvalue(key); lua_number2int(k, n); - if (luai_numeq(L, cast(lua_Number, k), nvalue(key))) /* index is int? */ + if (luai_numeq(cast(lua_Number, k), nvalue(key))) /* index is int? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } @@ -495,7 +495,7 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && !luai_numeq(L, nvalue(key), nvalue(key))) + else if (ttisnumber(key) && !luai_numeq(nvalue(key), nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } diff --git a/src/ltablib.c b/src/ltablib.c index 348b6ed5a8..453b23b378 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.35 2005/08/26 17:36:32 roberto Exp $ +** $Id: ltablib.c,v 1.38 2005/10/23 17:38:15 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -40,9 +40,7 @@ static int foreach (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TFUNCTION); lua_pushnil(L); /* first key */ - for (;;) { - if (lua_next(L, 1) == 0) - return 0; + while (lua_next(L, 1)) { lua_pushvalue(L, 2); /* function */ lua_pushvalue(L, -3); /* key */ lua_pushvalue(L, -3); /* value */ @@ -51,6 +49,23 @@ static int foreach (lua_State *L) { return 1; lua_pop(L, 2); /* remove value and result */ } + return 0; +} + + +static int maxn (lua_State *L) { + lua_Number max = 0; + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pop(L, 1); /* remove value */ + if (lua_type(L, -1) == LUA_TNUMBER) { + lua_Number v = lua_tonumber(L, -1); + if (v > max) max = v; + } + } + lua_pushnumber(L, max); + return 1; } @@ -75,16 +90,23 @@ static int setn (lua_State *L) { static int tinsert (lua_State *L) { int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ - if (lua_isnone(L, 3)) /* called with only 2 arguments */ - pos = e; /* insert new element at the end */ - else { - int i; - pos = luaL_checkint(L, 2); /* 2nd argument is the position */ - if (pos > e) e = pos; /* `grow' array if necessary */ - lua_settop(L, 3); /* function may be called with more than 3 args */ - for (i = e; i > pos; i--) { /* move up elements */ - lua_rawgeti(L, 1, i-1); - lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + int i; + pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + if (pos > e) e = pos; /* `grow' array if necessary */ + for (i = e; i > pos; i--) { /* move up elements */ + lua_rawgeti(L, 1, i-1); + lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); } } luaL_setn(L, 1, e); /* new size */ @@ -112,12 +134,11 @@ static int tremove (lua_State *L) { static int tconcat (lua_State *L) { luaL_Buffer b; size_t lsep; + int i, last; const char *sep = luaL_optlstring(L, 2, "", &lsep); - int i = luaL_optint(L, 3, 1); - int last = luaL_optint(L, 4, -2); luaL_checktype(L, 1, LUA_TTABLE); - if (last == -2) - last = luaL_getn(L, 1); + i = luaL_optint(L, 3, 1); + last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1)); luaL_buffinit(L, &b); for (; i <= last; i++) { lua_rawgeti(L, 1, i); @@ -241,6 +262,7 @@ static const luaL_Reg tab_funcs[] = { {"foreach", foreach}, {"foreachi", foreachi}, {"getn", getn}, + {"maxn", maxn}, {"insert", tinsert}, {"remove", tremove}, {"setn", setn}, diff --git a/src/lua.c b/src/lua.c index 14c5e20dff..bfae4449eb 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.150 2005/09/06 17:19:33 roberto Exp $ +** $Id: lua.c,v 1.154 2005/10/24 17:38:47 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -43,12 +43,13 @@ static void print_usage (void) { fprintf(stderr, "usage: %s [options] [script [args]].\n" "Available options are:\n" - " - execute stdin as a file\n" " -e stat execute string " LUA_QL("stat") "\n" - " -i enter interactive mode after executing " LUA_QL("script") "\n" " -l name require library " LUA_QL("name") "\n" + " -i enter interactive mode after executing " LUA_QL("script") "\n" " -v show version information\n" - " -- stop handling options\n" , + " -- stop handling options\n" + " - execute stdin and stop handling options\n" + , progname); fflush(stderr); } @@ -99,6 +100,8 @@ static int docall (lua_State *L, int narg, int clear) { status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); signal(SIGINT, SIG_DFL); lua_remove(L, base); /* remove traceback function */ + /* force a complete garbage collection in case of errors */ + if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); return status; } @@ -108,9 +111,12 @@ static void print_version (void) { } -static int getargs (lua_State *L, int argc, char **argv, int n) { - int narg = argc - (n + 1); /* number of arguments to the script */ +static int getargs (lua_State *L, char **argv, int n) { + int narg; int i; + int argc = 0; + while (argv[argc]) argc++; /* count total number of arguments */ + narg = argc - (n + 1); /* number of arguments to the script */ luaL_checkstack(L, narg + 3, "too many arguments to script"); for (i=n+1; i < argc; i++) lua_pushstring(L, argv[i]); @@ -229,86 +235,71 @@ static void dotty (lua_State *L) { } -#define clearinteractive(i) (*i &= 2) +static int handle_script (lua_State *L, char **argv, int n) { + int status; + const char *fname; + int narg = getargs(L, argv, n); /* collect arguments */ + lua_setglobal(L, "arg"); + fname = argv[n]; + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + fname = NULL; /* stdin */ + status = luaL_loadfile(L, fname); + lua_insert(L, -(narg+1)); + if (status == 0) + status = docall(L, narg, 0); + else + lua_pop(L, narg); + return report(L, status); +} -static int handle_argv (lua_State *L, int argc, char **argv, int *interactive) { - if (argv[1] == NULL) { /* no arguments? */ - *interactive = 0; - if (lua_stdin_is_tty()) - dotty(L); - else - dofile(L, NULL); /* executes stdin as a file */ - } - else { /* other arguments; loop over them */ - int i; - for (i = 1; argv[i] != NULL; i++) { - if (argv[i][0] != '-') break; /* not an option? */ - switch (argv[i][1]) { /* option */ - case '-': { /* `--' */ - if (argv[i][2] != '\0') { - print_usage(); - return 1; - } - i++; /* skip this argument */ - goto endloop; /* stop handling arguments */ - } - case '\0': { - clearinteractive(interactive); - dofile(L, NULL); /* executes stdin as a file */ - break; - } - case 'i': { - *interactive = 2; /* force interactive mode after arguments */ - break; - } - case 'v': { - clearinteractive(interactive); - print_version(); - break; - } - case 'e': { - const char *chunk = argv[i] + 2; - clearinteractive(interactive); - if (*chunk == '\0') chunk = argv[++i]; - if (chunk == NULL) { - print_usage(); - return 1; - } - if (dostring(L, chunk, "=(command line)") != 0) - return 1; - break; - } - case 'l': { - const char *filename = argv[i] + 2; - if (*filename == '\0') filename = argv[++i]; - if (filename == NULL) { - print_usage(); - return 1; - } - if (dolibrary(L, filename)) - return 1; /* stop if file fails */ - break; + +static int collectargs (char **argv, int *pi, int *pv, int *pe) { + int i; + for (i = 1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') /* not an option? */ + return i; + switch (argv[i][1]) { /* option */ + case '-': return (argv[i+1] != NULL ? i+1 : 0); + case '\0': return i; + case 'i': *pi = 1; break; + case 'v': *pv = 1; break; + case 'e': *pe = 1; /* go through */ + case 'l': + if (argv[i][2] == '\0') { + i++; + if (argv[i] == NULL) return -1; } - default: { - clearinteractive(interactive); - print_usage(); + break; + default: return -1; /* invalid option */ + } + } + return 0; +} + + +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + if (argv[i] == NULL) continue; + lua_assert(argv[i][0] == '-'); + switch (argv[i][1]) { /* option */ + case 'e': { + const char *chunk = argv[i] + 2; + if (*chunk == '\0') chunk = argv[++i]; + lua_assert(chunk != NULL); + if (dostring(L, chunk, "=(command line)") != 0) return 1; - } + break; } - } endloop: - if (argv[i] != NULL) { - int status; - const char *filename = argv[i]; - int narg = getargs(L, argc, argv, i); /* collect arguments */ - lua_setglobal(L, "arg"); - clearinteractive(interactive); - status = luaL_loadfile(L, filename); - lua_insert(L, -(narg+1)); - if (status == 0) - status = docall(L, narg, 0); - else - lua_pop(L, narg); - return report(L, status); + case 'l': { + const char *filename = argv[i] + 2; + if (*filename == '\0') filename = argv[++i]; + lua_assert(filename != NULL); + if (dolibrary(L, filename)) + return 1; /* stop if file fails */ + break; + } + default: break; } } return 0; @@ -334,17 +325,32 @@ struct Smain { static int pmain (lua_State *L) { struct Smain *s = (struct Smain *)lua_touserdata(L, 1); - int status; - int interactive = 1; - if (s->argv[0] && s->argv[0][0]) progname = s->argv[0]; + char **argv = s->argv; + int script; + int has_i = 0, has_v = 0, has_e = 0; globalL = L; + if (argv[0] && argv[0][0]) progname = argv[0]; luaL_openlibs(L); /* open libraries */ - status = handle_luainit(L); - if (status == 0) { - status = handle_argv(L, s->argc, s->argv, &interactive); - if (status == 0 && interactive) dotty(L); + s->status = handle_luainit(L); + if (s->status != 0) return 0; + script = collectargs(argv, &has_i, &has_v, &has_e); + if (script < 0) { /* invalid args? */ + print_usage(); + s->status = 1; + return 0; + } + if (has_v) print_version(); + s->status = runargs(L, argv, (script > 0) ? script : s->argc); + if (s->status != 0) return 0; + if (script) + s->status = handle_script(L, argv, script); + if (s->status != 0) return 0; + if (has_i) + dotty(L); + else if (script == 0 && !has_e && !has_v) { + if (lua_stdin_is_tty()) dotty(L); + else dofile(L, NULL); /* executes stdin as a file */ } - s->status = status; return 0; } diff --git a/src/lua.h b/src/lua.h index 339e076fdd..d612eec72c 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.212 2005/08/25 20:02:08 roberto Exp $ +** $Id: lua.h,v 1.214 2005/10/20 11:35:50 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -16,7 +16,7 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (alpha)" +#define LUA_VERSION "Lua 5.1 (beta)" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2005 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -221,9 +221,10 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCRESTART 1 #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 -#define LUA_GCSTEP 4 -#define LUA_GCSETPAUSE 5 -#define LUA_GCSETSTEPMUL 6 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -239,6 +240,7 @@ LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); diff --git a/src/luac.c b/src/luac.c index 374ea3ac16..2dd76b7653 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.51 2005/06/02 13:39:23 lhf Exp $ +** $Id: luac.c,v 1.52 2005/11/11 14:03:13 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -23,13 +23,8 @@ #include "lstring.h" #include "lundump.h" -#ifndef PROGNAME #define PROGNAME "luac" /* default program name */ -#endif - -#ifndef OUTPUT -#define OUTPUT "luac.out" /* default output file */ -#endif +#define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ @@ -152,15 +147,15 @@ static int writer(lua_State* L, const void* p, size_t size, void* u) } struct Smain { - int argc; - char **argv; + int argc; + char** argv; }; -static int pmain(lua_State *L) +static int pmain(lua_State* L) { - struct Smain *s = (struct Smain *)lua_touserdata(L, 1); + struct Smain* s = (struct Smain*)lua_touserdata(L, 1); int argc=s->argc; - char **argv=s->argv; + char** argv=s->argv; Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); diff --git a/src/luaconf.h b/src/luaconf.h index d6d4a2a739..ea685a2ddc 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.65 2005/09/09 18:24:42 roberto Exp $ +** $Id: luaconf.h,v 1.74 2005/11/16 16:24:28 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -19,8 +19,6 @@ */ - - /* @@ LUA_ANSI controls the use of non-ansi features. ** CHANGE it (define it) if you want Lua to avoid the use of any @@ -30,6 +28,31 @@ #define LUA_ANSI #endif +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#define LUA_USE_READLINE /* needs some extra libraries */ +#endif + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_DL_DYLD /* does not need extra library */ +#endif + + + +/* +@@ LUA_USE_POSIX includes all functionallity listed as X/Open System +@* Interfaces Extension (XSI). +** CHANGE it (define it) if your system is XSI compatible. +*/ +#if defined(LUA_USE_POSIX) +#define LUA_USE_MKSTEMP +#define LUA_USE_ISATTY +#define LUA_USE_POPEN +#define LUA_USE_ULONGJMP +#endif + /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for @@ -92,7 +115,7 @@ #define LUA_PATHSEP ";" #define LUA_PATH_MARK "?" #define LUA_EXECDIR "!" -#define LUA_IGMARK ":" +#define LUA_IGMARK "-" /* @@ -141,10 +164,12 @@ #if defined(luaall_c) #define LUAI_FUNC static #define LUAI_DATA /* empty */ + #elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) #define LUAI_FUNC __attribute__((visibility("hidden"))) extern #define LUAI_DATA LUAI_FUNC + #else #define LUAI_FUNC extern #define LUAI_DATA extern @@ -189,7 +214,7 @@ ** CHANGE it if you have a better definition for non-POSIX/non-Windows ** systems. */ -#if !defined(LUA_ANSI) && defined(_POSIX_C_SOURCE) +#if defined(LUA_USE_ISATTY) #include #define lua_stdin_is_tty() isatty(0) #elif !defined(LUA_ANSI) && defined(_WIN32) @@ -239,17 +264,17 @@ #include #include #include -#define lua_readline(L,b,p) (((b)=readline(p)) != NULL) +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ -#define lua_freeline(L,b) free(b) +#define lua_freeline(L,b) ((void)L, free(b)) #else #define lua_readline(L,b,p) \ - (fputs(p, stdout), fflush(stdout), /* show prompt */ \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) ((void)0) -#define lua_freeline(L,b) ((void)0) +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } #endif #endif @@ -315,13 +340,6 @@ */ #define LUA_COMPAT_LSTR 1 -/* -@@ LUA_COMPAT_FIND controls compatibility with old 'string.find' behavior. -** CHANGE it to undefined as soon as your programs use 'string.find' only -** to find patterns. -*/ -#define LUA_COMPAT_FIND - /* @@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. ** CHANGE it to undefined as soon as you rename 'string.gfind' to @@ -329,7 +347,6 @@ */ #define LUA_COMPAT_GFIND - /* @@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' @* behavior. @@ -349,10 +366,10 @@ */ #if defined(LUA_USE_APICHECK) #include -#define luai_apicheck(L,o) assert(o) +#define luai_apicheck(L,o) { (void)L; assert(o); } #else /* (By default lua_assert is empty, so luai_apicheck is also empty.) */ -#define luai_apicheck(L,o) lua_assert(o) +#define luai_apicheck(L,o) { (void)L; lua_assert(o); } #endif @@ -464,31 +481,6 @@ -/* -@@ lua_number2int is a macro to convert lua_Number to int. -@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. -** CHANGE them if you know a faster way to convert a lua_Number to -** int (with any rounding method and without throwing errors) in your -** system. In Pentium machines, a naive typecast from double to int -** in C is extremely slow, so any alternative is worth trying. -*/ - -/* On a Pentium, resort to a trick */ -#if !defined(LUA_ANSI) && !defined(__SSE2__) && \ - (defined(__i386) || defined (_M_IX86)) -union luai_Cast { double l_d; long l_l; }; -#define lua_number2int(i,d) \ - { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } -#define lua_number2integer(i,n) lua_number2int(i, n) - -/* this option always works, but may be slow */ -#else -#define lua_number2int(i,d) ((i)=(int)(d)) -#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) - -#endif - - /* ** {================================================================== @@ -525,16 +517,44 @@ union luai_Cast { double l_d; long l_l; }; /* @@ The luai_num* macros define the primitive operations over numbers. */ -#define luai_numadd(L,a,b) ((a)+(b)) -#define luai_numsub(L,a,b) ((a)-(b)) -#define luai_nummul(L,a,b) ((a)*(b)) -#define luai_numdiv(L,a,b) ((a)/(b)) -#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) -#define luai_numpow(L,a,b) pow(a,b) -#define luai_numunm(L,a) (-(a)) -#define luai_numeq(L,a,b) ((a)==(b)) -#define luai_numlt(L,a,b) ((a)<(b)) -#define luai_numle(L,a,b) ((a)<=(b)) +#if defined(LUA_CORE) +#include +#define luai_numadd(a,b) ((a)+(b)) +#define luai_numsub(a,b) ((a)-(b)) +#define luai_nummul(a,b) ((a)*(b)) +#define luai_numdiv(a,b) ((a)/(b)) +#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(a,b) (pow(a,b)) +#define luai_numunm(a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#endif + + +/* +@@ lua_number2int is a macro to convert lua_Number to int. +@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. +** CHANGE them if you know a faster way to convert a lua_Number to +** int (with any rounding method and without throwing errors) in your +** system. In Pentium machines, a naive typecast from double to int +** in C is extremely slow, so any alternative is worth trying. +*/ + +/* On a Pentium, resort to a trick */ +#if !defined(LUA_ANSI) && !defined(__SSE2__) && \ + (defined(__i386) || defined (_M_IX86) || defined(__i386__)) +union luai_Cast { double l_d; long l_l; }; +#define lua_number2int(i,d) \ + { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } +#define lua_number2integer(i,n) lua_number2int(i, n) + +/* this option always works, but may be slow */ +#else +#define lua_number2int(i,d) ((i)=(int)(d)) +#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) + +#endif /* }================================================================== */ @@ -597,7 +617,7 @@ union luai_Cast { double l_d; long l_l; }; */ #if defined(loslib_c) || defined(luaall_c) -#if !defined(LUA_ANSI) && defined(_POSIX_C_SOURCE) +#if defined(LUA_USE_MKSTEMP) #include #define LUA_TMPNAMBUFSIZE 32 #define lua_tmpnam(b,e) { \ @@ -605,6 +625,7 @@ union luai_Cast { double l_d; long l_l; }; e = mkstemp(b); \ if (e != -1) close(e); \ e = (e == -1); } + #else #define LUA_TMPNAMBUFSIZE L_tmpnam #define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } @@ -618,21 +639,21 @@ union luai_Cast { double l_d; long l_l; }; @* the file streams. ** CHANGE it if you have a way to implement it in your system. */ -#if !defined(LUA_ANSI) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 2 +#if defined(LUA_USE_POPEN) -#define lua_popen(L,c,m) popen(c,m) -#define lua_pclose(L,file) (pclose(file) != -1) +#define lua_popen(L,c,m) ((void)L, popen(c,m)) +#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) #elif !defined(LUA_ANSI) && defined(_WIN32) -#define lua_popen(L,c,m) _popen(c,m) -#define lua_pclose(L,file) (_pclose(file) != -1) +#define lua_popen(L,c,m) ((void)L, _popen(c,m)) +#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) #else #define lua_popen(L,c,m) \ ((void)c, (void)m, luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) -#define lua_pclose(L,file) ((void)file, 0) +#define lua_pclose(L,file) ((void)L, (void)file, 0) #endif @@ -647,16 +668,15 @@ union luai_Cast { double l_d; long l_l; }; ** automatically. (When you change the makefile to add -ldl, you must ** also add -DLUA_USE_DLOPEN.) ** If you do not want any kind of dynamic library, undefine all these -** options (or just remove these definitions). +** options. +** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. */ -#if !defined(LUA_ANSI) -#if defined(_WIN32) -#define LUA_DL_DLL -#elif defined(__APPLE__) && defined(__MACH__) -#define LUA_DL_DYLD -#elif defined(LUA_USE_DLOPEN) +#if defined(LUA_USE_DLOPEN) #define LUA_DL_DLOPEN #endif + +#if !defined(LUA_ANSI) && defined(_WIN32) +#define LUA_DL_DLL #endif @@ -674,10 +694,12 @@ union luai_Cast { double l_d; long l_l; }; ** CHANGE them if you defined LUAI_EXTRASPACE and need to do something ** extra when a thread is created/deleted/resumed/yielded. */ -#define luai_userstateopen(L) ((void)0) -#define luai_userstatefree(L) ((void)0) -#define luai_userstateresume(L,n) ((void)0) -#define luai_userstateyield(L,n) ((void)0) +#define luai_userstateopen(L) ((void)L) +#define luai_userstateclose(L) ((void)L) +#define luai_userstatethread(L,L1) ((void)L) +#define luai_userstatefree(L) ((void)L) +#define luai_userstateresume(L,n) ((void)L) +#define luai_userstateyield(L,n) ((void)L) diff --git a/src/lundump.c b/src/lundump.c index 726d021d44..60a0eeed3f 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,6 +1,6 @@ /* -** $Id: lundump.c,v 1.58 2005/09/02 01:54:47 lhf Exp $ -** load pre-compiled Lua chunks +** $Id: lundump.c,v 1.59 2005/11/11 14:03:13 lhf Exp $ +** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -15,42 +15,34 @@ #include "ldo.h" #include "lfunc.h" #include "lmem.h" -#include "lopcodes.h" +#include "lobject.h" #include "lstring.h" #include "lundump.h" #include "lzio.h" -#ifdef LUAC_TRUST_BINARIES -#define IF(c,s) -#else -#define IF(c,s) if (c) error(S,s) -#endif - typedef struct { lua_State* L; ZIO* Z; Mbuffer* b; const char* name; -#ifdef LUAC_SWAP_ON_LOAD - int swap; -#endif } LoadState; -#ifdef LUAC_SWAP_ON_LOAD -static void LoadMem (LoadState* S, void* b, int n, size_t size); +#ifdef LUAC_TRUST_BINARIES +#define IF(c,s) #else -#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) -#endif - -#define LoadByte(S) (lu_byte)LoadChar(S) -#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) -#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) +#define IF(c,s) if (c) error(S,s) static void error(LoadState* S, const char* why) { - luaO_pushfstring(S->L,"%s: %s",S->name,why); + luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); luaD_throw(S->L,LUA_ERRSYNTAX); } +#endif + +#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) +#define LoadByte(S) (lu_byte)LoadChar(S) +#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) +#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) static void LoadBlock(LoadState* S, void* b, size_t size) { @@ -102,39 +94,6 @@ static void LoadCode(LoadState* S, Proto* f) LoadVector(S,f->code,n,sizeof(Instruction)); } -static void LoadLocals(LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->locvars=luaM_newvector(S->L,n,LocVar); - f->sizelocvars=n; - for (i=0; ilocvars[i].varname=NULL; - for (i=0; ilocvars[i].varname=LoadString(S); - f->locvars[i].startpc=LoadInt(S); - f->locvars[i].endpc=LoadInt(S); - } -} - -static void LoadLines(LoadState* S, Proto* f) -{ - int n=LoadInt(S); - f->lineinfo=luaM_newvector(S->L,n,int); - f->sizelineinfo=n; - LoadVector(S,f->lineinfo,n,sizeof(int)); -} - -static void LoadUpvalues(LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->upvalues=luaM_newvector(S->L,n,TString*); - f->sizeupvalues=n; - for (i=0; iupvalues[i]=NULL; - for (i=0; iupvalues[i]=LoadString(S); -} - static Proto* LoadFunction(LoadState* S, TString* p); static void LoadConstants(LoadState* S, Proto* f) @@ -174,6 +133,30 @@ static void LoadConstants(LoadState* S, Proto* f) for (i=0; ip[i]=LoadFunction(S,f->source); } +static void LoadDebug(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->lineinfo=luaM_newvector(S->L,n,int); + f->sizelineinfo=n; + LoadVector(S,f->lineinfo,n,sizeof(int)); + n=LoadInt(S); + f->locvars=luaM_newvector(S->L,n,LocVar); + f->sizelocvars=n; + for (i=0; ilocvars[i].varname=NULL; + for (i=0; ilocvars[i].varname=LoadString(S); + f->locvars[i].startpc=LoadInt(S); + f->locvars[i].endpc=LoadInt(S); + } + n=LoadInt(S); + f->upvalues=luaM_newvector(S->L,n,TString*); + f->sizeupvalues=n; + for (i=0; iupvalues[i]=NULL; + for (i=0; iupvalues[i]=LoadString(S); +} + static Proto* LoadFunction(LoadState* S, TString* p) { Proto* f=luaF_newproto(S->L); @@ -185,11 +168,9 @@ static Proto* LoadFunction(LoadState* S, TString* p) f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); - LoadLines(S,f); - LoadLocals(S,f); - LoadUpvalues(S,f); - LoadConstants(S,f); LoadCode(S,f); + LoadConstants(S,f); + LoadDebug(S,f); IF (!luaG_checkcode(f), "bad code"); S->L->top--; return f; @@ -201,9 +182,6 @@ static void LoadHeader(LoadState* S) char s[LUAC_HEADERSIZE]; luaU_header(h); LoadBlock(S,s,LUAC_HEADERSIZE); -#ifdef LUAC_SWAP_ON_LOAD - S->swap=(s[6]!=h[6]); s[6]=h[6]; -#endif IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); } @@ -236,55 +214,10 @@ void luaU_header (char* h) h+=sizeof(LUA_SIGNATURE)-1; *h++=(char)LUAC_VERSION; *h++=(char)LUAC_FORMAT; - *h++=(char)*(char*)&x; + *h++=(char)*(char*)&x; /* endianness */ *h++=(char)sizeof(int); *h++=(char)sizeof(size_t); *h++=(char)sizeof(Instruction); *h++=(char)sizeof(lua_Number); - *h++=(char)(((lua_Number)0.5)==0); -} - -#ifdef LUAC_SWAP_ON_LOAD -static void LoadMem (LoadState* S, void* b, int n, size_t size) -{ - LoadBlock(S,b,n*size); - if (S->swap) - { - char* p=(char*) b; - char c; - switch (size) - { - case 1: - break; - case 2: - while (n--) - { - c=p[0]; p[0]=p[1]; p[1]=c; - p+=2; - } - break; - case 4: - while (n--) - { - c=p[0]; p[0]=p[3]; p[3]=c; - c=p[1]; p[1]=p[2]; p[2]=c; - p+=4; - } - break; - case 8: - while (n--) - { - c=p[0]; p[0]=p[7]; p[7]=c; - c=p[1]; p[1]=p[6]; p[6]=c; - c=p[2]; p[2]=p[5]; p[5]=c; - c=p[3]; p[3]=p[4]; p[4]=c; - p+=8; - } - break; - default: - IF(1, "bad size"); - break; - } - } + *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ } -#endif diff --git a/src/lundump.h b/src/lundump.h index 5de3c46e4a..58cca5d190 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,6 +1,6 @@ /* -** $Id: lundump.h,v 1.38 2005/09/02 01:54:47 lhf Exp $ -** load pre-compiled Lua chunks +** $Id: lundump.h,v 1.40 2005/11/11 14:03:13 lhf Exp $ +** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -10,12 +10,6 @@ #include "lobject.h" #include "lzio.h" -/* make it work with Lua 5.0 */ -#ifndef LUA_VERSION_NUM -#define LUAI_FUNC -#define lua_Writer lua_Chunkwriter -#endif - /* load one chunk; from lundump.c */ LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); @@ -25,8 +19,10 @@ LUAI_FUNC void luaU_header (char* h); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); +#ifdef luac_c /* print one chunk; from print.c */ LUAI_FUNC void luaU_print (const Proto* f, int full); +#endif /* for header of binary files -- this is Lua 5.1 */ #define LUAC_VERSION 0x51 @@ -37,26 +33,4 @@ LUAI_FUNC void luaU_print (const Proto* f, int full); /* size of header of binary files */ #define LUAC_HEADERSIZE 12 -/* make it work with Lua 5.0 */ -#ifndef LUA_VERSION_NUM -#define LUA_SIGNATURE "\033Lua" -#define TValue TObject -#define rawtsvalue tsvalue -#define linedefined lineDefined -#define lastlinedefined lineDefined -#define setptvalue2s(L,t,f) -#undef setsvalue2n -#define setsvalue2n(L,x,y) setsvalue(x,y) -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") -#undef LUAC_VERSION -#define LUAC_VERSION 0x50 -#ifdef lapi_c -#define luaU_dump(L,f,w,d) (luaU_dump)(L,f,w,d,0) -#endif -#ifdef ldo_c -#define luaU_undump(L,z,b) (luaU_undump)(L,z,b,z->name) -#endif -#endif - #endif diff --git a/src/lvm.c b/src/lvm.c index 92c853b27c..c94644f9f5 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,11 +1,10 @@ /* -** $Id: lvm.c,v 2.55 2005/09/09 18:23:35 roberto Exp $ +** $Id: lvm.c,v 2.59 2005/11/01 16:08:45 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ -#include #include #include #include @@ -66,7 +65,6 @@ static void traceexec (lua_State *L, const Instruction *pc) { if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); - return; } } if (mask & LUA_MASKLINE) { @@ -226,7 +224,7 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numlt(L, nvalue(l), nvalue(r)); + return luai_numlt(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) @@ -240,7 +238,7 @@ static int lessequal (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numle(L, nvalue(l), nvalue(r)); + return luai_numle(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ @@ -256,7 +254,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; - case LUA_TNUMBER: return luai_numeq(L, nvalue(t1), nvalue(t2)); + case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { @@ -319,13 +317,13 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { - case TM_ADD: setnvalue(ra, luai_numadd(L, nb, nc)); break; - case TM_SUB: setnvalue(ra, luai_numsub(L, nb, nc)); break; - case TM_MUL: setnvalue(ra, luai_nummul(L, nb, nc)); break; - case TM_DIV: setnvalue(ra, luai_numdiv(L, nb, nc)); break; - case TM_MOD: setnvalue(ra, luai_nummod(L, nb, nc)); break; - case TM_POW: setnvalue(ra, luai_numpow(L, nb, nc)); break; - case TM_UNM: setnvalue(ra, luai_numunm(L, nb)); break; + case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; + case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; + case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; + case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; + case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; + case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; + case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; default: lua_assert(0); break; } } @@ -358,6 +356,19 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, #define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } +#define arith_op(op,tm) { \ + TValue *rb = RKB(i); \ + TValue *rc = RKC(i); \ + if (ttisnumber(rb) && ttisnumber(rc)) { \ + lua_Number nb = nvalue(rb), nc = nvalue(rc); \ + setnvalue(ra, op(nb, nc)); \ + } \ + else \ + Protect(Arith(L, ra, rb, rc, tm)); \ + } + + + void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; StkId base; @@ -455,76 +466,34 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_ADD: { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numadd(L, nb, nc)); - } - else - Protect(Arith(L, ra, rb, rc, TM_ADD)); + arith_op(luai_numadd, TM_ADD); continue; } case OP_SUB: { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numsub(L, nb, nc)); - } - else - Protect(Arith(L, ra, rb, rc, TM_SUB)); + arith_op(luai_numsub, TM_SUB); continue; } case OP_MUL: { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_nummul(L, nb, nc)); - } - else - Protect(Arith(L, ra, rb, rc, TM_MUL)); + arith_op(luai_nummul, TM_MUL); continue; } case OP_DIV: { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numdiv(L, nb, nc)); - } - else - Protect(Arith(L, ra, rb, rc, TM_DIV)); + arith_op(luai_numdiv, TM_DIV); continue; } case OP_MOD: { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_nummod(L, nb, nc)); - } - else - Protect(Arith(L, ra, rb, rc, TM_MOD)); + arith_op(luai_nummod, TM_MOD); continue; } case OP_POW: { - TValue *rb = RKB(i); - TValue *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, luai_numpow(L, nb, nc)); - } - else - Protect(Arith(L, ra, rb, rc, TM_POW)); + arith_op(luai_numpow, TM_POW); continue; } case OP_UNM: { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); - setnvalue(ra, luai_numunm(L, nb)); + setnvalue(ra, luai_numunm(nb)); } else { Protect(Arith(L, ra, rb, rb, TM_UNM)); @@ -594,18 +563,18 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_TEST: { - if (l_isfalse(ra) == GETARG_C(i)) pc++; - else - dojump(L, pc, GETARG_sBx(*pc) + 1); + if (l_isfalse(ra) != GETARG_C(i)) + dojump(L, pc, GETARG_sBx(*pc)); + pc++; continue; } case OP_TESTSET: { TValue *rb = RB(i); - if (l_isfalse(rb) == GETARG_C(i)) pc++; - else { + if (l_isfalse(rb) != GETARG_C(i)) { setobjs2s(L, ra, rb); - dojump(L, pc, GETARG_sBx(*pc) + 1); + dojump(L, pc, GETARG_sBx(*pc)); } + pc++; continue; } case OP_CALL: { @@ -678,9 +647,9 @@ void luaV_execute (lua_State *L, int nexeccalls) { } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); - lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ + lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); - if (step > 0 ? luai_numle(L, idx, limit) : luai_numle(L, limit, idx)) { + if (step > 0 ? luai_numle(idx, limit) : luai_numle(limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ @@ -698,7 +667,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); - setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); + setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); dojump(L, pc, GETARG_sBx(i)); continue; } @@ -711,12 +680,11 @@ void luaV_execute (lua_State *L, int nexeccalls) { Protect(luaD_call(L, cb, GETARG_C(i))); L->top = L->ci->top; cb = RA(i) + 3; /* previous call may change the stack */ - if (ttisnil(cb)) /* break loop? */ - pc++; /* skip jump (break loop) */ - else { + if (!ttisnil(cb)) { /* continue loop? */ setobjs2s(L, cb-1, cb); /* save control variable */ - dojump(L, pc, GETARG_sBx(*pc) + 1); /* jump back */ + dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ } + pc++; continue; } case OP_SETLIST: { diff --git a/src/print.c b/src/print.c index 8090a2d5d2..cfecba9648 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.52 2005/06/08 14:40:44 lhf Exp $ +** $Id: print.c,v 1.53 2005/11/11 14:03:13 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -7,6 +7,7 @@ #include #include +#define luac_c #define LUA_CORE #include "ldebug.h" @@ -14,6 +15,8 @@ #include "lopcodes.h" #include "lundump.h" +#define PrintFunction luaU_print + #define Sizeof(x) ((int)sizeof(x)) #define VOID(p) ((const void*)(p)) @@ -203,7 +206,7 @@ static void PrintUpvalues(const Proto* f) } } -void luaU_print(const Proto* f, int full) +void PrintFunction(const Proto* f, int full) { int i,n=f->sizep; PrintHeader(f); @@ -214,5 +217,5 @@ void luaU_print(const Proto* f, int full) PrintLocals(f); PrintUpvalues(f); } - for (i=0; ip[i],full); + for (i=0; ip[i],full); } From 4f266285f998d0d14c4e83cc29772f0de1a7fbba Mon Sep 17 00:00:00 2001 From: Lua Team Date: Thu, 12 Jan 2006 12:00:00 +0000 Subject: [PATCH 26/97] Lua 5.1-rc1 --- COPYRIGHT | 2 +- HISTORY | 2 +- INSTALL | 57 +- MANIFEST | 214 +++--- Makefile | 34 +- README | 2 +- doc/contents.html | 271 +++---- doc/lua.1 | 37 +- doc/lua.html | 51 +- doc/luac.1 | 34 +- doc/luac.html | 50 +- doc/manual.html | 1822 ++++++++++++++++++++++++--------------------- src/Makefile | 51 +- src/lapi.c | 27 +- src/lauxlib.c | 18 +- src/lauxlib.h | 4 +- src/lbaselib.c | 6 +- src/lcode.c | 12 +- src/ldblib.c | 6 +- src/ldebug.c | 8 +- src/ldo.c | 17 +- src/lfunc.c | 6 +- src/lgc.c | 17 +- src/linit.c | 4 +- src/liolib.c | 8 +- src/llex.c | 52 +- src/llex.h | 6 +- src/llimits.h | 23 +- src/lmem.c | 18 +- src/loadlib.c | 65 +- src/lobject.c | 12 +- src/lobject.h | 14 +- src/lopcodes.h | 4 +- src/loslib.c | 48 +- src/lparser.c | 80 +- src/lstring.c | 4 +- src/lstrlib.c | 59 +- src/ltable.c | 92 ++- src/ltable.h | 15 +- src/ltm.c | 6 +- src/lua.c | 14 +- src/lua.h | 8 +- src/luaconf.h | 44 +- src/lualib.h | 8 +- src/lvm.c | 14 +- src/print.c | 7 +- 46 files changed, 1822 insertions(+), 1531 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 282351f320..84d401b1e4 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 1994-2005 Lua.org, PUC-Rio. +Copyright (C) 1994-2006 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/HISTORY b/HISTORY index 8cf6bfbb03..fc603c9628 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,4 @@ -This is Lua 5.1 (beta). +This is Lua 5.1. * Changes from version 5.0 to 5.1 ------------------------------- diff --git a/INSTALL b/INSTALL index aa881bd74e..bd3b540c8d 100644 --- a/INSTALL +++ b/INSTALL @@ -1,17 +1,27 @@ -This is Lua 5.1 (beta). +This is Lua 5.1. -* Installation +* Building Lua ------------ - Building Lua on a Unix system should be very easy: simply doing "make" - should work. This will build Lua in the src directory. + Lua is built in the src directory, but the build process can be + controlled from the top-level Makefile. - There are also special make targets for ansi, linux, bsd, mingw. + Building Lua on Unix systems should be very easy. First do "make" and + see if your platform is listed. If so, just do "make xxx", where xxx + is your platform name. The platforms currently supported are: + ansi bsd generic linux macosx mingw posix - See below for customization instructions. + See below for customization instructions and for instructions on how + to build with other Windows compilers. - If you want to install Lua in an official place in your system, then - do "make install". The official place and the way to install files are - defined in Makefile. You must have the right permissions to install files. + If you want to check that Lua has been built correctly, do "make test" + after building Lua. Also, have a look at the example programs in test. + +* Installing Lua + -------------- + Once you have built Lua, you may want to install it in an official + place in your system. In this case, do "make install". The official + place and the way to install files are defined in Makefile. You must + have the right permissions to install files. If you want to install Lua locally, then do "make local". This will create directories bin, include, lib, man, and install Lua there as @@ -25,8 +35,11 @@ This is Lua 5.1 (beta). These are the only directories you need for development. There are man pages for lua and luac, in both nroff and html, and a - reference manual in html in ./doc, some sample code in ./test, and some - useful stuff in ./etc. You don't need these directories for development. + reference manual in html in doc, some sample code in test, and some + useful stuff in etc. You don't need these directories for development. + + If you want to install Lua locally, but in some other directory, do + "make install INSTALL_TOP=xxx", where xxx is your chosen directory. See below for instructions for Windows and other systems. @@ -44,14 +57,16 @@ This is Lua 5.1 (beta). to edit src/luaconf.h. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. - We strongly recommend that you enable dynamic loading. See src/luaconf.h - and also src/Makefile. + We strongly recommend that you enable dynamic loading. This is done + automatically for all platforms listed above that have this feature + (and also Windows). See src/luaconf.h and also src/Makefile. -* Installation on Windows and other systems +* Building Lua on Windows and other systems ----------------------------------------- - The instructions for building Lua on other systems depend on the compiler - you use. You'll need to create projects (or whatever your compiler uses) - for building the library, the interpreter, and the compiler, as follows: + If you're not using the usual Unix tools, then the instructions for + building Lua depend on the compiler you use. You'll need to create + projects (or whatever your compiler uses) for building the library, + the interpreter, and the compiler, as follows: library: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c @@ -63,8 +78,11 @@ This is Lua 5.1 (beta). compiler: library, luac.c print.c + If you use Visual Studio .NET, you can use etc/luavs.bat + in its "Command Prompt". + If all you want is to build the Lua interpreter, you may put all .c files - in a single project, except for luac.c and print.c. Or use etc/all.c. + in a single project, except for luac.c and print.c. Or just use etc/all.c. To use Lua as a library in your own programs, you'll need to know how to create and use libraries with your compiler. @@ -72,7 +90,4 @@ This is Lua 5.1 (beta). As mentioned above, you may edit luaconf.h to select some features before building Lua. - If you use Visual Studio .NET, you can use etc/luavs.bat - in its "Command Prompt". - (end of INSTALL) diff --git a/MANIFEST b/MANIFEST index 964437ee87..964df73c4a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,108 +1,108 @@ -MANIFEST contents of Lua 5.1 (beta) distribution on Fri Nov 18 07:42:23 BRST 2005 -lua-5.1-beta -lua-5.1-beta/COPYRIGHT -lua-5.1-beta/HISTORY -lua-5.1-beta/INSTALL -lua-5.1-beta/MANIFEST -lua-5.1-beta/Makefile -lua-5.1-beta/README -lua-5.1-beta/doc -lua-5.1-beta/doc/contents.html -lua-5.1-beta/doc/logo.gif -lua-5.1-beta/doc/lua.1 -lua-5.1-beta/doc/lua.css -lua-5.1-beta/doc/lua.html -lua-5.1-beta/doc/luac.1 -lua-5.1-beta/doc/luac.html -lua-5.1-beta/doc/manual.html -lua-5.1-beta/doc/readme.html -lua-5.1-beta/etc -lua-5.1-beta/etc/Makefile -lua-5.1-beta/etc/README -lua-5.1-beta/etc/all.c -lua-5.1-beta/etc/lua.hpp -lua-5.1-beta/etc/lua.ico -lua-5.1-beta/etc/lua.pc -lua-5.1-beta/etc/luavs.bat -lua-5.1-beta/etc/min.c -lua-5.1-beta/etc/noparser.c -lua-5.1-beta/etc/strict.lua -lua-5.1-beta/src -lua-5.1-beta/src/Makefile -lua-5.1-beta/src/lapi.c -lua-5.1-beta/src/lapi.h -lua-5.1-beta/src/lauxlib.c -lua-5.1-beta/src/lauxlib.h -lua-5.1-beta/src/lbaselib.c -lua-5.1-beta/src/lcode.c -lua-5.1-beta/src/lcode.h -lua-5.1-beta/src/ldblib.c -lua-5.1-beta/src/ldebug.c -lua-5.1-beta/src/ldebug.h -lua-5.1-beta/src/ldo.c -lua-5.1-beta/src/ldo.h -lua-5.1-beta/src/ldump.c -lua-5.1-beta/src/lfunc.c -lua-5.1-beta/src/lfunc.h -lua-5.1-beta/src/lgc.c -lua-5.1-beta/src/lgc.h -lua-5.1-beta/src/linit.c -lua-5.1-beta/src/liolib.c -lua-5.1-beta/src/llex.c -lua-5.1-beta/src/llex.h -lua-5.1-beta/src/llimits.h -lua-5.1-beta/src/lmathlib.c -lua-5.1-beta/src/lmem.c -lua-5.1-beta/src/lmem.h -lua-5.1-beta/src/loadlib.c -lua-5.1-beta/src/lobject.c -lua-5.1-beta/src/lobject.h -lua-5.1-beta/src/lopcodes.c -lua-5.1-beta/src/lopcodes.h -lua-5.1-beta/src/loslib.c -lua-5.1-beta/src/lparser.c -lua-5.1-beta/src/lparser.h -lua-5.1-beta/src/lstate.c -lua-5.1-beta/src/lstate.h -lua-5.1-beta/src/lstring.c -lua-5.1-beta/src/lstring.h -lua-5.1-beta/src/lstrlib.c -lua-5.1-beta/src/ltable.c -lua-5.1-beta/src/ltable.h -lua-5.1-beta/src/ltablib.c -lua-5.1-beta/src/ltm.c -lua-5.1-beta/src/ltm.h -lua-5.1-beta/src/lua.c -lua-5.1-beta/src/lua.h -lua-5.1-beta/src/luac.c -lua-5.1-beta/src/luaconf.h -lua-5.1-beta/src/lualib.h -lua-5.1-beta/src/lundump.c -lua-5.1-beta/src/lundump.h -lua-5.1-beta/src/lvm.c -lua-5.1-beta/src/lvm.h -lua-5.1-beta/src/lzio.c -lua-5.1-beta/src/lzio.h -lua-5.1-beta/src/print.c -lua-5.1-beta/test -lua-5.1-beta/test/README -lua-5.1-beta/test/bisect.lua -lua-5.1-beta/test/cf.lua -lua-5.1-beta/test/echo.lua -lua-5.1-beta/test/env.lua -lua-5.1-beta/test/factorial.lua -lua-5.1-beta/test/fib.lua -lua-5.1-beta/test/fibfor.lua -lua-5.1-beta/test/globals.lua -lua-5.1-beta/test/hello.lua -lua-5.1-beta/test/life.lua -lua-5.1-beta/test/luac.lua -lua-5.1-beta/test/printf.lua -lua-5.1-beta/test/readonly.lua -lua-5.1-beta/test/sieve.lua -lua-5.1-beta/test/sort.lua -lua-5.1-beta/test/table.lua -lua-5.1-beta/test/trace-calls.lua -lua-5.1-beta/test/trace-globals.lua -lua-5.1-beta/test/xd.lua +MANIFEST contents of Lua 5.1 distribution on Wed Jan 11 22:50:45 BRST 2006 +lua-5.1 +lua-5.1/COPYRIGHT +lua-5.1/doc +lua-5.1/doc/contents.html +lua-5.1/doc/logo.gif +lua-5.1/doc/lua.1 +lua-5.1/doc/luac.1 +lua-5.1/doc/luac.html +lua-5.1/doc/lua.css +lua-5.1/doc/lua.html +lua-5.1/doc/manual.html +lua-5.1/doc/readme.html +lua-5.1/etc +lua-5.1/etc/all.c +lua-5.1/etc/lua.hpp +lua-5.1/etc/lua.ico +lua-5.1/etc/lua.pc +lua-5.1/etc/luavs.bat +lua-5.1/etc/Makefile +lua-5.1/etc/min.c +lua-5.1/etc/noparser.c +lua-5.1/etc/README +lua-5.1/etc/strict.lua +lua-5.1/HISTORY +lua-5.1/INSTALL +lua-5.1/Makefile +lua-5.1/MANIFEST +lua-5.1/README +lua-5.1/src +lua-5.1/src/lapi.c +lua-5.1/src/lapi.h +lua-5.1/src/lauxlib.c +lua-5.1/src/lauxlib.h +lua-5.1/src/lbaselib.c +lua-5.1/src/lcode.c +lua-5.1/src/lcode.h +lua-5.1/src/ldblib.c +lua-5.1/src/ldebug.c +lua-5.1/src/ldebug.h +lua-5.1/src/ldo.c +lua-5.1/src/ldo.h +lua-5.1/src/ldump.c +lua-5.1/src/lfunc.c +lua-5.1/src/lfunc.h +lua-5.1/src/lgc.c +lua-5.1/src/lgc.h +lua-5.1/src/linit.c +lua-5.1/src/liolib.c +lua-5.1/src/llex.c +lua-5.1/src/llex.h +lua-5.1/src/llimits.h +lua-5.1/src/lmathlib.c +lua-5.1/src/lmem.c +lua-5.1/src/lmem.h +lua-5.1/src/loadlib.c +lua-5.1/src/lobject.c +lua-5.1/src/lobject.h +lua-5.1/src/lopcodes.c +lua-5.1/src/lopcodes.h +lua-5.1/src/loslib.c +lua-5.1/src/lparser.c +lua-5.1/src/lparser.h +lua-5.1/src/lstate.c +lua-5.1/src/lstate.h +lua-5.1/src/lstring.c +lua-5.1/src/lstring.h +lua-5.1/src/lstrlib.c +lua-5.1/src/ltable.c +lua-5.1/src/ltable.h +lua-5.1/src/ltablib.c +lua-5.1/src/ltm.c +lua-5.1/src/ltm.h +lua-5.1/src/lua.c +lua-5.1/src/luac.c +lua-5.1/src/luaconf.h +lua-5.1/src/lua.h +lua-5.1/src/lualib.h +lua-5.1/src/lundump.c +lua-5.1/src/lundump.h +lua-5.1/src/lvm.c +lua-5.1/src/lvm.h +lua-5.1/src/lzio.c +lua-5.1/src/lzio.h +lua-5.1/src/Makefile +lua-5.1/src/print.c +lua-5.1/test +lua-5.1/test/bisect.lua +lua-5.1/test/cf.lua +lua-5.1/test/echo.lua +lua-5.1/test/env.lua +lua-5.1/test/factorial.lua +lua-5.1/test/fibfor.lua +lua-5.1/test/fib.lua +lua-5.1/test/globals.lua +lua-5.1/test/hello.lua +lua-5.1/test/life.lua +lua-5.1/test/luac.lua +lua-5.1/test/printf.lua +lua-5.1/test/README +lua-5.1/test/readonly.lua +lua-5.1/test/sieve.lua +lua-5.1/test/sort.lua +lua-5.1/test/table.lua +lua-5.1/test/trace-calls.lua +lua-5.1/test/trace-globals.lua +lua-5.1/test/xd.lua END OF MANIFEST diff --git a/Makefile b/Makefile index e554e18971..9e627259f5 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,9 @@ # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= +# Your platform. See PLATS for possible values. +PLAT= none + # Where to install. The installation starts in the src directory, so take care # if INSTALL_TOP is not an absolute path. (Man pages are installed from the # doc directory.) @@ -24,6 +27,9 @@ INSTALL_DATA= cp # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= +# Convenience platforms targets. +PLATS= ansi bsd generic linux macosx mingw posix + # What to install. TO_BIN= lua luac TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp @@ -33,7 +39,9 @@ TO_MAN= lua.1 luac.1 # Lua version. Currently used only for messages. V= 5.1 -all clean: +all: $(PLAT) + +$(PLATS) clean: cd src; $(MAKE) $@ test: all @@ -49,27 +57,8 @@ install: all local: $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -p" INSTALL_DATA="cp -p" -# convenience targets for usual platforms - -ansi: - cd src; $(MAKE) MYCFLAGS=-DLUA_ANSI - -linux: - cd src; $(MAKE) MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" - -macosx: - cd src; $(MAKE) MYCFLAGS=-DLUA_USE_MACOSX - -posix: - cd src; $(MAKE) MYCFLAGS=-DLUA_USE_POSIX - -bsd: - cd src; $(MAKE) MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" - -mingw: - cd src; $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ - "AR=gcc -shared -o" "RANLIB=strip --strip-unneeded" \ - "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe +none: + @echo "Please choose a platform: $(PLATS)" # echo config parameters echo: @@ -80,6 +69,7 @@ echo: @echo "" @echo "These are the parameters currently set in Makefile to install Lua $V:" @echo "" + @echo "PLAT = $(PLAT)" @echo "INSTALL_TOP = $(INSTALL_TOP)" @echo "INSTALL_BIN = $(INSTALL_BIN)" @echo "INSTALL_INC = $(INSTALL_INC)" diff --git a/README b/README index 5f950281fd..51dfeedeb9 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Lua 5.1 (beta). +This is Lua 5.1. See HISTORY for a summary of changes since the last released version. * What is Lua? diff --git a/doc/contents.html b/doc/contents.html index 25dd0c5a0f..7b890342bd 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -14,12 +14,14 @@

    Copyright -© 2005 Lua.org, PUC-Rio. All rights reserved. +© 2006 Lua.org, PUC-Rio. All rights reserved.
    +

    Contents

    -

    Word index

    - +

    Quick index

    + + + + + + +
    +

    Functions

    _G
    _VERSION
    assert
    @@ -146,52 +151,83 @@

    Word index

    load
    loadfile
    loadstring
    - -luaL_Buffer
    -luaL_Reg
    -luaL_addchar
    -luaL_addlstring
    -luaL_addsize
    -luaL_addstring
    -luaL_addvalue
    -luaL_argcheck
    -luaL_argerror
    -luaL_buffinit
    -luaL_callmeta
    -luaL_checkany
    -luaL_checkint
    -luaL_checkinteger
    -luaL_checklong
    -luaL_checklstring
    -luaL_checknumber
    -luaL_checkoption
    -luaL_checkstack
    -luaL_checkstring
    -luaL_checktype
    -luaL_checkudata
    -luaL_error
    -luaL_getmetafield
    -luaL_getmetatable
    -luaL_gsub
    -luaL_loadbuffer
    -luaL_loadfile
    -luaL_loadstring
    -luaL_newmetatable
    -luaL_newstate
    -luaL_optint
    -luaL_optinteger
    -luaL_optlong
    -luaL_optlstring
    -luaL_optnumber
    -luaL_optstring
    -luaL_prepbuffer
    -luaL_pushresult
    -luaL_ref
    -luaL_register
    -luaL_typename
    -luaL_typerror
    -luaL_unref
    -luaL_where
    +math.abs
    +math.acos
    +math.asin
    +math.atan
    +math.atan2
    +math.ceil
    +math.cos
    +math.cosh
    +math.def
    +math.exp
    +math.floor
    +math.fmod
    +math.ldexp
    +math.log
    +math.log10
    +math.pow
    +math.sin
    +math.sinh
    +math.sqrt
    +math.tan
    +math.tanh
    +module
    +next
    +os.clock
    +os.date
    +os.difftime
    +os.execute
    +os.exit
    +os.getenv
    +os.remove
    +os.rename
    +os.setlocale
    +os.time
    +os.tmpname
    +package.cpath
    +package.loaded
    +package.loadlib
    +package.path
    +package.preload
    +package.seeall
    +pairs
    +pcall
    +print
    +rawequal
    +rawget
    +rawset
    +require
    +select
    +setfenv
    +setmetatable
    +string.byte
    +string.char
    +string.dump
    +string.find
    +string.format
    +string.gmatch
    +string.gsub
    +string.len
    +string.lower
    +string.match
    +string.rep
    +string.reverse
    +string.sub
    +string.upper
    +table.concat
    +table.insert
    +table.maxn
    +table.remove
    +table.sort
    +tonumber
    +tostring
    +type
    +unpack
    +xpcall
    +
    +

    API

    lua_Alloc
    lua_CFunction
    lua_Debug
    @@ -256,6 +292,7 @@

    Word index

    lua_pushnil
    lua_pushnumber
    lua_pushstring
    +lua_pushthread
    lua_pushvalue
    lua_pushvfstring
    lua_rawequal
    @@ -275,6 +312,7 @@

    Word index

    lua_settable
    lua_settop
    lua_setupvalue
    +lua_status
    lua_toboolean
    lua_tocfunction
    lua_tointeger
    @@ -285,89 +323,66 @@

    Word index

    lua_tothread
    lua_touserdata
    lua_type
    +lua_typename
    lua_xmove
    lua_yield
    - -math.abs
    -math.acos
    -math.asin
    -math.atan
    -math.atan2
    -math.ceil
    -math.cos
    -math.cosh
    -math.def
    -math.exp
    -math.floor
    -math.fmod
    -math.ldexp
    -math.log
    -math.log10
    -math.pow
    -math.sin
    -math.sinh
    -math.sqrt
    -math.tan
    -math.tanh
    -module
    -next
    -os.clock
    -os.date
    -os.difftime
    -os.execute
    -os.exit
    -os.getenv
    -os.remove
    -os.rename
    -os.setlocale
    -os.time
    -os.tmpname
    -package.cpath
    -package.loaded
    -package.loadlib
    -package.path
    -package.preload
    -package.seeall
    -pairs
    -pcall
    -print
    -rawequal
    -rawget
    -rawset
    -require
    -select
    -setfenv
    -setmetatable
    -string.byte
    -string.char
    -string.dump
    -string.find
    -string.format
    -string.gmatch
    -string.gsub
    -string.len
    -string.lower
    -string.match
    -string.rep
    -string.reverse
    -string.sub
    -string.upper
    -table.concat
    -table.insert
    -table.maxn(table)
    -table.remove
    -table.sort
    -tonumber
    -tostring
    -type
    -unpack
    -xpcall
    +
    +

    Auxiliary library

    +luaL_Buffer
    +luaL_Reg
    +luaL_addchar
    +luaL_addlstring
    +luaL_addsize
    +luaL_addstring
    +luaL_addvalue
    +luaL_argcheck
    +luaL_argerror
    +luaL_buffinit
    +luaL_callmeta
    +luaL_checkany
    +luaL_checkint
    +luaL_checkinteger
    +luaL_checklong
    +luaL_checklstring
    +luaL_checknumber
    +luaL_checkoption
    +luaL_checkstack
    +luaL_checkstring
    +luaL_checktype
    +luaL_checkudata
    +luaL_error
    +luaL_getmetafield
    +luaL_getmetatable
    +luaL_gsub
    +luaL_loadbuffer
    +luaL_loadfile
    +luaL_loadstring
    +luaL_newmetatable
    +luaL_newstate
    +luaL_optint
    +luaL_optinteger
    +luaL_optlong
    +luaL_optlstring
    +luaL_optnumber
    +luaL_optstring
    +luaL_prepbuffer
    +luaL_pushresult
    +luaL_ref
    +luaL_register
    +luaL_typename
    +luaL_typerror
    +luaL_unref
    +luaL_where
    +


    Last update: -Tue Nov 1 15:40:46 BRST 2005 +Tue Jan 10 10:10:22 BRST 2006 diff --git a/doc/lua.1 b/doc/lua.1 index 39c7d8e483..24809cc6c1 100644 --- a/doc/lua.1 +++ b/doc/lua.1 @@ -1,5 +1,5 @@ -.\" $Id: lua.man,v 1.9 2005/09/02 16:29:34 lhf Exp $ -.TH LUA 1 "$Date: 2005/09/02 16:29:34 $" +.\" $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ +.TH LUA 1 "$Date: 2006/01/06 16:03:34 $" .SH NAME lua \- Lua interpreter .SH SYNOPSIS @@ -45,9 +45,9 @@ The arguments in .B arg start at 0, which contains the string -.RI ` script '. +.RI ' script '. The index of the last argument is stored in -.BR "arg.n" . +.BR arg.n . The arguments given in the command line before .IR script , including the name of the interpreter, @@ -63,17 +63,17 @@ if it is defined. If the value of .B LUA_INIT is of the form -.RI `@ filename ', +.RI '@ filename ', then .I filename is executed. Otherwise, the string is assumed to be a Lua statement and is executed. .LP Options start with -.B \- +.B '\-' and are described below. You can use -.B "\--" +.B "'\--'" to signal the end of options. .LP If no arguments are given, @@ -96,11 +96,11 @@ a syntax error is found. So, one way to interrupt the reading of an incomplete statement is to force a syntax error: adding a -.B `;' +.B ';' in the middle of a statement is a sure way of forcing a syntax error (except inside multiline strings and comments; these must be closed explicitly). If a line starts with -.BR `=' , +.BR '=' , then .B lua displays the values of all the expressions in the remainder of the @@ -115,11 +115,10 @@ So, to change the prompts, set the corresponding variable to a string of your choice. You can do that after calling the interpreter -or on the command line with -.BR "_PROMPT" "=\'lua: \'" , -for example. -(Note the need for quotes, because the string contains a space.) -The default prompts are ``> '' and ``>> ''. +or on the command line +(but in this case you have to be careful with quotes +if the prompt string contains a space; otherwise you may confuse the shell.) +The default prompts are "> " and ">> ". .SH OPTIONS .TP .B \- @@ -141,14 +140,12 @@ enter interactive mode after .I script is executed. .TP -.BI \-l " module" +.BI \-l " name" call -.BI require( module ) +.BI require(' name ') before executing -.IR script. -Typically used to load libraries -(hence the letter -.IR l ). +.IR script . +Typically used to load libraries. .TP .B \-v show version information. diff --git a/doc/lua.html b/doc/lua.html index 3bc0d8aed4..5900321f4c 100644 --- a/doc/lua.html +++ b/doc/lua.html @@ -1,4 +1,4 @@ - + LUA man page @@ -7,9 +7,9 @@ -

    NAME

    +

    NAME

    lua - Lua interpreter -

    SYNOPSIS

    +

    SYNOPSIS

    lua [ options @@ -20,7 +20,7 @@

    SYNOPSIS

    args ] ] -

    DESCRIPTION

    +

    DESCRIPTION

    lua is the stand-alone Lua interpreter. It loads and executes Lua programs, @@ -52,9 +52,9 @@

    DESCRIPTION

    arg start at 0, which contains the string -`script'. +'script'. The index of the last argument is stored in -"arg.n". +arg.n. The arguments given in the command line before script, including the name of the interpreter, @@ -70,17 +70,17 @@

    DESCRIPTION

    If the value of LUA_INIT is of the form -`@filename', +'@filename', then filename is executed. Otherwise, the string is assumed to be a Lua statement and is executed.

    Options start with -- +'-' and are described below. You can use -"--" +'--' to signal the end of options.

    If no arguments are given, @@ -103,11 +103,11 @@

    DESCRIPTION

    So, one way to interrupt the reading of an incomplete statement is to force a syntax error: adding a -`;' +';' in the middle of a statement is a sure way of forcing a syntax error (except inside multiline strings and comments; these must be closed explicitly). If a line starts with -`=', +'=', then lua displays the values of all the expressions in the remainder of the @@ -122,12 +122,11 @@

    DESCRIPTION

    to change the prompts, set the corresponding variable to a string of your choice. You can do that after calling the interpreter -or on the command line with -"_PROMPT" "=\'lua: \'", -for example. -(Note the need for quotes, because the string contains a space.) -The default prompts are ``> '' and ``>> ''. -

    OPTIONS

    +or on the command line +(but in this case you have to be careful with quotes +if the prompt string contains a space; otherwise you may confuse the shell.) +The default prompts are "> " and ">> ". +

    OPTIONS

    - load and execute the standard input as a file, @@ -135,7 +134,7 @@

    OPTIONS

    not interactively, even when the standard input is a terminal.

    --e "stat" +-e stat execute statement stat. You need to quote @@ -148,24 +147,22 @@

    OPTIONS

    script is executed.

    --l "module" +-l name call -require( module) +require(' name') before executing -script. -Typically used to load libraries -(hence the letter -l). +script. +Typically used to load libraries.

    -v show version information. -

    SEE ALSO

    +

    SEE ALSO

    luac(1)
    http://www.lua.org/ -

    DIAGNOSTICS

    +

    DIAGNOSTICS

    Error messages should be self explanatory. -

    AUTHORS

    +

    AUTHORS

    R. Ierusalimschy, L. H. de Figueiredo, and diff --git a/doc/luac.1 b/doc/luac.1 index 7a44e2f2f2..6bede1f363 100644 --- a/doc/luac.1 +++ b/doc/luac.1 @@ -1,5 +1,5 @@ -.\" $Id: luac.man,v 1.26 2005/09/02 16:29:34 lhf Exp $ -.TH LUAC 1 "$Date: 2005/09/02 16:29:34 $" +.\" $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ +.TH LUAC 1 "$Date: 2006/01/06 16:03:34 $" .SH NAME luac \- Lua compiler .SH SYNOPSIS @@ -17,7 +17,7 @@ into binary files that can be latter loaded and executed. .LP The main advantages of precompiling chunks are: faster loading, -protecting source code from user changes, +protecting source code from accidental user changes, and off-line syntax checking. .LP @@ -26,6 +26,13 @@ because in Lua chunks are always compiled into bytecodes before being executed. .B luac simply allows those bytecodes to be saved in a file for later execution. .LP +Pre-compiled chunks are not necessarily smaller than the corresponding source. +The main goal in pre-compiling is faster loading. +.LP +The binary files created by +.B luac +are portable only among architectures with the same word size and byte order. +.LP .B luac produces a single output file containing the bytecodes for all source files given. @@ -36,10 +43,6 @@ but you can change this with the .B \-o option. .LP -The binary files created by -.B luac -are portable only among architectures with the same word size and byte order. -.LP In the command line, you can mix text files containing Lua source and @@ -49,14 +52,14 @@ even from different (but compatible) platforms, into a single precompiled chunk. .LP You can use -.B "\-" +.B "'\-'" to indicate the standard input as a source file and -.B "\--" +.B "'\--'" to signal the end of options (that is, all remaining arguments will be treated as files even if they start with -.BR "\-" ). +.BR "'\-'" ). .LP The internal format of the binary files produced by .B luac @@ -81,6 +84,10 @@ output to .IR file , instead of the default .BR luac.out . +(You can use +.B "'\-'" +for standard output, +but not on platforms that open standard output in text mode.) The output file may be a source file because all files are loaded before the output file is written. Be careful not to overwrite precious files. @@ -105,9 +112,10 @@ No messages are displayed if the file passes the integrity test. .B \-s strip debug information before writing the output file. This saves some space in very large chunks, -but if errors occur when running these chunks, -then the error messages may not contain the full information they usually do -(line numbers and names of locals are lost). +but if errors occur when running a stripped chunk, +then the error messages may not contain the full information they usually do. +For instance, +line numbers and names of local variables are lost. .TP .B \-v show version information. diff --git a/doc/luac.html b/doc/luac.html index 586b38e869..3ecdfdf037 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -1,4 +1,4 @@ - + LUAC man page @@ -7,16 +7,16 @@ -

    NAME

    +

    NAME

    luac - Lua compiler -

    SYNOPSIS

    +

    SYNOPSIS

    luac [ options ] [ filenames ] -

    DESCRIPTION

    +

    DESCRIPTION

    luac is the Lua compiler. It translates programs written in the Lua programming language @@ -24,7 +24,7 @@

    DESCRIPTION

    The main advantages of precompiling chunks are: faster loading, -protecting source code from user changes, +protecting source code from accidental user changes, and off-line syntax checking.

    @@ -33,6 +33,13 @@

    DESCRIPTION

    luac simply allows those bytecodes to be saved in a file for later execution.

    +Pre-compiled chunks are not necessarily smaller than the corresponding source. +The main goal in pre-compiling is faster loading. +

    +The binary files created by +luac +are portable only among architectures with the same word size and byte order. +

    luac produces a single output file containing the bytecodes for all source files given. @@ -43,10 +50,6 @@

    DESCRIPTION

    -o option.

    -The binary files created by -luac -are portable only among architectures with the same word size and byte order. -

    In the command line, you can mix text files containing Lua source and @@ -56,14 +59,14 @@

    DESCRIPTION

    into a single precompiled chunk.

    You can use -"-" +'-' to indicate the standard input as a source file and -"--" +'--' to signal the end of options (that is, all remaining arguments will be treated as files even if they start with -"-"). +'-').

    The internal format of the binary files produced by luac @@ -71,7 +74,7 @@

    DESCRIPTION

    So, save the source files of all Lua programs that you precompile.

    -

    OPTIONS

    +

    OPTIONS

    Options must be separate.

    -l @@ -83,11 +86,15 @@

    OPTIONS

    luac.out and lists its contents.

    --o "file" +-o file output to file, instead of the default luac.out. +(You can use +'-' +for standard output, +but not on platforms that open standard output in text mode.) The output file may be a source file because all files are loaded before the output file is written. Be careful not to overwrite precious files. @@ -112,23 +119,24 @@

    OPTIONS

    -s strip debug information before writing the output file. This saves some space in very large chunks, -but if errors occur when running these chunks, -then the error messages may not contain the full information they usually do -(line numbers and names of locals are lost). +but if errors occur when running a stripped chunk, +then the error messages may not contain the full information they usually do. +For instance, +line numbers and names of local variables are lost.

    -v show version information. -

    FILES

    +

    FILES

    luac.out default output file -

    SEE ALSO

    +

    SEE ALSO

    lua(1)
    http://www.lua.org/ -

    DIAGNOSTICS

    +

    DIAGNOSTICS

    Error messages should be self explanatory. -

    AUTHORS

    +

    AUTHORS

    L. H. de Figueiredo, R. Ierusalimschy and W. Celes diff --git a/doc/manual.html b/doc/manual.html index 293532f1e6..df42a932e8 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -8,9 +8,9 @@ -
    +

    -[Lua logo] +[Lua logo] Lua 5.1 Reference Manual

    @@ -18,16 +18,15 @@

    Copyright -© 2005 Lua.org, PUC-Rio. All rights reserved. +© 2006 Lua.org, PUC-Rio. All rights reserved. -


    +

    -

    1 - Introduction

    Lua is an extension programming language designed to support @@ -36,7 +35,7 @@

    It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight -configuration language for any program that needs one. +scripting language for any program that needs one. Lua is implemented as a library, written in clean C (that is, in the common subset of ANSI C and C++). @@ -49,42 +48,21 @@

    Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. - -

    The Lua distribution includes a stand-alone embedding program, -lua, that uses the Lua library to offer a complete Lua interpreter. +The Lua distribution includes a sample host program called lua, +which uses the Lua library to offer a complete, stand-alone Lua interpreter.

    Lua is free software, and is provided as usual with no guarantees, -as stated in its copyright notice. +as stated in its license. The implementation described in this manual is available at Lua's official web site, www.lua.org.

    Like any other reference manual, this document is dry in places. For a discussion of the decisions behind the design of Lua, -see the papers below, -which are available at Lua's web site. -

      -
    • -R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. -Lua---an extensible extension language. -Software: Practice & Experience 26:6 (1996) 635--652. -
    • -L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. -The design and implementation of a language for extending applications. -Proceedings of XXI Brazilian Seminar on Software and Hardware -(1994) 273--283. -
    • -L. H. de Figueiredo, R. Ierusalimschy, and W. Celes. -Lua: an extensible embedded language. -Dr. Dobb's Journal 21:12 (Dec 1996) 26--33. -
    • -R. Ierusalimschy, L. H. de Figueiredo, and W. Celes. -The evolution of an extension language: a history of Lua, -Proceedings of V Brazilian Symposium on Programming Languages (2001) B-14--B-28. -
    - -

    Lua means "moon" in Portuguese and is pronounced LOO-ah. +see the technical papers available at Lua's web site. +For a detailed introduction to programming in Lua, +see Roberto's book, Programming in Lua.

    2 - The Language

    @@ -96,7 +74,7 @@

    how they can be combined, and what their combinations mean. -

    The language constructs will be explained using the usual extended BNF, +

    The language constructs will be explained using the usual extended BNF notation, in which {a} means 0 or more a's, and [a] means an optional a. @@ -104,16 +82,20 @@

    keywords are shown in bold, and other terminal symbols are shown in typewriter font, enclosed in single quotes. +The complete syntax of Lua can be found at the end of this manual.

    2.1 - Lexical Conventions

    -

    Names in Lua can be any string of letters, +

    Names +(also called identifiers) +in Lua can be any string of letters, digits, and underscores, not beginning with a digit. This coincides with the definition of names in most languages. (The definition of letter depends on the current locale: any character considered alphabetic by the current locale can be used in an identifier.) +Identifiers are used to name variables and table fields.

    The following keywords are reserved and cannot be used as names: @@ -130,7 +112,7 @@

    are two different, valid names. As a convention, names starting with an underscore followed by uppercase letters (such as _VERSION) -are reserved for internal variables used by Lua. +are reserved for internal global variables used by Lua.

    The following strings denote other tokens:

    @@ -152,8 +134,8 @@ 

  • \t --- horizontal tab
  • \v --- vertical tab
  • \\ --- backslash -
  • \" --- quotation mark -
  • \' --- apostrophe +
  • \" --- quotation mark (double quote) +
  • \' --- apostrophe (single quote) Moreover, a `\newline´ (that is, a backslash followed by a real newline) @@ -161,38 +143,51 @@

    A character in a string may also be specified by its numerical value using the escape sequence `\ddd´, where ddd is a sequence of up to three decimal digits. +(Note that if a numerical escape is to be followed by a digit, +it must be expressed using exactly three digits.) Strings in Lua may contain any 8-bit value, including embedded zeros, which can be specified as `\0´. +

    To put a double (single) quote, a newline, a backslash, +or an embedded zero +inside a literal string enclosed by double (single) quotes +you must use an escape sequence. +Any other character may be directly inserted into the literal. +(Some control characters may cause problems for the file system, +but Lua has no problem with them.) +

    Literal strings can also be defined using a long format -enclosed by l-brackets (long brackets). -We define an opening l-bracket of level n as an opening +enclosed by long brackets. +We define an opening long bracket of level n as an opening square bracket followed by n equal signs followed by another opening square bracket. -So, an opening l-bracket of level 0 is written as [[, -an opening l-bracket of level 1 is written as [=[, +So, an opening long bracket of level 0 is written as [[, +an opening long bracket of level 1 is written as [=[, and so on. -A closing l-bracket is defined similarly; -for instance, a closing l-bracket of level 4 is written as ]====]. -A long string starts with an opening l-bracket of any level and -ends at the first closing l-bracket of the same level. +A closing long bracket is defined similarly; +for instance, a closing long bracket of level 4 is written as ]====]. +A long string starts with an opening long bracket of any level and +ends at the first closing long bracket of the same level. Literals in this bracketed form may run for several lines, do not interpret any escape sequences, -and ignore l-brackets of any other level. +and ignore long brackets of any other level. +They may contain anything except a closing bracket of the proper level +or embedded zeros.

    For convenience, -when the opening l-bracket is immediately followed by a newline, +when the opening long bracket is immediately followed by a newline, the newline is not included in the string. As an example, in a system using ASCII (in which `a´ is coded as 97, newline is coded as 10, and `1´ is coded as 49), the four literals below denote the same string:

    -      (1)   "alo\n123\""
    -      (2)   '\97lo\10\04923"'
    -      (3)   [[alo
    +      (1)   'alo\n123"'
    +      (2)   "alo\n123\""
    +      (3)   '\97lo\10\04923"'
    +      (4)   [[alo
                 123"]]
    -      (4)   [==[
    +      (5)   [==[
                 alo
                 123"]==]
     
    @@ -204,13 +199,14 @@

    3 3.0 3.1416 314.16e-2 0.31416E1

  • -

    Comments start anywhere outside a string with a -double hyphen (--). -If the text immediately after -- is not an opening l-bracket, +

    Comments start with a double hyphen (--) +anywhere outside a string. +If the text immediately after -- is not an opening long bracket, the comment is a short comment, which runs until the end of the line. Otherwise, it is a long comment, -which runs until the corresponding closing l-bracket. +which runs until the corresponding closing long bracket. +Long comments are frequently used to disable code temporarily.

    2.2 - Values and Types

    @@ -220,15 +216,19 @@

    There are no type definitions in the language. All values carry their own type. +

    All values in Lua are first-class values. +That means that all values can be stored in variables, +passed as arguments to other functions, and returned as results. +

    There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table. Nil is the type of the value nil, whose main property is to be different from any other value; -usually it represents the absence of a useful value. +it usually represents the absence of a useful value. Boolean is the type of the values false and true. -In Lua, both nil and false make a condition false; +Both nil and false make a condition false; any other value makes it true. Number represents real (double-precision floating-point) numbers. (It is easy to build Lua interpreters that use other @@ -239,12 +239,9 @@

    Lua is 8-bit clean: Strings may contain any 8-bit character, -including embedded zeros ('\0') (see 2.1). +including embedded zeros (`\0´) (see 2.1). -

    Functions are first-class values in Lua. -That means that functions can be stored in variables, -passed as arguments to other functions, and returned as results. -Lua can call (and manipulate) functions written in Lua and +

    Lua can call (and manipulate) functions written in Lua and functions written in C (see 2.5.8). @@ -262,12 +259,14 @@

    The type thread represents independent threads of execution and it is used to implement coroutines (see 2.11). +Do not confuse Lua threads with operating-system threads. +Lua supports coroutines on all systems, +even those that do not support threads.

    The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, but with any value (except nil). -Moreover, -tables can be heterogeneous, +Tables can be heterogeneous; that is, they can contain values of all types (except nil). Tables are the sole data structuring mechanism in Lua; they may be used to represent ordinary arrays, @@ -281,11 +280,11 @@

    Like indices, the value of a table field can be of any type (except nil). In particular, -because functions are first class values, +because functions are first-class values, table fields may contain functions. Thus tables may also carry methods (see 2.5.9). -

    Tables, functions, and userdata values are objects: +

    Strings, tables, functions, and userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns @@ -300,7 +299,7 @@

    Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert -that string to a number, following the usual rules. +that string to a number, following the usual conversion rules. Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control of how numbers are converted to strings, @@ -315,12 +314,14 @@

    global variables, local variables, and table fields.

    A single name can denote a global variable or a local variable -(or a formal parameter of a function, -which is a particular form of local variable): +(or a function formal parameter, +which is a particular kind of local variable):

     	var ::= Name
     
    -Variables are assumed to be global unless explicitly declared local +Name denotes identifiers, as defined in (see 2.1). + +

    Variables are assumed to be global unless explicitly declared local (see 2.4.7). Local variables are lexically scoped: Local variables can be freely accessed by functions @@ -334,12 +335,12 @@

    The first expression (prefixexp) should result in a table value; the second expression (exp) -identifies a specific entry inside that table. +identifies a specific entry in that table. The expression denoting the table to be indexed has a restricted syntax; see 2.5 for details. -

    The syntax var.NAME is just syntactic sugar for -var["NAME"]: +

    The syntax var.Name is just syntactic sugar for +var["Name"] and is used to denote table fields:

     	var ::= prefixexp `.´ Name
     
    @@ -361,8 +362,10 @@

    will refer to that environment table. When a function is created, it inherits the environment from the function that created it. -To replace or get the environment table of a Lua function, -you call setfenv or getfenv. +To get the environment table of a Lua function, +you call setfenv. +To replace it, +you call setfenv. (You can only manipulate the environment of C functions through the debug library; (see 5.9).) @@ -384,7 +387,7 @@

    Lua supports an almost conventional set of statements, similar to those in Pascal or C. This set includes -assignment, control structures, procedure calls, +assignment, control structures, function calls, table constructors, and variable declarations.

    2.4.1 - Chunks

    @@ -396,6 +399,7 @@

     	chunk ::= {stat [`;´]}
     
    +There are no empty statements and thus `;;´ is not legal.

    Lua handles a chunk as the body of an anonymous function with a variable number of arguments @@ -404,7 +408,7 @@

    receive arguments, and return values.

    A chunk may be stored in a file or in a string inside the host program. -When a chunk is executed, first it is pre-compiled into opcodes for +When a chunk is executed, first it is pre-compiled into instructions for a virtual machine, and then the compiled code is executed by an interpreter for the virtual machine. @@ -417,7 +421,7 @@

    2.4.2 - Blocks

    A block is a list of statements; -syntactically, a block is equal to a chunk: +syntactically, a block is the same as a chunk:
     	block ::= chunk
     
    @@ -455,7 +459,7 @@

    If there are fewer values than needed, the list is extended with as many nil's as needed. If the list of expressions ends with a function call, -then all values returned by that function call enter in the list of values, +then all values returned by that call enter in the list of values, before the adjustment (except when the call is enclosed in parentheses; see 2.5). @@ -509,7 +513,7 @@

    Lua also has a for statement, in two flavors (see 2.4.5). -

    The condition expression exp of a +

    The condition expression of a control structure may return any value. Both false and nil are considered false. All values different from nil and false are considered true @@ -518,11 +522,11 @@

    In the repeat--until loop, the inner block does not end at the until keyword, but only after the condition. -That means the condition can refer to local variables -declared inside the loop. +So, the condition can refer to local variables +declared inside the loop block.

    The return statement is used to return values -from a function or from a chunk. +from a function or a chunk (which is just a function). Functions and chunks may return more than one value, so the syntax for the return statement is @@ -530,7 +534,7 @@

    stat ::= return [explist1]

    -

    The break statement can be used to terminate the execution of a +

    The break statement is used to terminate the execution of a while, repeat, or for loop, skipping to the next statement after the loop: @@ -539,7 +543,7 @@

    A break ends the innermost enclosing loop. -

    For syntactic reasons, return and break +

    The return and break statements can only be written as the last statement of a block. If it is really necessary to return or break in the middle of a block, @@ -599,11 +603,12 @@

    The generic for statement works over functions, called iterators. -For each iteration, it calls its iterator function to produce a new value, -stopping when the new value is nil. +On each iteration, the iterator function is called to produce a new value, +stopping when this new value is nil. The generic for loop has the following syntax:

    -	stat ::= for Name {`,´ Name} in explist1 do block end
    +	stat ::= for namelist in explist1 do block end
    +	namelist ::= Name {`,´ Name}
     
    A for statement like
    @@ -649,14 +654,13 @@ 

    The declaration may include an initial assignment:
     	stat ::= local namelist [`=´ explist1]
    -	namelist ::= Name {`,´ Name}
     
    If present, an initial assignment has the same semantics of a multiple assignment (see 2.4.3). Otherwise, all variables are initialized with nil.

    A chunk is also a block (see 2.4.1), -so local variables can be declared in a chunk outside any explicit block. +and so local variables can be declared in a chunk outside any explicit block. The scope of such local variables extends until the end of the chunk.

    The visibility rules for local variables are explained in 2.6. @@ -669,7 +673,7 @@

    exp ::= prefixexp exp ::= nil | false | true exp ::= Number - exp ::= Literal + exp ::= String exp ::= function exp ::= tableconstructor exp ::= `...´ @@ -684,7 +688,7 @@

    function calls are explained in 2.5.8; table constructors are explained in 2.5.7. Vararg expressions, -denoted by three dots (...), can only be used inside +denoted by three dots (`...´), can only be used inside vararg functions; they are explained in 2.5.9. @@ -738,18 +742,18 @@

    Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), -/ (division), % (modulus), and ^ (exponentiation); +/ (division), % (modulo), and ^ (exponentiation); and unary - (negation). If the operands are numbers, or strings that can be converted to numbers (see 2.2.1), then all operations have the usual meaning. Exponentiation works for any exponent. -For instance, x^-0.5 computes the inverse of the square root of x. +For instance, x^(-0.5) computes the inverse of the square root of x. Modulus is defined as
    -  a % b == a - math.floor(a/b)*b
    +       a % b == a - math.floor(a/b)*b
     
    -That is, it is the remaining of a division that rounds +That is, it is the remainder of a division that rounds the quotient towards minus infinity.

    2.5.2 - Relational Operators

    @@ -766,11 +770,12 @@

    Objects (tables, userdata, threads, and functions) are compared by reference: Two objects are considered equal only if they are the same object. -Every time you create a new object (a table, userdata, or function), +Every time you create a new object +(a table, userdata, thread, or function), this new object is different from any previously existing object.

    You can change the way that Lua compares tables and userdata -using the "eq" metamethod (see 2.8). +by using the "eq" metamethod (see 2.8).

    The conversion rules of 2.2.1 do not apply to equality comparisons. @@ -799,27 +804,29 @@

    and anything else as true. -

    The operator not always returns false or true. - -

    The conjunction operator and returns its first argument +

    The negation operator not always returns false or true. +The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument. The disjunction operator or returns its first argument if this value is different from nil and false; otherwise, or returns its second argument. -Both and and or use short-cut evaluation, +Both and and or use short-cut evaluation; that is, the second operand is evaluated only if necessary. -For example, +Here are some examples:

    -       10 or error()       -> 10
    -       nil or "a"          -> "a"
    -       nil and 10          -> nil
    -       false and error()   -> false
    -       false and nil       -> false
    -       false or nil        -> nil
    -       10 and 20           -> 20
    +       10 or 20            --> 10
    +       10 or error()       --> 10
    +       nil or "a"          --> "a"
    +       nil and 10          --> nil
    +       false and error()   --> false
    +       false and nil       --> false
    +       false or nil        --> nil
    +       10 and 20           --> 20
     
    +(Here and in the sequel, +`-->´ indicates the result of the preceding expression.)

    2.5.4 - Concatenation

    The string concatenation operator in Lua is @@ -830,21 +837,22 @@

    2.5.5 - The Length Operator

    -

    The length operator is denoted by the prefix #. +

    The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte). -The length of a table t is defined to be any + +

    The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n may be zero. - -

    For a regular array, with non-nil values from 1 to a given n, +For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), -then #t may be any of the indices that precede a nil value +then #t may be any of the indices that +directly precedes a nil value (that is, it may consider any such nil value as the end of the array). @@ -861,7 +869,8 @@

    not # - (unary) ^

    -You can use parentheses to change the precedences of an expression. +As usual, +you can use parentheses to change the precedences of an expression. The concatenation (`..´) and exponentiation (`^´) operators are right associative. All other binary operators are left associative. @@ -889,20 +898,20 @@

    Fields in the other formats do not affect this counting. For example,
    -       a = {[f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45}
    +       a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
     
    is equivalent to
            do
    -         local temp = {}
    -         temp[f(1)] = g
    -         temp[1] = "x"         -- 1st exp
    -         temp[2] = "y"         -- 2nd exp
    -         temp.x = 1            -- temp["x"] = 1
    -         temp[3] = f(x)        -- 3rd exp
    -         temp[30] = 23
    -         temp[4] = 45          -- 4th exp
    -         a = temp
    +         local t = {}
    +         t[f(1)] = g
    +         t[1] = "x"         -- 1st exp
    +         t[2] = "y"         -- 2nd exp
    +         t.x = 1            -- t["x"] = 1
    +         t[3] = f(x)        -- 3rd exp
    +         t[30] = 23
    +         t[4] = 45          -- 4th exp
    +         a = t
            end
     
    @@ -927,7 +936,7 @@

    If the value of prefixexp has type function, then that function is called with the given arguments. -Otherwise, its "call" metamethod is called, +Otherwise, the prefixexp "call" metamethod is called, having as first parameter the value of prefixexp, followed by the original call arguments (see 2.8). @@ -945,16 +954,14 @@

     	args ::= `(´ [explist1] `)´
     	args ::= tableconstructor
    -	args ::= Literal
    +	args ::= String
     
    All argument expressions are evaluated before the call. -A call of the form f{...} is syntactic sugar for -f({...}), that is, -the argument list is a single new table. +A call of the form f{...} is syntactic sugar for f({...}); +that is, the argument list is a single new table. A call of the form f'...' -(or f"..." or f[[...]]) is syntactic sugar for -f('...'), that is, -the argument list is a single literal string. +(or f"..." or f[[...]]) is syntactic sugar for f('...'); +that is, the argument list is a single literal string.

    As an exception to the free-format syntax of Lua, you cannot put a line break before the `(´ in a function call. @@ -964,7 +971,7 @@

    a = f (g).x(a)

    -Lua would read that as a = f(g).x(a). +Lua would see that as a single statement, a = f(g).x(a). So, if you want two statements, you must add a semi-colon between them. If you actually want to call f, you must remove the line break before (g). @@ -981,15 +988,15 @@

    calling function. Note that a tail call only happens with a particular syntax, where the return has one single function call as argument; -this syntax makes the calling function returns exactly +this syntax makes the calling function return exactly the returns of the called function. -So, all the following examples are not tail calls: +So, none of the following examples are tail calls:
    -  return (f(x))        -- results adjusted to 1
    -  return 2 * f(x)
    -  return x, f(x)       -- additional results
    -  f(x); return         -- results discarded
    -  return x or f(x)     -- results adjusted to 1
    +       return (f(x))        -- results adjusted to 1
    +       return 2 * f(x)
    +       return x, f(x)       -- additional results
    +       f(x); return         -- results discarded
    +       return x or f(x)     -- results adjusted to 1
     

    2.5.9 - Function Definitions

    @@ -1030,6 +1037,12 @@

            local f; f = function () ... end
     
    +not this: +
    +       local f = function () ... end
    +
    +(This only makes a difference when the body of the function +contains references to f.)

    A function definition is an executable expression, whose value has type function. @@ -1084,10 +1097,10 @@

    f(r(), 10) a=1, b=10 f(r()) a=1, b=2 - g(3) a=3, b=nil, ... -> (nothing) - g(3, 4) a=3, b=4, ... -> (nothing) - g(3, 4, 5, 8) a=3, b=4, ... -> 5 8 - g(5, r()) a=5, b=1, ... -> 2 3 + g(3) a=3, b=nil, ... --> (nothing) + g(3, 4) a=3, b=4, ... --> (nothing) + g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 + g(5, r()) a=5, b=1, ... --> 2 3

    Results are returned using the return statement (see 2.4.4). @@ -1114,36 +1127,29 @@

    The scope of variables begins at the first statement after their declaration and lasts until the end of the innermost block that includes the declaration. -For instance: -
    -  x = 10                -- global variable
    -  do                    -- new block
    -    local x = x         -- new `x', with value 10
    -    print(x)            --> 10
    -    x = x+1
    -    do                  -- another block
    -      local x = x+1     -- another `x'
    -      print(x)          --> 12
    -    end
    -    print(x)            --> 11
    -  end
    -  print(x)              --> 10  (the global one)
    +Consider the following example:
    +
    +       x = 10                -- global variable
    +       do                    -- new block
    +         local x = x         -- new `x', with value 10
    +         print(x)            --> 10
    +         x = x+1
    +         do                  -- another block
    +           local x = x+1     -- another `x'
    +           print(x)          --> 12
    +         end
    +         print(x)            --> 11
    +       end
    +       print(x)              --> 10  (the global one)
     
    -Notice that, in a declaration like local x = x, + +

    Notice that, in a declaration like local x = x, the new x being declared is not in scope yet, and so the second x refers to the outside variable.

    Because of the lexical scoping rules, local variables can be freely accessed by functions defined inside their scope. -For instance: -

    -  local counter = 0
    -  function inc (x)
    -    counter = counter + x
    -    return counter
    -  end
    -
    A local variable used by an inner function is called an upvalue, or external local variable, inside the inner function. @@ -1152,12 +1158,12 @@

    defines new local variables. Consider the following example:
    -  a = {}
    -  local x = 20
    -  for i=1,10 do
    -    local y = 0
    -    a[i] = function () y=y+1; return x+y end
    -  end
    +       a = {}
    +       local x = 20
    +       for i=1,10 do
    +         local y = 0
    +         a[i] = function () y=y+1; return x+y end
    +       end
     
    The loop creates ten closures (that is, ten instances of the anonymous function). @@ -1166,13 +1172,13 @@

    2.7 - Error Handling

    -

    Because Lua is an extension language, +

    Because Lua is an embedded extension language, all Lua actions start from C code in the host program calling a function from the Lua library (see ). Whenever an error occurs during Lua compilation or execution, control returns to C, which can take appropriate measures -(such as print an error message). +(such as printing an error message).

    Lua code can explicitly generate an error by calling the error function. @@ -1215,7 +1221,7 @@

    and for all strings, etc.

    A metatable may control how an object behaves in arithmetic operations, -order comparisons, concatenation, and indexing. +order comparisons, concatenation, length operation, and indexing. A metatable can also define a function to be called when a userdata is garbage collected. For each of those operations Lua associates a specific key @@ -1228,7 +1234,7 @@

    Metatables control the operations listed next. Each operation is identified by its corresponding name. The key for each operation is a string with its name prefixed by -two underscores; +two underscores, `__´; for instance, the key for operation "add" is the string "__add". The semantics of these operations is better explained by a Lua function @@ -1243,11 +1249,11 @@

    In particular, to retrieve the metamethod of a given object, we use the expression
    -  metatable(obj)[event]
    +       metatable(obj)[event]
     
    This should be read as
    -  rawget(metatable(obj) or {}, event)
    +       rawget(getmetatable(obj) or {}, event)
     
    That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail @@ -1522,11 +1528,11 @@

    Besides metatables, objects of types thread, function, and userdata have another table associated with them, -called environment. +called their environment. Like metatables, environments are regular tables and multiple objects can share the same environment. -

    Environments associated with userdata has no meaning for Lua. +

    Environments associated with userdata have no meaning for Lua. It is only a feature for programmers to associate a table to a userdata. @@ -1557,10 +1563,10 @@

    2.10 - Garbage Collection

    -

    Lua does automatic memory management. +

    Lua performs automatic memory management. That means that you do not have to worry about allocating memory for new objects -and freeing it when the objects are no longer needed. +not about freeing it when the objects are no longer needed. Lua manages memory automatically by running a garbage collector from time to time to collect all dead objects @@ -1568,9 +1574,12 @@

    All objects in Lua are subject to automatic management: tables, userdata, functions, threads, and strings. -

    Lua 5.1 implements an incremental mark-and-sweep collector. -It uses two numbers to control its garbage-collection cycles. -One number, the garbage-collector pause, +

    Lua implements an incremental mark-and-sweep collector. +It uses two numbers to control its garbage-collection cycles: +the garbage-collector pause and +the garbage-collector multiplier. + +

    The garbage-collector pause controls how long the collector waits before starting a new cycle. Larger values make the collector less aggressive. Values smaller than 1 mean the collector will not wait to @@ -1578,7 +1587,7 @@

    A value of 2 means that the collector waits more or less to double the total memory in use before starting a new cycle. -

    The other number, the garbage-collector multiplier, +

    The garbage-collector multiplier controls the relative speed of the collector relative to memory allocation. Larger values make the collector more aggressive but also increases @@ -1605,7 +1614,7 @@

    (such as closing files, network or database connections, or freeing your own memory). -

    Free userdata with a field __gc in their metatables are not +

    Garbage userdata with a field __gc in their metatables are not collected immediately by the garbage collector. Instead, Lua puts them in a list. After the collection, @@ -1676,8 +1685,8 @@

    the thread returned by coroutine.create, the coroutine starts its execution, at the first line of its main function. -Extra arguments passed to coroutine.resume are given as -parameters for the coroutine main function. +Extra arguments passed to coroutine.resume are passed on +to the coroutine main function. After the coroutine starts running, it runs until it terminates or yields. @@ -1703,43 +1712,39 @@

    with the call to coroutine.yield returning any extra arguments passed to coroutine.resume. -

    The coroutine.wrap function creates a coroutine -like coroutine.create, +

    The coroutine.wrap function creates a coroutine, +just like coroutine.create, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. Any arguments passed to that function -go as extra arguments to resume. -The function returns all the values returned by resume, +go as extra arguments to coroutine.resume. +coroutine.wrap returns all the values returned by coroutine.resume, except the first one (the boolean error code). Unlike coroutine.resume, -this function does not catch errors; +coroutine.wrap does not catch errors; any error is propagated to the caller.

    As an example, consider the next code:

    -function foo1 (a)
    +function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end
     
     co = coroutine.create(function (a,b)
           print("co-body", a, b)
    -      local r = foo1(a+1)
    +      local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)
            
    -a, b = coroutine.resume(co, 1, 10)
    -print("main", a, b)
    -a, b, c = coroutine.resume(co, "r")
    -print("main", a, b, c)
    -a, b, c = coroutine.resume(co, "x", "y")
    -print("main", a, b, c)
    -a, b = coroutine.resume(co, "x", "y")
    -print("main", a, b)
    +print("main", coroutine.resume(co, 1, 10))
    +print("main", coroutine.resume(co, "r"))
    +print("main", coroutine.resume(co, "x", "y"))
    +print("main", coroutine.resume(co, "x", "y"))
     
    When you run it, it produces the following output:
    @@ -1767,10 +1772,10 @@ 

    any facility in the API may be provided as a macro instead. All such macros use each of its arguments exactly once (except for the first argument, which is always a Lua state), -and so do not generate hidden side-effects. +and so do not generate any hidden side-effects. -

    Like in most C libraries, -the Lua API functions do not check their arguments. +

    As in most C libraries, +the Lua API functions do not check their arguments for validity or consistency. However, you can change this behavior by compiling Lua with a proper definition for the macro luai_apicheck, in file luaconf.h. @@ -1784,7 +1789,7 @@

    Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of C functions that are still active. -That stack initially contains any arguments to the C function, +That stack initially contains any arguments to the C function and it is where the C function pushes its results to be returned to the caller (see lua_CFunction). @@ -1794,7 +1799,7 @@

    by using an index: A positive index represents an absolute stack position (starting at 1); -a negative index represents an offset from the top of the stack. +a negative index represents an offset relative to the top of the stack. More specifically, if the stack has n elements, then index 1 represents the first element (that is, the element that was pushed onto the stack first) @@ -1811,6 +1816,8 @@

    3.2 - Stack Size

    When you interact with Lua API, +you are responsible for ensuring consistency. +In particular, you are responsible for controlling stack overflow. You can use the function lua_checkstack to grow the stack size. @@ -1828,7 +1835,7 @@

    More formally, we define an acceptable index as follows:
    -     (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
    +       (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
     
    Note that 0 is never an acceptable index. @@ -1837,8 +1844,8 @@

    Unless otherwise noted, any function that accepts valid indices can also be called with pseudo-indices, -which represent some Lua values that are accessible to the C code -but are not in the stack. +which represent some Lua values that are accessible to C code +but which are not in the stack. Pseudo-indices are used to access the thread environment, the function environment, the registry, @@ -1861,11 +1868,12 @@

    When a C function is created, it is possible to associate some values with it, thus creating a C closure; -these values are then accessible to the function whenever it is called +these values are called upvalues and are +accessible to the function whenever it is called (see lua_pushcclosure).

    Whenever a C function is called, -its associated values are located at specific pseudo-indices. +its upvalues are located at specific pseudo-indices. Those pseudo-indices are produced by the macro lua_upvalueindex. The first value associated with a function is at position @@ -1877,13 +1885,14 @@

    3.5 - Registry

    -

    Lua provides a registry, +

    Lua provides a registry, a pre-defined table that can be used by any C code to store whatever Lua value it needs to store. This table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, -as long as it chooses keys different from other libraries. +but it should take care to choose keys different from those used +by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name or a light userdata with the address of a C object in your code. @@ -1894,9 +1903,13 @@

    3.6 - Error Handling in C

    Internally, Lua uses the C longjmp facility to handle errors. +(You can also choose to use exceptions if you use C++; +See file luaconf.h.) When Lua faces any error -(such as memory allocation errors, type errors, syntax errors) -it raises an error, that is, it does a long jump. +(such as memory allocation errors, type errors, syntax errors, +and runtime errors) +it raises an error; +that is, it does a long jump. A protected environment uses setjmp to set a recover point; any error jumps to the most recent active recover point. @@ -1909,7 +1922,7 @@

    lua_newstate, lua_close, lua_load, lua_pcall, and lua_cpcall. -

    Inside a C function you can raise an error calling lua_error. +

    Inside a C function you can raise an error by calling lua_error.

    3.7 - Functions and Types

    @@ -1917,7 +1930,7 @@

    alphabetical order.

    -


    lua_Alloc

    +

    lua_Alloc

               typedef void * (*lua_Alloc) (void *ud,
                                            void *ptr,
    @@ -1927,12 +1940,12 @@ 

    -

    The allocator function used by Lua states. +

    The type of the memory allocation function used by Lua states. The allocator function must provide a functionality similar to realloc, but not exactly the same. -Its arguments are ud, -the opaque pointer passed to lua_newstate; +Its arguments are +ud, an opaque pointer passed to lua_newstate; ptr, a pointer to the block being allocated/reallocated/freed; osize, the original size of the block; nsize, the new size of the block. @@ -1943,30 +1956,30 @@

    When nsize is not zero, the allocator returns NULL if and only if it cannot fill the request. When nsize is not zero and osize is zero, -the allocator behaves like malloc. +the allocator should behave like malloc. When nsize and osize are not zero, the allocator behaves like realloc. Lua assumes that the allocator never fails when osize >= nsize. -

    A simple implementation for the allocator function -could be like this: +

    Here is a simple implementation for the allocator function. +It is used in the auxiliary library by lua_newstate.

     static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
       (void)ud;     /* not used */
       (void)osize;  /* not used */
       if (nsize == 0) {
    -    free(ptr);  /* ANSI ensures that free(NULL) has no effect */
    +    free(ptr);  /* ANSI requires that free(NULL) has no effect */
         return NULL;
       }
       else
    -    /* ANSI ensures that realloc(NULL, size) == malloc(size) */
    +    /* ANSI requires that realloc(NULL, size) == malloc(size) */
         return realloc(ptr, nsize);
     }
     

    -


    lua_atpanic

    +

    lua_atpanic

               lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
     
    @@ -1976,14 +1989,15 @@

    If an error happens outside any protected environment, Lua calls a panic function -and then calls exit(EXIT_FAILURE). -Your new panic function may avoid the application exit by +and then calls exit(EXIT_FAILURE), +thus exiting the host application. +Your panic function may avoid this exit by never returning (e.g., doing a long jump).

    The panic function can access the error message at the top of the stack.

    -


    lua_call

    +

    lua_call

               void lua_call (lua_State *L, int nargs, int nresults);
     
    @@ -1994,18 +2008,20 @@

    To call a function you must use the following protocol: First, the function to be called is pushed onto the stack; then, the arguments to the function are pushed -in direct order, that is, the first argument is pushed first. +in direct order; +that is, the first argument is pushed first. Finally you call lua_call; nargs is the number of arguments that you pushed onto the stack. -All arguments and the function value are popped from the stack, -and the function results are pushed. -The number of results are adjusted to nresults, +All arguments and the function value are popped from the stack +when the function is called. +The function results are pushed onto the stack when the function returns. +The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. In that case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), -so that after the call the last result is on the top. +so that after the call the last result is on the top of the stack.

    Any error inside the called function is propagated upwards (with a longjmp). @@ -2017,21 +2033,21 @@

    Here it is in C:
    -    lua_getfield(L, LUA_GLOBALSINDEX, "t");     /* global `t' (for later use) */
         lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* function to be called */
         lua_pushstring(L, "how");                                 /* 1st argument */
    -    lua_getfield(L, -3, "x");                 /* push result of t.x (2nd arg) */
    +    lua_getfield(L, LUA_GLOBALSINDEX, "t");            /* table to be indexed */
    +    lua_getfield(L, -1, "x");                 /* push result of t.x (2nd arg) */
    +    lua_remove(L, -2);                           /* remove `t' from the stack */
         lua_pushinteger(L, 14);                                   /* 3rd argument */
         lua_call(L, 3, 1);         /* call function with 3 arguments and 1 result */
         lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global variable `a' */
    -    lua_pop(L, 1);                               /* remove `t' from the stack */
     
    Note that the code above is "balanced": at its end, the stack is back to its original configuration. This is considered good programming practice.

    -


    lua_CFunction

    +

    lua_CFunction

               typedef int (*lua_CFunction) (lua_State *L);
     
    @@ -2040,17 +2056,19 @@

    Type for C functions.

    In order to communicate properly with Lua, -a C function must follow the following protocol, +a C function must use the following protocol, which defines the way parameters and results are passed: A C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first). So, when the function starts, -its first argument (if any) is at index 1. +lua_gettop(L) returns the number of arguments received by the function. +The first argument (if any) is at index 1 +and its last argument is at index lua_gettop(L). To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results. Any other value in the stack below the results will be properly -discharged by Lua. +discarded by Lua. Like a Lua function, a C function called by Lua can also return many results. @@ -2075,20 +2093,20 @@

    -


    lua_checkstack

    +

    lua_checkstack

               int lua_checkstack (lua_State *L, int extra);
     
    -

    Grows the stack size to top + extra elements; +

    Ensures that there are at least extra free stack slots in the stack. it returns false if it cannot grow the stack to that size. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged.

    -


    lua_close

    +

    lua_close

               void lua_close (lua_State *L);
     
    @@ -2105,7 +2123,7 @@

    to avoid growing too large.

    -


    lua_concat

    +

    lua_concat

               void lua_concat (lua_State *L, int n);
     
    @@ -2120,7 +2138,7 @@

    (see 2.5.4).

    -


    lua_cpcall

    +

    lua_cpcall

               int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
     
    @@ -2133,10 +2151,10 @@

    lua_cpcall returns the same error codes as lua_pcall, plus the error object on the top of the stack; otherwise, it returns zero, and does not change the stack. -Any value returned by func is discarded. +All values returned by func are discarded.

    -


    lua_createtable

    +

    lua_createtable

               void lua_createtable (lua_State *L, int narr, int nrec);
     
    @@ -2144,25 +2162,26 @@

    Creates a new empty table and pushes it onto the stack. The new table has space pre-allocated -for narr array elements plus nrec non-array elements. +for narr array elements and nrec non-array elements. This pre-allocation is useful when you know exactly how many elements the table will have. Otherwise you can use the function lua_newtable.

    -


    lua_dump

    +

    lua_dump

               int lua_dump (lua_State *L, lua_Writer writer, void *data);
     

    Dumps a function as a binary chunk. -This function receives a Lua function on the top of the stack +Receives a Lua function on the top of the stack and produces a binary chunk that, if loaded again, results in a function equivalent to the one dumped. As it produces parts of the chunk, lua_dump calls function writer (see lua_Writer) +with the given data to write them.

    The value returned is the error code returned by the last @@ -2172,7 +2191,7 @@

    This function does not pop the function from the stack.

    -


    lua_equal

    +

    lua_equal

               int lua_equal (lua_State *L, int index1, int index2);
     
    @@ -2183,23 +2202,24 @@

    following the semantics of the Lua == operator (that is, may call metamethods). Otherwise returns 0. -Also returns 0 if any of the indices are non valid. +Also returns 0 if any of the indices is non valid.

    -


    lua_error

    +

    lua_error

               int lua_error (lua_State *L);
     

    Generates a Lua error. -The error message (which actually can be any type of object) +The error message (which can actually be a Lua value of any type) must be on the stack top. This function does a long jump, and therefore never returns. +(see luaL_error).

    -


    lua_gc

    +

    lua_gc

               int lua_gc (lua_State *L, int what, int data);
     
    @@ -2227,28 +2247,28 @@

    The function returns 1 if that step finished a garbage-collection cycle.
  • LUA_GCSETPAUSE--- -sets data/100 as the new value +sets data/100 as the new value for the pause of the collector (see 2.10). The function returns the previous value of the pause.
  • LUA_GCSETSTEPMUL--- -sets arg/100 as the new value for the step multiplier of +sets arg/100 as the new value for the step multiplier of the collector (see 2.10). The function returns the previous value of the step multiplier.

    -


    lua_getallocf

    +

    lua_getallocf

               lua_Alloc lua_getallocf (lua_State *L, void **ud);
     
    -

    Returns the allocator function of a given state. -If ud is not NULL Lua stores in *ud the +

    Returns the memory allocator function of a given state. +If ud is not NULL, Lua stores in *ud the opaque pointer passed to lua_newstate.

    -


    lua_getfenv

    +

    lua_getfenv

               void lua_getfenv (lua_State *L, int index);
     
    @@ -2258,7 +2278,7 @@

    the value at the given index.

    -


    lua_getfield

    +

    lua_getfield

               void lua_getfield (lua_State *L, int index, const char *k);
     
    @@ -2270,7 +2290,7 @@

    for the "index" event (see 2.8).

    -


    lua_getmetatable

    +

    lua_getmetatable

               int lua_getmetatable (lua_State *L, int index);
     
    @@ -2283,7 +2303,7 @@

    returns 0 and pushes nothing on the stack.

    -


    lua_gettable

    +

    lua_gettable

               void lua_gettable (lua_State *L, int index);
     
    @@ -2299,7 +2319,7 @@

    for the "index" event (see 2.8).

    -


    lua_gettop

    +

    lua_gettop

               int lua_gettop (lua_State *L);
     
    @@ -2311,7 +2331,7 @@

    (and so 0 means an empty stack).

    -


    lua_insert

    +

    lua_insert

               void lua_insert (lua_State *L, int index);
     
    @@ -2323,7 +2343,7 @@

    because a pseudo-index is not an actual stack position.

    -


    lua_Integer

    +

    lua_Integer

               typedef ptrdiff_t lua_Integer;
     
    @@ -2332,11 +2352,11 @@

    The type used by the Lua API to represent integral values.

    By default it is a ptrdiff_t, -which is usually the largest type the machine handles +which is usually the largest integral type the machine handles "comfortably".

    -


    lua_isboolean

    +

    lua_isboolean

               int lua_isboolean (lua_State *L, int index);
     
    @@ -2346,7 +2366,7 @@

    and 0 otherwise.

    -


    lua_iscfunction

    +

    lua_iscfunction

               int lua_iscfunction (lua_State *L, int index);
     
    @@ -2356,7 +2376,7 @@

    and 0 otherwise.

    -


    lua_isfunction

    +

    lua_isfunction

               int lua_isfunction (lua_State *L, int index);
     
    @@ -2366,7 +2386,7 @@

    (either C or Lua), and 0 otherwise.

    -


    lua_islightuserdata

    +

    lua_islightuserdata

               int lua_islightuserdata (lua_State *L, int index);
     
    @@ -2376,7 +2396,7 @@

    and 0 otherwise.

    -


    lua_isnil

    +

    lua_isnil

               int lua_isnil (lua_State *L, int index);
     
    @@ -2386,7 +2406,7 @@

    and 0 otherwise.

    -


    lua_isnumber

    +

    lua_isnumber

               int lua_isnumber (lua_State *L, int index);
     
    @@ -2397,7 +2417,7 @@

    and 0 otherwise.

    -


    lua_isstring

    +

    lua_isstring

               int lua_isstring (lua_State *L, int index);
     
    @@ -2408,7 +2428,7 @@

    and 0 otherwise.

    -


    lua_istable

    +

    lua_istable

               int lua_istable (lua_State *L, int index);
     
    @@ -2418,7 +2438,7 @@

    and 0 otherwise.

    -


    lua_isthread

    +

    lua_isthread

               int lua_isthread (lua_State *L, int index);
     
    @@ -2428,7 +2448,7 @@

    and 0 otherwise.

    -


    lua_isuserdata

    +

    lua_isuserdata

               int lua_isuserdata (lua_State *L, int index);
     
    @@ -2438,21 +2458,21 @@

    (either full or light), and 0 otherwise.

    -


    lua_lessthan

    +

    lua_lessthan

               int lua_lessthan (lua_State *L, int index1, int index2);
     
    -

    Returns 1 if the value in acceptable index index1 is smaller -than the value in acceptable index index2, +

    Returns 1 if the value at acceptable index index1 is smaller +than the value at acceptable index index2, following the semantics of the Lua < operator (that is, may call metamethods). Otherwise returns 0. -Also returns 0 if any of the indices are non valid. +Also returns 0 if any of the indices is non valid.

    -


    lua_load

    +

    lua_load

               int lua_load (lua_State *L, lua_Reader reader, void *data,
                                           const char *chunkname);
    @@ -2481,11 +2501,11 @@ 

    (see lua_Reader). The data argument is an opaque value passed to the reader function. -

    The chunkname argument gives the chunk name. -It is used for error messages and debug information (see 3.8). +

    The chunkname argument gives a name to the chunk, +which is used for error messages and in debug information (see 3.8).

    -


    lua_newstate

    +

    lua_newstate

               lua_State *lua_newstate (lua_Alloc f, void *ud);
     
    @@ -2493,14 +2513,14 @@

    Creates a new, independent state. Returns NULL if cannot create the state -(not enough memory). +(due to lack of memory). The argument f is the allocator function; Lua does all memory allocation for that state through that function. The second argument, ud, is an opaque pointer that Lua simply passes to the allocator in every call.

    -


    lua_newtable

    +

    lua_newtable

               void lua_newtable (lua_State *L);
     
    @@ -2510,7 +2530,7 @@

    Equivalent to lua_createtable(L, 0, 0).

    -


    lua_newthread

    +

    lua_newthread

               lua_State *lua_newthread (lua_State *L);
     
    @@ -2520,14 +2540,14 @@

    and returns a pointer to a lua_State that represents this new thread. The new state returned by this function shares with the original state all global objects (such as tables), -but has an independent run-time stack. +but has an independent execution stack.

    There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object.

    -


    lua_newuserdata

    +

    lua_newuserdata

               void *lua_newuserdata (lua_State *L, size_t size);
     
    @@ -2544,21 +2564,22 @@

    and you can detect when it is being collected. A full userdata is only equal to itself (under raw equality). -

    When Lua collects a full userdata, -it calls the userdata's gc metamethod, if any, -and then it frees the userdata's corresponding memory. +

    When Lua collects a full userdata with a gc metamethod, +Lua calls the metamethod and marks the userdata as finalized. +When that userdata is collected again then +Lua frees its corresponding memory.

    -


    lua_next

    +

    lua_next

               int lua_next (lua_State *L, int index);
     

    Pops a key from the stack, -and pushes a key-value pair from the table +and pushes a key-value pair from the table at the given index (the "next" pair after the given key). -If there are no more elements, +If there are no more elements in the table, then lua_next returns 0 (and pushes nothing).

    A typical traversal looks like this: @@ -2581,33 +2602,34 @@

    this confuses the next call to lua_next.

    -


    lua_Number

    +

    lua_Number

               typedef double lua_Number;
     

    The type of numbers in Lua. +By default, it is double, but that can be changed in luaconf.h.

    Through the configuration file you can change Lua to operate with other type for numbers (e.g., float or long).

    -


    lua_objlen

    +

    lua_objlen

               size_t lua_objlen (lua_State *L, int index);
     

    Returns the "length" of the value at the given acceptable index: -For strings, this is the string length; -for tables, this is the result of the length operator (`#´). +for strings, this is the string length; +for tables, this is the result of the length operator (`#´); for userdata, this is the size of the block of memory allocated -for the userdatum. -For other values, returns 0. +for the userdata; +for other values, it is 0.

    -


    lua_pcall

    +

    lua_pcall

               lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
     
    @@ -2628,13 +2650,14 @@

    and its arguments from the stack.

    If errfunc is 0, -then the error message returned is exactly the original error message. +then the error message returned on the stack +is exactly the original error message. Otherwise, errfunc is the stack index of an error handler function. (In the current implementation, that index cannot be a pseudo-index.) In case of runtime errors, that function will be called with the error message -and its return value will be the message returned by lua_pcall. +and its return value will be the message returned on the stack by lua_pcall.

    Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. @@ -2653,7 +2676,7 @@

    -


    lua_pop

    +

    lua_pop

               void lua_pop (lua_State *L, int n);
     
    @@ -2662,7 +2685,7 @@

    Pops n elements from the stack.

    -


    lua_pushboolean

    +

    lua_pushboolean

               void lua_pushboolean (lua_State *L, int b);
     
    @@ -2671,7 +2694,7 @@

    Pushes a boolean value with value b onto the stack.

    -


    lua_pushcclosure

    +

    lua_pushcclosure

               void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
     
    @@ -2686,14 +2709,14 @@

    To associate values with a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). -Then the function lua_pushcclosure -is used to create and push the C function onto the stack, +Then lua_pushcclosure +is called to create and push the C function onto the stack, with the argument n telling how many values should be associated with the function. lua_pushcclosure also pops these values from the stack.

    -


    lua_pushcfunction

    +

    lua_pushcfunction

               void lua_pushcfunction (lua_State *L, lua_CFunction f);
     
    @@ -2703,7 +2726,7 @@

    This function is equivalent to lua_pushcclosure(L, f, 0);.

    -


    lua_pushfstring

    +

    lua_pushfstring

               const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
     
    @@ -2711,15 +2734,15 @@

    Pushes onto the stack a formatted string and returns a pointer to that string. -It is similar to the C function sprintf -but with some important differences: +It is similar to the C function sprintf, +but has some important differences:

    • You do not have to allocate the space for the result: The result is a Lua string and Lua takes care of memory allocation (and deallocation, through garbage collection).
    • The conversion specifiers are quite restricted. There are no flags, widths, or precisions. -The conversion specifiers can be simply +The conversion specifiers can only be `%%´ (inserts a `%´ in the string), `%s´ (inserts a zero-terminated string, with no size restrictions), `%f´ (inserts a lua_Number), @@ -2729,7 +2752,7 @@

    -


    lua_pushinteger

    +

    lua_pushinteger

               void lua_pushinteger (lua_State *L, lua_Integer n);
     
    @@ -2738,7 +2761,7 @@

    Pushes a number with value n onto the stack.

    -


    lua_pushlightuserdata

    +

    lua_pushlightuserdata

               void lua_pushlightuserdata (lua_State *L, void *p);
     
    @@ -2755,7 +2778,7 @@

    light userdata with the same C address.

    -


    lua_pushlstring

    +

    lua_pushlstring

               void lua_pushlstring (lua_State *L, const char *s, size_t len);
     
    @@ -2766,9 +2789,10 @@

    Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. +The string can contain embedded zeros.

    -


    lua_pushnil

    +

    lua_pushnil

               void lua_pushnil (lua_State *L);
     
    @@ -2777,7 +2801,7 @@

    Pushes a nil value onto the stack.

    -


    lua_pushnumber

    +

    lua_pushnumber

               void lua_pushnumber (lua_State *L, lua_Number n);
     
    @@ -2786,7 +2810,7 @@

    Pushes a number with value n onto the stack.

    -


    lua_pushstring

    +

    lua_pushstring

               void lua_pushstring (lua_State *L, const char *s);
     
    @@ -2797,9 +2821,20 @@

    Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. +The string cannot embedded zeros; +it is assumed to end at the first zero. + +

    +


    lua_pushthread

    +
    +          void lua_pushthread (lua_State *L);
    +
    + + +

    Pushes the thread represented by L onto the stack.

    -


    lua_pushvalue

    +

    lua_pushvalue

               void lua_pushvalue (lua_State *L, int index);
     
    @@ -2809,7 +2844,7 @@

    onto the stack.

    -


    lua_pushvfstring

    +

    lua_pushvfstring

               const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
     
    @@ -2819,7 +2854,7 @@

    instead of a variable number of arguments.

    -


    lua_rawequal

    +

    lua_rawequal

               int lua_rawequal (lua_State *L, int index1, int index2);
     
    @@ -2832,17 +2867,17 @@

    Also returns 0 if any of the indices are non valid.

    -


    lua_rawget

    +

    lua_rawget

               void lua_rawget (lua_State *L, int index);
     
    -

    Similar to lua_gettable, but doing a raw indexing +

    Similar to lua_gettable, but does a raw access (i.e., without metamethods).

    -


    lua_rawgeti

    +

    lua_rawgeti

               void lua_rawgeti (lua_State *L, int index, int n);
     
    @@ -2850,36 +2885,36 @@

    Pushes onto the stack the value t[n], where t is the value at the given valid index index. -The access is raw, +The access is raw; that is, it does not invoke metamethods.

    -


    lua_rawset

    +

    lua_rawset

               void lua_rawset (lua_State *L, int index);
     
    -

    Similar to lua_settable, but doing a raw assignment +

    Similar to lua_settable, but does a raw assignment (i.e., without metamethods).

    -


    lua_rawseti

    +

    lua_rawseti

               void lua_rawseti (lua_State *L, int index, int n);
     
    -

    Does the equivalent to t[n] = v, +

    Does the equivalent of t[n] = v, where t is the value at the given valid index index and v is the value at the top of the stack,

    This function pops the value from the stack. -The assignment is raw, +The assignment is raw; that is, it does not invoke metamethods.

    -


    lua_Reader

    +

    lua_Reader

               typedef const char * (*lua_Reader)
                                    (lua_State *L, void *data, size_t *size);
    @@ -2894,11 +2929,12 @@ 

    The reader must return a pointer to a block of memory with a new piece of the chunk and set size to the block size. -To signal the end of the chunk, the reader returns NULL. +The block must exist until the reader function is called again. +To signal the end of the chunk, the reader must return NULL. The reader function may return pieces of any size greater than zero.

    -


    lua_remove

    +

    lua_remove

               void lua_remove (lua_State *L, int index);
     
    @@ -2910,7 +2946,7 @@

    because a pseudo-index is not an actual stack position.

    -


    lua_replace

    +

    lua_replace

               void lua_replace (lua_State *L, int index);
     
    @@ -2921,7 +2957,7 @@

    (therefore replacing the value at the given position).

    -


    lua_resume

    +

    lua_resume

               int lua_resume (lua_State *L, int narg);
     
    @@ -2931,7 +2967,7 @@

    To start a coroutine, you first create a new thread (see lua_newthread); -then you push on its stack the body function plus any eventual arguments; +then you push on its stack the main function plus any eventual arguments; then you call lua_resume, with narg being the number of arguments. This call returns when the coroutine suspends or finishes its execution. @@ -2944,14 +2980,14 @@

    or an error code in case of errors (see lua_pcall). In case of errors, the stack is not unwound, -so you can use the debug API over it; +so you can use the debug API over it. The error message is on the top of the stack. To restart a coroutine, you put on its stack only the values to be passed as results from yield, and then call lua_resume.

    -


    lua_setallocf

    +

    lua_setallocf

               void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
     
    @@ -2961,7 +2997,7 @@

    with user data ud.

    -


    lua_setfenv

    +

    lua_setfenv

               int lua_setfenv (lua_State *L, int index);
     
    @@ -2971,10 +3007,11 @@

    the new environment for the value at the given index. If the value at the given index is neither a function nor a thread nor a userdata, -lua_setfenv returns 0 (false). +lua_setfenv returns 0. +Otherwise it returns 1.

    -


    lua_setfield

    +

    lua_setfield

               void lua_setfield (lua_State *L, int index, const char *k);
     
    @@ -2989,7 +3026,7 @@

    for the "newindex" event (see 2.8).

    -


    lua_setmetatable

    +

    lua_setmetatable

               int lua_setmetatable (lua_State *L, int index);
     
    @@ -3000,7 +3037,7 @@

    acceptable index.

    -


    lua_settable

    +

    lua_settable

               void lua_settable (lua_State *L, int index);
     
    @@ -3016,7 +3053,7 @@

    for the "newindex" event (see 2.8).

    -


    lua_settop

    +

    lua_settop

               void lua_settop (lua_State *L, int index);
     
    @@ -3029,7 +3066,7 @@

    If index is 0, then all stack elements are removed.

    -


    lua_State

    +

    lua_State

               typedef struct lua_State lua_State;
     
    @@ -3044,8 +3081,21 @@

    every function in the library, except to lua_newstate, which creates a Lua state from scratch. +

    +


    lua_status

    +
    +          int lua_status (lua_State *L);
    +
    + + +

    Returns the status of the thread L. + +

    The status can by 0 for a normal thread, +an error code if the thread finished its execution with an error, +or LUA_YIELD if the thread is suspended. +

    -


    lua_toboolean

    +

    lua_toboolean

               int lua_toboolean (lua_State *L, int index);
     
    @@ -3058,11 +3108,11 @@

    different from false and nil; otherwise it returns 0. It also returns 0 when called with a non-valid index. -(If you want to accept only real boolean values, +(If you want to accept only actual boolean values, use lua_isboolean to test the value's type.)

    -


    lua_tocfunction

    +

    lua_tocfunction

               lua_CFunction lua_tocfunction (lua_State *L, int index);
     
    @@ -3073,7 +3123,7 @@

    otherwise, returns NULL.

    -


    lua_tointeger

    +

    lua_tointeger

               lua_Integer lua_tointeger (lua_State *L, int idx);
     
    @@ -3089,7 +3139,7 @@

    it is truncated in some non-specified way.

    -


    lua_tolstring

    +

    lua_tolstring

               const char *lua_tolstring (lua_State *L, int index, size_t *len);
     
    @@ -3105,11 +3155,11 @@

    then lua_tolstring also changes the actual value in the stack to a string. (This change confuses lua_next -when lua_tolstring is applied to keys.) +when lua_tolstring is applied to keys during a table traversal.)

    lua_tolstring returns a fully aligned pointer to a string inside the Lua state. -This string always has a zero ('\0') +This string always has a zero (`\0´) after its last character (as in C), but may contain other zeros in its body. Because Lua has garbage collection, @@ -3117,7 +3167,7 @@

    will be valid after the corresponding value is removed from the stack.

    -


    lua_tonumber

    +

    lua_tonumber

               lua_Number lua_tonumber (lua_State *L, int index);
     
    @@ -3130,23 +3180,23 @@

    otherwise, lua_tonumber returns 0.

    -


    lua_topointer

    +

    lua_topointer

               const void *lua_topointer (lua_State *L, int index);
     

    Converts the value at the given acceptable index to a generic -C pointer (void *). +C pointer (void*). The value may be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. Lua ensures that different objects return different pointers. There is no direct way to convert the pointer back to its original value. -

    Typically this function is used for debug information. +

    Typically this function is used only for debug information.

    -


    lua_tostring

    +

    lua_tostring

               const char *lua_tostring (lua_State *L, int index);
     
    @@ -3155,19 +3205,19 @@

    Equivalent to lua_tolstring with len equal to NULL.

    -


    lua_tothread

    +

    lua_tothread

               lua_State *lua_tothread (lua_State *L, int index);
     

    Converts the value at the given acceptable index to a Lua thread -(represented as lua_State *). +(represented as lua_State*). This value must be a thread; otherwise, the function returns NULL.

    -


    lua_touserdata

    +

    lua_touserdata

               void *lua_touserdata (lua_State *L, int index);
     
    @@ -3180,7 +3230,7 @@

    Otherwise, returns NULL.

    -


    lua_type

    +

    lua_type

               int lua_type (lua_State *L, int index);
     
    @@ -3199,10 +3249,21 @@

    LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, +and LUA_TLIGHTUSERDATA. +

    +


    lua_typename

    +
    +          const char *lua_typename  (lua_State *L, int tp);
    +
    + + +

    Returns the name of the type encoded by the value tp, +which must be one the values returned by lua_type. +

    -


    lua_Writer

    +

    lua_Writer

               typedef int (*lua_Writer)
                               (lua_State *L, const void* p, size_t sz, void* ud);
    @@ -3223,19 +3284,19 @@ 

    calling the writer again.

    -


    lua_xmove

    +

    lua_xmove

               void lua_xmove (lua_State *from, lua_State *to, int n);
     
    -

    Exchange values between different threads of the same global state. +

    Exchange values between different threads of the same global state.

    This function pops n values from the stack from, and pushes them into the stack to.

    -


    lua_yield

    +

    lua_yield

               int lua_yield  (lua_State *L, int nresults);
     
    @@ -3243,7 +3304,7 @@

    Yields a coroutine. -

    This function can only be called as the +

    This function should only be called as the return expression of a C function, as follows:

            return lua_yield (L, nresults);
    @@ -3265,20 +3326,19 @@ 

    that need "inside information" from the interpreter.

    -


    lua_Debug

    +

    lua_Debug

               typedef struct lua_Debug {
                 int event;
    -            const char *name;      /* (n) */
    -            const char *namewhat;  /* (n) */
    -            const char *what;      /* (S) */
    -            const char *source;    /* (S) */
    -            int currentline;       /* (l) */
    -            int nups;              /* (u) number of upvalues */
    -            int linedefined;       /* (S) */
    -            int lastlinedefined;   /* (S) */
    +            const char *name;           /* (n) */
    +            const char *namewhat;       /* (n) */
    +            const char *what;           /* (S) */
    +            const char *source;         /* (S) */
    +            int currentline;            /* (l) */
    +            int nups;                   /* (u) number of upvalues */
    +            int linedefined;            /* (S) */
    +            int lastlinedefined;        /* (S) */
                 char short_src[LUA_IDSIZE]; /* (S) */
    -  
                 /* private part */
                 ...
               } lua_Debug;
    @@ -3295,36 +3355,37 @@ 

    The fields of lua_Debug have the following meaning:

      -
    • source +
    • source --- If the function was defined in a string, then source is that string. If the function was defined in a file, then source starts with a `@´ followed by the file name. -

    • short_src -A "printable" version of source, to be used in error messages. +

    • short_src --- +a "printable" version of source, to be used in error messages. -

    • linedefined +

    • linedefined --- the line number where the definition of the function starts. -

    • lastlinedefined +

    • lastlinedefined --- the line number where the definition of the function ends. -

    • what the string "Lua" if this is a Lua function, -"C" if this is a C function, -"main" if this is the main part of a chunk, -and "tail" if this was a function that did a tail call. +

    • what --- +the string "Lua" if the function is a Lua function, +"C" if it is a C function, +"main" if it is the main part of a chunk, +and "tail" if it was a function that did a tail call. In the latter case, -Lua has no other information about this function. +Lua has no other information about the function. -

    • currentline +

    • currentline --- the current line where the given function is executing. When no line information is available, currentline is set to -1. -

    • name +

    • name --- a reasonable name for the given function. -Because functions in Lua are first class values, +Because functions in Lua are first-class values, they do not have a fixed name: Some functions may be the value of multiple global variables, while others may be stored only in a table field. @@ -3333,21 +3394,21 @@

      If it cannot find a name, then name is set to NULL. -

    • namewhat -Explains the name field. +

    • namewhat --- +explains the name field. The value of namewhat can be "global", "local", "method", "field", "upvalue", or "" (the empty string), according to how the function was called. (Lua uses the empty string when no other option seems to apply.) -

    • nups -The number of upvalues of the function. +

    • nups --- +the number of upvalues of the function.

    -


    lua_gethook

    +

    lua_gethook

               lua_Hook lua_gethook (lua_State *L);
     
    @@ -3356,7 +3417,7 @@

    Returns the current hook function.

    -


    lua_gethookcount

    +

    lua_gethookcount

               int lua_gethookcount (lua_State *L);
     
    @@ -3365,7 +3426,7 @@

    Returns the current hook count.

    -


    lua_gethookmask

    +

    lua_gethookmask

               int lua_gethookmask (lua_State *L);
     
    @@ -3374,7 +3435,7 @@

    Returns the current hook mask.

    -


    lua_getinfo

    +

    lua_getinfo

               int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
     
    @@ -3408,7 +3469,7 @@

    -


    lua_getlocal

    +

    lua_getlocal

               const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
     
    @@ -3421,7 +3482,7 @@

    The index n selects which local variable to inspect (1 is the first parameter or active local variable, and so on, until the last active local variable). -lua_getlocal pushes the variable's value onto the stack, +lua_getlocal pushes the variable's value onto the stack and returns its name.

    Variable names starting with `(´ (open parentheses) @@ -3433,7 +3494,7 @@

    the number of active local variables.

    -


    lua_getstack

    +

    lua_getstack

               int lua_getstack (lua_State *L, int level, lua_Debug *ar);
     
    @@ -3451,7 +3512,7 @@

    it returns 0.

    -


    lua_getupvalue

    +

    lua_getupvalue

               const char *lua_getupvalue (lua_State *L, int funcindex, int n);
     
    @@ -3466,7 +3527,8 @@

    and returns its name. funcindex points to the closure in the stack. (Upvalues have no particular order, -as they are active through the whole function.) +as they are active through the whole function. +So, they are numbered in an arbitrary order.)

    Returns NULL (and pushes nothing) when the index is greater than the number of upvalues. @@ -3474,7 +3536,7 @@

    as a name for all upvalues.

    -


    lua_Hook

    +

    lua_Hook

               typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
     
    @@ -3502,7 +3564,7 @@

    that execution occurs without any calls to hooks.

    -


    lua_sethook

    +

    lua_sethook

               int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
     
    @@ -3512,7 +3574,7 @@

    func is the hook function. mask specifies on which events the hook will be called: -It is formed by a disjunction of the constants +It is formed by a bitwise or of the constants LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, @@ -3522,9 +3584,11 @@

    For each event, the hook is called as explained below:
    • The call hook is called when the interpreter calls a function. -The hook is called just after Lua enters the new function. +The hook is called just after Lua enters the new function, +before the function gets its arguments.
    • The return hook is called when the interpreter returns from a function. The hook is called just before Lua leaves the function. +You have no access to the values to be returned by the function.
    • The line hook is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). @@ -3537,14 +3601,14 @@

      A hook is disabled by setting mask to zero.

      -


      lua_setlocal

      +

      lua_setlocal

                 const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
       

      Sets the value of a local variable of a given activation record. -Parameters ar and n are like in lua_getlocal +Parameters ar and n are as in lua_getlocal (see ). lua_setlocal assigns the value at the top of the stack to the variable and returns its name. @@ -3555,14 +3619,14 @@

      the number of active local variables.

      -


      lua_setupvalue

      +

      lua_setupvalue

                 const char *lua_setupvalue (lua_State *L, int funcindex, int n);
       

      Sets the value of a closure's upvalue. -Parameters funcindex and n are like in lua_getupvalue +Parameters funcindex and n are as in lua_getupvalue (see ). It assigns the value at the top of the stack to the upvalue and returns its name. @@ -3586,17 +3650,17 @@

      are defined in header file lauxlib.h and have a prefix luaL_. -

      All functions in the auxiliary library are build on -top of the basic API, so they provide nothing that cannot -be done with that API. +

      All functions in the auxiliary library are built on +top of the basic API, +and so they provide nothing that cannot be done with that API.

      Several functions in the auxiliary library are used to check C function arguments. Their names are always luaL_check* or luaL_opt*. -All those functions raise an error if the check is not satisfied. +All of these functions raise an error if the check is not satisfied. Because the error message is formatted for arguments (e.g., "bad argument #1"), -you should not use those functions for other stack values. +you should not use these functions for other stack values.

      4.1 - Functions and Types

      @@ -3604,7 +3668,7 @@

      in alphabetical order.

      -


      luaL_addchar

      +

      luaL_addchar

                 void luaL_addchar (luaL_Buffer B, char c);
       
      @@ -3614,7 +3678,7 @@

      (see luaL_Buffer).

      -


      luaL_addlstring

      +

      luaL_addlstring

                 void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
       
      @@ -3623,9 +3687,10 @@

      Adds the string pointed by s with length l to the buffer B (see luaL_Buffer). +The string may contain embedded zeros.

      -


      luaL_addsize

      +

      luaL_addsize

                 void luaL_addsize (luaL_Buffer B, size_t n);
       
      @@ -3636,7 +3701,7 @@

      (see luaL_Buffer).

      -


      luaL_addstring

      +

      luaL_addstring

                 void luaL_addstring (luaL_Buffer *B, const char *s);
       
      @@ -3645,9 +3710,10 @@

      Adds the zero-terminated string pointed by s to the buffer B (see luaL_Buffer). +The string may not contain embedded zeros.

      -


      luaL_addvalue

      +

      luaL_addvalue

                 void luaL_addvalue (luaL_Buffer *B);
       
      @@ -3663,7 +3729,7 @@

      which is the value to be added to the buffer.

      -


      luaL_argcheck

      +

      luaL_argcheck

                 void luaL_argcheck (lua_State *L, int cond, int numarg,
                                     const char *extramsg);
      @@ -3671,12 +3737,12 @@ 

      Checks whether cond is true. -If not, raise an error with message +If not, raises an error with message "bad argument #<numarg> to <func> (<extramsg>)", where func is retrieved from the call stack.

      -


      luaL_argerror

      +

      luaL_argerror

                 int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
       
      @@ -3686,10 +3752,12 @@

      "bad argument #<numarg> to <func> (<extramsg>)", where func is retrieved from the call stack. -

      This function never returns. +

      This function never returns, +but it is an idiom to use it as return luaL_argerror ... +in C functions.

      -


      luaL_Buffer

      +

      luaL_Buffer

                 typedef struct luaL_Buffer luaL_Buffer;
       
      @@ -3700,21 +3768,23 @@

      A string buffer allows C code to build Lua strings piecemeal. Its pattern of use is as follows:

        -
      • Fist you declare a variable b of type luaL_Buffer. -
      • Then you initialize it with a call luaL_buffinit(L, &b);. +
      • First you declare a variable b of type luaL_Buffer. +
      • Then you initialize it with a call luaL_buffinit(L, &b).
      • Then you add string pieces to the buffer calling any of the luaL_add* functions.
      • You finish calling luaL_pushresult(&b). That call leaves the final string on the top of the stack.
      -

      During its normal operation a string buffer uses a -variable number of stack slots. +

      During its normal operation, +a string buffer uses a variable number of stack slots. So, while using a buffer, you cannot assume that you know where -is the top of the stack. -You can use the stack between successive calls to buffer operations, -as long as that use is balanced, that is, -when you call a buffer operation the stack is at the same level +the top of the stack is. +You can use the stack between successive calls to buffer operations +as long as that use is balanced; +that is, +when you call a buffer operation, +the stack is at the same level it was immediately after the previous buffer operation. (The only exception to this rule is luaL_addvalue.) After calling luaL_pushresult the stack is back to its @@ -3722,7 +3792,7 @@

      plus the final string on its top.

      -


      luaL_buffinit

      +

      luaL_buffinit

                 void luaL_buffinit (lua_State *L, luaL_Buffer *B);
       
      @@ -3734,7 +3804,7 @@

      (see luaL_Buffer).

      -


      luaL_callmeta

      +

      luaL_callmeta

                 int luaL_callmeta (lua_State *L, int obj, const char *e);
       
      @@ -3744,53 +3814,54 @@

      If the object at index obj has a metatable and that metatable has a field e, -calls that field passing the object as argument. -In that case the function returns 1 and pushes on the +this function calls that field and passes the object as its only argument. +In that case this function returns 1 and pushes on the stack the value returned by the call. -If there is no metatable or no metamethod returns 0 -(without pushing any value on the stack). +If there is no metatable or no metamethod, +this function returns 0 (without pushing any value on the stack).

      -


      luaL_checkany

      +

      luaL_checkany

                 void luaL_checkany (lua_State *L, int narg);
       
      -

      Checks whether the function has an argument narg. +

      Checks whether the function has an argument +of any type (including nil) at position narg.

      -


      luaL_checkint

      +

      luaL_checkint

                 int luaL_checkint (lua_State *L, int narg);
       

      Checks whether the function argument narg is a number -and returns that number casted to an int. +and returns that number cast to an int.

      -


      luaL_checkinteger

      +

      luaL_checkinteger

      -          lua_Integer luaL_checkinteger (lua_State *L, int numArg);
      +          lua_Integer luaL_checkinteger (lua_State *L, int narg);
       

      Checks whether the function argument narg is a number -and returns that number casted to a lua_Integer. +and returns that number cast to a lua_Integer.

      -


      luaL_checklong

      +

      luaL_checklong

                 long luaL_checklong (lua_State *L, int narg);
       

      Checks whether the function argument narg is a number -and returns that number casted to a long. +and returns that number cast to a long.

      -


      luaL_checklstring

      +

      luaL_checklstring

                 const char *luaL_checklstring (lua_State *L, int numArg, size_t *l);
       
      @@ -3798,11 +3869,11 @@

      Checks whether the function argument narg is a string and returns that string; -if l is not NULL fills the position *l +if l is not NULL fills *l with the string's length.

      -


      luaL_checknumber

      +

      luaL_checknumber

                 lua_Number luaL_checknumber (lua_State *L, int numArg);
       
      @@ -3812,7 +3883,7 @@

      and returns that number.

      -


      luaL_checkoption

      +

      luaL_checkoption

                 int luaL_checkoption (lua_State *L, int narg, const char *def,
                                       const char *const lst[]);
      @@ -3830,8 +3901,12 @@ 

      Raises an error if the argument is not a string or if the string cannot be found. +

      This is a useful function for mapping strings to C enums. +The usual interfaces in Lua libraries is to use strings instead of numbers +to select options. +

      -


      luaL_checkstack

      +

      luaL_checkstack

                 void luaL_checkstack (lua_State *L, int sz, const char *msg);
       
      @@ -3842,7 +3917,7 @@

      msg is an additional text to go into the error message.

      -


      luaL_checkstring

      +

      luaL_checkstring

                 const char *luaL_checkstring (lua_State *L, int narg);
       
      @@ -3852,7 +3927,7 @@

      and returns that string.

      -


      luaL_checktype

      +

      luaL_checktype

                 void luaL_checktype (lua_State *L, int narg, int t);
       
      @@ -3861,7 +3936,7 @@

      Checks whether the function argument narg has type t.

      -


      luaL_checkudata

      +

      luaL_checkudata

                 void *luaL_checkudata (lua_State *L, int ud, const char *tname);
       
      @@ -3871,7 +3946,7 @@

      of the type tname (see luaL_newmetatable).

      -


      luaL_error

      +

      luaL_error

                 int luaL_error (lua_State *L, const char *fmt, ...);
       
      @@ -3885,10 +3960,12 @@

      the line number where the error occurred, if that information is available. -

      This function never returns. +

      This function never returns, +but it is an idiom to use it as return luaL_error ... +in C functions.

      -


      luaL_getmetafield

      +

      luaL_getmetafield

                 int luaL_getmetafield (lua_State *L, int obj, const char *e);
       
      @@ -3898,10 +3975,10 @@

      of the object at index obj. If the object does not have a metatable, or if the metatable does not have that field, -returns 0 (false) and pushes nothing. +returns 0 and pushes nothing.

      -


      luaL_getmetatable

      +

      luaL_getmetatable

                 void luaL_getmetatable (lua_State *L, const char *tname);
       
      @@ -3911,19 +3988,20 @@

      in the registry (see luaL_newmetatable).

      -


      luaL_gsub

      +

      luaL_gsub

                 const char *luaL_gsub (lua_State *L, const char *s,
                                        const char *p, const char *r);
       
      -

      Creates a copy of string s changing any occurrence of p -by the string r. +

      Creates a copy of string s by replacing any occurrence +any occurrence of the string p +wth the string r. Pushes the resulting string on the stack and returns it.

      -


      luaL_loadbuffer

      +

      luaL_loadbuffer

                 int luaL_loadbuffer (lua_State *L, const char *buff,
                                      size_t sz, const char *name);
      @@ -3939,7 +4017,7 @@ 

      used for debug information and error messages.

      -


      luaL_loadfile

      +

      luaL_loadfile

                 int luaL_loadfile (lua_State *L, const char *filename);
       
      @@ -3948,14 +4026,16 @@

      Loads a file as a Lua chunk. This function uses lua_load to load the chunk in the file named filename. -If the file's first line starts with a # it is ignored. +If filename is NULL, +then it loads from the standard input. +The first line in the file is ignored if it starts with a #.

      This function returns the same results as lua_load, but it has an extra error code LUA_ERRFILE -if it cannot open the file. +if it cannot open/read the file.

      -


      luaL_loadstring

      +

      luaL_loadstring

                 int luaL_loadstring (lua_State *L, const char *s);
       
      @@ -3968,24 +4048,24 @@

      This function returns the same results as lua_load.

      -


      luaL_newmetatable

      +

      luaL_newmetatable

                 int luaL_newmetatable (lua_State *L, const char *tname);
       
      -

      If the register already has the key "tname", +

      If the registry already has the key "tname", returns 0. Otherwise, -creates a new table to be used as metatables for userdata, -adds it to the register with key "tname", +creates a new table to be used as a metatable for userdata, +adds it to the registry with key "tname", and returns 1.

      In both cases pushes on the stack the final value associated with "tname" in the registry.

      -


      luaL_newstate

      +

      luaL_newstate

                 lua_State *luaL_newstate (void);
       
      @@ -3993,7 +4073,7 @@

      Creates a new Lua state, calling lua_newstate with an allocation function based on the standard C realloc function -and setting a panic function ((see lua_atpanic)) that prints +and setting a panic function (see lua_atpanic) that prints an error message to the standard error output in case of fatal errors. @@ -4001,46 +4081,46 @@

      or NULL if there is a memory allocation error.

      -


      luaL_optint

      +

      luaL_optint

                 int luaL_optint (lua_State *L, int narg, int d);
       

      If the function argument narg is a number, -returns that number casted to an int. +returns that number cast to an int. If that argument is absent or is nil, returns d. -Otherwise, raise an error. +Otherwise, raises an error.

      -


      luaL_optinteger

      +

      luaL_optinteger

                 lua_Integer luaL_optinteger (lua_State *L, int nArg, lua_Integer d);
       

      If the function argument narg is a number, -returns that number casted to a lua_Integer. +returns that number cast to a lua_Integer. If that argument is absent or is nil, returns d. -Otherwise, raise an error. +Otherwise, raises an error.

      -


      luaL_optlong

      +

      luaL_optlong

                 long luaL_optlong (lua_State *L, int narg, long d);
       

      If the function argument narg is a number, -returns that number casted to a long. +returns that number cast to a long. If that argument is absent or is nil, returns d. -Otherwise, raise an error. +Otherwise, raises an error.

      -


      luaL_optlstring

      +

      luaL_optlstring

                 const char *luaL_optlstring (lua_State *L, int numArg,
                                              const char *d, size_t *l);
      @@ -4051,13 +4131,13 @@ 

      returns that string. If that argument is absent or is nil, returns d. -Otherwise, raise an error. +Otherwise, raises an error. -

      If l is not NULL fills the position *l -with the results's length. +

      If l is not NULL, +fills the position *l with the results's length.

      -


      luaL_optnumber

      +

      luaL_optnumber

                 lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number d);
       
      @@ -4067,10 +4147,10 @@

      returns that number. If that argument is absent or is nil, returns d. -Otherwise, raise an error. +Otherwise, raises an error.

      -


      luaL_optstring

      +

      luaL_optstring

                 const char *luaL_optstring (lua_State *L, int narg, const char *d);
       
      @@ -4080,24 +4160,24 @@

      returns that string. If that argument is absent or is nil, returns d. -Otherwise, raise an error. +Otherwise, raises an error.

      -


      luaL_prepbuffer

      +

      luaL_prepbuffer

                 char *luaL_prepbuffer (luaL_Buffer *B);
       

      Returns an address to a space of size LUAL_BUFFERSIZE -wherein you can copy a string to be added to buffer B +where you can copy a string to be added to buffer B (see luaL_Buffer). After copying the string into that space you must call luaL_addsize with the size of the string to actually add it to the buffer.

      -


      luaL_pushresult

      +

      luaL_pushresult

                 void luaL_pushresult (luaL_Buffer *B);
       
      @@ -4107,7 +4187,7 @@

      the top of the stack.

      -


      luaL_ref

      +

      luaL_ref

                 int luaL_ref (lua_State *L, int t);
       
      @@ -4118,19 +4198,19 @@

      for the object at the top of the stack (and pops the object).

      A reference is a unique integer key. -As long as you do not add integer keys into table t, +As long as you do not manually add integer keys into table t, luaL_ref ensures the uniqueness of the key it returns. You can retrieve an object referred by reference r -calling lua_rawgeti(L, t, r). +by calling lua_rawgeti(L, t, r). Function luaL_unref frees a reference and its associated object. -

      Whenever the object at the top of the stack is nil, +

      If the object at the top of the stack is nil, luaL_ref returns the same reference LUA_REFNIL. -The constant LUA_NOREF is garanteed to be different +The constant LUA_NOREF is guaranteed to be different from any reference returned by luaL_ref.

      -


      luaL_Reg

      +

      luaL_Reg

                 typedef struct luaL_Reg {
                   const char *name;
      @@ -4140,15 +4220,15 @@ 

      -

      Format for arrays of functions to be registered by +

      Type for arrays of functions to be registered by luaL_register. name is the function name and func is a pointer to the function. Any array of luaL_Reg must end with an sentinel entry -wherein both name and func are NULL. +in which both name and func are NULL.

      -


      luaL_register

      +

      luaL_register

                 void luaL_register (lua_State *L, const char *libname,
                                     const luaL_Reg *l);
      @@ -4163,7 +4243,7 @@ 

      When called with a non-null libname, creates a new table t, -sets it as the value of the variable libname, +sets it as the value of the global variable libname, sets it as the value of package.loaded[libname], and registers on it all functions in the list l. If there is a table in package.loaded[libname] or in @@ -4174,7 +4254,7 @@

      on the top of the stack.

      -


      luaL_typename

      +

      luaL_typename

                 const char *luaL_typename (lua_State *L, int idx);
       
      @@ -4183,7 +4263,7 @@

      Returns the name of the type of the value at index idx.

      -


      luaL_typerror

      +

      luaL_typerror

                 int luaL_typerror (lua_State *L, int narg, const char *tname);
       
      @@ -4198,7 +4278,7 @@

      and <realt> is the type name of the actual argument.

      -


      luaL_unref

      +

      luaL_unref

                 void luaL_unref (lua_State *L, int t, int ref);
       
      @@ -4214,7 +4294,7 @@

      luaL_unref does nothing.

      -


      luaL_where

      +

      luaL_where

                 void luaL_where (lua_State *L, int lvl);
       
      @@ -4224,20 +4304,21 @@

      of the control at level lvl in the call stack. Typically this string has the format <chunkname>:<currentline>:. Level 0 is the running function, -level 1 is the function that called the running function. +level 1 is the function that called the running function, +etc.

      This function is used to build a prefix for error messages.

      5 - Standard Libraries

      -

      The standard libraries provide useful functions +

      The standard Lua libraries provide useful functions that are implemented directly through the C API. Some of these functions provide essential services to the language (e.g., type and getmetatable); others provide access to "outside" services (e.g., I/O); and others could be implemented in Lua itself, -but are quite useful or have critical performance to +but are quite useful or have critical performance requirements that deserve an implementation in C (e.g., sort).

      All libraries are implemented through the official C API @@ -4258,9 +4339,11 @@

      or as methods of its objects.

      To have access to these libraries, -the C host program must first call the function -luaL_openlibs; -or else it can open them individually calling +the C host program must call +luaL_openlibs, +which open all standard libraries. +Alternatively, +it can open them individually by calling luaopen_base (for the basic library), luaopen_package (for the package library), luaopen_string (for the string library), @@ -4268,86 +4351,90 @@

      luaopen_math (for the mathematical library), luaopen_io (for the I/O and the Operating System libraries), and luaopen_debug (for the debug library). -These functions are declared in lualib.h. +These functions are declared in lualib.h +and should not be called directly: +you must call them like any other Lua C function, +e.g., by using lua_call.

      5.1 - Basic Functions

      The basic library provides some core functions to Lua. If you do not include this library in your application, -you should check carefully whether you need to provide some alternative -implementation for some of its facilities. +you should check carefully whether you need to provide +implementations for some of its facilities. -


      assert (v [, message])

      +


      assert (v [, message])

      Issues an error when -the value of its argument v is nil or false; +the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!" -


      collectgarbage (opt [, arg])

      +


      collectgarbage (opt [, arg])

      This function is a generic interface to the garbage collector. It performs different functions according to its first argument, opt:

        -
      • "stop" stops the garbage collector. -
      • "restart" restarts the garbage collector. -
      • "collect" performs a full garbage-collection cycle. -
      • "count" returns the total memory in use by Lua (in Kbytes). -
      • "step" performs a garbage-collection step. +
      • "stop" --- stops the garbage collector. +
      • "restart" --- restarts the garbage collector. +
      • "collect" --- performs a full garbage-collection cycle. +
      • "count" --- returns the total memory in use by Lua (in Kbytes). +
      • "step" --- performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. If you want to control the step size you must tune experimentally the value of arg. Returns true if that step finished a collection cycle. -
      • "steppause" -sets arg/100 as the new value for the pause of +
      • "steppause" --- +sets arg/100 as the new value for the pause of the collector (see 2.10). -
      • "setstepmul" -sets arg/100 as the new value for the step multiplier of +
      • "setstepmul" --- +sets arg/100 as the new value for the step multiplier of the collector (see 2.10).
      -


      dofile (filename)

      +


      dofile (filename)

      Opens the named file and executes its contents as a Lua chunk. When called without arguments, -dofile executes the contents of the standard input (stdin). -Returns any value returned by the chunk. -In case of errors, dofile propagates the error -to its caller (that is, it does not run in protected mode). +dofile executes the contents of the standard input (stdin). +Returns all values returned by the chunk. +In case of errors, dofile propagates the error +to its caller (that is, dofile does not run in protected mode). -


      error (message [, level])

      +


      error (message [, level])

      Terminates the last protected function called and returns message as the error message. -Function error never returns. +Function error never returns. -

      Usually, error adds some information about the error position +

      Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the -error function was called. +error function was called. Level 2 points the error to where the function -that called error was called; and so on. +that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message. -


      _G

      +


      _G

      A global variable (not a function) that holds the global environment (that is, _G._G = _G). Lua itself does not use this variable; -changing its value does not affect any environment. +changing its value does not affect any environment, +nor vice-versa. (Use setfenv to change environments.) -


      getfenv (f)

      +


      getfenv (f)

      Returns the current environment in use by the function. -f can be a Lua function or a number, -which specifies the function at that stack level: -Level 1 is the function calling getfenv. +f can be a Lua function or a number +that specifies the function at that stack level: +Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, -getfenv returns the global environment. +getfenv returns the global environment. The default for f is 1. -


      getmetatable (object)

      +


      getmetatable (object)

      If object does not have a metatable, returns nil. Otherwise, @@ -4355,9 +4442,9 @@

      returns the associated value. Otherwise, returns the metatable of the given object. -


      ipairs (t)

      +


      ipairs (t)

      -

      Returns an iterator function, the table t, and 0, +

      Returns three values: an iterator function, the table t, and 0, so that the construction

              for i,v in ipairs(t) do ... end
      @@ -4365,7 +4452,9 @@ 

      will iterate over the pairs (1,t[1]), (2,t[2]), ..., up to the first integer key with a nil value in the table. -


      load (func [, chunkname])

      +

      See next for the caveats of modifying the table during its traversal. + +


      load (func [, chunkname])

      Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates @@ -4380,12 +4469,14 @@

      chunkname is used as the chunk name for error messages and debug information. -


      loadfile (filename)

      +


      loadfile ([filename])

      Similar to load, -but gets the chunk from file filename. +but gets the chunk from file filename +or from the standard input, +if no file name given. -


      loadstring (string [, chunkname])

      +


      loadstring (string [, chunkname])

      Similar to load, but gets the chunk from the given string. @@ -4395,106 +4486,112 @@

      assert(loadstring(s))()

      -


      next (table [, index])

      +


      next (table [, index])

      Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. -next returns the next index of the table and the -value associated with the index. +next returns the next index of the table +and its associated value. When called with nil as its second argument, -next returns the first index -of the table and its associated value. +next returns an initial index +and its associated value. When called with the last index, or with nil in an empty table, -next returns nil. +next returns nil. If the second argument is absent, then it is interpreted as nil. +In particular, +you can use next(t) to check whether a table is empty. -

      Lua has no declaration of fields; +

      Lua has no declaration of fields. There is no difference between a field not present in a table or a field with value nil. -Therefore, next only considers fields with non-nil values. +Therefore, next only considers fields with non-nil values. The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.) -

      The behavior of next is undefined if, +

      The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. +You may however modify existing fields. +In particular, you may clear existing fields. -


      pairs (t)

      +


      pairs (t)

      -

      Returns the next function and the table t (plus a nil), +

      Returns three values: the next function, the table t, and nil, so that the construction

              for k,v in pairs(t) do ... end
       
      will iterate over all key--value pairs of table t. -


      pcall (f, arg1, arg2, ...)

      +

      See next for the caveats of modifying the table during its traversal. + +


      pcall (f, arg1, arg2, ...)

      Calls function f with the given arguments in protected mode. That means that any error inside f is not propagated; -instead, pcall catches the error +instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. -In such case, pcall also returns all results from the call, +In such case, pcall also returns all results from the call, after this first result. -In case of any error, pcall returns false plus the error message. +In case of any error, pcall returns false plus the error message. -


      print (e1, e2, ...)

      +


      print (e1, e2, ...)

      Receives any number of arguments, and prints their values in stdout, using the tostring function to convert them to strings. -This function is not intended for formatted output, +print is not intended for formatted output, but only as a quick way to show a value, typically for debugging. -For formatted output, use format (see 5.4). +For formatted output, use string.format. -


      rawequal (v1, v2)

      +


      rawequal (v1, v2)

      Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean. -


      rawget (table, index)

      +


      rawget (table, index)

      Gets the real value of table[index], without invoking any metamethod. -table must be a table; -index is any value different from nil. +table must be a table and +index any value different from nil. -


      rawset (table, index, value)

      +


      rawset (table, index, value)

      Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, -index is any value different from nil, -and value is any Lua value. +index any value different from nil, +and value any Lua value. -


      select (index, ...)

      +


      select (index, ...)

      If index is a number, -returns all argument after argument number index. +returns all arguments after argument number index. Otherwise, index must be the string "#", and select returns the total number of extra arguments it received. -


      setfenv (f, table)

      +


      setfenv (f, table)

      Sets the environment to be used by the given function. -f can be a Lua function or a number, -which specifies the function at that stack level: -Level 1 is the function calling setfenv. -setfenv returns the given function. +f can be a Lua function or a number +that specifies the function at that stack level: +Level 1 is the function calling setfenv. +setfenv returns the given function. -

      As a special case, when f is 0 setfenv changes +

      As a special case, when f is 0 setfenv changes the environment of the running thread. -In this case, setfenv returns no values. +In this case, setfenv returns no values. -


      setmetatable (table, metatable)

      +


      setmetatable (table, metatable)

      Sets the metatable for the given table. -(You cannot change the metatable of other types from Lua.) +(You cannot change the metatable of other types from Lua, only from C.) If metatable is nil, removes the metatable of the given table. If the original metatable has a "__metatable" field, @@ -4502,10 +4599,10 @@

      This function returns table. -


      tonumber (e [, base])

      +


      tonumber (e [, base])

      Tries to convert its argument to a number. If the argument is already a number or a string convertible -to a number, then tonumber returns that number; +to a number, then tonumber returns that number; otherwise, it returns nil.

      An optional argument specifies the base to interpret the numeral. @@ -4514,21 +4611,21 @@

      represents 10, `B´ represents 11, and so forth, with `Z´ representing 35. In base 10 (the default), the number may have a decimal part, -as well as an optional exponent part (see 2.2.1). +as well as an optional exponent part (see 2.1). In other bases, only unsigned integers are accepted. -


      tostring (e)

      +


      tostring (e)

      Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, -use string.format (see 5.4). +use string.format.

      If the metatable of e has a "__tostring" field, -tostring calls the corresponding value +then tostring calls the corresponding value with e as argument, and uses the result of the call as its result. -


      type (v)

      +


      type (v)

      Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), @@ -4540,8 +4637,8 @@

      "thread", and "userdata". -


      unpack (list [, i [, j]])

      -Returns the elements from the given list. +


      unpack (list [, i [, j]])

      +Returns the elements from the given table. This function is equivalent to
         return list[i], list[i+1], ..., list[j]
      @@ -4549,30 +4646,30 @@ 

      except that the above code can be written only for a fixed number of elements. By default, i is 1 and j is the length of the list, -as defined by the length operator. +as defined by the length operator (see 2.5.5). -


      _VERSION

      +


      _VERSION

      A global variable (not a function) that holds a string containing the current interpreter version. The current contents of this variable is "Lua 5.1". -


      xpcall (f, err)

      +


      xpcall (f, err)

      -

      This function is similar to pcall, +

      This function is similar to pcall, except that you can set a new error handler. -

      xpcall calls function f in protected mode, +

      xpcall calls function f in protected mode, using err as the error handler. Any error inside f is not propagated; -instead, xpcall catches the error, +instead, xpcall catches the error, calls the err function with the original error object, and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. -In such case, xpcall also returns all results from the call, +In this case, xpcall also returns all results from the call, after this first result. In case of any error, -xpcall returns false plus the result from err. +xpcall returns false plus the result from err.

      5.2 - Coroutine Manipulation

      @@ -4580,22 +4677,24 @@

      the basic library and come inside the table coroutine. See 2.11 for a general description of coroutines. -


      coroutine.create (f)

      +


      coroutine.create (f)

      Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". -


      coroutine.resume (co, val1, ...)

      +


      coroutine.resume (co [, val1, ..., valn])

      Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. -The arguments val1, ... go as the arguments to the body function. +The values val1, ..., valn are passed +as the arguments to the body function. If the coroutine has yielded, resume restarts it; -the arguments val1, ... go as the results from the yield. +the values val1, ..., valn are passed +as the results from the yield.

      If the coroutine runs without any errors, resume returns true plus any values passed to yield @@ -4604,12 +4703,12 @@

      If there is any error, resume returns false plus the error message. -


      coroutine.running ()

      +


      coroutine.running ()

      Returns the running coroutine, or nil when called by the main thread. -


      coroutine.status (co)

      +


      coroutine.status (co)

      Returns the status of coroutine co, as a string: "running", @@ -4621,7 +4720,7 @@

      and "dead" if the coroutine has finished its body function, or if it has stopped with an error. -


      coroutine.wrap (f)

      +


      coroutine.wrap (f)

      Creates a new coroutine, with body f. f must be a Lua function. @@ -4632,22 +4731,22 @@

      except the first boolean. In case of error, propagates the error. -


      coroutine.yield (val1, ...)

      +


      coroutine.yield ([val1, ..., valn])

      Suspends the execution of the calling coroutine. -The coroutine cannot be running neither a C function, +The coroutine can be running neither a C function, nor a metamethod, nor an iterator. -Any arguments to yield go as extra results to resume. +Any arguments to yield are passed as extra results to resume. -

      5.3 - Packages and Modules

      +

      5.3 - Modules

      The package library provides basic -facilities for packages and modules in Lua. +facilities for loading and building modules in Lua. It exports two of its functions directly in the global environment: require and module. Everything else is exported in a table package. -


      module (name [, ...])

      +


      module (name [, ...])

      Creates a module. If there is a table in package.loaded[name], @@ -4666,51 +4765,51 @@

      so that require returns t.

      If name is a compound name -(that is, one with components separated by dots) -module creates (or reuses, if they already exists) +(that is, one with components separated by dots), +module creates (or reuses, if they already exist) tables for each component. For instance, if name is a.b.c, -module stores the module table in field c of +then module stores the module table in field c of field b of global a.

      This function may receive optional options after the module name, where each option is a function to be applied over the module. -


      require (modname)

      +


      require (modname)

      Loads the given module. The function starts by looking into the table package.loaded to determine whether modname is already loaded. -If it is, then require returns the value stored +If it is, then require returns the value stored at package.loaded[modname]. -Otherwise, it tries to find a loader for that module. +Otherwise, it tries to find a loader for that module.

      To find a loader, -first require queries package.preload[modname]. -If it is a true value, +first require queries package.preload[modname]. +If it has a value, that value (which should be a function) is the loader. -Otherwise require searches for a Lua loader using the +Otherwise require searches for a Lua loader using the path stored in package.path. -if that also fails, it searches for a C loader using the +If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, -it tries an all-in-one loader. +it tries an all-in-one loader (see below).

      When loading a C library, -require first uses a dynamic link facility to link the +require first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside that library to be used as the loader. The name of that C function is the string "luaopen_" -concatenated with a copy of the module name wherein each dot +concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its prefix up to (and including) the first hyphen is removed. For instance, if the module name is a.v1-b.c, the function name will be luaopen_b_c. -

      If require finds neither a Lua library nor a +

      If require finds neither a Lua library nor a C library for a module, it calls the all-in-one loader. That loader searches the C path for a library for @@ -4725,29 +4824,29 @@

      with each submodule keeping its original open function.

      Once a loader is found, -require calls the loader with a sinle argument, modname. +require calls the loader with a single argument, modname. If the loader returns any value, -require assigns it to package.loaded[modname]. +require assigns it to package.loaded[modname]. If the loader returns no value and has not assigned any value to package.loaded[modname], -require assigns true to that entry. +then require assigns true to that entry. In any case, require returns the final value of package.loaded[modname].

      If there is any error loading or running the module, or if it cannot find any loader for that module, -then require signals an error. +then require signals an error. -


      package.cpath

      +


      package.cpath

      The path used by require to search for a C loader.

      Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH -(plus another compiled-defined default path). +(plus another default path defined in luaconf.h). -


      package.loaded

      +


      package.loaded

      A table used by require to control which modules are already loaded. @@ -4755,27 +4854,34 @@

      package.loaded[modname] is not false, require simply returns the value stored there. -


      package.loadlib (libname, funcname)

      +


      package.loadlib (libname, funcname)

      -

      Links the program with the dynamic C library libname. +

      Dynamically links the host program with the C library libname. Inside this library, looks for a function funcname and returns this function as a C function. +(So, funcname must follow the protocol (see lua_CFunction)). -

      libname must be the complete file name of the C library, -including any eventual path and extension. +

      This is a low-level function. +It completely bypasses the package and module system. +Unlike require, +it does not perform any path searching or automatically adds extensions. +libname must be the complete file name of the C library, +including if necessary a path and extension. +funcname must be the exact name exported by the C library +(which may depend on the C compiler and linker used).

      This function is not supported by ANSI C. As such, it is only available on some platforms -(Windows, Linux, Solaris, BSD, plus other Unix systems that -support the dlfcn standard). +(Windows, Linux, Mac OS X, Solaris, BSD, +plus other Unix systems that support the dlfcn standard). -


      package.path

      +


      package.path

      The path used by require to search for a Lua loader.

      At start-up, Lua initializes this variable with the value of the environment variable LUA_PATH or -with a compiled-defined default path, +with a default path defined in luaconf.h, if the environment variable is not defined. Any ";;" in the value of the environment variable is replaced by the default path. @@ -4790,21 +4896,21 @@

         "./?.lua;./?.lc;/usr/local/?/init.lua"
       
      -the search for a Lua loader for module mod +the search for a Lua loader for module foo will try to load the files -./mod.lua, ./mod.lc, and -/usr/local/mod/init.lua, in that order. +./foo.lua, ./foo.lc, and +/usr/local/foo/init.lua, in that order. -


      package.preload

      +


      package.preload

      A table to store loaders for specific modules (see require). -


      package.seeall (module)

      +


      package.seeall (module)

      Sets a metatable for module with -its __index field refering to the global environment, -so that this module inherits undefined values +its __index field referring to the global environment, +so that this module inherits values from the global environment. To be used as an option to function module. @@ -4821,12 +4927,12 @@

      The string library provides all its functions inside the table string. It also sets a metatable for strings -wherein __index points to itself. -Therefore, you can use the string function is object-oriented style. +where the __index field points to the metatable itself. +Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s, i) can be written as s:byte(i). -


      string.byte (s [, i [, j]])

      +


      string.byte (s [, i [, j]])

      Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; @@ -4834,25 +4940,25 @@

      Note that numerical codes are not necessarily portable across platforms. -


      string.char (i1, i2, ...)

      +


      string.char (i1, i2, ...)

      Receives 0 or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal -to its correspondent argument. +to its corresponding argument.

      Note that numerical codes are not necessarily portable across platforms. -


      string.dump (function)

      +


      string.dump (function)

      -

      Returns a binary representation of the given function, +

      Returns a string containing a binary representation of the given function, so that a later loadstring on that string returns a copy of the function. -function must be a Lua function. +function must be a Lua function without upvalues. -


      string.find (s, pattern [, init [, plain]])

      -Looks for the first match of +


      string.find (s, pattern [, init [, plain]])

      +Looks for the first match of pattern in the string s. -If it finds one, then find returns the indices of s +If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies @@ -4862,26 +4968,27 @@

      turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". -Note that if plain is given, then init must be given too. +Note that if plain is given, then init must be given as well.

      If the pattern has captures, then in a successful match the captured values are also returned, after the two indices. -


      string.format (formatstring, e1, e2, ...)

      +


      string.format (formatstring, e1, e2, ...)

      Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. The only differences are that the options/modifiers *, l, L, n, p, -and h are not supported, -and there is an extra option, q. +and h are not supported +and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: The string is written between double quotes, -and all double quotes, newlines, and backslashes in the string +and all double quotes, newlines, embedded zeros, +and backslashes in the string are correctly escaped when written. For instance, the call
      @@ -4901,12 +5008,12 @@ 

      This function does not accept string values containing embedded zeros. -


      string.gmatch (s, pat)

      +


      string.gmatch (s, pattern)

      Returns an iterator function that, each time it is called, -returns the next captures from pattern pat over string s. +returns the next captures from pattern over string s. -

      If pat specifies no captures, +

      If pattern specifies no captures, then the whole match is produced in each call.

      As an example, the following loop @@ -4928,11 +5035,12 @@

      end

      -


      string.gsub (s, pat, repl [, n])

      +


      string.gsub (s, pattern, repl [, n])

      Returns a copy of s -in which all occurrences of the pattern pat have been -replaced by a replacement string specified by repl. -gsub also returns, as a second value, +in which all occurrences of the pattern have been +replaced by a replacement string specified by repl, +which may be a string, a table, or a function. +gsub also returns, as its second value, the total number of substitutions made.

      If repl is a string, then its value is used for replacement. @@ -4943,6 +5051,11 @@

      The sequence %0 stands for the whole match. The sequence %% stands for a single %. +

      If repl is a table, then the table is queried for every match, +using the first capture as the key; +if the pattern specifies no captures, +then the whole match is used as the key. +

      If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order; @@ -4951,9 +5064,10 @@

      If repl is a table, then this table is queried with the value of the first capture or of the whole match, if the pattern specifies no captures. -In both cases, -if the value returned by the function or resulted by the query -is a string, + +

      In both cases, +if the value returned by the function or by the table query +is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement @@ -4962,7 +5076,7 @@

      The optional last parameter n limits the maximum number of substitutions to occur. For instance, when n is 1 only the first occurrence of -pat is replaced. +pattern is replaced.

      Here are some examples:

      @@ -4983,24 +5097,24 @@ 

      end) --> x="4+5 = 9" - local t = {name="lua", version="5.0"} - x = string.gsub("$name_$version.tar.gz", "%$(%w+)", t) - --> x="lua_5.0.tar.gz" + local t = {name="lua", version="5.1"} + x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t) + --> x="lua-5.1.tar.gz"

      -


      string.len (s)

      +


      string.len (s)

      Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5. -


      string.lower (s)

      +


      string.lower (s)

      Receives a string and returns a copy of that string with all uppercase letters changed to lowercase. All other characters are left unchanged. -The definition of what is an uppercase letter depends on the current locale. +The definition of what an uppercase letter is depends on the current locale. -


      string.match (s, pattern [, init])

      +


      string.match (s, pattern [, init])

      Looks for the first match of pattern in the string s. If it finds one, then match returns @@ -5012,14 +5126,14 @@

      where to start the search; its default value is 1 and may be negative. -


      string.rep (s, n)

      +


      string.rep (s, n)

      Returns a string that is the concatenation of n copies of the string s. -


      string.reverse (s)

      +


      string.reverse (s)

      Returns a string that is the string s reversed. -


      string.sub (s, i [, j])

      +


      string.sub (s, i [, j])

      Returns the substring of s that starts at i and continues until j; i and j may be negative. @@ -5031,11 +5145,11 @@

      and string.sub(s, -i) returns a suffix of s with length i. -


      string.upper (s)

      +


      string.upper (s)

      Receives a string and returns a copy of that string with all lowercase letters changed to uppercase. All other characters are left unchanged. -The definition of what is a lowercase letter depends on the current locale. +The definition of what a lowercase letter is depends on the current locale.

      Patterns

      @@ -5043,7 +5157,7 @@

      A character class is used to represent a set of characters. The following combinations are allowed in describing a character class:
        -
      • x (where x is not one of the magic characters +
      • x (where x is not one of the magic characters ^$()%.[]*+-?) --- represents the character x itself.
      • . --- (a dot) represents all characters. @@ -5117,11 +5231,11 @@

        a single character class followed by `?´, which matches 0 or 1 occurrence of a character in the class;
      • -%n, for n between 1 and 9; +%n, for n between 1 and 9; such item matches a substring equal to the n-th captured string (see below);
      • -%bxy, where x and y are two distinct characters; +%bxy, where x and y are two distinct characters; such item matches strings that start with x, end with y, and where the x and y are balanced. This means that, if one reads the string from left to right, @@ -5149,8 +5263,8 @@

        For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is stored as the first capture (and therefore has number 1); -the character matching . is captured with number 2, -and the part matching %s* has number 3. +the character matching "." is captured with number 2, +and the part matching "%s*" has number 3.

        As a special case, the empty capture () captures the current string position (a number). @@ -5168,14 +5282,14 @@

        For those functions, when we talk about "the length" of a table we mean the result of the length operator. -


        table.concat (table [, sep [, i [, j]]])

        +


        table.concat (table [, sep [, i [, j]]])

        Returns table[i]..sep..table[i+1] ... sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string. -


        table.insert (table, [pos,] value)

        +


        table.insert (table, [pos,] value)

        Inserts element value at position pos in table, shifting up other elements to open space, if necessary. @@ -5184,12 +5298,12 @@

        so that a call table.insert(t,x) inserts x at the end of table t. -


        table.maxn(table)

        +


        table.maxn (table)

        Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. -


        table.remove (table [, pos])

        +


        table.remove (table [, pos])

        Removes from table the element at position pos, shifting down other elements to close the space, if necessary. @@ -5199,7 +5313,7 @@

        so that a call table.remove(t) removes the last element of table t. -


        table.sort (table [, comp])

        +


        table.sort (table [, comp])

        Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. @@ -5211,7 +5325,7 @@

        If comp is not given, then the standard Lua operator < is used instead. -

        The sort algorithm is not stable, +

        The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort. @@ -5276,7 +5390,7 @@

        5.7 - Input and Output Facilities

        The I/O library provides two different styles for file manipulation. -The first one uses implicit file descriptors, +The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over those default files. @@ -5297,16 +5411,16 @@

        (plus an error message as a second result) and some value different from nil on success. -


        io.close ([file])

        +


        io.close ([file])

        Equivalent to file:close(). Without a file, closes the default output file. -


        io.flush ()

        +


        io.flush ()

        Equivalent to file:flush over the default output file. -


        io.input ([file])

        +


        io.input ([file])

        When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. @@ -5318,7 +5432,7 @@

        In case of errors this function raises the error, instead of returning an error code. -


        io.lines ([filename])

        +


        io.lines ([filename])

        Opens the given file name in read mode and returns an iterator function that, @@ -5333,11 +5447,11 @@

        it returns nil (to finish the loop) and automatically closes the file.

        The call io.lines() (without a file name) is equivalent -to io.input():lines(), that is, it iterates over the -lines of the default input file. +to io.input():lines(); +that is, it iterates over the lines of the default input file. In that case it does not close the file when the loop ends. -


        io.open (filename [, mode])

        +


        io.open (filename [, mode])

        This function opens a file, in the mode specified in the string mode. @@ -5346,24 +5460,24 @@

        The mode string can be any of the following:

          -
        • "r" read mode (the default); -
        • "w" write mode; -
        • "a" append mode; -
        • "r+" update mode, all previous data is preserved; -
        • "w+" update mode, all previous data is erased; -
        • "a+" append update mode, previous data is preserved, +
        • "r" --- read mode (the default); +
        • "w" --- write mode; +
        • "a" --- append mode; +
        • "r+" --- update mode, all previous data is preserved; +
        • "w+" --- update mode, all previous data is erased; +
        • "a+" --- append update mode, previous data is preserved, writing is only allowed at the end of file.
        -The mode string may also have a b at the end, +The mode string may also have a `b´ at the end, which is needed in some systems to open the file in binary mode. This string is exactly what is used in the standard C function fopen. -


        io.output ([file])

        +


        io.output ([file])

        Similar to io.input, but operates over the default output file. -


        io.popen ([prog [, mode]])

        +


        io.popen ([prog [, mode]])

        Starts program prog in a separated process and returns a file handle that you can use to read data from that program @@ -5372,40 +5486,41 @@

        (if mode is "w").

        This function is system dependent and is not available -in all platforms. +on all platforms. -


        io.read (format1, ...)

        +


        io.read (format1, ...)

        Equivalent to io.input():read. -


        io.tmpfile ()

        +


        io.tmpfile ()

        Returns a handle for a temporary file. -This file is open in update mode +This file is opened in update mode and it is automatically removed when the program ends. -


        io.type (obj)

        +


        io.type (obj)

        Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, and nil if obj is not a file handle. -


        io.write (value1, ...)

        +


        io.write (value1, ...)

        Equivalent to io.output():write. -


        file:close ()

        +


        file:close ()

        Closes file. -Note that files are automatically closed when garbage collected, +Note that files are automatically closed when +their handles are garbage collected, but that takes an unpredictable time to happen. -


        file:flush ()

        +


        file:flush ()

        Saves any written data to file. -


        file:lines ()

        +


        file:lines ()

        Returns an iterator function that, each time it is called, @@ -5418,7 +5533,7 @@

        (Unlike io.lines, this function does not close the file when the loop ends.) -


        file:read (format1, ...)

        +


        file:read (format1, ...)

        Reads the file file, according to the given formats, which specify what to read. @@ -5445,7 +5560,7 @@

        or nil on end of file.

      -


      file:seek ([whence] [, offset])

      +


      file:seek ([whence] [, offset])

      Sets and gets the file position, measured from the beginning of the file, @@ -5470,26 +5585,29 @@

      and the call file:seek("end") sets the position to the end of the file, and returns its size. -


      file:setvbuf (mode [, size])

      +


      file:setvbuf (mode [, size])

      Sets the buffering mode for an output file. There are three available modes:

        -
      • "no" no buffering; any output operation appear immediately. -
      • "full" full buffering; output operation is performed only -when the buffer is full (or when you flush the file (see 5.7)). -
      • "line" line buffering; output is buffered until a newline is -output or there is any input from some special files +
      • "no" --- +no buffering; the result of any output operation appears immediately. +
      • "full" --- +full buffering; output operation is performed only +when the buffer is full (or when you explicitly flush the file (see 5.7)). +
      • "line" --- +line buffering; output is buffered until a newline is output +or there is any input from some special files (such as a terminal device).
      For the last two cases, sizes specifies the size of the buffer, in bytes. The default is an appropriate size. -


      file:write (value1, ...)

      +


      file:write (value1, ...)

      Writes the value of each of its arguments to -the filehandle file. +the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write. @@ -5498,12 +5616,12 @@

      This library is implemented through table os. -


      os.clock ()

      +


      os.clock ()

      -

      Returns an approximation of the amount of CPU time -used by the program, in seconds. +

      Returns an approximation of the amount in seconds of CPU time +used by the program. -


      os.date ([format [, time]])

      +


      os.date ([format [, time]])

      Returns a string or a table containing date and time, formatted according to the given string format. @@ -5533,43 +5651,46 @@

      the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")). -


      os.difftime (t2, t1)

      +


      os.difftime (t2, t1)

      Returns the number of seconds from time t1 to time t2. In Posix, Windows, and some other systems, this value is exactly t2-t1. -


      os.execute (command)

      +


      os.execute ([command])

      This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. +If command is absent, then it returns nonzero if a shell is available +and zero otherwise. -


      os.exit ([code])

      +


      os.exit ([code])

      Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. -


      os.getenv (varname)

      +


      os.getenv (varname)

      Returns the value of the process environment variable varname, or nil if the variable is not defined. -


      os.remove (filename)

      +


      os.remove (filename)

      -

      Deletes the file with the given name. +

      Deletes the file or directory with the given name. +Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error. -


      os.rename (oldname, newname)

      +


      os.rename (oldname, newname)

      -

      Renames file named oldname to newname. +

      Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error. -


      os.setlocale (locale [, category])

      +


      os.setlocale (locale [, category])

      Sets the current locale of the program. locale is a string specifying a locale; @@ -5580,7 +5701,7 @@

      The function returns the name of the new locale, or nil if the request cannot be honored. -


      os.time ([table])

      +


      os.time ([table])

      Returns the current time when called without arguments, or a time representing the date and time specified by the given table. @@ -5595,16 +5716,16 @@

      and the number returned by time can be used only as an argument to date and difftime. -


      os.tmpname ()

      +


      os.tmpname ()

      Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use -and removed when no longer needed. +and explicitly removed when no longer needed. -

      5.9 - The Reflexive Debug Interface

      +

      5.9 - The Debug Library

      -

      The debug library provides +

      This library provides the functionality of the debug interface to Lua programs. You should exert care when using this library. The functions provided here should be used exclusively for debugging @@ -5614,14 +5735,15 @@

      They can be very slow. Moreover, several of its functions violate some assumptions about Lua code -(e.g., that local variables cannot be accessed from outside or +(e.g., that variables local to a function +cannot be accessed from outside or that userdata metatables cannot be changed by Lua code) -and therefore can compromise some otherwise secure code. +and therefore can compromise otherwise secure code.

      All functions in this library are provided -inside a debug table. +inside the debug table. -


      debug.debug ()

      +


      debug.debug ()

      Enters an interactive mode with the user, running each string that the user enters. @@ -5631,22 +5753,22 @@

      A line containing only the word cont finishes this function, so that the caller continues its execution. -

      Note that commands for debug.debug are not lexically nested -with any function, so they have no direct access to local variables. +

      Note that commands for debug.debug are not lexically nested +within any function, and so have no direct access to local variables. -


      debug.getfenv (o)

      +


      debug.getfenv (o)

      Returns the environment of object o. -


      debug.gethook ()

      +


      debug.gethook ()

      Returns the current hook settings, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function). -


      debug.getinfo (function [, what])

      +


      debug.getinfo (function [, what])

      -

      This function returns a table with information about a function. +

      Returns a table with information about a function. You can give the function directly, or you can give a number as the value of function, which means the function running at level function of the call stack: @@ -5664,11 +5786,11 @@

      adds a field named func with the function itself.

      For instance, the expression debug.getinfo(1,"n").name returns -the name of the current function, if a reasonable name can be found, +a name of the current function, if a reasonable name can be found, and debug.getinfo(print) returns a table with all available information about the print function. -


      debug.getlocal (level, local)

      +


      debug.getlocal (level, local)

      This function returns the name and the value of the local variable with index local of the function at level level of the stack. @@ -5683,26 +5805,26 @@

      represent internal variables (loop control variables, temporaries, and C function locals). -


      debug.getmetatable (object)

      +


      debug.getmetatable (object)

      -

      If object does not have a metatable, returns nil. -Otherwise, returns the metatable of the given object. +

      Returns the metatable of the given object +or nil if it does not have a metatable. -


      debug.getregistry ()

      +


      debug.getregistry ()

      Returns the registry table (see 3.5). -


      debug.getupvalue (func, up)

      +


      debug.getupvalue (func, up)

      This function returns the name and the value of the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index. -


      debug.setfenv (o, table)

      +


      debug.setfenv (object, table)

      -

      Sets the environment of the given object. +

      Sets the environment of the given object to the given table. -


      debug.sethook (hook, mask [, count])

      +


      debug.sethook (hook, mask [, count])

      Sets the given function as a hook. The string mask and the number count describe @@ -5710,22 +5832,22 @@

      The string mask may have the following characters, with the given meaning:
        -
      • "c" The hook is called every time Lua calls a function; -
      • "r" The hook is called every time Lua returns from a function; -
      • "l" The hook is called every time Lua enters a new line of code. +
      • "c" --- The hook is called every time Lua calls a function; +
      • "r" --- The hook is called every time Lua returns from a function; +
      • "l" --- The hook is called every time Lua enters a new line of code.
      With a count different from zero, the hook is called after every count instructions.

      When called without arguments, -the debug.sethook function turns off the hook. +debug.sethook turns off the hook. -

      When the hook is called, its first parameter is always a string -describing the event that triggered its call: +

      When the hook is called, its first parameter is a string +describing the event that has triggered its call: "call", "return" (or "tail return"), "line", and "count". -Moreover, for line events, -it also gets as its second parameter the new line number. +For line events, +the hook also gets the new line number as its second parameter. Inside a hook, you can call getinfo with level 2 to get more information about the running function @@ -5735,7 +5857,7 @@

      In this case, Lua is only simulating the return, and a call to getinfo will return invalid data. -


      debug.setlocal (level, local, value)

      +


      debug.setlocal (level, local, value)

      This function assigns the value value to the local variable with index local of the function at level level of the stack. @@ -5745,11 +5867,12 @@

      (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable. -


      debug.setmetatable (o, metatable)

      +


      debug.setmetatable (object, table)

      -

      Sets the metatable for the given object. +

      Sets the metatable for the given object to the given id@{table} +(which can be nil). -


      debug.setupvalue (func, up, value)

      +


      debug.setupvalue (func, up, value)

      This function assigns the value value to the upvalue with index up of the function func. @@ -5757,7 +5880,7 @@

      with the given index. Otherwise, it returns the name of the upvalue. -


      debug.traceback ([message])

      +


      debug.traceback ([message])

      Returns a string with a traceback of the call stack. An optional message string is appended @@ -5775,7 +5898,7 @@

      called simply lua, is provided with the standard distribution. The stand-alone interpreter includes -all standard libraries plus the reflexive debug interface. +all standard libraries, including the debug library. Its usage is:
             lua [options] [script [args]]
      @@ -5790,30 +5913,31 @@ 

    • - executes stdin as a file and stops handling options.
    After handling its options, lua runs the given script, -passing to it the given args. +passing to it the given args as string arguments. When called without arguments, -lua behaves as lua -v -i when stdin is a terminal, +lua behaves as lua -v -i +when the standard input (stdin) is a terminal, and as lua - otherwise.

    Before running any argument, the interpreter checks for an environment variable LUA_INIT. If its format is @filename, -then lua executes the file. -Otherwise, lua executes the string itself. +then lua executes the file. +Otherwise, lua executes the string itself.

    All options are handled in order, except -i. For instance, an invocation like

            $ lua -e'a=1' -e 'print(a)' script.lua
     
    -will first set a to 1, then print a, -and finally run the file script.lua. +will first set a to 1, then print the value of a (which is `1´), +and finally run the file script.lua with no arguments. (Here $ is the shell prompt. Your prompt may be different.)

    Before starting to run the script, lua collects all arguments in the command line in a global table called arg. -The script name is stored in index 0, +The script name is stored at index 0, the first argument after the script name goes to index 1, and so on. Any arguments before the script name @@ -5821,34 +5945,40 @@

    go to negative indices. For instance, in the call
    -       $ lua -la.lua b.lua t1 t2
    +       $ lua -la b.lua t1 t2
     
    the interpreter first runs the file a.lua, then creates a table
    -       arg = { [-2] = "lua", [-1] = "-la.lua", [0] = "b.lua",
    +       arg = { [-2] = "lua", [-1] = "-la",
    +               [0] = "b.lua",
                    [1] = "t1", [2] = "t2" }
     
    and finally runs the file b.lua. The script is called with arg[1], arg[2], ... as arguments; -it can access those arguments with the vararg expression .... +it can also access those arguments with the vararg expression `...´.

    In interactive mode, if you write an incomplete statement, -the interpreter waits for its completion. +the interpreter waits for its completion +by issuing a different prompt. -

    If the global variable _PROMPT is defined as a string, +

    If the global variable _PROMPT contains a string, then its value is used as the prompt. -Therefore, the prompt can be changed directly on the command line: +Similarly, if the global variable _PROMPT2 contains a string, +it its value is used as the secondary prompt +(issued during incomplete statements). +Therefore, both prompts can be changed directly on the command line. +For instance,

            $ lua -e"_PROMPT='myprompt> '" -i
     
    (the outer pair of quotes is for the shell, -the inner is for Lua), +the inner pair is for Lua), or in any Lua programs by assigning to _PROMPT. Note the use of -i to enter interactive mode; otherwise, -the program would end just after the assignment to _PROMPT. +the program would just end silently right after the assignment to _PROMPT.

    To allow the use of Lua as a script interpreter in Unix systems, @@ -5869,17 +5999,17 @@

    is a more portable solution.) -


    +


    -

    Incompatibilities with Previous Version

    +

    Incompatibilities with the Previous Version

    -

    Here we list the incompatibilities when moving a program +

    Here we list the incompatibilities that may be found when moving a program from Lua 5.0 to Lua 5.1. You can avoid most of the incompatibilities compiling Lua with -appropriate options. +appropriate options (see file luaconf.h). However, -all those compatibility options will be removed in the next version. +all those compatibility options will be removed in the next version of Lua.

    Incompatibilities with version 5.0

    @@ -5888,25 +6018,21 @@

  • The vararg system changed from the pseudo-argument arg with a table with the extra arguments to the vararg expression. -(Option LUA_COMPAT_VARARG) +(Option LUA_COMPAT_VARARG in luaconf.h.)

  • There was a subtle change in the scope of the implicit -variables of the for constructor. +variables of the for statement and for the repeat statement.

  • The long string/long comment syntax ([[...]]) does not allow nesting. You can use the new syntax ([=[...]=]) in those cases. -(Option LUA_COMPAT_LSTR) +(Option LUA_COMPAT_LSTR in luaconf.h.)

    Changes in the Libraries

      -
    • -Function string.find does not return its captures. -Use string.match for that. -(Option LUA_COMPAT_FIND)

    • Function string.gfind was renamed string.gmatch. @@ -5935,10 +6061,10 @@

      (Option LUA_COMPAT_MOD)

    • -There was substantial changes in function require due to +There were substantial changes in function require due to the new module system. However, the new behavior is mostly compatible with the old, -but it gets the path from package.path instead +but require gets the path from package.path instead of from LUA_PATH.

    • @@ -5952,7 +6078,7 @@

      • Function lua_open was replaced by lua_newstate to -allow the user to set an allocation function. +allow the user to set a memory allocation function. You can use luaL_newstate from the standard library to create a state with a standard allocation function (based on realloc). @@ -5973,6 +6099,11 @@

        The Complete Syntax of Lua

        +

        Here is the complete syntax of Lua in extended BNF. +It does not describe operator priorities nor some syntactical restrictions, +such as return and break statements +can only appear as the last statement of a block. +

        @@ -5991,7 +6122,7 @@ 

        for namelist in explist1 do block end | function funcname funcbody | local function Name funcbody | - local namelist [init] + local namelist [`=´ explist1] laststat ::= return [explist1] | break @@ -6003,18 +6134,16 @@

        namelist ::= Name {`,´ Name} - init ::= `=´ explist1 - explist1 ::= {exp `,´} exp - exp ::= nil | false | true | Number | Literal | `...´ | + exp ::= nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp prefixexp ::= var | functioncall | `(´ exp `)´ functioncall ::= prefixexp args | prefixexp `:´ Name args - args ::= `(´ [explist1] `)´ | tableconstructor | Literal + args ::= `(´ [explist1] `)´ | tableconstructor | String function ::= function funcbody @@ -6026,7 +6155,7 @@

        fieldlist ::= field {fieldsep field} [fieldsep] - field ::= `[´ exp `]´ `=´ exp | name `=´ exp | exp + field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp fieldsep ::= `,´ | `;´ @@ -6042,10 +6171,5 @@

        -


        - -Last update: -Tue Nov 1 15:20:21 BRST 2005 - - + diff --git a/src/Makefile b/src/Makefile index 60fd14c83c..b042d9abf1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,6 +4,9 @@ # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= +# Your platform. See PLATS for possible values. +PLAT= none + CC= gcc CFLAGS= -O2 -Wall $(MYCFLAGS) AR= ar rcu @@ -14,12 +17,11 @@ LIBS= -lm $(MYLIBS) MYCFLAGS= MYLDFLAGS= MYLIBS= -# enable dynamic loading and line editing in Linux -# MYCFLAGS= -DLUA_USE_DLOPEN -DLUA_USE_READLINE -# MYLIBS= -Wl,-E -ldl -lreadline -lhistory -lncurses # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= +PLATS= ansi bsd generic linux macosx mingw posix + LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ @@ -37,6 +39,8 @@ ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) ALL_A= $(LUA_A) +default: $(PLAT) + all: $(ALL_T) o: $(ALL_O) @@ -60,6 +64,7 @@ depend: @$(CC) $(CFLAGS) -MM l*.c print.c echo: + @echo "PLAT = $(PLAT)" @echo "CC = $(CC)" @echo "CFLAGS = $(CFLAGS)" @echo "AR = $(AR)" @@ -69,6 +74,34 @@ echo: @echo "MYLDFLAGS = $(MYLDFLAGS)" @echo "MYLIBS = $(MYLIBS)" +# convenience targets for usual platforms + +none: + @echo "Please choose a platform: $(PLATS)" + +ansi: + $(MAKE) all MYCFLAGS=-DLUA_ANSI + +bsd: + $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" + +generic: + $(MAKE) all MYCFLAGS= + +linux: + $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" + +macosx: + $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX + +mingw: + $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ + "AR=gcc -shared -o" "RANLIB=strip --strip-unneeded" \ + "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe + +posix: + $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX + # DO NOT DELETE lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ @@ -86,8 +119,8 @@ ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h ltable.h \ lstring.h lundump.h lvm.h -ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lopcodes.h lstate.h \ - ltm.h lzio.h lmem.h lundump.h +ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ + lzio.h lmem.h lundump.h lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ lstate.h ltm.h lzio.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ @@ -99,10 +132,11 @@ llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h -loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h +loadlib.o: loadlib.c lauxlib.h lua.h luaconf.h lobject.h llimits.h \ + lualib.h lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h -lopcodes.o: lopcodes.c lua.h luaconf.h lobject.h llimits.h lopcodes.h +lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h \ @@ -122,8 +156,7 @@ luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ lundump.h lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ - llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lopcodes.h lstring.h lgc.h \ - lundump.h + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ diff --git a/src/lapi.c b/src/lapi.c index 71daabdae8..ce7bcf6f3a 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.51 2005/10/20 11:35:50 roberto Exp $ +** $Id: lapi.c,v 2.53 2006/01/10 12:50:00 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -40,7 +40,7 @@ const char lua_ident[] = #define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) -#define api_checkvalidindex(L, i) api_check(L, (i) != &luaO_nilobject) +#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) #define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} @@ -50,7 +50,7 @@ static TValue *index2adr (lua_State *L, int idx) { if (idx > 0) { TValue *o = L->base + (idx - 1); api_check(L, idx <= L->ci->top - L->base); - if (o >= L->top) return cast(TValue *, &luaO_nilobject); + if (o >= L->top) return cast(TValue *, luaO_nilobject); else return o; } else if (idx > LUA_REGISTRYINDEX) { @@ -70,7 +70,7 @@ static TValue *index2adr (lua_State *L, int idx) { idx = LUA_GLOBALSINDEX - idx; return (idx <= func->c.nupvalues) ? &func->c.upvalue[idx-1] - : cast(TValue *, &luaO_nilobject); + : cast(TValue *, luaO_nilobject); } } } @@ -153,7 +153,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API int lua_gettop (lua_State *L) { - return cast(int, L->top - L->base); + return cast_int(L->top - L->base); } @@ -234,7 +234,7 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2adr(L, idx); - return (o == &luaO_nilobject) ? LUA_TNONE : ttype(o); + return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -272,7 +272,7 @@ LUA_API int lua_isuserdata (lua_State *L, int idx) { LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = index2adr(L, index1); StkId o2 = index2adr(L, index2); - return (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaO_rawequalObj(o1, o2); } @@ -283,8 +283,7 @@ LUA_API int lua_equal (lua_State *L, int index1, int index2) { lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); - i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 - : equalobj(L, o1, o2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); lua_unlock(L); return i; } @@ -296,7 +295,7 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); - i = (o1 == &luaO_nilobject || o2 == &luaO_nilobject) ? 0 + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaV_lessthan(L, o1, o2); lua_unlock(L); return i; @@ -430,7 +429,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { lua_lock(L); - setnvalue(L->top, cast(lua_Number, n)); + setnvalue(L->top, cast_num(n)); api_incr_top(L); lua_unlock(L); } @@ -910,11 +909,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ - res = cast(int, g->totalbytes >> 10); + res = cast_int(g->totalbytes >> 10); break; } case LUA_GCCOUNTB: { - res = cast(int, g->totalbytes & 0x3ff); + res = cast_int(g->totalbytes & 0x3ff); break; } case LUA_GCSTEP: { @@ -983,7 +982,7 @@ LUA_API void lua_concat (lua_State *L, int n) { api_checknelems(L, n); if (n >= 2) { luaC_checkGC(L); - luaV_concat(L, n, cast(int, L->top - L->base) - 1); + luaV_concat(L, n, cast_int(L->top - L->base) - 1); L->top -= (n-1); } else if (n == 0) { /* push empty string */ diff --git a/src/lauxlib.c b/src/lauxlib.c index 0462097975..d3b54ee4b1 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.156 2005/10/21 13:47:42 roberto Exp $ +** $Id: lauxlib.c,v 1.157 2005/12/29 15:32:11 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -226,16 +226,24 @@ LUALIB_API void (luaL_register) (lua_State *L, const char *libname, } +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l->name; l++) size++; + return size; +} + + LUALIB_API void luaI_openlib (lua_State *L, const char *libname, const luaL_Reg *l, int nup) { if (libname) { + int size = libsize(l); /* check whether lib already exists */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); lua_getfield(L, -1, libname); /* get _LOADED[libname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ - if (luaL_findtable(L, LUA_GLOBALSINDEX, libname) != NULL) + if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) luaL_error(L, "name conflict for module " LUA_QS, libname); lua_pushvalue(L, -1); lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ @@ -331,7 +339,7 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, LUALIB_API const char *luaL_findtable (lua_State *L, int idx, - const char *fname) { + const char *fname, int szhint) { const char *e; lua_pushvalue(L, idx); do { @@ -341,7 +349,7 @@ LUALIB_API const char *luaL_findtable (lua_State *L, int idx, lua_rawget(L, -2); if (lua_isnil(L, -1)) { /* no such field? */ lua_pop(L, 1); /* remove this nil */ - lua_newtable(L); /* create a new table for field */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_pushlstring(L, fname, e - fname); lua_pushvalue(L, -2); lua_settable(L, -4); /* set new table into field */ diff --git a/src/lauxlib.h b/src/lauxlib.h index ee503cc84a..1bba1c04f8 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.86 2005/10/21 13:47:42 roberto Exp $ +** $Id: lauxlib.h,v 1.87 2005/12/29 15:32:11 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -86,7 +86,7 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, - const char *fname); + const char *fname, int szhint); diff --git a/src/lbaselib.c b/src/lbaselib.c index 7d8724a563..1778e775ea 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.186 2005/10/21 13:47:42 roberto Exp $ +** $Id: lbaselib.c,v 1.188 2005/12/29 15:32:11 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -201,7 +201,7 @@ static int luaB_collectgarbage (lua_State *L) { switch (optsnum[o]) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, ((lua_Number)res*1024 + b)/1000); + lua_pushnumber(L, ((lua_Number)res*1024 + b)/1024); return 1; } case LUA_GCSTEP: { @@ -625,7 +625,7 @@ static void base_open (lua_State *L) { auxopen(L, "ipairs", luaB_ipairs, ipairsaux); auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ - lua_newtable(L); /* new table `w' */ + lua_createtable(L, 0, 1); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ lua_setmetatable(L, -2); lua_pushliteral(L, "kv"); diff --git a/src/lcode.c b/src/lcode.c index ecda5cbfe2..dd3e37e78c 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.22 2005/11/16 11:55:27 roberto Exp $ +** $Id: lcode.c,v 2.24 2005/12/22 16:19:56 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -196,7 +196,7 @@ void luaK_checkstack (FuncState *fs, int n) { if (newstack > fs->f->maxstacksize) { if (newstack >= MAXSTACK) luaX_syntaxerror(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = cast(lu_byte, newstack); + fs->f->maxstacksize = cast_byte(newstack); } } @@ -227,11 +227,11 @@ static int addk (FuncState *fs, TValue *k, TValue *v) { Proto *f = fs->f; int oldsize = f->sizek; if (ttisnumber(idx)) { - lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v)); - return cast(int, nvalue(idx)); + lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); + return cast_int(nvalue(idx)); } else { /* constant not found; create a new entry */ - setnvalue(idx, cast(lua_Number, fs->nk)); + setnvalue(idx, cast_num(fs->nk)); luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, MAXARG_Bx, "constant table overflow"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); @@ -647,7 +647,7 @@ static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { case OP_LEN: return 0; /* no constant folding for 'len' */ default: lua_assert(0); r = 0; break; } - if (r != r) return 0; /* do not attempt to produce NaN */ + if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ e1->u.nval = r; return 1; } diff --git a/src/ldblib.c b/src/ldblib.c index 5da6e1da9a..26a19b6a6f 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.103 2005/11/01 16:08:32 roberto Exp $ +** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -116,7 +116,7 @@ static int db_getinfo (lua_State *L) { return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); - lua_newtable(L); + lua_createtable(L, 0, 2); if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); @@ -246,7 +246,7 @@ static void gethooktable (lua_State *L) { lua_rawget(L, LUA_REGISTRYINDEX); if (!lua_istable(L, -1)) { lua_pop(L, 1); - lua_newtable(L); + lua_createtable(L, 0, 1); lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); diff --git a/src/ldebug.c b/src/ldebug.c index 5fb11ce11f..8919a01739 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.28 2005/11/01 16:08:52 roberto Exp $ +** $Id: ldebug.c,v 2.29 2005/12/22 16:19:56 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -61,7 +61,7 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { L->hook = func; L->basehookcount = count; resethookcount(L); - L->hookmask = cast(lu_byte, mask); + L->hookmask = cast_byte(mask); return 1; } @@ -92,7 +92,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { } if (level == 0 && ci > L->base_ci) { /* level found? */ status = 1; - ar->i_ci = cast(int, ci - L->base_ci); + ar->i_ci = cast_int(ci - L->base_ci); } else if (level < 0) { /* level is of a lost tail call? */ status = 1; @@ -550,7 +550,7 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? - getobjname(L, L->ci, cast(int, o - L->base), &name) : + getobjname(L, L->ci, cast_int(o - L->base), &name) : NULL; if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", diff --git a/src/ldo.c b/src/ldo.c index cb510dd84b..b8eb1a8a59 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.36 2005/10/23 17:52:42 roberto Exp $ +** $Id: ldo.c,v 2.37 2005/12/22 16:19:56 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -71,7 +71,7 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { static void restore_stack_limit (lua_State *L) { lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ - int inuse = cast(int, L->ci - L->base_ci); + int inuse = cast_int(L->ci - L->base_ci); if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ luaD_reallocCI(L, LUAI_MAXCALLS); } @@ -97,7 +97,7 @@ void luaD_throw (lua_State *L, int errcode) { LUAI_THROW(L, L->errorJmp); } else { - L->status = cast(lu_byte, errcode); + L->status = cast_byte(errcode); if (G(L)->panic) { resetstack(L, errcode); lua_unlock(L); @@ -189,7 +189,7 @@ void luaD_callhook (lua_State *L, int event, int line) { if (event == LUA_HOOKTAILRET) ar.i_ci = 0; /* tail call; no debug information about it */ else - ar.i_ci = cast(int, L->ci - L->base_ci); + ar.i_ci = cast_int(L->ci - L->base_ci); luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; lua_assert(L->ci->top <= L->stack_last); @@ -221,8 +221,7 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { for (i=0; itop - nvar + i); /* store counter in field `n' */ - setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), - cast(lua_Number, nvar)); + setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); } #endif /* move fixed parameters to final position */ @@ -282,7 +281,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { L->top = base + p->numparams; } else { /* vararg function */ - int nargs = cast(int, L->top - func) - 1; + int nargs = cast_int(L->top - func) - 1; base = adjust_varargs(L, p, nargs); func = restorestack(L, funcr); /* previous call may change the stack */ } @@ -401,7 +400,7 @@ static void resume (lua_State *L, void *ud) { L->base = L->ci->base; } L->status = 0; - luaV_execute(L, cast(int, L->ci - L->base_ci)); + luaV_execute(L, cast_int(L->ci - L->base_ci)); } @@ -427,7 +426,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { lua_assert(L->errfunc == 0 && L->nCcalls == 0); status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status != 0) { /* error? */ - L->status = cast(lu_byte, status); /* mark thread as `dead' */ + L->status = cast_byte(status); /* mark thread as `dead' */ luaD_seterrorobj(L, status, L->top); L->ci->top = L->top; } diff --git a/src/lfunc.c b/src/lfunc.c index c9286d9159..b8cd67b267 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.11 2005/05/05 20:47:02 roberto Exp $ +** $Id: lfunc.c,v 2.12 2005/12/22 16:19:56 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -25,7 +25,7 @@ Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; c->c.env = e; - c->c.nupvalues = cast(lu_byte, nelems); + c->c.nupvalues = cast_byte(nelems); return c; } @@ -35,7 +35,7 @@ Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->l.isC = 0; c->l.env = e; - c->l.nupvalues = cast(lu_byte, nelems); + c->l.nupvalues = cast_byte(nelems); while (nelems--) c->l.upvals[nelems] = NULL; return c; } diff --git a/src/lgc.c b/src/lgc.c index 0f30104f5d..691565db49 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.36 2005/08/24 17:06:36 roberto Exp $ +** $Id: lgc.c,v 2.37 2005/12/22 16:19:56 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -29,11 +29,10 @@ #define GCFINALIZECOST 100 -#define maskmarks \ - cast(lu_byte, ~(bitmask(BLACKBIT)|WHITEBITS)) +#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) #define makewhite(g,x) \ - ((x)->gch.marked = ((x)->gch.marked & maskmarks) | luaC_white(g)) + ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) @@ -169,8 +168,8 @@ static int traversetable (global_State *g, Table *h) { weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ - h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) | - (weakvalue << VALUEWEAKBIT)); + h->marked |= cast_byte((weakkey << KEYWEAKBIT) | + (weakvalue << VALUEWEAKBIT)); h->gclist = g->weak; /* must be cleared after GC, ... */ g->weak = obj2gco(h); /* ... so put in the appropriate list */ } @@ -240,8 +239,8 @@ static void traverseclosure (global_State *g, Closure *cl) { static void checkstacksizes (lua_State *L, StkId max) { - int ci_used = cast(int, L->ci - L->base_ci); /* number of `ci' in use */ - int s_used = cast(int, max - L->stack); /* part of stack in use */ + int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ + int s_used = cast_int(max - L->stack); /* part of stack in use */ if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ return; /* do not touch the stacks */ if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) @@ -544,7 +543,7 @@ static void atomic (lua_State *L) { propagateall(g); /* remark, to propagate `preserveness' */ cleartable(g->weak); /* remove collected objects from weak tables */ /* flip current white */ - g->currentwhite = cast(lu_byte, otherwhite(g)); + g->currentwhite = cast_byte(otherwhite(g)); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; g->gcstate = GCSsweepstring; diff --git a/src/linit.c b/src/linit.c index d30ff1e3aa..483d9c8c28 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.13 2005/08/26 17:36:32 roberto Exp $ +** $Id: linit.c,v 1.14 2005/12/29 15:32:11 roberto Exp $ ** Initialization of libraries for lua.c ** See Copyright Notice in lua.h */ @@ -16,13 +16,13 @@ static const luaL_Reg lualibs[] = { {"", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, - {LUA_LOADLIBNAME, luaopen_package}, {NULL, NULL} }; diff --git a/src/liolib.c b/src/liolib.c index cc493aff82..f0a7602a5c 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.69 2005/10/19 13:05:11 roberto Exp $ +** $Id: liolib.c,v 2.70 2005/12/29 15:32:11 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -507,8 +507,8 @@ static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { LUALIB_API int luaopen_io (lua_State *L) { createmeta(L); - /* create new (private) environment */ - lua_newtable(L); + /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ + lua_createtable(L, 2, 1); lua_replace(L, LUA_ENVIRONINDEX); /* open library */ luaL_register(L, LUA_IOLIBNAME, iolib); @@ -518,7 +518,7 @@ LUALIB_API int luaopen_io (lua_State *L) { createstdfile(L, stderr, 0, "stderr"); /* create environment for 'popen' */ lua_getfield(L, -1, "popen"); - lua_newtable(L); + lua_createtable(L, 0, 1); lua_pushcfunction(L, io_pclose); lua_setfield(L, -2, "__close"); lua_setfenv(L, -2); diff --git a/src/llex.c b/src/llex.c index d7753394a0..2792ea9ef1 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,11 +1,12 @@ /* -** $Id: llex.c,v 2.13 2005/11/08 19:45:14 roberto Exp $ +** $Id: llex.c,v 2.17 2005/12/22 16:19:56 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #include +#include #include #define llex_c @@ -65,7 +66,7 @@ void luaX_init (lua_State *L) { TString *ts = luaS_new(L, luaX_tokens[i]); luaS_fix(ts); /* reserved words are never collected */ lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); - ts->tsv.reserved = cast(lu_byte, i+1); /* reserved word */ + ts->tsv.reserved = cast_byte(i+1); /* reserved word */ } } @@ -134,6 +135,7 @@ static void inclinenumber (LexState *ls) { void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { + ls->decpoint = '.'; ls->L = L; ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->z = z; @@ -163,6 +165,27 @@ static int check_next (LexState *ls, const char *set) { } +static void buffreplace (LexState *ls, char from, char to) { + int n = luaZ_bufflen(ls->buff); + char *p = luaZ_buffer(ls->buff); + while (n--) + if (p[n] == from) p[n] = to; +} + + +static void trydecpoint (LexState *ls, SemInfo *seminfo) { + /* format error: try to update decimal point separator */ + struct lconv *cv = localeconv(); + char old = ls->decpoint; + ls->decpoint = (cv ? cv->decimal_point[0] : '.'); + buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { + /* format error with correct decimal point: no more options */ + buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ + luaX_lexerror(ls, "malformed number", TK_NUMBER); + } +} + /* LUA_NUMBER */ static void read_numeral (LexState *ls, SemInfo *seminfo) { @@ -177,8 +200,9 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { } } save(ls, '\0'); - if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) - luaX_lexerror(ls, "malformed number", TK_NUMBER); + buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ + if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ } @@ -306,7 +330,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { } -int luaX_lex (LexState *ls, SemInfo *seminfo) { +static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); for (;;) { switch (ls->current) { @@ -419,4 +443,20 @@ int luaX_lex (LexState *ls, SemInfo *seminfo) { } } -#undef next + +void luaX_next (LexState *ls) { + ls->lastline = ls->linenumber; + if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ + ls->t = ls->lookahead; /* use this one */ + ls->lookahead.token = TK_EOS; /* and discharge it */ + } + else + ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ +} + + +void luaX_lookahead (LexState *ls) { + lua_assert(ls->lookahead.token == TK_EOS); + ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); +} + diff --git a/src/llex.h b/src/llex.h index 08a0b25413..d4ca7f20e1 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.55 2005/06/06 13:30:25 roberto Exp $ +** $Id: llex.h,v 1.57 2005/12/07 15:43:05 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -63,6 +63,7 @@ typedef struct LexState { ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ TString *source; /* current source name */ + char decpoint; /* locale decimal point */ } LexState; @@ -70,7 +71,8 @@ LUAI_FUNC void luaX_init (lua_State *L); LUAI_FUNC void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source); LUAI_FUNC TString *luaX_newstring (LexState *LS, const char *str, size_t l); -LUAI_FUNC int luaX_lex (LexState *LS, SemInfo *seminfo); +LUAI_FUNC void luaX_next (LexState *ls); +LUAI_FUNC void luaX_lookahead (LexState *ls); LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); diff --git a/src/llimits.h b/src/llimits.h index 68c28c8c7e..b03221aeec 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.67 2005/08/24 16:15:49 roberto Exp $ +** $Id: llimits.h,v 1.69 2005/12/27 17:12:00 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -15,9 +15,6 @@ #include "lua.h" -#define api_check luai_apicheck - - typedef LUAI_UINT32 lu_int32; typedef LUAI_UMEM lu_mem; @@ -54,7 +51,19 @@ typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; typedef LUAI_UACNUMBER l_uacNumber; -#define check_exp(c,e) (lua_assert(c), (e)) +/* internal assertions for in-house debugging */ +#ifdef lua_assert + +#define check_exp(c,e) (lua_assert(c), (e)) +#define api_check(l,e) lua_assert(e) + +#else + +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define api_check luai_apicheck + +#endif #ifndef UNUSED @@ -66,6 +75,10 @@ typedef LUAI_UACNUMBER l_uacNumber; #define cast(t, exp) ((t)(exp)) #endif +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) + /* diff --git a/src/lmem.c b/src/lmem.c index dd9096552a..cef2bc5f85 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.69 2005/02/23 17:30:22 roberto Exp $ +** $Id: lmem.c,v 1.70 2005/12/26 13:35:47 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -81,22 +81,6 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { luaD_throw(L, LUA_ERRMEM); lua_assert((nsize == 0) == (block == NULL)); g->totalbytes = (g->totalbytes - osize) + nsize; -#if 0 - { /* auxiliar patch to monitor garbage collection */ - static unsigned long total = 0; /* our "time" */ - static lu_mem last = 0; /* last totalmem that generated an output */ - static FILE *f = NULL; /* output file */ - if (nsize <= osize) total += 1; /* "time" always grow */ - else total += (nsize - osize); - if ((int)g->totalbytes - (int)last > 1000 || - (int)g->totalbytes - (int)last < -1000) { - last = g->totalbytes; - if (f == NULL) f = fopen("trace", "w"); - fprintf(f, "%lu %u %u %u %d\n", total, g->totalbytes, g->GCthreshold, - g->estimate, g->gcstate); - } - } -#endif return block; } diff --git a/src/loadlib.c b/src/loadlib.c index 9f992086b6..19edaca0fd 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.48 2005/10/17 18:01:51 roberto Exp $ +** $Id: loadlib.c,v 1.51 2005/12/29 15:32:11 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -16,8 +16,9 @@ #define loadlib_c #define LUA_LIB -#include "lua.h" #include "lauxlib.h" +#include "lobject.h" +#include "lua.h" #include "lualib.h" @@ -236,11 +237,8 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #define LIB_FAIL "absent" -#if defined(__ELF__) || defined(__sun) || defined(sgi) || defined(__hpux) -#define DLMSG LUA_QL("loadlib") " not enabled; check your Lua installation" -#else -#define DLMSG LUA_QL("loadlib") " not supported" -#endif +#define DLMSG "dynamic libraries not enabled; check your Lua installation" + static void ll_unloadlib (void *lib) { (void)lib; /* to avoid warnings */ @@ -362,20 +360,23 @@ static const char *findfile (lua_State *L, const char *name, path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + lua_pushstring(L, ""); /* error accumulator */ while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename; filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ lua_pop(L, 2); /* remove path template and file name */ + luaO_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_concat(L, 2); } return NULL; /* not found */ } -static void loaderror (lua_State *L) { - luaL_error(L, "error loading module " LUA_QS " (%s)", - lua_tostring(L, 1), lua_tostring(L, -1)); +static void loaderror (lua_State *L, const char *filename) { + luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); } @@ -383,9 +384,9 @@ static int loader_Lua (lua_State *L) { const char *filename; const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path"); - if (filename == NULL) return 0; /* library not found in this path */ + if (filename == NULL) return 1; /* library not found in this path */ if (luaL_loadfile(L, filename) != 0) - loaderror(L); + loaderror(L, filename); return 1; /* library loaded successfully */ } @@ -405,10 +406,10 @@ static int loader_C (lua_State *L) { const char *funcname; const char *name = luaL_checkstring(L, 1); const char *filename = findfile(L, name, "cpath"); - if (filename == NULL) return 0; /* library not found in this path */ + if (filename == NULL) return 1; /* library not found in this path */ funcname = mkfuncname(L, name); if (ll_loadfunc(L, filename, funcname) != 0) - loaderror(L); + loaderror(L, filename); return 1; /* library loaded successfully */ } @@ -422,22 +423,26 @@ static int loader_Croot (lua_State *L) { if (p == NULL) return 0; /* is root */ lua_pushlstring(L, name, p - name); filename = findfile(L, lua_tostring(L, -1), "cpath"); - if (filename == NULL) return 0; /* root not found */ + if (filename == NULL) return 1; /* root not found */ funcname = mkfuncname(L, name); if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { - if (stat == ERRFUNC) return 0; /* function not found */ - else - loaderror(L); /* real error */ + if (stat != ERRFUNC) loaderror(L, filename); /* real error */ + luaO_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, + name, filename); + return 1; /* function not found */ } return 1; } static int loader_preload (lua_State *L) { + const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_ENVIRONINDEX, "preload"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.preload") " must be a table"); - lua_getfield(L, -1, luaL_checkstring(L, 1)); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) /* not found? */ + luaO_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } @@ -461,14 +466,20 @@ static int ll_require (lua_State *L) { lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.loaders") " must be a table"); + lua_pushstring(L, ""); /* error message accumulator */ for (i=1; ; i++) { - lua_rawgeti(L, -1, i); /* get a loader */ + lua_rawgeti(L, -2, i); /* get a loader */ if (lua_isnil(L, -1)) - luaL_error(L, "module " LUA_QS " not found", name); + luaL_error(L, "module " LUA_QS " not found:%s", + name, lua_tostring(L, -2)); lua_pushstring(L, name); lua_call(L, 1, 1); /* call it */ - if (lua_isnil(L, -1)) lua_pop(L, 1); /* did not found module */ - else break; /* module loaded successfully */ + if (lua_isfunction(L, -1)) /* did it find module? */ + break; /* module loaded successfully */ + else if (lua_isstring(L, -1)) /* loader returned error message? */ + lua_concat(L, 2); /* accumulate it */ + else + lua_pop(L, 1); } lua_pushlightuserdata(L, sentinel); lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ @@ -539,7 +550,7 @@ static int ll_module (lua_State *L) { if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ - if (luaL_findtable(L, LUA_GLOBALSINDEX, modname) != NULL) + if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) return luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ @@ -562,7 +573,7 @@ static int ll_module (lua_State *L) { static int ll_seeall (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); if (!lua_getmetatable(L, 1)) { - lua_newtable(L); /* create new metatable */ + lua_createtable(L, 0, 1); /* create new metatable */ lua_pushvalue(L, -1); lua_setmetatable(L, 1); } @@ -629,7 +640,7 @@ LUALIB_API int luaopen_package (lua_State *L) { lua_pushvalue(L, -1); lua_replace(L, LUA_ENVIRONINDEX); /* create `loaders' table */ - lua_newtable(L); + lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { lua_pushcfunction(L, loaders[i]); @@ -643,7 +654,7 @@ LUALIB_API int luaopen_package (lua_State *L) { LUA_EXECDIR "\n" LUA_IGMARK); lua_setfield(L, -2, "config"); /* set field `loaded' */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); lua_setfield(L, -2, "loaded"); /* set field `preload' */ lua_newtable(L); diff --git a/src/lobject.c b/src/lobject.c index 3974c68311..e83b5240c9 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.19 2005/10/24 17:37:52 roberto Exp $ +** $Id: lobject.c,v 2.21 2006/01/10 12:50:00 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ -const TValue luaO_nilobject = {{NULL}, LUA_TNIL}; +const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; /* @@ -39,7 +39,7 @@ int luaO_int2fb (unsigned int x) { e++; } if (x < 8) return x; - else return ((e+1) << 3) | (cast(int, x) - 8); + else return ((e+1) << 3) | (cast_int(x) - 8); } @@ -129,12 +129,12 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { break; } case 'd': { - setnvalue(L->top, cast(lua_Number, va_arg(argp, int))); + setnvalue(L->top, cast_num(va_arg(argp, int))); incr_top(L); break; } case 'f': { - setnvalue(L->top, cast(lua_Number, va_arg(argp, l_uacNumber))); + setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); incr_top(L); break; } @@ -161,7 +161,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { fmt = e+2; } pushstr(L, fmt); - luaV_concat(L, n+1, cast(int, L->top - L->base) - 1); + luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); L->top -= n; return svalue(L->top - 1); } diff --git a/src/lobject.h b/src/lobject.h index 1416e360ee..928bedc761 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.18 2005/10/24 17:37:33 roberto Exp $ +** $Id: lobject.h,v 2.19 2006/01/10 12:51:53 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -323,9 +323,12 @@ typedef union Closure { ** Tables */ -typedef struct TKey { - TValuefields; - struct Node *next; /* for chaining */ +typedef union TKey { + struct { + TValuefields; + struct Node *next; /* for chaining */ + } nk; + TValue tvk; } TKey; @@ -360,8 +363,9 @@ typedef struct Table { #define sizenode(t) (twoto((t)->lsizenode)) +#define luaO_nilobject (&luaO_nilobject_) -LUAI_DATA const TValue luaO_nilobject; +LUAI_DATA const TValue luaO_nilobject_; #define ceillog2(x) (luaO_log2((x)-1) + 1) diff --git a/src/lopcodes.h b/src/lopcodes.h index 88e7e65ccc..2834b1d74d 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.123 2005/10/23 17:37:55 roberto Exp $ +** $Id: lopcodes.h,v 1.124 2005/12/02 18:42:08 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -208,7 +208,7 @@ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ } OpCode; -#define NUM_OPCODES (cast(int, OP_VARARG+1)) +#define NUM_OPCODES (cast(int, OP_VARARG) + 1) diff --git a/src/loslib.c b/src/loslib.c index 01458b90ef..235377e4f5 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.14 2005/10/21 13:47:42 roberto Exp $ +** $Id: loslib.c,v 1.16 2005/12/22 16:19:56 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -37,26 +37,26 @@ static int os_pushresult (lua_State *L, int i, const char *filename) { } -static int io_execute (lua_State *L) { +static int os_execute (lua_State *L) { lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); return 1; } -static int io_remove (lua_State *L) { +static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return os_pushresult(L, remove(filename) == 0, filename); } -static int io_rename (lua_State *L) { +static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return os_pushresult(L, rename(fromname, toname) == 0, fromname); } -static int io_tmpname (lua_State *L) { +static int os_tmpname (lua_State *L) { char buff[LUA_TMPNAMBUFSIZE]; int err; lua_tmpnam(buff, err); @@ -67,13 +67,13 @@ static int io_tmpname (lua_State *L) { } -static int io_getenv (lua_State *L) { +static int os_getenv (lua_State *L) { lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ return 1; } -static int io_clock (lua_State *L) { +static int os_clock (lua_State *L) { lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); return 1; } @@ -123,7 +123,7 @@ static int getfield (lua_State *L, const char *key, int d) { } -static int io_date (lua_State *L) { +static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = lua_isnoneornil(L, 2) ? time(NULL) : (time_t)luaL_checknumber(L, 2); @@ -159,7 +159,7 @@ static int io_date (lua_State *L) { } -static int io_time (lua_State *L) { +static int os_time (lua_State *L) { time_t t; if (lua_isnoneornil(L, 1)) /* called without args? */ t = time(NULL); /* get current time */ @@ -179,12 +179,12 @@ static int io_time (lua_State *L) { if (t == (time_t)(-1)) lua_pushnil(L); else - lua_pushnumber(L, t); + lua_pushnumber(L, (lua_Number)t); return 1; } -static int io_difftime (lua_State *L) { +static int os_difftime (lua_State *L) { lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), (time_t)(luaL_optnumber(L, 2, 0)))); return 1; @@ -193,7 +193,7 @@ static int io_difftime (lua_State *L) { /* }====================================================== */ -static int io_setloc (lua_State *L) { +static int os_setlocale (lua_State *L) { static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; static const char *const catnames[] = {"all", "collate", "ctype", "monetary", @@ -206,23 +206,23 @@ static int io_setloc (lua_State *L) { } -static int io_exit (lua_State *L) { +static int os_exit (lua_State *L) { exit(luaL_optint(L, 1, EXIT_SUCCESS)); return 0; /* to avoid warnings */ } static const luaL_Reg syslib[] = { - {"clock", io_clock}, - {"date", io_date}, - {"difftime", io_difftime}, - {"execute", io_execute}, - {"exit", io_exit}, - {"getenv", io_getenv}, - {"remove", io_remove}, - {"rename", io_rename}, - {"setlocale", io_setloc}, - {"time", io_time}, - {"tmpname", io_tmpname}, + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"execute", os_execute}, + {"exit", os_exit}, + {"getenv", os_getenv}, + {"remove", os_remove}, + {"rename", os_rename}, + {"setlocale", os_setlocale}, + {"time", os_time}, + {"tmpname", os_tmpname}, {NULL, NULL} }; diff --git a/src/lparser.c b/src/lparser.c index dd4715d0f2..b40ee794fe 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.38 2005/10/24 17:38:47 roberto Exp $ +** $Id: lparser.c,v 2.40 2005/12/22 16:19:56 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -54,24 +54,6 @@ static void chunk (LexState *ls); static void expr (LexState *ls, expdesc *v); - -static void next (LexState *ls) { - ls->lastline = ls->linenumber; - if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ - ls->t = ls->lookahead; /* use this one */ - ls->lookahead.token = TK_EOS; /* and discharge it */ - } - else - ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */ -} - - -static void lookahead (LexState *ls) { - lua_assert(ls->lookahead.token == TK_EOS); - ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo); -} - - static void anchor_token (LexState *ls) { if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { TString *ts = ls->t.seminfo.ts; @@ -97,7 +79,7 @@ static void errorlimit (FuncState *fs, int limit, const char *what) { static int testnext (LexState *ls, int c) { if (ls->t.token == c) { - next(ls); + luaX_next(ls); return 1; } else return 0; @@ -111,7 +93,7 @@ static void check (LexState *ls, int c) { static void checknext (LexState *ls, int c) { check(ls, c); - next(ls); + luaX_next(ls); } @@ -136,7 +118,7 @@ static TString *str_checkname (LexState *ls) { TString *ts; check(ls, TK_NAME); ts = ls->t.seminfo.ts; - next(ls); + luaX_next(ls); return ts; } @@ -184,7 +166,7 @@ static void new_localvar (LexState *ls, TString *name, int n) { static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - fs->nactvar = cast(lu_byte, fs->nactvar + nvars); + fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; } @@ -216,8 +198,8 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { f->upvalues[f->nups] = name; luaC_objbarrier(fs->L, f, name); lua_assert(v->k == VLOCAL || v->k == VUPVAL); - fs->upvalues[f->nups].k = cast(lu_byte, v->k); - fs->upvalues[f->nups].info = cast(lu_byte, v->u.s.info); + fs->upvalues[f->nups].k = cast_byte(v->k); + fs->upvalues[f->nups].info = cast_byte(v->u.s.info); return f->nups++; } @@ -404,7 +386,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ - next(&lexstate); /* read first token */ + luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); @@ -426,7 +408,7 @@ static void field (LexState *ls, expdesc *v) { FuncState *fs = ls->fs; expdesc key; luaK_exp2anyreg(fs, v); - next(ls); /* skip the dot or colon */ + luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); } @@ -434,7 +416,7 @@ static void field (LexState *ls, expdesc *v) { static void yindex (LexState *ls, expdesc *v) { /* index -> '[' expr ']' */ - next(ls); /* skip the '[' */ + luaX_next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); checknext(ls, ']'); @@ -530,7 +512,7 @@ static void constructor (LexState *ls, expdesc *t) { closelistfield(fs, &cc); switch(ls->t.token) { case TK_NAME: { /* may be listfields or recfields */ - lookahead(ls); + luaX_lookahead(ls); if (ls->lookahead.token != '=') /* expression? */ listfield(ls, &cc); else @@ -571,7 +553,7 @@ static void parlist (LexState *ls) { break; } case TK_DOTS: { /* param -> `...' */ - next(ls); + luaX_next(ls); #if defined(LUA_COMPAT_VARARG) /* use `arg' as default name */ new_localvarliteral(ls, "arg", nparams++); @@ -585,7 +567,7 @@ static void parlist (LexState *ls) { } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); - f->numparams = fs->nactvar - (f->is_vararg & VARARG_HASARG); + f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -632,7 +614,7 @@ static void funcargs (LexState *ls, expdesc *f) { case '(': { /* funcargs -> `(' [ explist1 ] `)' */ if (line != ls->lastline) luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); - next(ls); + luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { @@ -648,7 +630,7 @@ static void funcargs (LexState *ls, expdesc *f) { } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); - next(ls); /* must use `seminfo' before `next' */ + luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { @@ -686,7 +668,7 @@ static void prefixexp (LexState *ls, expdesc *v) { switch (ls->t.token) { case '(': { int line = ls->linenumber; - next(ls); + luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); @@ -724,7 +706,7 @@ static void primaryexp (LexState *ls, expdesc *v) { } case ':': { /* `:' NAME funcargs */ expdesc key; - next(ls); + luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); @@ -779,7 +761,7 @@ static void simpleexp (LexState *ls, expdesc *v) { return; } case TK_FUNCTION: { - next(ls); + luaX_next(ls); body(ls, v, 0, ls->linenumber); return; } @@ -788,7 +770,7 @@ static void simpleexp (LexState *ls, expdesc *v) { return; } } - next(ls); + luaX_next(ls); } @@ -848,7 +830,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { - next(ls); + luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v); } @@ -858,7 +840,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; - next(ls); + luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); @@ -1009,7 +991,7 @@ static void whilestat (LexState *ls, int line) { int whileinit; int condexit; BlockCnt bl; - next(ls); /* skip WHILE */ + luaX_next(ls); /* skip WHILE */ whileinit = luaK_getlabel(fs); condexit = cond(ls); enterblock(fs, &bl, 1); @@ -1030,7 +1012,7 @@ static void repeatstat (LexState *ls, int line) { BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ - next(ls); /* skip REPEAT */ + luaX_next(ls); /* skip REPEAT */ chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ @@ -1130,7 +1112,7 @@ static void forstat (LexState *ls, int line) { TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ - next(ls); /* skip `for' */ + luaX_next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; @@ -1145,7 +1127,7 @@ static void forstat (LexState *ls, int line) { static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ int condexit; - next(ls); /* skip IF or ELSEIF */ + luaX_next(ls); /* skip IF or ELSEIF */ condexit = cond(ls); checknext(ls, TK_THEN); block(ls); /* `then' part */ @@ -1167,7 +1149,7 @@ static void ifstat (LexState *ls, int line) { if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); - next(ls); /* skip ELSE (after patch, for correct line info) */ + luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else @@ -1228,7 +1210,7 @@ static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int needself; expdesc v, b; - next(ls); /* skip FUNCTION */ + luaX_next(ls); /* skip FUNCTION */ needself = funcname(ls, &v); body(ls, &b, needself, line); luaK_storevar(ls->fs, &v, &b); @@ -1255,7 +1237,7 @@ static void retstat (LexState *ls) { FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ - next(ls); /* skip RETURN */ + luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { @@ -1295,7 +1277,7 @@ static int statement (LexState *ls) { return 0; } case TK_DO: { /* stat -> DO block END */ - next(ls); /* skip DO */ + luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); return 0; @@ -1313,7 +1295,7 @@ static int statement (LexState *ls) { return 0; } case TK_LOCAL: { /* stat -> localstat */ - next(ls); /* skip LOCAL */ + luaX_next(ls); /* skip LOCAL */ if (testnext(ls, TK_FUNCTION)) /* local function? */ localfunc(ls); else @@ -1325,7 +1307,7 @@ static int statement (LexState *ls) { return 1; /* must be last statement */ } case TK_BREAK: { /* stat -> breakstat */ - next(ls); /* skip BREAK */ + luaX_next(ls); /* skip BREAK */ breakstat(ls); return 1; /* must be last statement */ } diff --git a/src/lstring.c b/src/lstring.c index 897089a4b3..4319930c96 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.7 2005/02/18 12:40:02 roberto Exp $ +** $Id: lstring.c,v 2.8 2005/12/22 16:19:56 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -35,7 +35,7 @@ void luaS_resize (lua_State *L, int newsize) { GCObject *next = p->gch.next; /* save next */ unsigned int h = gco2ts(p)->hash; int h1 = lmod(h, newsize); /* new position */ - lua_assert(cast(int, h%newsize) == lmod(h, newsize)); + lua_assert(cast_int(h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ newhash[h1] = p; p = next; diff --git a/src/lstrlib.c b/src/lstrlib.c index 25258bfe03..84478fd106 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.127 2005/10/26 13:28:19 roberto Exp $ +** $Id: lstrlib.c,v 1.130 2005/12/29 15:32:11 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -683,8 +683,13 @@ static int str_gsub (lua_State *L) { /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 -/* maximum size of each format specification (such as '%-099.99d') */ -#define MAX_FORMAT 20 +/* valid flags in a format specification */ +#define FLAGS "-+ #0" +/* +** maximum size of each format specification (such as '%-099.99d') +** (+10 accounts for %99.99x plus margin of error) +*/ +#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { @@ -712,30 +717,37 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { luaL_addchar(b, '"'); } - -static const char *scanformat (lua_State *L, const char *strfrmt, - char *form, int *hasprecision) { +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; - while (strchr("-+ #0", *p)) p++; /* skip flags */ + while (strchr(FLAGS, *p)) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) + luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; - *hasprecision = 1; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); - if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */ - luaL_error(L, "invalid format (too long)"); - form[0] = L_ESC; - strncpy(form+1, strfrmt, p-strfrmt+1); - form[p-strfrmt+2] = 0; + *(form++) = '%'; + strncpy(form, strfrmt, p - strfrmt + 1); + form += p - strfrmt + 1; + *form = '\0'; return p; } +static void addintlen (char *form) { + size_t l = strlen(form); + char spec = form[l - 1]; + strcpy(form + l - 1, LUA_INTFRMLEN); + form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; + form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; +} + + static int str_format (lua_State *L) { int arg = 1; size_t sfl; @@ -751,21 +763,26 @@ static int str_format (lua_State *L) { else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ - int hasprecision = 0; arg++; - strfrmt = scanformat(L, strfrmt, form, &hasprecision); + strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { - case 'c': case 'd': case 'i': { - sprintf(buff, form, luaL_checkint(L, arg)); + case 'c': { + sprintf(buff, form, (int)luaL_checknumber(L, arg)); + break; + } + case 'd': case 'i': { + addintlen(form); + sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'o': case 'u': case 'x': case 'X': { - sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg))); + addintlen(form); + sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { - sprintf(buff, form, luaL_checknumber(L, arg)); + sprintf(buff, form, (double)luaL_checknumber(L, arg)); break; } case 'q': { @@ -775,7 +792,7 @@ static int str_format (lua_State *L) { case 's': { size_t l; const char *s = luaL_checklstring(L, arg, &l); - if (!hasprecision && l >= 100) { + if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ lua_pushvalue(L, arg); @@ -820,7 +837,7 @@ static const luaL_Reg strlib[] = { static void createmetatable (lua_State *L) { - lua_newtable(L); /* create metatable for strings */ + lua_createtable(L, 0, 1); /* create metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ lua_pushvalue(L, -2); lua_setmetatable(L, -2); /* set string metatable */ diff --git a/src/ltable.c b/src/ltable.c index 5d4a828a4f..029cd506c7 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.27 2005/10/24 17:37:52 roberto Exp $ +** $Id: ltable.c,v 2.31 2006/01/10 13:13:06 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -66,13 +66,15 @@ /* ** number of ints inside a lua_Number */ -#define numints cast(int, sizeof(lua_Number)/sizeof(int)) +#define numints cast_int(sizeof(lua_Number)/sizeof(int)) -const Node luaH_dummynode = { +#define dummynode (&dummynode_) + +static const Node dummynode_ = { {{NULL}, LUA_TNIL}, /* value */ - {{NULL}, LUA_TNIL, NULL} /* key */ + {{{NULL}, LUA_TNIL, NULL}} /* key */ }; @@ -95,7 +97,7 @@ static Node *hashnum (const Table *t, lua_Number n) { ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ -Node *luaH_mainposition (const Table *t, const TValue *key) { +static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); @@ -120,7 +122,7 @@ static int arrayindex (const TValue *key) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); - if (luai_numeq(cast(lua_Number, k), nvalue(key))) + if (luai_numeq(cast_num(k), nvalue(key))) return k; } return -1; /* `key' did not match some condition */ @@ -139,13 +141,13 @@ static int findindex (lua_State *L, Table *t, StkId key) { if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ else { - Node *n = luaH_mainposition(t, key); + Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in `next' */ if (luaO_rawequalObj(key2tval(n), key) || (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && gcvalue(gkey(n)) == gcvalue(key))) { - i = cast(int, n - gnode(t, 0)); /* key index in hash table */ + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ return i + t->sizearray; } @@ -161,7 +163,7 @@ int luaH_next (lua_State *L, Table *t, StkId key) { int i = findindex(L, t, key); /* find original element */ for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setnvalue(key, cast(lua_Number, i+1)); + setnvalue(key, cast_num(i+1)); setobj2s(L, key+1, &t->array[i]); return 1; } @@ -270,7 +272,7 @@ static void setarrayvector (lua_State *L, Table *t, int size) { static void setnodevector (lua_State *L, Table *t, int size) { int lsize; if (size == 0) { /* no elements to hash part? */ - t->node = cast(Node *, &luaH_dummynode); /* use common `dummynode' */ + t->node = cast(Node *, dummynode); /* use common `dummynode' */ lsize = 0; } else { @@ -281,12 +283,13 @@ static void setnodevector (lua_State *L, Table *t, int size) { size = twoto(lsize); t->node = luaM_newvector(L, size, Node); for (i=0; inode[i]) = NULL; - setnilvalue(gkey(gnode(t, i))); - setnilvalue(gval(gnode(t, i))); + Node *n = gnode(t, i); + gnext(n) = NULL; + setnilvalue(gkey(n)); + setnilvalue(gval(n)); } } - t->lsizenode = cast(lu_byte, lsize); + t->lsizenode = cast_byte(lsize); t->lastfree = gnode(t, size); /* all positions are free */ } @@ -316,13 +319,13 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { if (!ttisnil(gval(old))) setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } - if (nold != &luaH_dummynode) + if (nold != dummynode) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ } void luaH_resizearray (lua_State *L, Table *t, int nasize) { - int nsize = (t->node == &luaH_dummynode) ? 0 : sizenode(t); + int nsize = (t->node == dummynode) ? 0 : sizenode(t); resize(L, t, nasize, nsize); } @@ -356,12 +359,12 @@ Table *luaH_new (lua_State *L, int narray, int nhash) { Table *t = luaM_new(L, Table); luaC_link(L, obj2gco(t), LUA_TTABLE); t->metatable = NULL; - t->flags = cast(lu_byte, ~0); + t->flags = cast_byte(~0); /* temporary values (kept only if some malloc fails) */ t->array = NULL; t->sizearray = 0; t->lsizenode = 0; - t->node = cast(Node *, &luaH_dummynode); + t->node = cast(Node *, dummynode); setarrayvector(L, t, narray); setnodevector(L, t, nhash); return t; @@ -369,7 +372,7 @@ Table *luaH_new (lua_State *L, int narray, int nhash) { void luaH_free (lua_State *L, Table *t) { - if (t->node != &luaH_dummynode) + if (t->node != dummynode) luaM_freearray(L, t->node, sizenode(t), Node); luaM_freearray(L, t->array, t->sizearray, TValue); luaM_free(L, t); @@ -394,16 +397,16 @@ static Node *getfreepos (Table *t) { ** position), new key goes to an empty position. */ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { - Node *mp = luaH_mainposition(t, key); - if (!ttisnil(gval(mp)) || mp == &luaH_dummynode) { + Node *mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || mp == dummynode) { Node *othern; Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ return luaH_set(L, t, key); /* re-insert key into grown table */ } - lua_assert(n != &luaH_dummynode); - othern = luaH_mainposition(t, key2tval(mp)); + lua_assert(n != dummynode); + othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ @@ -434,14 +437,14 @@ const TValue *luaH_getnum (Table *t, int key) { if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; else { - lua_Number nk = cast(lua_Number, key); + lua_Number nk = cast_num(key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); - return &luaO_nilobject; + return luaO_nilobject; } } @@ -456,7 +459,7 @@ const TValue *luaH_getstr (Table *t, TString *key) { return gval(n); /* that's it */ else n = gnext(n); } while (n); - return &luaO_nilobject; + return luaO_nilobject; } @@ -465,24 +468,24 @@ const TValue *luaH_getstr (Table *t, TString *key) { */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TNIL: return &luaO_nilobject; + case LUA_TNIL: return luaO_nilobject; case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; lua_Number n = nvalue(key); lua_number2int(k, n); - if (luai_numeq(cast(lua_Number, k), nvalue(key))) /* index is int? */ + if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } default: { - Node *n = luaH_mainposition(t, key); + Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ if (luaO_rawequalObj(key2tval(n), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); - return &luaO_nilobject; + return luaO_nilobject; } } } @@ -491,11 +494,11 @@ const TValue *luaH_get (Table *t, const TValue *key) { TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { const TValue *p = luaH_get(t, key); t->flags = 0; - if (p != &luaO_nilobject) + if (p != luaO_nilobject) return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && !luai_numeq(nvalue(key), nvalue(key))) + else if (ttisnumber(key) && luai_numisnan(nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } @@ -504,11 +507,11 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { TValue *luaH_setnum (lua_State *L, Table *t, int key) { const TValue *p = luaH_getnum(t, key); - if (p != &luaO_nilobject) + if (p != luaO_nilobject) return cast(TValue *, p); else { TValue k; - setnvalue(&k, cast(lua_Number, key)); + setnvalue(&k, cast_num(key)); return newkey(L, t, &k); } } @@ -516,7 +519,7 @@ TValue *luaH_setnum (lua_State *L, Table *t, int key) { TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { const TValue *p = luaH_getstr(t, key); - if (p != &luaO_nilobject) + if (p != luaO_nilobject) return cast(TValue *, p); else { TValue k; @@ -528,11 +531,11 @@ TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ - j = j+1; + j++; /* find `i' and `j' such that i is present and j is not */ while (!ttisnil(luaH_getnum(t, j))) { i = j; - j = i*2; + j *= 2; if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; @@ -541,7 +544,7 @@ static int unbound_search (Table *t, unsigned int j) { } } /* now do a binary search between them */ - while (i < j-1) { + while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(luaH_getnum(t, m))) j = m; else i = m; @@ -567,8 +570,19 @@ int luaH_getn (Table *t) { return i; } /* else must find a boundary in hash part */ - else if (t->node == &luaH_dummynode) /* hash part is empty? */ + else if (t->node == dummynode) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t, j); } + + +#if defined(LUA_DEBUG) + +Node *luaH_mainposition (const Table *t, const TValue *key) { + return mainposition(t, key); +} + +int luaH_isdummy (Node *n) { return n == dummynode; } + +#endif diff --git a/src/ltable.h b/src/ltable.h index 14a20448a6..09193cdbe0 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.8 2005/06/06 13:30:25 roberto Exp $ +** $Id: ltable.h,v 2.10 2006/01/10 13:13:06 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -11,15 +11,13 @@ #define gnode(t,i) (&(t)->node[i]) -#define gkey(n) (&(n)->i_key) +#define gkey(n) (&(n)->i_key.nk) #define gval(n) (&(n)->i_val) -#define gnext(n) ((n)->i_key.next) +#define gnext(n) ((n)->i_key.nk.next) -#define key2tval(n) (cast(const TValue *, gkey(n))) +#define key2tval(n) (&(n)->i_key.tvk) -LUAI_DATA const Node luaH_dummynode; - LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); @@ -32,8 +30,11 @@ LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC int luaH_getn (Table *t); -/* exported only for debugging */ + +#if defined(LUA_DEBUG) LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); +LUAI_FUNC int luaH_isdummy (Node *n); +#endif #endif diff --git a/src/ltm.c b/src/ltm.c index 591134da54..097b815ad3 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.6 2005/05/20 15:53:42 roberto Exp $ +** $Id: ltm.c,v 2.8 2006/01/10 12:50:00 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -51,7 +51,7 @@ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ - events->flags |= cast(lu_byte, 1u<flags |= cast_byte(1u<mt[ttype(o)]; } - return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : &luaO_nilobject); + return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } diff --git a/src/lua.c b/src/lua.c index bfae4449eb..6df527db30 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.154 2005/10/24 17:38:47 roberto Exp $ +** $Id: lua.c,v 1.157 2005/12/29 16:23:32 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -120,7 +120,7 @@ static int getargs (lua_State *L, char **argv, int n) { luaL_checkstack(L, narg + 3, "too many arguments to script"); for (i=n+1; i < argc; i++) lua_pushstring(L, argv[i]); - lua_newtable(L); + lua_createtable(L, narg, n + 1); for (i=0; i < argc; i++) { lua_pushstring(L, argv[i]); lua_rawseti(L, -2, i - n); @@ -215,7 +215,6 @@ static void dotty (lua_State *L) { int status; const char *oldprogname = progname; progname = NULL; - print_version(); while ((status = loadline(L)) != -1) { if (status == 0) status = docall(L, 0, 0); report(L, status); @@ -261,7 +260,7 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { switch (argv[i][1]) { /* option */ case '-': return (argv[i+1] != NULL ? i+1 : 0); case '\0': return i; - case 'i': *pi = 1; break; + case 'i': *pi = 1; /* go through */ case 'v': *pv = 1; break; case 'e': *pe = 1; /* go through */ case 'l': @@ -330,7 +329,9 @@ static int pmain (lua_State *L) { int has_i = 0, has_v = 0, has_e = 0; globalL = L; if (argv[0] && argv[0][0]) progname = argv[0]; + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ luaL_openlibs(L); /* open libraries */ + lua_gc(L, LUA_GCRESTART, 0); s->status = handle_luainit(L); if (s->status != 0) return 0; script = collectargs(argv, &has_i, &has_v, &has_e); @@ -348,7 +349,10 @@ static int pmain (lua_State *L) { if (has_i) dotty(L); else if (script == 0 && !has_e && !has_v) { - if (lua_stdin_is_tty()) dotty(L); + if (lua_stdin_is_tty()) { + print_version(); + dotty(L); + } else dofile(L, NULL); /* executes stdin as a file */ } return 0; diff --git a/src/lua.h b/src/lua.h index d612eec72c..881f834555 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.214 2005/10/20 11:35:50 roberto Exp $ +** $Id: lua.h,v 1.216 2006/01/10 12:50:13 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -16,9 +16,9 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1 (beta)" +#define LUA_VERSION "Lua 5.1" #define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2005 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT "Copyright (C) 1994-2006 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -358,7 +358,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2005 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2006 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/luaconf.h b/src/luaconf.h index ea685a2ddc..374929554f 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.74 2005/11/16 16:24:28 roberto Exp $ +** $Id: luaconf.h,v 1.77 2005/12/27 17:12:00 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -28,6 +28,11 @@ #define LUA_ANSI #endif + +#if !defined(LUA_ANSI) && defined(_WIN32) +#define LUA_WIN +#endif + #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ @@ -177,13 +182,6 @@ -/* -@@ lua_assert describes the internal assertions in Lua. -** CHANGE that only if you need to debug Lua. -*/ -#define lua_assert(c) ((void)0) - - /* @@ LUA_QL describes how error messages quote program elements. ** CHANGE it if you want a different appearance. @@ -217,7 +215,7 @@ #if defined(LUA_USE_ISATTY) #include #define lua_stdin_is_tty() isatty(0) -#elif !defined(LUA_ANSI) && defined(_WIN32) +#elif defined(LUA_WIN) #include #include #define lua_stdin_is_tty() _isatty(_fileno(stdin)) @@ -368,8 +366,7 @@ #include #define luai_apicheck(L,o) { (void)L; assert(o); } #else -/* (By default lua_assert is empty, so luai_apicheck is also empty.) */ -#define luai_apicheck(L,o) { (void)L; lua_assert(o); } +#define luai_apicheck(L,o) { (void)L; } #endif @@ -529,6 +526,7 @@ #define luai_numeq(a,b) ((a)==(b)) #define luai_numlt(a,b) ((a)<(b)) #define luai_numle(a,b) ((a)<=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) #endif @@ -644,7 +642,7 @@ union luai_Cast { double l_d; long l_l; }; #define lua_popen(L,c,m) ((void)L, popen(c,m)) #define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) -#elif !defined(LUA_ANSI) && defined(_WIN32) +#elif defined(LUA_WIN) #define lua_popen(L,c,m) ((void)L, _popen(c,m)) #define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) @@ -675,7 +673,7 @@ union luai_Cast { double l_d; long l_l; }; #define LUA_DL_DLOPEN #endif -#if !defined(LUA_ANSI) && defined(_WIN32) +#if defined(LUA_WIN) #define LUA_DL_DLL #endif @@ -702,6 +700,26 @@ union luai_Cast { double l_d; long l_l; }; #define luai_userstateyield(L,n) ((void)L) +/* +@@ LUA_INTFRMLEN is the length modifier for integer conversions +@* in 'string.fomat'. +@@ LUA_INTFRM_T is the integer type correspoding to the previous length +@* modifier. +** CHANGE them if your system supports long long or does not support long. +*/ + +#if defined(LUA_USELONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long + +#endif + /* =================================================================== */ diff --git a/src/lualib.h b/src/lualib.h index f52bb888bd..0c76232c0d 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.35 2005/08/10 18:06:58 roberto Exp $ +** $Id: lualib.h,v 1.36 2005/12/27 17:12:00 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -44,4 +44,10 @@ LUALIB_API int (luaopen_package) (lua_State *L); LUALIB_API void (luaL_openlibs) (lua_State *L); + +#ifndef lua_assert +#define lua_assert(x) ((void)0) +#endif + + #endif diff --git a/src/lvm.c b/src/lvm.c index c94644f9f5..ef41fddd2b 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.59 2005/11/01 16:08:45 roberto Exp $ +** $Id: lvm.c,v 2.61 2006/01/10 12:50:00 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -509,16 +509,16 @@ void luaV_execute (lua_State *L, int nexeccalls) { const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { - setnvalue(ra, cast(lua_Number, luaH_getn(hvalue(rb)))); + setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); break; } case LUA_TSTRING: { - setnvalue(ra, cast(lua_Number, tsvalue(rb)->len)); + setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } default: { /* try metamethod */ Protect( - if (!call_binTM(L, rb, &luaO_nilobject, ra, TM_LEN)) + if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) luaG_typeerror(L, rb, "get length of"); ) } @@ -693,10 +693,10 @@ void luaV_execute (lua_State *L, int nexeccalls) { int last; Table *h; if (n == 0) { - n = cast(int, L->top - ra) - 1; + n = cast_int(L->top - ra) - 1; L->top = L->ci->top; } - if (c == 0) c = cast(int, *pc++); + if (c == 0) c = cast_int(*pc++); runtime_check(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; @@ -737,7 +737,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { int b = GETARG_B(i) - 1; int j; CallInfo *ci = L->ci; - int n = cast(int, ci->base - ci->func) - cl->p->numparams - 1; + int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; if (b == LUA_MULTRET) { Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ diff --git a/src/print.c b/src/print.c index cfecba9648..1c3a4457c4 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.53 2005/11/11 14:03:13 lhf Exp $ +** $Id: print.c,v 1.54 2006/01/11 22:49:27 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -36,7 +36,10 @@ static void PrintString(const Proto* f, int n) case '\r': printf("\\r"); break; case '\t': printf("\\t"); break; case '\v': printf("\\v"); break; - default: printf(isprint((unsigned char)*s) ? "%c" : "\\%03d",*s); + default: if (isprint((unsigned char)*s)) + printf("%c",*s); + else + printf("\\%03u",(unsigned char)*s); } } putchar('"'); From b487a3dce43e449acf3852ec56345e2860cfeab7 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 24 Jan 2006 12:00:00 +0000 Subject: [PATCH 27/97] Lua 5.1-rc2 --- HISTORY | 3 ++- INSTALL | 4 ++-- MANIFEST | 2 +- Makefile | 13 +++++++++---- README | 4 +++- doc/manual.html | 34 ++++++++++++++++++++++------------ etc/lua.pc | 7 +++++-- src/Makefile | 14 ++++++++++---- src/lauxlib.c | 28 +++++++++++++++++++--------- src/lbaselib.c | 4 ++-- src/liolib.c | 9 +++++---- src/llex.c | 10 ++++------ src/lobject.h | 5 +---- src/ltable.c | 4 ++-- src/luaconf.h | 5 +++-- src/lvm.c | 8 +++++--- 16 files changed, 95 insertions(+), 59 deletions(-) diff --git a/HISTORY b/HISTORY index fc603c9628..122f656370 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,4 @@ -This is Lua 5.1. +HISTORY for Lua 5.1 * Changes from version 5.0 to 5.1 ------------------------------- @@ -14,6 +14,7 @@ This is Lua 5.1. API: + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + user supplies memory allocator (lua_open becomes lua_newstate). + + luaopen_* functionst be called through Lua. Implementation: + new configuration scheme via luaconf.h. + incremental garbage collection. diff --git a/INSTALL b/INSTALL index bd3b540c8d..293b44ea61 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -This is Lua 5.1. +INSTALL for Lua 5.1 * Building Lua ------------ @@ -8,7 +8,7 @@ This is Lua 5.1. Building Lua on Unix systems should be very easy. First do "make" and see if your platform is listed. If so, just do "make xxx", where xxx is your platform name. The platforms currently supported are: - ansi bsd generic linux macosx mingw posix + ansi bsd generic linux macosx mingw posix solaris See below for customization instructions and for instructions on how to build with other Windows compilers. diff --git a/MANIFEST b/MANIFEST index 964df73c4a..a554dc122c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,4 +1,4 @@ -MANIFEST contents of Lua 5.1 distribution on Wed Jan 11 22:50:45 BRST 2006 +MANIFEST contents of Lua 5.1 distribution on Tue Jan 24 16:12:03 BRST 2006 lua-5.1 lua-5.1/COPYRIGHT lua-5.1/doc diff --git a/Makefile b/Makefile index 9e627259f5..db9bb3d9a4 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,8 @@ INSTALL_BIN= $(INSTALL_TOP)/bin INSTALL_INC= $(INSTALL_TOP)/include INSTALL_LIB= $(INSTALL_TOP)/lib INSTALL_MAN= $(INSTALL_TOP)/man/man1 +INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V +INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V # How to install. You may prefer "install" instead of "cp" if you have it. # To remove debug information from binaries, use "install -s" in INSTALL_EXEC. @@ -28,7 +30,7 @@ INSTALL_DATA= cp # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= # Convenience platforms targets. -PLATS= ansi bsd generic linux macosx mingw posix +PLATS= ansi bsd generic linux macosx mingw posix solaris # What to install. TO_BIN= lua luac @@ -39,7 +41,7 @@ TO_MAN= lua.1 luac.1 # Lua version. Currently used only for messages. V= 5.1 -all: $(PLAT) +all: $(PLAT) $(PLATS) clean: cd src; $(MAKE) $@ @@ -47,8 +49,8 @@ $(PLATS) clean: test: all src/lua test/hello.lua -install: all - cd src; mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) +install: + cd src; mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) cd src; $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) cd src; $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) cd src; $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) @@ -77,6 +79,9 @@ echo: @echo "INSTALL_MAN = $(INSTALL_MAN)" @echo "INSTALL_EXEC = $(INSTALL_EXEC)" @echo "INSTALL_DATA = $(INSTALL_DATA)" + @echo "INSTALL_LMOD = $(INSTALL_LMOD)" + @echo "INSTALL_CMOD = $(INSTALL_CMOD)" + @echo "INSTALL_CMOD = $(INSTALL_CMOD)" @echo "" @echo "See also src/luaconf.h ." @echo "" diff --git a/README b/README index 51dfeedeb9..f082d40460 100644 --- a/README +++ b/README @@ -1,4 +1,6 @@ -This is Lua 5.1. +README for Lua 5.1 + +See INSTALL for installation instructions. See HISTORY for a summary of changes since the last released version. * What is Lua? diff --git a/doc/manual.html b/doc/manual.html index df42a932e8..9a115e740f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1174,7 +1174,7 @@

        Because Lua is an embedded extension language, all Lua actions start from C code in the host program -calling a function from the Lua library (see ). +calling a function from the Lua library (see lua_pcall). Whenever an error occurs during Lua compilation or execution, control returns to C, which can take appropriate measures @@ -1509,11 +1509,11 @@

          function function_event (func, ...)
            if type(func) == "function" then
        -     return func(unpack(arg))   -- primitive call
        +     return func(...)   -- primitive call
            else
              local h = metatable(func).__call
              if h then
        -       return h(func, unpack(arg))
        +       return h(func, ...)
              else
                error("...")
              end
        @@ -1553,7 +1553,7 @@ 

        They are used as the default environment for other Lua functions created by that function. -

        You can change the environment of a Lua function of the +

        You can change the environment of a Lua function or the running thread calling setfenv. You can get the environment of a Lua function or the running thread calling getfenv. @@ -1565,8 +1565,8 @@

        Lua performs automatic memory management. That means that -you do not have to worry about allocating memory for new objects -not about freeing it when the objects are no longer needed. +you do not have to worry neither about allocating memory for new objects +nor about freeing it when the objects are no longer needed. Lua manages memory automatically by running a garbage collector from time to time to collect all dead objects @@ -2821,7 +2821,7 @@

        Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. -The string cannot embedded zeros; +The string cannot contain embedded zeros; it is assumed to end at the first zero.

        @@ -3609,7 +3609,7 @@

        Sets the value of a local variable of a given activation record. Parameters ar and n are as in lua_getlocal -(see ). +(see lua_getlocal). lua_setlocal assigns the value at the top of the stack to the variable and returns its name. It also pops the value from the stack. @@ -3627,7 +3627,7 @@

        Sets the value of a closure's upvalue. Parameters funcindex and n are as in lua_getupvalue -(see ). +(see lua_getupvalue). It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. @@ -3995,9 +3995,9 @@

        -

        Creates a copy of string s by replacing any occurrence +

        Creates a copy of string s by replacing any occurrence of the string p -wth the string r. +with the string r. Pushes the resulting string on the stack and returns it.

        @@ -5302,6 +5302,8 @@

        Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. +(To do its job this function does a linear traversal of +the whole table.)


        table.remove (table [, pos])

        @@ -6076,7 +6078,15 @@

        Changes in the API

          -
        • + +

        • +The luaopen_* functions (to open libraries) +cannot be called directly, +like a regular C function. +They must be called through Lua, +like a Lua function. + +

        • Function lua_open was replaced by lua_newstate to allow the user to set a memory allocation function. You can use luaL_newstate from the standard library to diff --git a/etc/lua.pc b/etc/lua.pc index c476f7e48b..f0d6e2ff7a 100644 --- a/etc/lua.pc +++ b/etc/lua.pc @@ -1,13 +1,16 @@ # lua.pc -- pkg-config data for Lua # vars from install Makefile -# grep ^INSTALL_...= ../Makefile +# grep '^INSTALL_.*=' ../Makefile INSTALL_TOP= /usr/local INSTALL_BIN= $(INSTALL_TOP)/bin INSTALL_INC= $(INSTALL_TOP)/include INSTALL_LIB= $(INSTALL_TOP)/lib INSTALL_MAN= $(INSTALL_TOP)/man/man1 -# grep ^V= ../Makefile +INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V +INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V + +# grep '^V=' ../Makefile V= 5.1 prefix=${INSTALL_TOP} diff --git a/src/Makefile b/src/Makefile index b042d9abf1..13d0d4970d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ # makefile for building Lua -# see INSTALL for installation instructions +# see ../INSTALL for installation instructions # see ../Makefile and luaconf.h for further customization # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= @@ -20,7 +20,7 @@ MYLIBS= # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= -PLATS= ansi bsd generic linux macosx mingw posix +PLATS= ansi bsd generic linux macosx mingw posix solaris LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ @@ -74,7 +74,7 @@ echo: @echo "MYLDFLAGS = $(MYLDFLAGS)" @echo "MYLIBS = $(MYLIBS)" -# convenience targets for usual platforms +# convenience targets for popular platforms none: @echo "Please choose a platform: $(PLATS)" @@ -93,15 +93,21 @@ linux: macosx: $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX +# use this on Mac OS X 10.4 +# $(MAKE) all MYCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" MYLIBS="-lreadline" mingw: $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ - "AR=gcc -shared -o" "RANLIB=strip --strip-unneeded" \ + "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe posix: $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX +solaris: + $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" + + # DO NOT DELETE lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ diff --git a/src/lauxlib.c b/src/lauxlib.c index d3b54ee4b1..317a48d108 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.157 2005/12/29 15:32:11 roberto Exp $ +** $Id: lauxlib.c,v 1.158 2006/01/16 12:42:21 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -295,23 +295,33 @@ static void getsizes (lua_State *L) { LUALIB_API void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); - getsizes(L); - lua_pushvalue(L, t); - lua_pushinteger(L, n); - lua_rawset(L, -3); /* sizes[t] = n */ - lua_pop(L, 1); /* remove `sizes' */ + lua_pushliteral(L, "n"); + lua_rawget(L, t); + if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ + lua_pushliteral(L, "n"); /* use it */ + lua_pushinteger(L, n); + lua_rawset(L, t); + } + else { /* use `sizes' */ + getsizes(L); + lua_pushvalue(L, t); + lua_pushinteger(L, n); + lua_rawset(L, -3); /* sizes[t] = n */ + lua_pop(L, 1); /* remove `sizes' */ + } } LUALIB_API int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); - getsizes(L); /* try sizes[t] */ + lua_pushliteral(L, "n"); /* try t.n */ + lua_rawget(L, t); + if ((n = checkint(L, 1)) >= 0) return n; + getsizes(L); /* else try sizes[t] */ lua_pushvalue(L, t); lua_rawget(L, -2); if ((n = checkint(L, 2)) >= 0) return n; - lua_getfield(L, t, "n"); /* else try t.n */ - if ((n = checkint(L, 1)) >= 0) return n; return (int)lua_objlen(L, t); } diff --git a/src/lbaselib.c b/src/lbaselib.c index 1778e775ea..1d922a8105 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.188 2005/12/29 15:32:11 roberto Exp $ +** $Id: lbaselib.c,v 1.189 2006/01/18 11:49:12 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -201,7 +201,7 @@ static int luaB_collectgarbage (lua_State *L) { switch (optsnum[o]) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, ((lua_Number)res*1024 + b)/1024); + lua_pushnumber(L, res + ((lua_Number)b/1024)); return 1; } case LUA_GCSTEP: { diff --git a/src/liolib.c b/src/liolib.c index f0a7602a5c..fd7894c9ef 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.70 2005/12/29 15:32:11 roberto Exp $ +** $Id: liolib.c,v 2.71 2006/01/17 13:54:02 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -28,6 +28,7 @@ static const char *const fnames[] = {"input", "output"}; static int pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ if (i) { lua_pushboolean(L, 1); return 1; @@ -35,10 +36,10 @@ static int pushresult (lua_State *L, int i, const char *filename) { else { lua_pushnil(L); if (filename) - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); else - lua_pushfstring(L, "%s", strerror(errno)); - lua_pushinteger(L, errno); + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); return 3; } } diff --git a/src/llex.c b/src/llex.c index 2792ea9ef1..9918b2f4a2 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.17 2005/12/22 16:19:56 roberto Exp $ +** $Id: llex.c,v 2.18 2006/01/23 20:06:19 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -193,12 +193,10 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { do { save_and_next(ls); } while (isdigit(ls->current) || ls->current == '.'); - if (check_next(ls, "Ee")) { /* `E'? */ + if (check_next(ls, "Ee")) /* `E'? */ check_next(ls, "+-"); /* optional exponent sign */ - while (isdigit(ls->current)) { - save_and_next(ls); - } - } + while (isalnum(ls->current) || ls->current == '_') + save_and_next(ls); save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ diff --git a/src/lobject.h b/src/lobject.h index 928bedc761..8ce4405b6a 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.19 2006/01/10 12:51:53 roberto Exp $ +** $Id: lobject.h,v 2.20 2006/01/18 11:37:34 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -119,9 +119,6 @@ typedef struct lua_TValue { #define setnvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } -#define chgnvalue(obj,x) \ - check_exp(ttype(obj)==LUA_TNUMBER, (obj)->value.n=(x)) - #define setpvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } diff --git a/src/ltable.c b/src/ltable.c index 029cd506c7..bc91cacd63 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.31 2006/01/10 13:13:06 roberto Exp $ +** $Id: ltable.c,v 2.32 2006/01/18 11:49:02 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -122,7 +122,7 @@ static int arrayindex (const TValue *key) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); - if (luai_numeq(cast_num(k), nvalue(key))) + if (luai_numeq(cast_num(k), n)) return k; } return -1; /* `key' did not match some condition */ diff --git a/src/luaconf.h b/src/luaconf.h index 374929554f..5670598590 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.77 2005/12/27 17:12:00 roberto Exp $ +** $Id: luaconf.h,v 1.79 2006/01/23 19:51:43 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -488,6 +488,7 @@ ** =================================================================== */ +#define LUA_NUMBER_DOUBLE #define LUA_NUMBER double /* @@ -702,7 +703,7 @@ union luai_Cast { double l_d; long l_l; }; /* @@ LUA_INTFRMLEN is the length modifier for integer conversions -@* in 'string.fomat'. +@* in 'string.format'. @@ LUA_INTFRM_T is the integer type correspoding to the previous length @* modifier. ** CHANGE them if your system supports long long or does not support long. diff --git a/src/lvm.c b/src/lvm.c index ef41fddd2b..6f4c0291c9 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.61 2006/01/10 12:50:00 roberto Exp $ +** $Id: lvm.c,v 2.62 2006/01/23 19:51:43 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -95,7 +95,8 @@ static void callTMres (lua_State *L, StkId res, const TValue *f, -static void callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, const TValue *p3) { +static void callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, const TValue *p3) { setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */ @@ -649,7 +650,8 @@ void luaV_execute (lua_State *L, int nexeccalls) { lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); - if (step > 0 ? luai_numle(idx, limit) : luai_numle(limit, idx)) { + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ From 43fb64048e381a76d6cd363dedd9ccc8a85b9b31 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 7 Feb 2006 12:00:00 +0000 Subject: [PATCH 28/97] Lua 5.1-rc3 --- HISTORY | 2 +- INSTALL | 3 + MANIFEST | 28 +- Makefile | 35 ++- doc/contents.html | 28 +- doc/lua.html | 2 +- doc/luac.html | 10 +- doc/manual.html | 668 +++++++++++++++++++++++++--------------------- etc/Makefile | 21 +- etc/README | 9 +- etc/lua.pc | 18 +- src/Makefile | 2 + src/liolib.c | 4 +- src/llex.c | 4 +- src/loslib.c | 9 +- src/lstate.h | 10 +- src/luaconf.h | 4 +- 17 files changed, 480 insertions(+), 377 deletions(-) diff --git a/HISTORY b/HISTORY index 122f656370..885c35baf9 100644 --- a/HISTORY +++ b/HISTORY @@ -14,7 +14,7 @@ HISTORY for Lua 5.1 API: + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + user supplies memory allocator (lua_open becomes lua_newstate). - + luaopen_* functionst be called through Lua. + + luaopen_* functionst must be called through Lua. Implementation: + new configuration scheme via luaconf.h. + incremental garbage collection. diff --git a/INSTALL b/INSTALL index 293b44ea61..65f6f1eb07 100644 --- a/INSTALL +++ b/INSTALL @@ -23,6 +23,9 @@ INSTALL for Lua 5.1 place and the way to install files are defined in Makefile. You must have the right permissions to install files. + If you want to build and install Lua in one step, do "make xxx install", + where xxx is your platform name. + If you want to install Lua locally, then do "make local". This will create directories bin, include, lib, man, and install Lua there as follows: diff --git a/MANIFEST b/MANIFEST index a554dc122c..1f70c5e8d5 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,33 +1,34 @@ -MANIFEST contents of Lua 5.1 distribution on Tue Jan 24 16:12:03 BRST 2006 +MANIFEST contents of Lua 5.1 distribution on Tue Feb 7 15:05:04 BRST 2006 lua-5.1 lua-5.1/COPYRIGHT +lua-5.1/HISTORY +lua-5.1/INSTALL +lua-5.1/MANIFEST +lua-5.1/Makefile +lua-5.1/README lua-5.1/doc lua-5.1/doc/contents.html lua-5.1/doc/logo.gif lua-5.1/doc/lua.1 -lua-5.1/doc/luac.1 -lua-5.1/doc/luac.html lua-5.1/doc/lua.css lua-5.1/doc/lua.html +lua-5.1/doc/luac.1 +lua-5.1/doc/luac.html lua-5.1/doc/manual.html lua-5.1/doc/readme.html lua-5.1/etc +lua-5.1/etc/Makefile +lua-5.1/etc/README lua-5.1/etc/all.c lua-5.1/etc/lua.hpp lua-5.1/etc/lua.ico lua-5.1/etc/lua.pc lua-5.1/etc/luavs.bat -lua-5.1/etc/Makefile lua-5.1/etc/min.c lua-5.1/etc/noparser.c -lua-5.1/etc/README lua-5.1/etc/strict.lua -lua-5.1/HISTORY -lua-5.1/INSTALL -lua-5.1/Makefile -lua-5.1/MANIFEST -lua-5.1/README lua-5.1/src +lua-5.1/src/Makefile lua-5.1/src/lapi.c lua-5.1/src/lapi.h lua-5.1/src/lauxlib.c @@ -72,9 +73,9 @@ lua-5.1/src/ltablib.c lua-5.1/src/ltm.c lua-5.1/src/ltm.h lua-5.1/src/lua.c +lua-5.1/src/lua.h lua-5.1/src/luac.c lua-5.1/src/luaconf.h -lua-5.1/src/lua.h lua-5.1/src/lualib.h lua-5.1/src/lundump.c lua-5.1/src/lundump.h @@ -82,22 +83,21 @@ lua-5.1/src/lvm.c lua-5.1/src/lvm.h lua-5.1/src/lzio.c lua-5.1/src/lzio.h -lua-5.1/src/Makefile lua-5.1/src/print.c lua-5.1/test +lua-5.1/test/README lua-5.1/test/bisect.lua lua-5.1/test/cf.lua lua-5.1/test/echo.lua lua-5.1/test/env.lua lua-5.1/test/factorial.lua -lua-5.1/test/fibfor.lua lua-5.1/test/fib.lua +lua-5.1/test/fibfor.lua lua-5.1/test/globals.lua lua-5.1/test/hello.lua lua-5.1/test/life.lua lua-5.1/test/luac.lua lua-5.1/test/printf.lua -lua-5.1/test/README lua-5.1/test/readonly.lua lua-5.1/test/sieve.lua lua-5.1/test/sort.lua diff --git a/Makefile b/Makefile index db9bb3d9a4..682256b426 100644 --- a/Makefile +++ b/Makefile @@ -22,10 +22,17 @@ INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V # How to install. You may prefer "install" instead of "cp" if you have it. # To remove debug information from binaries, use "install -s" in INSTALL_EXEC. # -INSTALL_EXEC= cp -INSTALL_DATA= cp -#INSTALL_EXEC= install -m 0755 -#INSTALL_DATA= install -m 0644 +INSTALL_EXEC= $(CP) +INSTALL_DATA= $(CP) +#INSTALL_EXEC= $(INSTALL) -m 0755 +#INSTALL_DATA= $(INSTALL) -m 0644 + +# Utilities. +CP= cp +FIND= find +INSTALL= install +MKDIR= mkdir +RANLIB= ranlib # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= @@ -46,15 +53,16 @@ all: $(PLAT) $(PLATS) clean: cd src; $(MAKE) $@ -test: all +test: dummy src/lua test/hello.lua -install: - cd src; mkdir -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) +install: dummy + cd src; $(MKDIR) -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) cd src; $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) cd src; $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) cd src; $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) cd doc; $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) +# $(RANLIB) $(INSTALL_LIB)/$(TO_LIB) local: $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -p" INSTALL_DATA="cp -p" @@ -62,6 +70,9 @@ local: none: @echo "Please choose a platform: $(PLATS)" +# make may get confused with test/ and INSTALL in a case-insensitive OS +dummy: + # echo config parameters echo: @echo "" @@ -77,11 +88,10 @@ echo: @echo "INSTALL_INC = $(INSTALL_INC)" @echo "INSTALL_LIB = $(INSTALL_LIB)" @echo "INSTALL_MAN = $(INSTALL_MAN)" - @echo "INSTALL_EXEC = $(INSTALL_EXEC)" - @echo "INSTALL_DATA = $(INSTALL_DATA)" @echo "INSTALL_LMOD = $(INSTALL_LMOD)" @echo "INSTALL_CMOD = $(INSTALL_CMOD)" - @echo "INSTALL_CMOD = $(INSTALL_CMOD)" + @echo "INSTALL_EXEC = $(INSTALL_EXEC)" + @echo "INSTALL_DATA = $(INSTALL_DATA)" @echo "" @echo "See also src/luaconf.h ." @echo "" @@ -104,6 +114,9 @@ lecho: # show what has changed since we unpacked newer: - @find . -newer MANIFEST -type f + @$(FIND) . -newer MANIFEST -type f + +# list targets that do not create files (but not all makes understand .PHONY) +.PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho newer # (end of Makefile) diff --git a/doc/contents.html b/doc/contents.html index 7b890342bd..323bfaef65 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -154,24 +154,31 @@

          Functions

          math.abs
          math.acos
          math.asin
          -math.atan
          math.atan2
          +math.atan
          math.ceil
          -math.cos
          math.cosh
          -math.def
          +math.cos
          +math.deg
          math.exp
          math.floor
          math.fmod
          +math.frexp
          math.ldexp
          -math.log
          math.log10
          +math.log
          +math.max
          +math.min
          +math.modf
          math.pow
          -math.sin
          +math.rad
          +math.random
          +math.randomseed
          math.sinh
          +math.sin
          math.sqrt
          -math.tan
          math.tanh
          +math.tan
          module
          next
          os.clock
          @@ -225,6 +232,7 @@

          Functions

          type
          unpack
          xpcall
          +

          API

          @@ -251,6 +259,7 @@

          API

          lua_getallocf
          lua_getfenv
          lua_getfield
          +lua_getglobal
          lua_gethook
          lua_gethookcount
          lua_gethookmask
          @@ -300,12 +309,14 @@

          API

          lua_rawgeti
          lua_rawset
          lua_rawseti
          +lua_register
          lua_remove
          lua_replace
          lua_resume
          lua_setallocf
          lua_setfenv
          lua_setfield
          +lua_setglobal
          lua_sethook
          lua_setlocal
          lua_setmetatable
          @@ -326,6 +337,7 @@

          API

          lua_typename
          lua_xmove
          lua_yield
          +

          Auxiliary library

          @@ -360,6 +372,7 @@

          Auxiliary library

          luaL_loadstring
          luaL_newmetatable
          luaL_newstate
          +luaL_openlibs
          luaL_optint
          luaL_optinteger
          luaL_optlong
          @@ -374,6 +387,7 @@

          Auxiliary library

          luaL_typerror
          luaL_unref
          luaL_where
          + @@ -382,7 +396,7 @@

          Auxiliary library


          Last update: -Tue Jan 10 10:10:22 BRST 2006 +Tue Feb 7 14:37:59 BRST 2006 diff --git a/doc/lua.html b/doc/lua.html index 5900321f4c..1d435ab029 100644 --- a/doc/lua.html +++ b/doc/lua.html @@ -149,7 +149,7 @@

          OPTIONS

          -l name call -require(' name') +require('name') before executing script. Typically used to load libraries. diff --git a/doc/luac.html b/doc/luac.html index 3ecdfdf037..7b7e0f7002 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -28,13 +28,13 @@

          DESCRIPTION

          and off-line syntax checking.

          -Pre-compiling does not imply faster execution +Precompiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. luac simply allows those bytecodes to be saved in a file for later execution.

          -Pre-compiled chunks are not necessarily smaller than the corresponding source. -The main goal in pre-compiling is faster loading. +Precompiled chunks are not necessarily smaller than the corresponding source. +The main goal in precompiling is faster loading.

          The binary files created by luac @@ -54,9 +54,9 @@

          DESCRIPTION

          you can mix text files containing Lua source and binary files containing precompiled chunks. -This is useful to combine several precompiled chunks, +This is useful because several precompiled chunks, even from different (but compatible) platforms, -into a single precompiled chunk. +can be combined into a single precompiled chunk.

          You can use '-' diff --git a/doc/manual.html b/doc/manual.html index 9a115e740f..e7a3cfa47c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -8,9 +8,9 @@ -


          +

          -[Lua logo] +[Lua logo] Lua 5.1 Reference Manual

          @@ -20,7 +20,7 @@

          Copyright © 2006 Lua.org, PUC-Rio. All rights reserved. -
          +

          @@ -302,7 +302,7 @@

          that string to a number, following the usual conversion rules. Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. -For complete control of how numbers are converted to strings, +For complete control over how numbers are converted to strings, use the format function from the string library (see string.format). @@ -1554,9 +1554,9 @@

          created by that function.

          You can change the environment of a Lua function or the -running thread calling setfenv. +running thread by calling setfenv. You can get the environment of a Lua function or the running thread -calling getfenv. +by calling getfenv. To manipulate the environment of other objects (userdata, C functions, other threads) you must use the C API. @@ -1565,7 +1565,7 @@

          Lua performs automatic memory management. That means that -you do not have to worry neither about allocating memory for new objects +you have to worry neither about allocating memory for new objects nor about freeing it when the objects are no longer needed. Lua manages memory automatically by running a garbage collector from time to time @@ -1577,7 +1577,7 @@

          Lua implements an incremental mark-and-sweep collector. It uses two numbers to control its garbage-collection cycles: the garbage-collector pause and -the garbage-collector multiplier. +the garbage-collector step multiplier.

          The garbage-collector pause controls how long the collector waits before starting a new cycle. @@ -1587,7 +1587,7 @@

          A value of 2 means that the collector waits more or less to double the total memory in use before starting a new cycle. -

          The garbage-collector multiplier +

          The step multiplier controls the relative speed of the collector relative to memory allocation. Larger values make the collector more aggressive but also increases @@ -1898,7 +1898,7 @@

          The integer keys in the registry are used by the reference mechanism, implemented by the auxiliary library, -and therefore should not be used by other purposes. +and therefore should not be used for other purposes.

          3.6 - Error Handling in C

          @@ -1930,7 +1930,7 @@

          alphabetical order.

          -


          lua_Alloc

          +

          lua_Alloc

                     typedef void * (*lua_Alloc) (void *ud,
                                                  void *ptr,
          @@ -1979,7 +1979,7 @@ 

          -


          lua_atpanic

          +

          lua_atpanic

                     lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
           
          @@ -1997,7 +1997,7 @@

          The panic function can access the error message at the top of the stack.

          -


          lua_call

          +

          lua_call

                     void lua_call (lua_State *L, int nargs, int nresults);
           
          @@ -2047,7 +2047,7 @@

          This is considered good programming practice.

          -


          lua_CFunction

          +

          lua_CFunction

                     typedef int (*lua_CFunction) (lua_State *L);
           
          @@ -2093,20 +2093,20 @@

        -


        lua_checkstack

        +

        lua_checkstack

                   int lua_checkstack (lua_State *L, int extra);
         

        Ensures that there are at least extra free stack slots in the stack. -it returns false if it cannot grow the stack to that size. +It returns false if it cannot grow the stack to that size. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged.

        -


        lua_close

        +

        lua_close

                   void lua_close (lua_State *L);
         
        @@ -2123,7 +2123,7 @@

        to avoid growing too large.

        -


        lua_concat

        +

        lua_concat

                   void lua_concat (lua_State *L, int n);
         
        @@ -2138,7 +2138,7 @@

        (see 2.5.4).

        -


        lua_cpcall

        +

        lua_cpcall

                   int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
         
        @@ -2154,7 +2154,7 @@

        All values returned by func are discarded.

        -


        lua_createtable

        +

        lua_createtable

                   void lua_createtable (lua_State *L, int narr, int nrec);
         
        @@ -2168,7 +2168,7 @@

        Otherwise you can use the function lua_newtable.

        -


        lua_dump

        +

        lua_dump

                   int lua_dump (lua_State *L, lua_Writer writer, void *data);
         
        @@ -2191,7 +2191,7 @@

        This function does not pop the function from the stack.

        -


        lua_equal

        +

        lua_equal

                   int lua_equal (lua_State *L, int index1, int index2);
         
        @@ -2205,7 +2205,7 @@

        Also returns 0 if any of the indices is non valid.

        -


        lua_error

        +

        lua_error

                   int lua_error (lua_State *L);
         
        @@ -2219,7 +2219,7 @@

        (see luaL_error).

        -


        lua_gc

        +

        lua_gc

                   int lua_gc (lua_State *L, int what, int data);
         
        @@ -2257,7 +2257,7 @@

      -


      lua_getallocf

      +

      lua_getallocf

                 lua_Alloc lua_getallocf (lua_State *L, void **ud);
       
      @@ -2268,7 +2268,7 @@

      opaque pointer passed to lua_newstate.

      -


      lua_getfenv

      +

      lua_getfenv

                 void lua_getfenv (lua_State *L, int index);
       
      @@ -2278,7 +2278,7 @@

      the value at the given index.

      -


      lua_getfield

      +

      lua_getfield

                 void lua_getfield (lua_State *L, int index, const char *k);
       
      @@ -2289,8 +2289,21 @@

      As in Lua, this function may trigger a metamethod for the "index" event (see 2.8). +

      +


      lua_getglobal

      +
      +          void lua_getglobal (lua_State *L, const char *name);
      +
      + + +

      Pushes onto the stack the value of the global name. +It is defined as a macro: +

      +#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
      +
      +

      -


      lua_getmetatable

      +

      lua_getmetatable

                 int lua_getmetatable (lua_State *L, int index);
       
      @@ -2300,10 +2313,10 @@

      acceptable index. If the index is not valid, or if the value does not have a metatable, -returns 0 and pushes nothing on the stack. +the function returns 0 and pushes nothing on the stack.

      -


      lua_gettable

      +

      lua_gettable

                 void lua_gettable (lua_State *L, int index);
       
      @@ -2319,7 +2332,7 @@

      for the "index" event (see 2.8).

      -


      lua_gettop

      +

      lua_gettop

                 int lua_gettop (lua_State *L);
       
      @@ -2331,7 +2344,7 @@

      (and so 0 means an empty stack).

      -


      lua_insert

      +

      lua_insert

                 void lua_insert (lua_State *L, int index);
       
      @@ -2343,7 +2356,7 @@

      because a pseudo-index is not an actual stack position.

      -


      lua_Integer

      +

      lua_Integer

                 typedef ptrdiff_t lua_Integer;
       
      @@ -2356,7 +2369,7 @@

      "comfortably".

      -


      lua_isboolean

      +

      lua_isboolean

                 int lua_isboolean (lua_State *L, int index);
       
      @@ -2366,7 +2379,7 @@

      and 0 otherwise.

      -


      lua_iscfunction

      +

      lua_iscfunction

                 int lua_iscfunction (lua_State *L, int index);
       
      @@ -2376,7 +2389,7 @@

      and 0 otherwise.

      -


      lua_isfunction

      +

      lua_isfunction

                 int lua_isfunction (lua_State *L, int index);
       
      @@ -2386,7 +2399,7 @@

      (either C or Lua), and 0 otherwise.

      -


      lua_islightuserdata

      +

      lua_islightuserdata

                 int lua_islightuserdata (lua_State *L, int index);
       
      @@ -2396,7 +2409,7 @@

      and 0 otherwise.

      -


      lua_isnil

      +

      lua_isnil

                 int lua_isnil (lua_State *L, int index);
       
      @@ -2406,7 +2419,7 @@

      and 0 otherwise.

      -


      lua_isnumber

      +

      lua_isnumber

                 int lua_isnumber (lua_State *L, int index);
       
      @@ -2417,7 +2430,7 @@

      and 0 otherwise.

      -


      lua_isstring

      +

      lua_isstring

                 int lua_isstring (lua_State *L, int index);
       
      @@ -2428,7 +2441,7 @@

      and 0 otherwise.

      -


      lua_istable

      +

      lua_istable

                 int lua_istable (lua_State *L, int index);
       
      @@ -2438,7 +2451,7 @@

      and 0 otherwise.

      -


      lua_isthread

      +

      lua_isthread

                 int lua_isthread (lua_State *L, int index);
       
      @@ -2448,7 +2461,7 @@

      and 0 otherwise.

      -


      lua_isuserdata

      +

      lua_isuserdata

                 int lua_isuserdata (lua_State *L, int index);
       
      @@ -2458,7 +2471,7 @@

      (either full or light), and 0 otherwise.

      -


      lua_lessthan

      +

      lua_lessthan

                 int lua_lessthan (lua_State *L, int index1, int index2);
       
      @@ -2472,7 +2485,7 @@

      Also returns 0 if any of the indices is non valid.

      -


      lua_load

      +

      lua_load

                 int lua_load (lua_State *L, lua_Reader reader, void *data,
                                             const char *chunkname);
      @@ -2505,7 +2518,7 @@ 

      which is used for error messages and in debug information (see 3.8).

      -


      lua_newstate

      +

      lua_newstate

                 lua_State *lua_newstate (lua_Alloc f, void *ud);
       
      @@ -2520,7 +2533,7 @@

      simply passes to the allocator in every call.

      -


      lua_newtable

      +

      lua_newtable

                 void lua_newtable (lua_State *L);
       
      @@ -2530,7 +2543,7 @@

      Equivalent to lua_createtable(L, 0, 0).

      -


      lua_newthread

      +

      lua_newthread

                 lua_State *lua_newthread (lua_State *L);
       
      @@ -2547,7 +2560,7 @@

      like any Lua object.

      -


      lua_newuserdata

      +

      lua_newuserdata

                 void *lua_newuserdata (lua_State *L, size_t size);
       
      @@ -2570,7 +2583,7 @@

      Lua frees its corresponding memory.

      -


      lua_next

      +

      lua_next

                 int lua_next (lua_State *L, int index);
       
      @@ -2602,7 +2615,7 @@

      this confuses the next call to lua_next.

      -


      lua_Number

      +

      lua_Number

                 typedef double lua_Number;
       
      @@ -2612,10 +2625,10 @@

      By default, it is double, but that can be changed in luaconf.h.

      Through the configuration file you can change -Lua to operate with other type for numbers (e.g., float or long). +Lua to operate with another type for numbers (e.g., float or long).

      -


      lua_objlen

      +

      lua_objlen

                 size_t lua_objlen (lua_State *L, int index);
       
      @@ -2629,7 +2642,7 @@

      for other values, it is 0.

      -


      lua_pcall

      +

      lua_pcall

                 lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
       
      @@ -2676,7 +2689,7 @@

    -


    lua_pop

    +

    lua_pop

               void lua_pop (lua_State *L, int n);
     
    @@ -2685,7 +2698,7 @@

    Pops n elements from the stack.

    -


    lua_pushboolean

    +

    lua_pushboolean

               void lua_pushboolean (lua_State *L, int b);
     
    @@ -2694,7 +2707,7 @@

    Pushes a boolean value with value b onto the stack.

    -


    lua_pushcclosure

    +

    lua_pushcclosure

               void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
     
    @@ -2716,17 +2729,26 @@

    lua_pushcclosure also pops these values from the stack.

    -


    lua_pushcfunction

    +

    lua_pushcfunction

               void lua_pushcfunction (lua_State *L, lua_CFunction f);
     

    Pushes a C function onto the stack. -This function is equivalent to lua_pushcclosure(L, f, 0);. +This function receives a pointer to a C function +and pushes on the stack a Lua value of type function that, +when called, invokes the corresponding C function. + +

    Any function to be registered in Lua must +follow the correct protocol to receive its parameters +and return its results (see lua_CFunction). + +

    The call lua_pushcfunction(L, f) is equivalent to +lua_pushcclosure(L, f, 0).

    -


    lua_pushfstring

    +

    lua_pushfstring

               const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
     
    @@ -2752,7 +2774,7 @@

    -


    lua_pushinteger

    +

    lua_pushinteger

               void lua_pushinteger (lua_State *L, lua_Integer n);
     
    @@ -2761,7 +2783,7 @@

    Pushes a number with value n onto the stack.

    -


    lua_pushlightuserdata

    +

    lua_pushlightuserdata

               void lua_pushlightuserdata (lua_State *L, void *p);
     
    @@ -2778,7 +2800,7 @@

    light userdata with the same C address.

    -


    lua_pushlstring

    +

    lua_pushlstring

               void lua_pushlstring (lua_State *L, const char *s, size_t len);
     
    @@ -2792,7 +2814,7 @@

    The string can contain embedded zeros.

    -


    lua_pushnil

    +

    lua_pushnil

               void lua_pushnil (lua_State *L);
     
    @@ -2801,7 +2823,7 @@

    Pushes a nil value onto the stack.

    -


    lua_pushnumber

    +

    lua_pushnumber

               void lua_pushnumber (lua_State *L, lua_Number n);
     
    @@ -2810,7 +2832,7 @@

    Pushes a number with value n onto the stack.

    -


    lua_pushstring

    +

    lua_pushstring

               void lua_pushstring (lua_State *L, const char *s);
     
    @@ -2825,7 +2847,7 @@

    it is assumed to end at the first zero.

    -


    lua_pushthread

    +

    lua_pushthread

               void lua_pushthread (lua_State *L);
     
    @@ -2834,7 +2856,7 @@

    Pushes the thread represented by L onto the stack.

    -


    lua_pushvalue

    +

    lua_pushvalue

               void lua_pushvalue (lua_State *L, int index);
     
    @@ -2844,7 +2866,7 @@

    onto the stack.

    -


    lua_pushvfstring

    +

    lua_pushvfstring

               const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
     
    @@ -2854,7 +2876,7 @@

    instead of a variable number of arguments.

    -


    lua_rawequal

    +

    lua_rawequal

               int lua_rawequal (lua_State *L, int index1, int index2);
     
    @@ -2867,7 +2889,7 @@

    Also returns 0 if any of the indices are non valid.

    -


    lua_rawget

    +

    lua_rawget

               void lua_rawget (lua_State *L, int index);
     
    @@ -2877,7 +2899,7 @@

    (i.e., without metamethods).

    -


    lua_rawgeti

    +

    lua_rawgeti

               void lua_rawgeti (lua_State *L, int index, int n);
     
    @@ -2889,7 +2911,7 @@

    that is, it does not invoke metamethods.

    -


    lua_rawset

    +

    lua_rawset

               void lua_rawset (lua_State *L, int index);
     
    @@ -2899,7 +2921,7 @@

    (i.e., without metamethods).

    -


    lua_rawseti

    +

    lua_rawseti

               void lua_rawseti (lua_State *L, int index, int n);
     
    @@ -2914,7 +2936,7 @@

    that is, it does not invoke metamethods.

    -


    lua_Reader

    +

    lua_Reader

               typedef const char * (*lua_Reader)
                                    (lua_State *L, void *data, size_t *size);
    @@ -2933,8 +2955,21 @@ 

    To signal the end of the chunk, the reader must return NULL. The reader function may return pieces of any size greater than zero. +

    +


    lua_register

    +
    +          void lua_register (lua_State *L, const char *name, lua_CFunction f);
    +
    + + +

    Sets the C function f as the new value of global name. +It is defined as a macro: +

    +#define lua_register(L,n,f)  (lua_pushcfunction(L, f), lua_setglobal(L, n))
    +
    +

    -


    lua_remove

    +

    lua_remove

               void lua_remove (lua_State *L, int index);
     
    @@ -2946,7 +2981,7 @@

    because a pseudo-index is not an actual stack position.

    -


    lua_replace

    +

    lua_replace

               void lua_replace (lua_State *L, int index);
     
    @@ -2957,7 +2992,7 @@

    (therefore replacing the value at the given position).

    -


    lua_resume

    +

    lua_resume

               int lua_resume (lua_State *L, int narg);
     
    @@ -2987,7 +3022,7 @@

    and then call lua_resume.

    -


    lua_setallocf

    +

    lua_setallocf

               void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
     
    @@ -2997,7 +3032,7 @@

    with user data ud.

    -


    lua_setfenv

    +

    lua_setfenv

               int lua_setfenv (lua_State *L, int index);
     
    @@ -3011,7 +3046,7 @@

    Otherwise it returns 1.

    -


    lua_setfield

    +

    lua_setfield

               void lua_setfield (lua_State *L, int index, const char *k);
     
    @@ -3025,8 +3060,22 @@

    As in Lua, this function may trigger a metamethod for the "newindex" event (see 2.8). +

    +


    lua_setglobal

    +
    +          void lua_setglobal (lua_State *L, const char *name);
    +
    + + +

    Pops a value from the stack and +sets it as the new value of global name. +It is defined as a macro: +

    +#define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
    +
    +

    -


    lua_setmetatable

    +

    lua_setmetatable

               int lua_setmetatable (lua_State *L, int index);
     
    @@ -3037,7 +3086,7 @@

    acceptable index.

    -


    lua_settable

    +

    lua_settable

               void lua_settable (lua_State *L, int index);
     
    @@ -3053,7 +3102,7 @@

    for the "newindex" event (see 2.8).

    -


    lua_settop

    +

    lua_settop

               void lua_settop (lua_State *L, int index);
     
    @@ -3066,7 +3115,7 @@

    If index is 0, then all stack elements are removed.

    -


    lua_State

    +

    lua_State

               typedef struct lua_State lua_State;
     
    @@ -3082,7 +3131,7 @@

    which creates a Lua state from scratch.

    -


    lua_status

    +

    lua_status

               int lua_status (lua_State *L);
     
    @@ -3090,19 +3139,19 @@

    Returns the status of the thread L. -

    The status can by 0 for a normal thread, +

    The status can be 0 for a normal thread, an error code if the thread finished its execution with an error, or LUA_YIELD if the thread is suspended.

    -


    lua_toboolean

    +

    lua_toboolean

               int lua_toboolean (lua_State *L, int index);
     

    Converts the Lua value at the given acceptable index to a C boolean -value ((0 or 1). +value (0 or 1). Like all tests in Lua, lua_toboolean returns 1 for any Lua value different from false and nil; @@ -3112,7 +3161,7 @@

    use lua_isboolean to test the value's type.)

    -


    lua_tocfunction

    +

    lua_tocfunction

               lua_CFunction lua_tocfunction (lua_State *L, int index);
     
    @@ -3123,7 +3172,7 @@

    otherwise, returns NULL.

    -


    lua_tointeger

    +

    lua_tointeger

               lua_Integer lua_tointeger (lua_State *L, int idx);
     
    @@ -3131,7 +3180,7 @@

    Converts the Lua value at the given acceptable index to the signed integral type lua_Integer. -The Lua value must be a number or a string convertible to number +The Lua value must be a number or a string convertible to a number (see 2.2.1); otherwise, lua_tointeger returns 0. @@ -3139,7 +3188,7 @@

    it is truncated in some non-specified way.

    -


    lua_tolstring

    +

    lua_tolstring

               const char *lua_tolstring (lua_State *L, int index, size_t *len);
     
    @@ -3167,7 +3216,7 @@

    will be valid after the corresponding value is removed from the stack.

    -


    lua_tonumber

    +

    lua_tonumber

               lua_Number lua_tonumber (lua_State *L, int index);
     
    @@ -3175,12 +3224,12 @@

    Converts the Lua value at the given acceptable index to a number (see lua_Number). -The Lua value must be a number or a string convertible to number +The Lua value must be a number or a string convertible to a number (see 2.2.1); otherwise, lua_tonumber returns 0.

    -


    lua_topointer

    +

    lua_topointer

               const void *lua_topointer (lua_State *L, int index);
     
    @@ -3196,7 +3245,7 @@

    Typically this function is used only for debug information.

    -


    lua_tostring

    +

    lua_tostring

               const char *lua_tostring (lua_State *L, int index);
     
    @@ -3205,7 +3254,7 @@

    Equivalent to lua_tolstring with len equal to NULL.

    -


    lua_tothread

    +

    lua_tothread

               lua_State *lua_tothread (lua_State *L, int index);
     
    @@ -3217,7 +3266,7 @@

    otherwise, the function returns NULL.

    -


    lua_touserdata

    +

    lua_touserdata

               void *lua_touserdata (lua_State *L, int index);
     
    @@ -3230,13 +3279,13 @@

    Otherwise, returns NULL.

    -


    lua_type

    +

    lua_type

               int lua_type (lua_State *L, int index);
     
    -

    Returns the type of a value in the given acceptable index, +

    Returns the type of the value in the given acceptable index, or LUA_TNONE for a non-valid index (that is, an index to an "empty" stack position). The types returned by lua_type are coded by the following constants @@ -3253,7 +3302,7 @@

    LUA_TLIGHTUSERDATA.

    -


    lua_typename

    +

    lua_typename

               const char *lua_typename  (lua_State *L, int tp);
     
    @@ -3263,7 +3312,7 @@

    which must be one the values returned by lua_type.

    -


    lua_Writer

    +

    lua_Writer

               typedef int (*lua_Writer)
                               (lua_State *L, const void* p, size_t sz, void* ud);
    @@ -3284,7 +3333,7 @@ 

    calling the writer again.

    -


    lua_xmove

    +

    lua_xmove

               void lua_xmove (lua_State *from, lua_State *to, int n);
     
    @@ -3293,10 +3342,10 @@

    Exchange values between different threads of the same global state.

    This function pops n values from the stack from, -and pushes them into the stack to. +and pushes them onto the stack to.

    -


    lua_yield

    +

    lua_yield

               int lua_yield  (lua_State *L, int nresults);
     
    @@ -3326,7 +3375,7 @@

    that need "inside information" from the interpreter.

    -


    lua_Debug

    +

    lua_Debug

               typedef struct lua_Debug {
                 int event;
    @@ -3408,7 +3457,7 @@ 

    -


    lua_gethook

    +

    lua_gethook

               lua_Hook lua_gethook (lua_State *L);
     
    @@ -3417,7 +3466,7 @@

    Returns the current hook function.

    -


    lua_gethookcount

    +

    lua_gethookcount

               int lua_gethookcount (lua_State *L);
     
    @@ -3426,7 +3475,7 @@

    Returns the current hook count.

    -


    lua_gethookmask

    +

    lua_gethookmask

               int lua_gethookmask (lua_State *L);
     
    @@ -3435,7 +3484,7 @@

    Returns the current hook mask.

    -


    lua_getinfo

    +

    lua_getinfo

               int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
     
    @@ -3469,7 +3518,7 @@

    -


    lua_getlocal

    +

    lua_getlocal

               const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
     
    @@ -3494,7 +3543,7 @@

    the number of active local variables.

    -


    lua_getstack

    +

    lua_getstack

               int lua_getstack (lua_State *L, int level, lua_Debug *ar);
     
    @@ -3512,7 +3561,7 @@

    it returns 0.

    -


    lua_getupvalue

    +

    lua_getupvalue

               const char *lua_getupvalue (lua_State *L, int funcindex, int n);
     
    @@ -3536,7 +3585,7 @@

    as a name for all upvalues.

    -


    lua_Hook

    +

    lua_Hook

               typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
     
    @@ -3564,7 +3613,7 @@

    that execution occurs without any calls to hooks.

    -


    lua_sethook

    +

    lua_sethook

               int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
     
    @@ -3601,7 +3650,7 @@

    A hook is disabled by setting mask to zero.

    -


    lua_setlocal

    +

    lua_setlocal

               const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
     
    @@ -3619,7 +3668,7 @@

    the number of active local variables.

    -


    lua_setupvalue

    +

    lua_setupvalue

               const char *lua_setupvalue (lua_State *L, int funcindex, int n);
     
    @@ -3668,7 +3717,7 @@

    in alphabetical order.

    -


    luaL_addchar

    +

    luaL_addchar

               void luaL_addchar (luaL_Buffer B, char c);
     
    @@ -3678,7 +3727,7 @@

    (see luaL_Buffer).

    -


    luaL_addlstring

    +

    luaL_addlstring

               void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
     
    @@ -3690,7 +3739,7 @@

    The string may contain embedded zeros.

    -


    luaL_addsize

    +

    luaL_addsize

               void luaL_addsize (luaL_Buffer B, size_t n);
     
    @@ -3701,7 +3750,7 @@

    (see luaL_Buffer).

    -


    luaL_addstring

    +

    luaL_addstring

               void luaL_addstring (luaL_Buffer *B, const char *s);
     
    @@ -3713,7 +3762,7 @@

    The string may not contain embedded zeros.

    -


    luaL_addvalue

    +

    luaL_addvalue

               void luaL_addvalue (luaL_Buffer *B);
     
    @@ -3729,7 +3778,7 @@

    which is the value to be added to the buffer.

    -


    luaL_argcheck

    +

    luaL_argcheck

               void luaL_argcheck (lua_State *L, int cond, int numarg,
                                   const char *extramsg);
    @@ -3742,7 +3791,7 @@ 

    where func is retrieved from the call stack.

    -


    luaL_argerror

    +

    luaL_argerror

               int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
     
    @@ -3757,7 +3806,7 @@

    in C functions.

    -


    luaL_Buffer

    +

    luaL_Buffer

               typedef struct luaL_Buffer luaL_Buffer;
     
    @@ -3772,7 +3821,7 @@

  • Then you initialize it with a call luaL_buffinit(L, &b).
  • Then you add string pieces to the buffer calling any of the luaL_add* functions. -
  • You finish calling luaL_pushresult(&b). +
  • You finish by calling luaL_pushresult(&b). That call leaves the final string on the top of the stack. @@ -3792,7 +3841,7 @@

    plus the final string on its top.

    -


    luaL_buffinit

    +

    luaL_buffinit

               void luaL_buffinit (lua_State *L, luaL_Buffer *B);
     
    @@ -3804,7 +3853,7 @@

    (see luaL_Buffer).

    -


    luaL_callmeta

    +

    luaL_callmeta

               int luaL_callmeta (lua_State *L, int obj, const char *e);
     
    @@ -3821,7 +3870,7 @@

    this function returns 0 (without pushing any value on the stack).

    -


    luaL_checkany

    +

    luaL_checkany

               void luaL_checkany (lua_State *L, int narg);
     
    @@ -3831,7 +3880,7 @@

    of any type (including nil) at position narg.

    -


    luaL_checkint

    +

    luaL_checkint

               int luaL_checkint (lua_State *L, int narg);
     
    @@ -3841,7 +3890,7 @@

    and returns that number cast to an int.

    -


    luaL_checkinteger

    +

    luaL_checkinteger

               lua_Integer luaL_checkinteger (lua_State *L, int narg);
     
    @@ -3851,7 +3900,7 @@

    and returns that number cast to a lua_Integer.

    -


    luaL_checklong

    +

    luaL_checklong

               long luaL_checklong (lua_State *L, int narg);
     
    @@ -3861,9 +3910,9 @@

    and returns that number cast to a long.

    -


    luaL_checklstring

    +

    luaL_checklstring

    -          const char *luaL_checklstring (lua_State *L, int numArg, size_t *l);
    +          const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
     
    @@ -3873,9 +3922,9 @@

    with the string's length.

    -


    luaL_checknumber

    +

    luaL_checknumber

    -          lua_Number luaL_checknumber (lua_State *L, int numArg);
    +          lua_Number luaL_checknumber (lua_State *L, int narg);
     
    @@ -3883,7 +3932,7 @@

    and returns that number.

    -


    luaL_checkoption

    +

    luaL_checkoption

               int luaL_checkoption (lua_State *L, int narg, const char *def,
                                     const char *const lst[]);
    @@ -3902,11 +3951,11 @@ 

    if the string cannot be found.

    This is a useful function for mapping strings to C enums. -The usual interfaces in Lua libraries is to use strings instead of numbers +The usual convention in Lua libraries is to use strings instead of numbers to select options.

    -


    luaL_checkstack

    +

    luaL_checkstack

               void luaL_checkstack (lua_State *L, int sz, const char *msg);
     
    @@ -3917,7 +3966,7 @@

    msg is an additional text to go into the error message.

    -


    luaL_checkstring

    +

    luaL_checkstring

               const char *luaL_checkstring (lua_State *L, int narg);
     
    @@ -3927,7 +3976,7 @@

    and returns that string.

    -


    luaL_checktype

    +

    luaL_checktype

               void luaL_checktype (lua_State *L, int narg, int t);
     
    @@ -3936,9 +3985,9 @@

    Checks whether the function argument narg has type t.

    -


    luaL_checkudata

    +

    luaL_checkudata

    -          void *luaL_checkudata (lua_State *L, int ud, const char *tname);
    +          void *luaL_checkudata (lua_State *L, int narg, const char *tname);
     
    @@ -3946,7 +3995,7 @@

    of the type tname (see luaL_newmetatable).

    -


    luaL_error

    +

    luaL_error

               int luaL_error (lua_State *L, const char *fmt, ...);
     
    @@ -3954,7 +4003,7 @@

    Raises an error. The error message format is given by fmt -plus any extra argument, +plus any extra arguments, following the same rules of lua_pushfstring. It also adds at the beginning of the message the file name and the line number where the error occurred, @@ -3965,7 +4014,7 @@

    in C functions.

    -


    luaL_getmetafield

    +

    luaL_getmetafield

               int luaL_getmetafield (lua_State *L, int obj, const char *e);
     
    @@ -3978,7 +4027,7 @@

    returns 0 and pushes nothing.

    -


    luaL_getmetatable

    +

    luaL_getmetatable

               void luaL_getmetatable (lua_State *L, const char *tname);
     
    @@ -3988,7 +4037,7 @@

    in the registry (see luaL_newmetatable).

    -


    luaL_gsub

    +

    luaL_gsub

               const char *luaL_gsub (lua_State *L, const char *s,
                                      const char *p, const char *r);
    @@ -4001,7 +4050,7 @@ 

    Pushes the resulting string on the stack and returns it.

    -


    luaL_loadbuffer

    +

    luaL_loadbuffer

               int luaL_loadbuffer (lua_State *L, const char *buff,
                                    size_t sz, const char *name);
    @@ -4017,7 +4066,7 @@ 

    used for debug information and error messages.

    -


    luaL_loadfile

    +

    luaL_loadfile

               int luaL_loadfile (lua_State *L, const char *filename);
     
    @@ -4035,7 +4084,7 @@

    if it cannot open/read the file.

    -


    luaL_loadstring

    +

    luaL_loadstring

               int luaL_loadstring (lua_State *L, const char *s);
     
    @@ -4048,24 +4097,24 @@

    This function returns the same results as lua_load.

    -


    luaL_newmetatable

    +

    luaL_newmetatable

               int luaL_newmetatable (lua_State *L, const char *tname);
     
    -

    If the registry already has the key "tname", +

    If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used as a metatable for userdata, -adds it to the registry with key "tname", +adds it to the registry with key tname, and returns 1.

    In both cases pushes on the stack the final value associated -with "tname" in the registry. +with tname in the registry.

    -


    luaL_newstate

    +

    luaL_newstate

               lua_State *luaL_newstate (void);
     
    @@ -4080,8 +4129,17 @@

    Returns the new state, or NULL if there is a memory allocation error. +

    +


    luaL_openlibs

    +
    +          void luaL_openlibs (lua_State *L);
    +
    + + +

    Opens all standard Lua libraries into the given state. +

    -


    luaL_optint

    +

    luaL_optint

               int luaL_optint (lua_State *L, int narg, int d);
     
    @@ -4094,9 +4152,9 @@

    Otherwise, raises an error.

    -


    luaL_optinteger

    +

    luaL_optinteger

    -          lua_Integer luaL_optinteger (lua_State *L, int nArg, lua_Integer d);
    +          lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer d);
     
    @@ -4107,7 +4165,7 @@

    Otherwise, raises an error.

    -


    luaL_optlong

    +

    luaL_optlong

               long luaL_optlong (lua_State *L, int narg, long d);
     
    @@ -4120,9 +4178,9 @@

    Otherwise, raises an error.

    -


    luaL_optlstring

    +

    luaL_optlstring

    -          const char *luaL_optlstring (lua_State *L, int numArg,
    +          const char *luaL_optlstring (lua_State *L, int narg,
                                            const char *d, size_t *l);
     
    @@ -4137,9 +4195,9 @@

    fills the position *l with the results's length.

    -


    luaL_optnumber

    +

    luaL_optnumber

    -          lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number d);
    +          lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
     
    @@ -4150,7 +4208,7 @@

    Otherwise, raises an error.

    -


    luaL_optstring

    +

    luaL_optstring

               const char *luaL_optstring (lua_State *L, int narg, const char *d);
     
    @@ -4163,7 +4221,7 @@

    Otherwise, raises an error.

    -


    luaL_prepbuffer

    +

    luaL_prepbuffer

               char *luaL_prepbuffer (luaL_Buffer *B);
     
    @@ -4177,7 +4235,7 @@

    it to the buffer.

    -


    luaL_pushresult

    +

    luaL_pushresult

               void luaL_pushresult (luaL_Buffer *B);
     
    @@ -4187,7 +4245,7 @@

    the top of the stack.

    -


    luaL_ref

    +

    luaL_ref

               int luaL_ref (lua_State *L, int t);
     
    @@ -4205,12 +4263,12 @@

    Function luaL_unref frees a reference and its associated object.

    If the object at the top of the stack is nil, -luaL_ref returns the same reference LUA_REFNIL. +luaL_ref returns the constant LUA_REFNIL. The constant LUA_NOREF is guaranteed to be different from any reference returned by luaL_ref.

    -


    luaL_Reg

    +

    luaL_Reg

               typedef struct luaL_Reg {
                 const char *name;
    @@ -4228,7 +4286,7 @@ 

    in which both name and func are NULL.

    -


    luaL_register

    +

    luaL_register

               void luaL_register (lua_State *L, const char *libname,
                                   const luaL_Reg *l);
    @@ -4254,7 +4312,7 @@ 

    on the top of the stack.

    -


    luaL_typename

    +

    luaL_typename

               const char *luaL_typename (lua_State *L, int idx);
     
    @@ -4263,7 +4321,7 @@

    Returns the name of the type of the value at index idx.

    -


    luaL_typerror

    +

    luaL_typerror

               int luaL_typerror (lua_State *L, int narg, const char *tname);
     
    @@ -4278,7 +4336,7 @@

    and <realt> is the type name of the actual argument.

    -


    luaL_unref

    +

    luaL_unref

               void luaL_unref (lua_State *L, int t, int ref);
     
    @@ -4294,7 +4352,7 @@

    luaL_unref does nothing.

    -


    luaL_where

    +

    luaL_where

               void luaL_where (lua_State *L, int lvl);
     
    @@ -4363,14 +4421,14 @@

    you should check carefully whether you need to provide implementations for some of its facilities. -


    assert (v [, message])

    +


    assert (v [, message])

    Issues an error when the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!" -


    collectgarbage (opt [, arg])

    +


    collectgarbage (opt [, arg])

    This function is a generic interface to the garbage collector. It performs different functions according to its first argument, opt: @@ -4393,7 +4451,7 @@

    the collector (see 2.10). -


    dofile (filename)

    +


    dofile (filename)

    Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). @@ -4401,7 +4459,7 @@

    In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode). -


    error (message [, level])

    +


    error (message [, level])

    Terminates the last protected function called and returns message as the error message. Function error never returns. @@ -4416,7 +4474,7 @@

    Passing a level 0 avoids the addition of error position information to the message. -


    _G

    +


    _G

    A global variable (not a function) that holds the global environment (that is, _G._G = _G). Lua itself does not use this variable; @@ -4424,7 +4482,7 @@

    nor vice-versa. (Use setfenv to change environments.) -


    getfenv (f)

    +


    getfenv (f)

    Returns the current environment in use by the function. f can be a Lua function or a number that specifies the function at that stack level: @@ -4434,7 +4492,7 @@

    getfenv returns the global environment. The default for f is 1. -


    getmetatable (object)

    +


    getmetatable (object)

    If object does not have a metatable, returns nil. Otherwise, @@ -4442,7 +4500,7 @@

    returns the associated value. Otherwise, returns the metatable of the given object. -


    ipairs (t)

    +


    ipairs (t)

    Returns three values: an iterator function, the table t, and 0, so that the construction @@ -4454,7 +4512,7 @@

    See next for the caveats of modifying the table during its traversal. -


    load (func [, chunkname])

    +


    load (func [, chunkname])

    Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates @@ -4469,14 +4527,14 @@

    chunkname is used as the chunk name for error messages and debug information. -


    loadfile ([filename])

    +


    loadfile ([filename])

    Similar to load, but gets the chunk from file filename or from the standard input, -if no file name given. +if no file name is given. -


    loadstring (string [, chunkname])

    +


    loadstring (string [, chunkname])

    Similar to load, but gets the chunk from the given string. @@ -4486,7 +4544,7 @@

    assert(loadstring(s))()

    -


    next (table [, index])

    +


    next (table [, index])

    Allows a program to traverse all fields of a table. Its first argument is a table and its second argument @@ -4518,7 +4576,7 @@

    You may however modify existing fields. In particular, you may clear existing fields. -


    pairs (t)

    +


    pairs (t)

    Returns three values: the next function, the table t, and nil, so that the construction @@ -4529,7 +4587,7 @@

    See next for the caveats of modifying the table during its traversal. -


    pcall (f, arg1, arg2, ...)

    +


    pcall (f, arg1, arg2, ...)

    Calls function f with the given arguments in protected mode. @@ -4542,7 +4600,7 @@

    after this first result. In case of any error, pcall returns false plus the error message. -


    print (e1, e2, ...)

    +


    print (e1, e2, ...)

    Receives any number of arguments, and prints their values in stdout, using the tostring function to convert them to strings. @@ -4551,32 +4609,32 @@

    typically for debugging. For formatted output, use string.format. -


    rawequal (v1, v2)

    +


    rawequal (v1, v2)

    Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean. -


    rawget (table, index)

    +


    rawget (table, index)

    Gets the real value of table[index], without invoking any metamethod. table must be a table and index any value different from nil. -


    rawset (table, index, value)

    +


    rawset (table, index, value)

    Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil, and value any Lua value. -


    select (index, ...)

    +


    select (index, ...)

    If index is a number, returns all arguments after argument number index. Otherwise, index must be the string "#", and select returns the total number of extra arguments it received. -


    setfenv (f, table)

    +


    setfenv (f, table)

    Sets the environment to be used by the given function. f can be a Lua function or a number @@ -4588,7 +4646,7 @@

    the environment of the running thread. In this case, setfenv returns no values. -


    setmetatable (table, metatable)

    +


    setmetatable (table, metatable)

    Sets the metatable for the given table. (You cannot change the metatable of other types from Lua, only from C.) @@ -4599,7 +4657,7 @@

    This function returns table. -


    tonumber (e [, base])

    +


    tonumber (e [, base])

    Tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns that number; @@ -4614,7 +4672,7 @@

    as well as an optional exponent part (see 2.1). In other bases, only unsigned integers are accepted. -


    tostring (e)

    +


    tostring (e)

    Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, @@ -4625,7 +4683,7 @@

    with e as argument, and uses the result of the call as its result. -


    type (v)

    +


    type (v)

    Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), @@ -4637,7 +4695,7 @@

    "thread", and "userdata". -


    unpack (list [, i [, j]])

    +


    unpack (list [, i [, j]])

    Returns the elements from the given table. This function is equivalent to
    @@ -4648,12 +4706,12 @@ 

    By default, i is 1 and j is the length of the list, as defined by the length operator (see 2.5.5). -


    _VERSION

    +


    _VERSION

    A global variable (not a function) that holds a string containing the current interpreter version. The current contents of this variable is "Lua 5.1". -


    xpcall (f, err)

    +


    xpcall (f, err)

    This function is similar to pcall, except that you can set a new error handler. @@ -4677,14 +4735,14 @@

    the basic library and come inside the table coroutine. See 2.11 for a general description of coroutines. -


    coroutine.create (f)

    +


    coroutine.create (f)

    Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". -


    coroutine.resume (co [, val1, ..., valn])

    +


    coroutine.resume (co [, val1, ..., valn])

    Starts or continues the execution of coroutine co. The first time you resume a coroutine, @@ -4703,12 +4761,12 @@

    If there is any error, resume returns false plus the error message. -


    coroutine.running ()

    +


    coroutine.running ()

    Returns the running coroutine, or nil when called by the main thread. -


    coroutine.status (co)

    +


    coroutine.status (co)

    Returns the status of coroutine co, as a string: "running", @@ -4720,7 +4778,7 @@

    and "dead" if the coroutine has finished its body function, or if it has stopped with an error. -


    coroutine.wrap (f)

    +


    coroutine.wrap (f)

    Creates a new coroutine, with body f. f must be a Lua function. @@ -4731,7 +4789,7 @@

    except the first boolean. In case of error, propagates the error. -


    coroutine.yield ([val1, ..., valn])

    +


    coroutine.yield ([val1, ..., valn])

    Suspends the execution of the calling coroutine. The coroutine can be running neither a C function, @@ -4746,7 +4804,7 @@

    require and module. Everything else is exported in a table package. -


    module (name [, ...])

    +


    module (name [, ...])

    Creates a module. If there is a table in package.loaded[name], @@ -4776,7 +4834,7 @@

    the module name, where each option is a function to be applied over the module. -


    require (modname)

    +


    require (modname)

    Loads the given module. The function starts by looking into the table package.loaded @@ -4830,14 +4888,14 @@

    If the loader returns no value and has not assigned any value to package.loaded[modname], then require assigns true to that entry. -In any case, require returns the +In any case, require returns the final value of package.loaded[modname].

    If there is any error loading or running the module, or if it cannot find any loader for that module, then require signals an error. -


    package.cpath

    +


    package.cpath

    The path used by require to search for a C loader. @@ -4846,7 +4904,7 @@

    using the environment variable LUA_CPATH (plus another default path defined in luaconf.h). -


    package.loaded

    +


    package.loaded

    A table used by require to control which modules are already loaded. @@ -4854,7 +4912,7 @@

    package.loaded[modname] is not false, require simply returns the value stored there. -


    package.loadlib (libname, funcname)

    +


    package.loadlib (libname, funcname)

    Dynamically links the host program with the C library libname. Inside this library, looks for a function funcname @@ -4864,7 +4922,8 @@

    This is a low-level function. It completely bypasses the package and module system. Unlike require, -it does not perform any path searching or automatically adds extensions. +it does not perform any path searching and +does not automatically adds extensions. libname must be the complete file name of the C library, including if necessary a path and extension. funcname must be the exact name exported by the C library @@ -4875,7 +4934,7 @@

    (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard). -


    package.path

    +


    package.path

    The path used by require to search for a Lua loader. @@ -4901,12 +4960,12 @@

    ./foo.lua, ./foo.lc, and /usr/local/foo/init.lua, in that order. -


    package.preload

    +


    package.preload

    A table to store loaders for specific modules (see require). -


    package.seeall (module)

    +


    package.seeall (module)

    Sets a metatable for module with its __index field referring to the global environment, @@ -4932,7 +4991,7 @@

    For instance, string.byte(s, i) can be written as s:byte(i). -


    string.byte (s [, i [, j]])

    +


    string.byte (s [, i [, j]])

    Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; @@ -4940,7 +4999,7 @@

    Note that numerical codes are not necessarily portable across platforms. -


    string.char (i1, i2, ...)

    +


    string.char (i1, i2, ...)

    Receives 0 or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal @@ -4948,14 +5007,14 @@

    Note that numerical codes are not necessarily portable across platforms. -


    string.dump (function)

    +


    string.dump (function)

    Returns a string containing a binary representation of the given function, so that a later loadstring on that string returns a copy of the function. function must be a Lua function without upvalues. -


    string.find (s, pattern [, init [, plain]])

    +


    string.find (s, pattern [, init [, plain]])

    Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s @@ -4975,7 +5034,7 @@

    the captured values are also returned, after the two indices. -


    string.format (formatstring, e1, e2, ...)

    +


    string.format (formatstring, e1, e2, ...)

    Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of @@ -5008,7 +5067,7 @@

    This function does not accept string values containing embedded zeros. -


    string.gmatch (s, pattern)

    +


    string.gmatch (s, pattern)

    Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. @@ -5035,7 +5094,7 @@

    end

    -


    string.gsub (s, pattern, repl [, n])

    +


    string.gsub (s, pattern, repl [, n])

    Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, @@ -5061,12 +5120,8 @@

    in order; if the pattern specifies no captures, then the whole match is passed as a sole argument. -If repl is a table, then this table is queried with the -value of the first capture or of the whole match, -if the pattern specifies no captures. -

    In both cases, -if the value returned by the function or by the table query +

    If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, @@ -5102,19 +5157,19 @@

    --> x="lua-5.1.tar.gz"

    -


    string.len (s)

    +


    string.len (s)

    Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5. -


    string.lower (s)

    +


    string.lower (s)

    Receives a string and returns a copy of that string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. -


    string.match (s, pattern [, init])

    +


    string.match (s, pattern [, init])

    Looks for the first match of pattern in the string s. If it finds one, then match returns @@ -5126,14 +5181,14 @@

    where to start the search; its default value is 1 and may be negative. -


    string.rep (s, n)

    +


    string.rep (s, n)

    Returns a string that is the concatenation of n copies of the string s. -


    string.reverse (s)

    +


    string.reverse (s)

    Returns a string that is the string s reversed. -


    string.sub (s, i [, j])

    +


    string.sub (s, i [, j])

    Returns the substring of s that starts at i and continues until j; i and j may be negative. @@ -5145,7 +5200,7 @@

    and string.sub(s, -i) returns a suffix of s with length i. -


    string.upper (s)

    +


    string.upper (s)

    Receives a string and returns a copy of that string with all lowercase letters changed to uppercase. All other characters are left unchanged. @@ -5279,17 +5334,17 @@

    Most functions in the table library assume that the table represents an array or a list. -For those functions, when we talk about "the length" of a table +For those functions, when we talk about the "length" of a table we mean the result of the length operator. -


    table.concat (table [, sep [, i [, j]]])

    +


    table.concat (table [, sep [, i [, j]]])

    Returns table[i]..sep..table[i+1] ... sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string. -


    table.insert (table, [pos,] value)

    +


    table.insert (table, [pos,] value)

    Inserts element value at position pos in table, shifting up other elements to open space, if necessary. @@ -5298,14 +5353,14 @@

    so that a call table.insert(t,x) inserts x at the end of table t. -


    table.maxn (table)

    +


    table.maxn (table)

    Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. (To do its job this function does a linear traversal of the whole table.) -


    table.remove (table [, pos])

    +


    table.remove (table [, pos])

    Removes from table the element at position pos, shifting down other elements to close the space, if necessary. @@ -5315,7 +5370,7 @@

    so that a call table.remove(t) removes the last element of table t. -


    table.sort (table [, comp])

    +


    table.sort (table [, comp])

    Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. @@ -5336,16 +5391,17 @@

    This library is an interface to the standard C math library. It provides all its functions inside the table math. The library provides the following functions: - - - - - - - + + + + + + + +

            math.abs     math.acos    math.asin    math.atan    math.atan2
    -       math.ceil    math.cosh    math.cos     math.deg     math.exp
    +       math.ceil    math.cos     math.cosh    math.deg     math.exp
            math.floor   math.fmod    math.frexp   math.ldexp   math.log
            math.log10   math.max     math.min     math.modf    math.pow
            math.rad     math.random  math.randomseed           math.sin
    @@ -5413,16 +5469,16 @@ 

    (plus an error message as a second result) and some value different from nil on success. -


    io.close ([file])

    +


    io.close ([file])

    Equivalent to file:close(). Without a file, closes the default output file. -


    io.flush ()

    +


    io.flush ()

    Equivalent to file:flush over the default output file. -


    io.input ([file])

    +


    io.input ([file])

    When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. @@ -5434,7 +5490,7 @@

    In case of errors this function raises the error, instead of returning an error code. -


    io.lines ([filename])

    +


    io.lines ([filename])

    Opens the given file name in read mode and returns an iterator function that, @@ -5453,7 +5509,7 @@

    that is, it iterates over the lines of the default input file. In that case it does not close the file when the loop ends. -


    io.open (filename [, mode])

    +


    io.open (filename [, mode])

    This function opens a file, in the mode specified in the string mode. @@ -5475,11 +5531,11 @@

    This string is exactly what is used in the standard C function fopen. -


    io.output ([file])

    +


    io.output ([file])

    Similar to io.input, but operates over the default output file. -


    io.popen ([prog [, mode]])

    +


    io.popen ([prog [, mode]])

    Starts program prog in a separated process and returns a file handle that you can use to read data from that program @@ -5490,39 +5546,39 @@

    This function is system dependent and is not available on all platforms. -


    io.read (format1, ...)

    +


    io.read (format1, ...)

    Equivalent to io.input():read. -


    io.tmpfile ()

    +


    io.tmpfile ()

    Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. -


    io.type (obj)

    +


    io.type (obj)

    Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, and nil if obj is not a file handle. -


    io.write (value1, ...)

    +


    io.write (value1, ...)

    Equivalent to io.output():write. -


    file:close ()

    +


    file:close ()

    Closes file. Note that files are automatically closed when their handles are garbage collected, -but that takes an unpredictable time to happen. +but that takes an unpredictable amount of time to happen. -


    file:flush ()

    +


    file:flush ()

    Saves any written data to file. -


    file:lines ()

    +


    file:lines ()

    Returns an iterator function that, each time it is called, @@ -5535,7 +5591,7 @@

    (Unlike io.lines, this function does not close the file when the loop ends.) -


    file:read (format1, ...)

    +


    file:read (format1, ...)

    Reads the file file, according to the given formats, which specify what to read. @@ -5562,16 +5618,16 @@

    or nil on end of file. -


    file:seek ([whence] [, offset])

    +


    file:seek ([whence] [, offset])

    Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows:

      -
    • "set" base is position 0 (beginning of the file); -
    • "cur" base is current position; -
    • "end" base is end of file; +
    • "set" --- base is position 0 (beginning of the file); +
    • "cur" --- base is current position; +
    • "end" --- base is end of file;
    In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. @@ -5587,7 +5643,7 @@

    and the call file:seek("end") sets the position to the end of the file, and returns its size. -


    file:setvbuf (mode [, size])

    +


    file:setvbuf (mode [, size])

    Sets the buffering mode for an output file. There are three available modes: @@ -5606,7 +5662,7 @@

    specifies the size of the buffer, in bytes. The default is an appropriate size. -


    file:write (value1, ...)

    +


    file:write (value1, ...)

    Writes the value of each of its arguments to the file. @@ -5618,12 +5674,12 @@

    This library is implemented through table os. -


    os.clock ()

    +


    os.clock ()

    Returns an approximation of the amount in seconds of CPU time used by the program. -


    os.date ([format [, time]])

    +


    os.date ([format [, time]])

    Returns a string or a table containing date and time, formatted according to the given string format. @@ -5653,13 +5709,13 @@

    the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")). -


    os.difftime (t2, t1)

    +


    os.difftime (t2, t1)

    Returns the number of seconds from time t1 to time t2. -In Posix, Windows, and some other systems, +In POSIX, Windows, and some other systems, this value is exactly t2-t1. -


    os.execute ([command])

    +


    os.execute ([command])

    This function is equivalent to the C function system. It passes command to be executed by an operating system shell. @@ -5667,32 +5723,32 @@

    If command is absent, then it returns nonzero if a shell is available and zero otherwise. -


    os.exit ([code])

    +


    os.exit ([code])

    Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. -


    os.getenv (varname)

    +


    os.getenv (varname)

    Returns the value of the process environment variable varname, or nil if the variable is not defined. -


    os.remove (filename)

    +


    os.remove (filename)

    Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error. -


    os.rename (oldname, newname)

    +


    os.rename (oldname, newname)

    Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error. -


    os.setlocale (locale [, category])

    +


    os.setlocale (locale [, category])

    Sets the current locale of the program. locale is a string specifying a locale; @@ -5703,7 +5759,7 @@

    The function returns the name of the new locale, or nil if the request cannot be honored. -


    os.time ([table])

    +


    os.time ([table])

    Returns the current time when called without arguments, or a time representing the date and time specified by the given table. @@ -5712,13 +5768,13 @@

    (for a description of these fields, see the os.date function).

    The returned value is a number, whose meaning depends on your system. -In Posix, Windows, and some other systems, this number counts the number +In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to date and difftime. -


    os.tmpname ()

    +


    os.tmpname ()

    Returns a string with a file name that can be used for a temporary file. @@ -5745,7 +5801,7 @@

    All functions in this library are provided inside the debug table. -


    debug.debug ()

    +


    debug.debug ()

    Enters an interactive mode with the user, running each string that the user enters. @@ -5758,17 +5814,17 @@

    Note that commands for debug.debug are not lexically nested within any function, and so have no direct access to local variables. -


    debug.getfenv (o)

    +


    debug.getfenv (o)

    Returns the environment of object o. -


    debug.gethook ()

    +


    debug.gethook ()

    Returns the current hook settings, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function). -


    debug.getinfo (function [, what])

    +


    debug.getinfo (function [, what])

    Returns a table with information about a function. You can give the function directly, @@ -5792,7 +5848,7 @@

    and debug.getinfo(print) returns a table with all available information about the print function. -


    debug.getlocal (level, local)

    +


    debug.getlocal (level, local)

    This function returns the name and the value of the local variable with index local of the function at level level of the stack. @@ -5807,26 +5863,26 @@

    represent internal variables (loop control variables, temporaries, and C function locals). -


    debug.getmetatable (object)

    +


    debug.getmetatable (object)

    Returns the metatable of the given object or nil if it does not have a metatable. -


    debug.getregistry ()

    +


    debug.getregistry ()

    Returns the registry table (see 3.5). -


    debug.getupvalue (func, up)

    +


    debug.getupvalue (func, up)

    This function returns the name and the value of the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index. -


    debug.setfenv (object, table)

    +


    debug.setfenv (object, table)

    Sets the environment of the given object to the given table. -


    debug.sethook (hook, mask [, count])

    +


    debug.sethook (hook, mask [, count])

    Sets the given function as a hook. The string mask and the number count describe @@ -5859,7 +5915,7 @@

    In this case, Lua is only simulating the return, and a call to getinfo will return invalid data. -


    debug.setlocal (level, local, value)

    +


    debug.setlocal (level, local, value)

    This function assigns the value value to the local variable with index local of the function at level level of the stack. @@ -5869,12 +5925,12 @@

    (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable. -


    debug.setmetatable (object, table)

    +


    debug.setmetatable (object, table)

    -

    Sets the metatable for the given object to the given id@{table} +

    Sets the metatable for the given object to the given table (which can be nil). -


    debug.setupvalue (func, up, value)

    +


    debug.setupvalue (func, up, value)

    This function assigns the value value to the upvalue with index up of the function func. @@ -5882,7 +5938,7 @@

    with the given index. Otherwise, it returns the name of the upvalue. -


    debug.traceback ([message])

    +


    debug.traceback ([message])

    Returns a string with a traceback of the call stack. An optional message string is appended @@ -5969,7 +6025,7 @@

    If the global variable _PROMPT contains a string, then its value is used as the prompt. Similarly, if the global variable _PROMPT2 contains a string, -it its value is used as the secondary prompt +its value is used as the secondary prompt (issued during incomplete statements). Therefore, both prompts can be changed directly on the command line. For instance, @@ -6001,7 +6057,7 @@

    is a more portable solution.) -


    +


    Incompatibilities with the Previous Version

    @@ -6110,7 +6166,7 @@

    Here is the complete syntax of Lua in extended BNF. -It does not describe operator priorities nor some syntactical restrictions, +It does not describe operator priorities or some syntactical restrictions, such as return and break statements can only appear as the last statement of a block. diff --git a/etc/Makefile b/etc/Makefile index 2dfc937ce7..02f0942336 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -8,14 +8,15 @@ SRC= $(TOP)/src TST= $(TOP)/test CC= gcc -CFLAGS= -O2 -Wall $(MYCFLAGS) -MYCFLAGS= -ansi -I$(INC) +CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) +MYCFLAGS= MYLDFLAGS= -Wl,-E -MYLIBS= -lm -ldl +MYLIBS= -lm +#MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses RM= rm -f -all: - @echo 'choose a target: min noparser one clean' +default: + @echo 'Please choose a target: min noparser one clean' min: min.c $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS) @@ -31,5 +32,13 @@ one: $(CC) $(CFLAGS) all.c $(MYLIBS) ./a.out $(TST)/hello.lua +strict: + -$(BIN)/lua -e 'print(a);b=2' + -$(BIN)/lua -lstrict -e 'print(a)' + -$(BIN)/lua -e 'function f() b=2 end f()' + -$(BIN)/lua -lstrict -e 'function f() b=2 end f()' + clean: - $(RM) noparser.o a.out core core.* *.o luac.out + $(RM) a.out core core.* *.o luac.out + +.PHONY: default min noparser one strict clean diff --git a/etc/README b/etc/README index 5e42ec5652..ad9ca6ab87 100644 --- a/etc/README +++ b/etc/README @@ -1,9 +1,12 @@ This directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. +If any of the makes fail, you're probably not using the same libraries +used to build Lua. Set MYLIBS in Makefile accordingly. + all.c Full Lua interpreter in a single file. - Do "make one". + Do "make one" for a demo. lua.hpp Lua header files for C++ using 'extern "C"'. @@ -21,11 +24,13 @@ luavs.bat min.c A minimal Lua interpreter. Good for learning and for starting your own. + Do "make min" for a demo. noparser.c Linking with noparser.o avoids loading the parsing modules in lualib.a. - Do "make noparser" to see a demo. + Do "make noparser" for a demo. strict.lua Traps uses of undeclared global variables. + Do "make strict" for a demo. diff --git a/etc/lua.pc b/etc/lua.pc index f0d6e2ff7a..5fd2b1ed1f 100644 --- a/etc/lua.pc +++ b/etc/lua.pc @@ -1,19 +1,19 @@ # lua.pc -- pkg-config data for Lua # vars from install Makefile -# grep '^INSTALL_.*=' ../Makefile -INSTALL_TOP= /usr/local -INSTALL_BIN= $(INSTALL_TOP)/bin -INSTALL_INC= $(INSTALL_TOP)/include -INSTALL_LIB= $(INSTALL_TOP)/lib -INSTALL_MAN= $(INSTALL_TOP)/man/man1 -INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V -INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V # grep '^V=' ../Makefile V= 5.1 -prefix=${INSTALL_TOP} +# grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' +prefix= /usr/local +INSTALL_BIN= ${prefix}/bin +INSTALL_INC= ${prefix}/include +INSTALL_LIB= ${prefix}/lib +INSTALL_MAN= ${prefix}/man/man1 +INSTALL_LMOD= ${prefix}/share/lua/${V} +INSTALL_CMOD= ${prefix}/lib/lua/${V} + exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include diff --git a/src/Makefile b/src/Makefile index 13d0d4970d..fb69ce1e13 100644 --- a/src/Makefile +++ b/src/Makefile @@ -107,6 +107,8 @@ posix: solaris: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" +# list targets that do not create files (but not all makes understand .PHONY) +.PHONY: all $(PLATS) default o a clean depend echo none # DO NOT DELETE diff --git a/src/liolib.c b/src/liolib.c index fd7894c9ef..bb3b5194d9 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.71 2006/01/17 13:54:02 roberto Exp $ +** $Id: liolib.c,v 2.72 2006/01/28 12:59:13 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -283,7 +283,7 @@ static int read_line (lua_State *L, FILE *f) { return (lua_strlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); - if (p[l-1] != '\n') + if (l == 0 || p[l-1] != '\n') luaL_addsize(&b, l); else { luaL_addsize(&b, l - 1); /* do not include `eol' */ diff --git a/src/llex.c b/src/llex.c index 9918b2f4a2..f3022df596 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.18 2006/01/23 20:06:19 roberto Exp $ +** $Id: llex.c,v 2.19 2006/02/06 18:28:16 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -166,7 +166,7 @@ static int check_next (LexState *ls, const char *set) { static void buffreplace (LexState *ls, char from, char to) { - int n = luaZ_bufflen(ls->buff); + size_t n = luaZ_bufflen(ls->buff); char *p = luaZ_buffer(ls->buff); while (n--) if (p[n] == from) p[n] = to; diff --git a/src/loslib.c b/src/loslib.c index 235377e4f5..509d7b72e4 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.16 2005/12/22 16:19:56 roberto Exp $ +** $Id: loslib.c,v 1.17 2006/01/27 13:54:31 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -21,6 +21,7 @@ static int os_pushresult (lua_State *L, int i, const char *filename) { + int en = errno; /* calls to Lua API may change this value */ if (i) { lua_pushboolean(L, 1); return 1; @@ -28,10 +29,10 @@ static int os_pushresult (lua_State *L, int i, const char *filename) { else { lua_pushnil(L); if (filename) - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); else - lua_pushfstring(L, "%s", strerror(errno)); - lua_pushinteger(L, errno); + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); return 3; } } diff --git a/src/lstate.h b/src/lstate.h index e8bc15ab9a..d296a4cab9 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.23 2005/07/09 13:22:34 roberto Exp $ +** $Id: lstate.h,v 2.24 2006/02/06 18:27:59 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -49,8 +49,8 @@ typedef struct CallInfo { StkId base; /* base for this function */ StkId func; /* function index in the stack */ StkId top; /* top for this function */ - int nresults; /* expected number of results from this function */ const Instruction *savedpc; + int nresults; /* expected number of results from this function */ int tailcalls; /* number of tail calls lost under this entry */ } CallInfo; @@ -71,9 +71,9 @@ typedef struct global_State { void *ud; /* auxiliary data to `frealloc' */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ + int sweepstrgc; /* position of sweep in `strt' */ GCObject *rootgc; /* list of all collectable objects */ GCObject **sweepgc; /* position of sweep in `rootgc' */ - int sweepstrgc; /* position of sweep in `strt' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of weak tables (to be cleared) */ @@ -99,6 +99,7 @@ typedef struct global_State { */ struct lua_State { CommonHeader; + lu_byte status; StkId top; /* first free slot in the stack */ StkId base; /* base of current function */ global_State *l_G; @@ -106,14 +107,13 @@ struct lua_State { const Instruction *savedpc; /* `savedpc' of current function */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ - int stacksize; CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo's */ + int stacksize; int size_ci; /* size of array `base_ci' */ unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; - lu_byte status; int basehookcount; int hookcount; lua_Hook hook; diff --git a/src/luaconf.h b/src/luaconf.h index 5670598590..3f3e2bbef4 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.79 2006/01/23 19:51:43 roberto Exp $ +** $Id: luaconf.h,v 1.80 2006/01/27 13:54:39 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -541,7 +541,7 @@ */ /* On a Pentium, resort to a trick */ -#if !defined(LUA_ANSI) && !defined(__SSE2__) && \ +#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ (defined(__i386) || defined (_M_IX86) || defined(__i386__)) union luai_Cast { double l_d; long l_l; }; #define lua_number2int(i,d) \ From 69c6ee1f592c6588bc11a8e02811230e77e984cf Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 10 Feb 2006 12:00:00 +0000 Subject: [PATCH 29/97] Lua 5.1-rc4 --- MANIFEST | 28 ++++++++++++++-------------- doc/contents.html | 4 +++- doc/manual.html | 6 +++++- etc/Makefile | 2 +- etc/min.c | 17 ++++------------- src/lobject.c | 4 +++- src/luaconf.h | 8 ++++---- 7 files changed, 34 insertions(+), 35 deletions(-) diff --git a/MANIFEST b/MANIFEST index 1f70c5e8d5..cf063eea74 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,34 +1,33 @@ -MANIFEST contents of Lua 5.1 distribution on Tue Feb 7 15:05:04 BRST 2006 +MANIFEST contents of Lua 5.1 distribution on Fri Feb 10 17:19:52 BRST 2006 lua-5.1 lua-5.1/COPYRIGHT -lua-5.1/HISTORY -lua-5.1/INSTALL -lua-5.1/MANIFEST -lua-5.1/Makefile -lua-5.1/README lua-5.1/doc lua-5.1/doc/contents.html lua-5.1/doc/logo.gif lua-5.1/doc/lua.1 -lua-5.1/doc/lua.css -lua-5.1/doc/lua.html lua-5.1/doc/luac.1 lua-5.1/doc/luac.html +lua-5.1/doc/lua.css +lua-5.1/doc/lua.html lua-5.1/doc/manual.html lua-5.1/doc/readme.html lua-5.1/etc -lua-5.1/etc/Makefile -lua-5.1/etc/README lua-5.1/etc/all.c lua-5.1/etc/lua.hpp lua-5.1/etc/lua.ico lua-5.1/etc/lua.pc lua-5.1/etc/luavs.bat +lua-5.1/etc/Makefile lua-5.1/etc/min.c lua-5.1/etc/noparser.c +lua-5.1/etc/README lua-5.1/etc/strict.lua +lua-5.1/HISTORY +lua-5.1/INSTALL +lua-5.1/Makefile +lua-5.1/MANIFEST +lua-5.1/README lua-5.1/src -lua-5.1/src/Makefile lua-5.1/src/lapi.c lua-5.1/src/lapi.h lua-5.1/src/lauxlib.c @@ -73,9 +72,9 @@ lua-5.1/src/ltablib.c lua-5.1/src/ltm.c lua-5.1/src/ltm.h lua-5.1/src/lua.c -lua-5.1/src/lua.h lua-5.1/src/luac.c lua-5.1/src/luaconf.h +lua-5.1/src/lua.h lua-5.1/src/lualib.h lua-5.1/src/lundump.c lua-5.1/src/lundump.h @@ -83,21 +82,22 @@ lua-5.1/src/lvm.c lua-5.1/src/lvm.h lua-5.1/src/lzio.c lua-5.1/src/lzio.h +lua-5.1/src/Makefile lua-5.1/src/print.c lua-5.1/test -lua-5.1/test/README lua-5.1/test/bisect.lua lua-5.1/test/cf.lua lua-5.1/test/echo.lua lua-5.1/test/env.lua lua-5.1/test/factorial.lua -lua-5.1/test/fib.lua lua-5.1/test/fibfor.lua +lua-5.1/test/fib.lua lua-5.1/test/globals.lua lua-5.1/test/hello.lua lua-5.1/test/life.lua lua-5.1/test/luac.lua lua-5.1/test/printf.lua +lua-5.1/test/README lua-5.1/test/readonly.lua lua-5.1/test/sieve.lua lua-5.1/test/sort.lua diff --git a/doc/contents.html b/doc/contents.html index 323bfaef65..564377c942 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -93,7 +93,9 @@

    Contents

  • 5.9 - The Debug Library
  • 6 - Lua Stand-alone +
  • Incompatibilities with the Previous Version
  • The Complete Syntax of Lua +

    Quick index

    @@ -396,7 +398,7 @@

    Auxiliary library


    Last update: -Tue Feb 7 14:37:59 BRST 2006 +Fri Feb 10 17:15:37 BRST 2006 diff --git a/doc/manual.html b/doc/manual.html index e7a3cfa47c..3ec55870c6 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -6059,7 +6059,7 @@


    -

    Incompatibilities with the Previous Version

    +

    Incompatibilities with the Previous Version

    Here we list the incompatibilities that may be found when moving a program @@ -6118,6 +6118,10 @@

    Function math.mod was renamed math.fmod. (Option LUA_COMPAT_MOD) +

  • +Functions table.foreach and table.foreachi are deprecated. +You can use a for loop with pairs or ipairs instead. +

  • There were substantial changes in function require due to the new module system. diff --git a/etc/Makefile b/etc/Makefile index 02f0942336..6d00008d98 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -16,7 +16,7 @@ MYLIBS= -lm RM= rm -f default: - @echo 'Please choose a target: min noparser one clean' + @echo 'Please choose a target: min noparser one strict clean' min: min.c $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS) diff --git a/etc/min.c b/etc/min.c index b1200c05c0..404bd50385 100644 --- a/etc/min.c +++ b/etc/min.c @@ -5,6 +5,7 @@ */ #include + #include "lua.h" #include "lauxlib.h" @@ -17,32 +18,22 @@ static int print(lua_State *L) if (i>1) printf("\t"); if (lua_isstring(L,i)) printf("%s",lua_tostring(L,i)); - else if (lua_isnil(L,i)) + else if (lua_isnil(L,i)==2) printf("%s","nil"); else if (lua_isboolean(L,i)) printf("%s",lua_toboolean(L,i) ? "true" : "false"); else - printf("%s:%p",lua_typename(L,lua_type(L,i)),lua_topointer(L,i)); + printf("%s:%p",luaL_typename(L,i),lua_topointer(L,i)); } printf("\n"); return 0; } -static const char *getF(lua_State *L, void *ud, size_t *size) -{ - FILE *f=(FILE *)ud; - static char buff[512]; - if (feof(f)) return NULL; - *size=fread(buff,1,sizeof(buff),f); - return (*size>0) ? buff : NULL; -} - int main(void) { lua_State *L=lua_open(); lua_register(L,"print",print); - if (lua_load(L,getF,stdin,"=stdin") || lua_pcall(L,0,0,0)) - fprintf(stderr,"%s\n",lua_tostring(L,-1)); + if (luaL_dofile(L,NULL)!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); lua_close(L); return 0; } diff --git a/src/lobject.c b/src/lobject.c index e83b5240c9..acde82ccdf 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.21 2006/01/10 12:50:00 roberto Exp $ +** $Id: lobject.c,v 2.22 2006/02/10 17:43:52 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -91,6 +91,8 @@ int luaO_str2d (const char *s, lua_Number *result) { char *endptr; *result = lua_str2number(s, &endptr); if (endptr == s) return 0; /* conversion failed */ + if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ + *result = cast_num(strtoul(s, &endptr, 16)); if (*endptr == '\0') return 1; /* most common case */ while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ diff --git a/src/luaconf.h b/src/luaconf.h index 3f3e2bbef4..97a3e30c0e 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.80 2006/01/27 13:54:39 roberto Exp $ +** $Id: luaconf.h,v 1.81 2006/02/10 17:44:06 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -650,9 +650,9 @@ union luai_Cast { double l_d; long l_l; }; #else -#define lua_popen(L,c,m) \ - ((void)c, (void)m, luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) -#define lua_pclose(L,file) ((void)L, (void)file, 0) +#define lua_popen(L,c,m) ((void)((void)c, m), \ + luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) +#define lua_pclose(L,file) ((void)((void)L, file), 0) #endif From f6f9af6cbce3516054b6fd2a8e9d3a1b168ce4be Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 21 Feb 2006 12:00:00 +0000 Subject: [PATCH 30/97] Lua 5.1 --- HISTORY | 4 +- MANIFEST | 28 +++--- Makefile | 22 +++-- doc/luac.1 | 2 +- doc/luac.html | 2 +- doc/manual.html | 248 ++++++++++++++++++++++++------------------------ src/Makefile | 7 +- src/ldump.c | 4 +- src/lundump.c | 4 +- 9 files changed, 165 insertions(+), 156 deletions(-) diff --git a/HISTORY b/HISTORY index 885c35baf9..d807a53383 100644 --- a/HISTORY +++ b/HISTORY @@ -20,8 +20,8 @@ HISTORY for Lua 5.1 + incremental garbage collection. + better handling of end-of-line in the lexer. + fully reentrant parser (new Lua function `load') - + better support for 64-bit machines (special thanks to Mike Pall). - + native loadlib support for Mac OS X (thanks to Matthew Cox). + + better support for 64-bit machines. + + native loadlib support for Mac OS X. + standard distribution in only one library (lualib.a merged into lua.a) * Changes from version 4.0 to 5.0 diff --git a/MANIFEST b/MANIFEST index cf063eea74..fd18c8bb9e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,33 +1,34 @@ -MANIFEST contents of Lua 5.1 distribution on Fri Feb 10 17:19:52 BRST 2006 +MANIFEST contents of Lua 5.1 distribution on Mon Feb 20 11:37:30 BRT 2006 lua-5.1 lua-5.1/COPYRIGHT +lua-5.1/HISTORY +lua-5.1/INSTALL +lua-5.1/MANIFEST +lua-5.1/Makefile +lua-5.1/README lua-5.1/doc lua-5.1/doc/contents.html lua-5.1/doc/logo.gif lua-5.1/doc/lua.1 -lua-5.1/doc/luac.1 -lua-5.1/doc/luac.html lua-5.1/doc/lua.css lua-5.1/doc/lua.html +lua-5.1/doc/luac.1 +lua-5.1/doc/luac.html lua-5.1/doc/manual.html lua-5.1/doc/readme.html lua-5.1/etc +lua-5.1/etc/Makefile +lua-5.1/etc/README lua-5.1/etc/all.c lua-5.1/etc/lua.hpp lua-5.1/etc/lua.ico lua-5.1/etc/lua.pc lua-5.1/etc/luavs.bat -lua-5.1/etc/Makefile lua-5.1/etc/min.c lua-5.1/etc/noparser.c -lua-5.1/etc/README lua-5.1/etc/strict.lua -lua-5.1/HISTORY -lua-5.1/INSTALL -lua-5.1/Makefile -lua-5.1/MANIFEST -lua-5.1/README lua-5.1/src +lua-5.1/src/Makefile lua-5.1/src/lapi.c lua-5.1/src/lapi.h lua-5.1/src/lauxlib.c @@ -72,9 +73,9 @@ lua-5.1/src/ltablib.c lua-5.1/src/ltm.c lua-5.1/src/ltm.h lua-5.1/src/lua.c +lua-5.1/src/lua.h lua-5.1/src/luac.c lua-5.1/src/luaconf.h -lua-5.1/src/lua.h lua-5.1/src/lualib.h lua-5.1/src/lundump.c lua-5.1/src/lundump.h @@ -82,22 +83,21 @@ lua-5.1/src/lvm.c lua-5.1/src/lvm.h lua-5.1/src/lzio.c lua-5.1/src/lzio.h -lua-5.1/src/Makefile lua-5.1/src/print.c lua-5.1/test +lua-5.1/test/README lua-5.1/test/bisect.lua lua-5.1/test/cf.lua lua-5.1/test/echo.lua lua-5.1/test/env.lua lua-5.1/test/factorial.lua -lua-5.1/test/fibfor.lua lua-5.1/test/fib.lua +lua-5.1/test/fibfor.lua lua-5.1/test/globals.lua lua-5.1/test/hello.lua lua-5.1/test/life.lua lua-5.1/test/luac.lua lua-5.1/test/printf.lua -lua-5.1/test/README lua-5.1/test/readonly.lua lua-5.1/test/sieve.lua lua-5.1/test/sort.lua diff --git a/Makefile b/Makefile index 682256b426..56a9b665dd 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ RANLIB= ranlib # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= # Convenience platforms targets. -PLATS= ansi bsd generic linux macosx mingw posix solaris +PLATS= aix ansi bsd generic linux macosx mingw posix solaris # What to install. TO_BIN= lua luac @@ -51,24 +51,28 @@ V= 5.1 all: $(PLAT) $(PLATS) clean: - cd src; $(MAKE) $@ + cd src && $(MAKE) $@ test: dummy src/lua test/hello.lua install: dummy - cd src; $(MKDIR) -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) - cd src; $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) - cd src; $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) - cd src; $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) - cd doc; $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) + cd src && $(MKDIR) -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) + cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) + cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) + cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) + cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) # $(RANLIB) $(INSTALL_LIB)/$(TO_LIB) local: $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -p" INSTALL_DATA="cp -p" none: - @echo "Please choose a platform: $(PLATS)" + @echo "Please do" + @echo " make PLATFORM" + @echo "where PLATFORM is one of these:" + @echo " $(PLATS)" + @echo "See INSTALL for complete instructions." # make may get confused with test/ and INSTALL in a case-insensitive OS dummy: @@ -78,7 +82,7 @@ echo: @echo "" @echo "These are the parameters currently set in src/Makefile to build Lua $V:" @echo "" - @cd src; $(MAKE) -s echo + @cd src && $(MAKE) -s echo @echo "" @echo "These are the parameters currently set in Makefile to install Lua $V:" @echo "" diff --git a/doc/luac.1 b/doc/luac.1 index 6bede1f363..d8146782df 100644 --- a/doc/luac.1 +++ b/doc/luac.1 @@ -13,7 +13,7 @@ luac \- Lua compiler .B luac is the Lua compiler. It translates programs written in the Lua programming language -into binary files that can be latter loaded and executed. +into binary files that can be later loaded and executed. .LP The main advantages of precompiling chunks are: faster loading, diff --git a/doc/luac.html b/doc/luac.html index 7b7e0f7002..179ffe8288 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -20,7 +20,7 @@

    DESCRIPTION

    luac is the Lua compiler. It translates programs written in the Lua programming language -into binary files that can be latter loaded and executed. +into binary files that can be later loaded and executed.

    The main advantages of precompiling chunks are: faster loading, diff --git a/doc/manual.html b/doc/manual.html index 3ec55870c6..a44d2e8ea3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -194,9 +194,11 @@

    Numerical constants may be written with an optional decimal part and an optional decimal exponent. +Lua also accepts integer hexadecimal constants, +by prefixing them with 0x. Examples of valid numerical constants are

    -       3     3.0     3.1416  314.16e-2   0.31416E1
    +       3       3.0     3.1416  314.16e-2   0.31416E1  0xff  0x56
     

    Comments start with a double hyphen (--) @@ -211,13 +213,13 @@

    2.2 - Values and Types

    Lua is a dynamically typed language. -That means that +This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type.

    All values in Lua are first-class values. -That means that all values can be stored in variables, +This means that all values can be stored in variables, passed as arguments to other functions, and returned as results.

    There are eight basic types in Lua: @@ -284,7 +286,7 @@

    table fields may contain functions. Thus tables may also carry methods (see 2.5.9). -

    Strings, tables, functions, and userdata values are objects: +

    Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns @@ -299,7 +301,7 @@

    Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert -that string to a number, following the usual conversion rules. +this string to a number, following the usual conversion rules. Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control over how numbers are converted to strings, @@ -314,7 +316,7 @@

    global variables, local variables, and table fields.

    A single name can denote a global variable or a local variable -(or a function formal parameter, +(or a function's formal parameter, which is a particular kind of local variable):

     	var ::= Name
    @@ -335,7 +337,7 @@ 

    The first expression (prefixexp) should result in a table value; the second expression (exp) -identifies a specific entry in that table. +identifies a specific entry in this table. The expression denoting the table to be indexed has a restricted syntax; see 2.5 for details. @@ -358,12 +360,12 @@

    called environment tables or simply environments (see 2.9). Each function has its own reference to an environment, -so that all global variables in that function -will refer to that environment table. +so that all global variables in this function +will refer to this environment table. When a function is created, it inherits the environment from the function that created it. To get the environment table of a Lua function, -you call setfenv. +you call getfenv. To replace it, you call setfenv. (You can only manipulate the environment of C functions @@ -459,7 +461,7 @@

    If there are fewer values than needed, the list is extended with as many nil's as needed. If the list of expressions ends with a function call, -then all values returned by that call enter in the list of values, +then all values returned by this call enter in the list of values, before the adjustment (except when the call is enclosed in parentheses; see 2.5). @@ -825,7 +827,7 @@

    false or nil --> nil 10 and 20 --> 20

  • -(Here and in the sequel, +(In this manual, `-->´ indicates the result of the preceding expression.)

    2.5.4 - Concatenation

    @@ -917,7 +919,7 @@

    If the last field in the list has the form exp and the expression is a function call or a vararg expression, -then all values returned by that expression enter the list consecutively +then all values returned by this expression enter the list consecutively (see 2.5.8). To avoid this, enclose the function call (or the vararg expression) @@ -934,7 +936,7 @@

    In a function call, first prefixexp and args are evaluated. If the value of prefixexp has type function, -then that function is called +then this function is called with the given arguments. Otherwise, the prefixexp "call" metamethod is called, having as first parameter the value of prefixexp, @@ -965,7 +967,7 @@

    As an exception to the free-format syntax of Lua, you cannot put a line break before the `(´ in a function call. -That restriction avoids some ambiguities in the language. +This restriction avoids some ambiguities in the language. If you write

            a = f
    @@ -1196,7 +1198,7 @@ 

    For instance, when a non-numeric value is the operand of an addition, Lua checks for a function in the field "__add" in its metatable. If it finds one, -Lua calls that function to perform the addition. +Lua calls this function to perform the addition.

    We call the keys in a metatable events and the values metamethods. @@ -1224,10 +1226,10 @@

    order comparisons, concatenation, length operation, and indexing. A metatable can also define a function to be called when a userdata is garbage collected. -For each of those operations Lua associates a specific key +For each of these operations Lua associates a specific key called an event. -When Lua performs one of those operations over a value, -it checks whether that value has a metatable with the corresponding event. +When Lua performs one of these operations over a value, +it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) controls how Lua will perform the operation. @@ -1238,7 +1240,7 @@

    for instance, the key for operation "add" is the string "__add". The semantics of these operations is better explained by a Lua function -describing how the interpreter executes that operation. +describing how the interpreter executes the operation.

    The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter @@ -1273,7 +1275,7 @@

    return metatable(op1)[event] or metatable(op2)[event] end

    -Using that function, +Using this function, the behavior of the op1 + op2 is
      function add_event (op1, op2)
    @@ -1539,19 +1541,19 @@ 

    Environments associated with threads are called global environments. They are used as the default environment for threads and -non-nested functions created by that thread +non-nested functions created by the thread (through loadfile, loadstring or load) and can be directly accessed by C code (see 3.3).

    Environments associated with C functions can be directly accessed by C code (see 3.3). They are used as the default environment for other C functions -created by that function. +created by the function.

    Environments associated with Lua functions are used to resolve -all accesses to global variables within that function (see 2.3). +all accesses to global variables within the function (see 2.3). They are used as the default environment for other Lua functions -created by that function. +created by the function.

    You can change the environment of a Lua function or the running thread by calling setfenv. @@ -1564,13 +1566,13 @@

    2.10 - Garbage Collection

    Lua performs automatic memory management. -That means that +This means that you have to worry neither about allocating memory for new objects nor about freeing it when the objects are no longer needed. Lua manages memory automatically by running a garbage collector from time to time to collect all dead objects -(that is, those objects that are no longer accessible from Lua). +(that is, these objects that are no longer accessible from Lua). All objects in Lua are subject to automatic management: tables, userdata, functions, threads, and strings. @@ -1584,8 +1586,8 @@

    Larger values make the collector less aggressive. Values smaller than 1 mean the collector will not wait to start a new cycle. -A value of 2 means that the collector waits more or less to double -the total memory in use before starting a new cycle. +A value of 2 means that the collector waits for the total memory in use +to double before starting a new cycle.

    The step multiplier controls the relative speed of the collector relative to @@ -1597,12 +1599,12 @@

    The default, 2, means that the collector runs at "twice" the speed of memory allocation. -

    You can change those numbers calling lua_gc in C +

    You can change these numbers by calling lua_gc in C or collectgarbage in Lua. Both get as arguments percentage points (so an argument 100 means a real value of 1). -With those functions you can also get direct control -of the collector (e.g., stop and restart it). +With these functions you can also control +the collector directly (e.g., stop and restart it).

    2.10.1 - Garbage-Collection Metamethods

    @@ -1643,7 +1645,7 @@

    A weak reference is ignored by the garbage collector. In other words, if the only references to an object are weak references, -then the garbage collector will collect that object. +then the garbage collector will collect this object.

    A weak table can have weak keys, weak values, or both. A table with weak keys allows the collection of its keys, @@ -1716,7 +1718,7 @@

    just like coroutine.create, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. -Any arguments passed to that function +Any arguments passed to this function go as extra arguments to coroutine.resume. coroutine.wrap returns all the values returned by coroutine.resume, except the first one (the boolean error code). @@ -1789,7 +1791,7 @@

    Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of C functions that are still active. -That stack initially contains any arguments to the C function +This stack initially contains any arguments to the C function and it is where the C function pushes its results to be returned to the caller (see lua_CFunction). @@ -1874,7 +1876,7 @@

    Whenever a C function is called, its upvalues are located at specific pseudo-indices. -Those pseudo-indices are produced by the macro +These pseudo-indices are produced by the macro lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. @@ -1952,7 +1954,7 @@

    ptr is NULL if and only if osize is zero. When nsize is zero, the allocator must return NULL; if osize is not zero, -it should free the block pointed by ptr. +it should free the block pointed to by ptr. When nsize is not zero, the allocator returns NULL if and only if it cannot fill the request. When nsize is not zero and osize is zero, @@ -2017,7 +2019,7 @@

    The function results are pushed onto the stack when the function returns. The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. -In that case, all results from the function are pushed. +In this case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), @@ -2114,7 +2116,7 @@

    Destroys all objects in the given Lua state (calling the corresponding garbage-collection metamethods, if any) -and frees all dynamic memory used by that state. +and frees all dynamic memory used by this state. On several platforms, you may not need to call this function, because all resources are naturally released when the host program ends. On the other hand, long-running programs, @@ -2131,7 +2133,7 @@

    Concatenates the n values at the top of the stack, pops them, and leaves the result at the top. -If n is 1, the result is that single string +If n is 1, the result is the single string on the stack (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is done following the usual semantics of Lua @@ -2188,7 +2190,7 @@

    call to the writer; 0 means no errors. -

    This function does not pop the function from the stack. +

    This function does not pop the Lua function from the stack.


    lua_equal

    @@ -2244,7 +2246,7 @@

    (larger values mean more steps) in a non-specified way. If you want to control the step size you must tune experimentally the value of data. -The function returns 1 if that step finished a +The function returns 1 if the step finished a garbage-collection cycle.
  • LUA_GCSETPAUSE--- sets data/100 as the new value @@ -2340,7 +2342,7 @@

    Returns the index of the top element in the stack. Because indices start at 1, -that result is equal to the number of elements in the stack +this result is equal to the number of elements in the stack (and so 0 means an empty stack).

    @@ -2351,7 +2353,7 @@

    Moves the top element into the given valid index, -shifting up the elements above that position to open space. +shifting up the elements above this index to open space. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. @@ -2528,7 +2530,7 @@

    Returns NULL if cannot create the state (due to lack of memory). The argument f is the allocator function; -Lua does all memory allocation for that state through that function. +Lua does all memory allocation for this state through this function. The second argument, ud, is an opaque pointer that Lua simply passes to the allocator in every call. @@ -2579,7 +2581,7 @@

    When Lua collects a full userdata with a gc metamethod, Lua calls the metamethod and marks the userdata as finalized. -When that userdata is collected again then +When this userdata is collected again then Lua frees its corresponding memory.

    @@ -2667,9 +2669,9 @@

    is exactly the original error message. Otherwise, errfunc is the stack index of an error handler function. -(In the current implementation, that index cannot be a pseudo-index.) +(In the current implementation, this index cannot be a pseudo-index.) In case of runtime errors, -that function will be called with the error message +this function will be called with the error message and its return value will be the message returned on the stack by lua_pcall.

    Typically, the error handler function is used to add more debug @@ -2755,11 +2757,11 @@

    Pushes onto the stack a formatted string -and returns a pointer to that string. +and returns a pointer to this string. It is similar to the C function sprintf, but has some important differences:

      -
    • You do not have to allocate the space for the result: +
    • You do not have to allocate space for the result: The result is a Lua string and Lua takes care of memory allocation (and deallocation, through garbage collection).
    • The conversion specifiers are quite restricted. @@ -2768,7 +2770,7 @@

      `%%´ (inserts a `%´ in the string), `%s´ (inserts a zero-terminated string, with no size restrictions), `%f´ (inserts a lua_Number), -`%p´ (inserts a pointer as an hexadecimal numeral), +`%p´ (inserts a pointer as a hexadecimal numeral), `%d´ (inserts an int), and `%c´ (inserts an int as a character).

    @@ -2806,7 +2808,7 @@

  • -

    Pushes the string pointed by s with size len +

    Pushes the string pointed to by s with size len onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after @@ -2838,7 +2840,7 @@

    -

    Pushes the zero-terminated string pointed by s +

    Pushes the zero-terminated string pointed to by s onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after @@ -2976,7 +2978,7 @@

    Removes the element at the given valid index, -shifting down the elements above that position to fill the gap. +shifting down the elements above this index to fill the gap. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. @@ -3109,7 +3111,7 @@

    Accepts any acceptable index, or 0, -and sets the stack top to that index. +and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. If index is 0, then all stack elements are removed. @@ -3570,7 +3572,7 @@

    Gets information about a closure's upvalue. (For Lua functions, upvalues are the external local variables that the function uses, -and that consequently are included in its closure.) +and that are consequently included in its closure.) lua_getupvalue gets the index n of an upvalue, pushes the upvalue's value onto the stack, and returns its name. @@ -3610,7 +3612,7 @@

    While Lua is running a hook, it disables other calls to hooks. Therefore, if a hook calls back Lua to execute a function or a chunk, -that execution occurs without any calls to hooks. +this execution occurs without any calls to hooks.


    lua_sethook

    @@ -3701,7 +3703,7 @@

    All functions in the auxiliary library are built on top of the basic API, -and so they provide nothing that cannot be done with that API. +and so they provide nothing that cannot be done with this API.

    Several functions in the auxiliary library are used to check C function arguments. @@ -3733,7 +3735,7 @@

    -

    Adds the string pointed by s with length l to +

    Adds the string pointed to by s with length l to the buffer B (see luaL_Buffer). The string may contain embedded zeros. @@ -3756,7 +3758,7 @@

  • -

    Adds the zero-terminated string pointed by s +

    Adds the zero-terminated string pointed to by s to the buffer B (see luaL_Buffer). The string may not contain embedded zeros. @@ -3822,7 +3824,7 @@

  • Then you add string pieces to the buffer calling any of the luaL_add* functions.
  • You finish by calling luaL_pushresult(&b). -That call leaves the final string on the top of the stack. +This call leaves the final string on the top of the stack.

    During its normal operation, @@ -3861,10 +3863,10 @@

    Calls a metamethod. -

    If the object at index obj has a metatable and that +

    If the object at index obj has a metatable and this metatable has a field e, -this function calls that field and passes the object as its only argument. -In that case this function returns 1 and pushes on the +this function calls this field and passes the object as its only argument. +In this case this function returns 1 and pushes on the stack the value returned by the call. If there is no metatable or no metamethod, this function returns 0 (without pushing any value on the stack). @@ -3887,7 +3889,7 @@

    Checks whether the function argument narg is a number -and returns that number cast to an int. +and returns this number cast to an int.


    luaL_checkinteger

    @@ -3897,7 +3899,7 @@

    Checks whether the function argument narg is a number -and returns that number cast to a lua_Integer. +and returns this number cast to a lua_Integer.


    luaL_checklong

    @@ -3907,7 +3909,7 @@

    Checks whether the function argument narg is a number -and returns that number cast to a long. +and returns this number cast to a long.


    luaL_checklstring

    @@ -3917,7 +3919,7 @@

    Checks whether the function argument narg is a string -and returns that string; +and returns this string; if l is not NULL fills *l with the string's length. @@ -3929,7 +3931,7 @@

    Checks whether the function argument narg is a number -and returns that number. +and returns this number.


    luaL_checkoption

    @@ -3940,11 +3942,11 @@

    Checks whether the function argument narg is a string and -searches for that string into the array lst +searches for this string in the array lst (which must be NULL-terminated). If def is not NULL, uses def as a default value when -the function has no argument narg or if that argument is nil. +the function has no argument narg or if this argument is nil.

    Returns the index in the array where the string was found. Raises an error if the argument is not a string or @@ -3973,7 +3975,7 @@

    Checks whether the function argument narg is a string -and returns that string. +and returns this string.


    luaL_checktype

    @@ -4007,7 +4009,7 @@

    following the same rules of lua_pushfstring. It also adds at the beginning of the message the file name and the line number where the error occurred, -if that information is available. +if this information is available.

    This function never returns, but it is an idiom to use it as return luaL_error ... @@ -4023,7 +4025,7 @@

    Pushes on the stack the field e from the metatable of the object at index obj. If the object does not have a metatable, -or if the metatable does not have that field, +or if the metatable does not have this field, returns 0 and pushes nothing.

    @@ -4033,7 +4035,7 @@

  • -

    Pushes on the stack the metatable associated to name tname +

    Pushes on the stack the metatable associated with name tname in the registry (see luaL_newmetatable).

    @@ -4059,7 +4061,7 @@

    Loads a buffer as a Lua chunk. This function uses lua_load to load the chunk in the -buffer pointed by buff with size sz. +buffer pointed to by buff with size sz.

    This function returns the same results as lua_load. name is the chunk name, @@ -4146,8 +4148,8 @@

    If the function argument narg is a number, -returns that number cast to an int. -If that argument is absent or is nil, +returns this number cast to an int. +If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -4159,8 +4161,8 @@

    If the function argument narg is a number, -returns that number cast to a lua_Integer. -If that argument is absent or is nil, +returns this number cast to a lua_Integer. +If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -4172,8 +4174,8 @@

    If the function argument narg is a number, -returns that number cast to a long. -If that argument is absent or is nil, +returns this number cast to a long. +If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -4186,8 +4188,8 @@

    If the function argument narg is a string, -returns that string. -If that argument is absent or is nil, +returns this string. +If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -4202,8 +4204,8 @@

    If the function argument narg is a number, -returns that number. -If that argument is absent or is nil, +returns this number. +If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -4215,8 +4217,8 @@

    If the function argument narg is a string, -returns that string. -If that argument is absent or is nil, +returns this string. +If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -4230,7 +4232,7 @@

    Returns an address to a space of size LUAL_BUFFERSIZE where you can copy a string to be added to buffer B (see luaL_Buffer). -After copying the string into that space you must call +After copying the string into this space you must call luaL_addsize with the size of the string to actually add it to the buffer. @@ -4306,7 +4308,7 @@

    and registers on it all functions in the list l. If there is a table in package.loaded[libname] or in variable libname, -reuses that table instead of creating a new one. +reuses this table instead of creating a new one.

    In any case the function leaves the table on the top of the stack. @@ -4442,7 +4444,7 @@

    (larger values mean more steps) in a non-specified way. If you want to control the step size you must tune experimentally the value of arg. -Returns true if that step finished a collection cycle. +Returns true if the step finished a collection cycle.
  • "steppause" --- sets arg/100 as the new value for the pause of the collector (see 2.10). @@ -4591,7 +4593,7 @@

    Calls function f with the given arguments in protected mode. -That means that any error inside f is not propagated; +This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), @@ -4602,7 +4604,7 @@


    print (e1, e2, ...)

    Receives any number of arguments, -and prints their values in stdout, +and prints their values to stdout, using the tostring function to convert them to strings. print is not intended for formatted output, but only as a quick way to show a value, @@ -4660,7 +4662,7 @@


    tonumber (e [, base])

    Tries to convert its argument to a number. If the argument is already a number or a string convertible -to a number, then tonumber returns that number; +to a number, then tonumber returns this number; otherwise, it returns nil.

    An optional argument specifies the base to interpret the numeral. @@ -4792,8 +4794,8 @@


    coroutine.yield ([val1, ..., valn])

    Suspends the execution of the calling coroutine. -The coroutine can be running neither a C function, -nor a metamethod, nor an iterator. +The coroutine cannot be running a C function, +a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume.

    5.3 - Modules

    @@ -4808,9 +4810,9 @@

    Creates a module. If there is a table in package.loaded[name], -that table is the module. +this table is the module. Otherwise, if there is a global table t with the given name, -that table is the module. +this table is the module. Otherwise creates a new table t and sets it as the value of the global name and the value of package.loaded[name]. @@ -4841,12 +4843,12 @@

    to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. -Otherwise, it tries to find a loader for that module. +Otherwise, it tries to find a loader for the module.

    To find a loader, first require queries package.preload[modname]. If it has a value, -that value (which should be a function) is the loader. +this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the @@ -4857,9 +4859,9 @@

    When loading a C library, require first uses a dynamic link facility to link the application with the library. -Then it tries to find a C function inside that library to +Then it tries to find a C function inside this library to be used as the loader. -The name of that C function is the string "luaopen_" +The name of this C function is the string "luaopen_" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, @@ -4870,14 +4872,14 @@

    If require finds neither a Lua library nor a C library for a module, it calls the all-in-one loader. -That loader searches the C path for a library for +This loader searches the C path for a library for the root name of the given module. For instance, when requiring a.b.c, it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. -With that facility, a package can pack several C submodules +With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function. @@ -4887,12 +4889,12 @@

    require assigns it to package.loaded[modname]. If the loader returns no value and has not assigned any value to package.loaded[modname], -then require assigns true to that entry. +then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname].

    If there is any error loading or running the module, -or if it cannot find any loader for that module, +or if it cannot find any loader for the module, then require signals an error.


    package.cpath

    @@ -5010,7 +5012,7 @@


    string.dump (function)

    Returns a string containing a binary representation of the given function, -so that a later loadstring on that string returns +so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues. @@ -5164,7 +5166,7 @@

    so "a\000bc\000" has length 5.


    string.lower (s)

    -Receives a string and returns a copy of that string with all +Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. @@ -5201,7 +5203,7 @@

    with length i.


    string.upper (s)

    -Receives a string and returns a copy of that string with all +Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. @@ -5334,7 +5336,7 @@

    Most functions in the table library assume that the table represents an array or a list. -For those functions, when we talk about the "length" of a table +For these functions, when we talk about the "length" of a table we mean the result of the length operator.


    table.concat (table [, sep [, i [, j]]])

    @@ -5410,7 +5412,7 @@

    plus a variable math.pi and a variable math.huge, with the value HUGE_VAL. -Most of those functions +Most of these functions are only interfaces to the corresponding functions in the C library. All trigonometric functions work in radians. The functions math.deg and math.rad convert @@ -5451,7 +5453,7 @@

    The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, -and all input/output operations are over those default files. +and all input/output operations are over these default files. The second style uses explicit file descriptors.

    When using implicit file descriptors, @@ -5483,7 +5485,7 @@

    When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, -it simply sets that file handle as the default input file. +it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file. @@ -5507,7 +5509,7 @@

    The call io.lines() (without a file name) is equivalent to io.input():lines(); that is, it iterates over the lines of the default input file. -In that case it does not close the file when the loop ends. +In this case it does not close the file when the loop ends.


    io.open (filename [, mode])

    @@ -5538,9 +5540,9 @@


    io.popen ([prog [, mode]])

    Starts program prog in a separated process and returns -a file handle that you can use to read data from that program +a file handle that you can use to read data from this program (if mode is "r", the default) -or to write data to that program +or to write data to this program (if mode is "w").

    This function is system dependent and is not available @@ -5561,7 +5563,7 @@

    Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, -and nil if obj is not a file handle. +or nil if obj is not a file handle.


    io.write (value1, ...)

    @@ -5611,7 +5613,7 @@

  • "*l" reads the next line (skipping the end of line), returning nil on end of file. This is the default format. -
  • number reads a string with up to that number of characters, +
  • number reads a string with up to this number of characters, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, @@ -5691,7 +5693,7 @@

    If format starts with `!´, then the date is formatted in Coordinated Universal Time. -After that optional character, +After this optional character, if format is *t, then date returns a table with the following fields: year (four digits), month (1--12), day (1--31), @@ -6015,7 +6017,7 @@

    and finally runs the file b.lua. The script is called with arg[1], arg[2], ... as arguments; -it can also access those arguments with the vararg expression `...´. +it can also access these arguments with the vararg expression `...´.

    In interactive mode, if you write an incomplete statement, @@ -6067,7 +6069,7 @@

    You can avoid most of the incompatibilities compiling Lua with appropriate options (see file luaconf.h). However, -all those compatibility options will be removed in the next version of Lua. +all these compatibility options will be removed in the next version of Lua.

    Incompatibilities with version 5.0

    @@ -6084,7 +6086,7 @@

  • The long string/long comment syntax ([[...]]) does not allow nesting. -You can use the new syntax ([=[...]=]) in those cases. +You can use the new syntax ([=[...]=]) in these cases. (Option LUA_COMPAT_LSTR in luaconf.h.)

    @@ -6099,7 +6101,7 @@

  • When string.gsub is called with a function as its third argument, -whenever that function returns nil or false the +whenever this function returns nil or false the replacement string is the whole match, instead of the empty string. diff --git a/src/Makefile b/src/Makefile index fb69ce1e13..1d46d3423a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,7 @@ MYLIBS= # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= -PLATS= ansi bsd generic linux macosx mingw posix solaris +PLATS= aix ansi bsd generic linux macosx mingw posix solaris LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ @@ -79,6 +79,9 @@ echo: none: @echo "Please choose a platform: $(PLATS)" +aix: + $(MAKE) all CC="xlc" CFLAGS="-O2" MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + ansi: $(MAKE) all MYCFLAGS=-DLUA_ANSI @@ -108,7 +111,7 @@ solaris: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" # list targets that do not create files (but not all makes understand .PHONY) -.PHONY: all $(PLATS) default o a clean depend echo none +.PHONY: all $(PLATS) default o a clean depend echo none # DO NOT DELETE diff --git a/src/ldump.c b/src/ldump.c index 7346341010..f08277d3ac 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.14 2005/11/11 14:03:13 lhf Exp $ +** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -128,7 +128,7 @@ static void DumpDebug(const Proto* f, DumpState* D) static void DumpFunction(const Proto* f, const TString* p, DumpState* D) { - DumpString((f->source==p) ? NULL : f->source,D); + DumpString((f->source==p || D->strip) ? NULL : f->source,D); DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); DumpChar(f->nups,D); diff --git a/src/lundump.c b/src/lundump.c index 60a0eeed3f..7fc635eeb7 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.59 2005/11/11 14:03:13 lhf Exp $ +** $Id: lundump.c,v 1.60 2006/02/16 15:53:49 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -201,7 +201,7 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) S.Z=Z; S.b=buff; LoadHeader(&S); - return LoadFunction(&S,NULL); + return LoadFunction(&S,luaS_newliteral(L,"=?")); } /* From 60e37e0252c2758c935c8f382ace44b5100f6f21 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Thu, 1 Jun 2006 12:00:00 +0000 Subject: [PATCH 31/97] Lua 5.1.1-rc1 --- MANIFEST | 108 - Makefile | 2 +- doc/contents.html | 46 +- doc/lua.css | 7 + doc/manual.html | 7512 +++++++++++++++++++++++++++++---------------- src/Makefile | 20 +- src/lauxlib.c | 18 +- src/lauxlib.h | 8 +- src/lbaselib.c | 4 +- src/lcode.c | 14 +- src/lcode.h | 3 +- src/lgc.c | 12 +- src/liolib.c | 6 +- src/llex.c | 3 +- src/llex.h | 6 +- src/loadlib.c | 6 +- src/lopcodes.h | 6 +- src/loslib.c | 13 +- src/lparser.c | 4 +- src/lparser.h | 3 +- src/lstate.c | 4 +- src/lstrlib.c | 9 +- src/lua.c | 29 +- src/lua.h | 4 +- src/luac.c | 18 +- src/luaconf.h | 28 +- src/print.c | 21 +- 27 files changed, 5046 insertions(+), 2868 deletions(-) delete mode 100644 MANIFEST diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index fd18c8bb9e..0000000000 --- a/MANIFEST +++ /dev/null @@ -1,108 +0,0 @@ -MANIFEST contents of Lua 5.1 distribution on Mon Feb 20 11:37:30 BRT 2006 -lua-5.1 -lua-5.1/COPYRIGHT -lua-5.1/HISTORY -lua-5.1/INSTALL -lua-5.1/MANIFEST -lua-5.1/Makefile -lua-5.1/README -lua-5.1/doc -lua-5.1/doc/contents.html -lua-5.1/doc/logo.gif -lua-5.1/doc/lua.1 -lua-5.1/doc/lua.css -lua-5.1/doc/lua.html -lua-5.1/doc/luac.1 -lua-5.1/doc/luac.html -lua-5.1/doc/manual.html -lua-5.1/doc/readme.html -lua-5.1/etc -lua-5.1/etc/Makefile -lua-5.1/etc/README -lua-5.1/etc/all.c -lua-5.1/etc/lua.hpp -lua-5.1/etc/lua.ico -lua-5.1/etc/lua.pc -lua-5.1/etc/luavs.bat -lua-5.1/etc/min.c -lua-5.1/etc/noparser.c -lua-5.1/etc/strict.lua -lua-5.1/src -lua-5.1/src/Makefile -lua-5.1/src/lapi.c -lua-5.1/src/lapi.h -lua-5.1/src/lauxlib.c -lua-5.1/src/lauxlib.h -lua-5.1/src/lbaselib.c -lua-5.1/src/lcode.c -lua-5.1/src/lcode.h -lua-5.1/src/ldblib.c -lua-5.1/src/ldebug.c -lua-5.1/src/ldebug.h -lua-5.1/src/ldo.c -lua-5.1/src/ldo.h -lua-5.1/src/ldump.c -lua-5.1/src/lfunc.c -lua-5.1/src/lfunc.h -lua-5.1/src/lgc.c -lua-5.1/src/lgc.h -lua-5.1/src/linit.c -lua-5.1/src/liolib.c -lua-5.1/src/llex.c -lua-5.1/src/llex.h -lua-5.1/src/llimits.h -lua-5.1/src/lmathlib.c -lua-5.1/src/lmem.c -lua-5.1/src/lmem.h -lua-5.1/src/loadlib.c -lua-5.1/src/lobject.c -lua-5.1/src/lobject.h -lua-5.1/src/lopcodes.c -lua-5.1/src/lopcodes.h -lua-5.1/src/loslib.c -lua-5.1/src/lparser.c -lua-5.1/src/lparser.h -lua-5.1/src/lstate.c -lua-5.1/src/lstate.h -lua-5.1/src/lstring.c -lua-5.1/src/lstring.h -lua-5.1/src/lstrlib.c -lua-5.1/src/ltable.c -lua-5.1/src/ltable.h -lua-5.1/src/ltablib.c -lua-5.1/src/ltm.c -lua-5.1/src/ltm.h -lua-5.1/src/lua.c -lua-5.1/src/lua.h -lua-5.1/src/luac.c -lua-5.1/src/luaconf.h -lua-5.1/src/lualib.h -lua-5.1/src/lundump.c -lua-5.1/src/lundump.h -lua-5.1/src/lvm.c -lua-5.1/src/lvm.h -lua-5.1/src/lzio.c -lua-5.1/src/lzio.h -lua-5.1/src/print.c -lua-5.1/test -lua-5.1/test/README -lua-5.1/test/bisect.lua -lua-5.1/test/cf.lua -lua-5.1/test/echo.lua -lua-5.1/test/env.lua -lua-5.1/test/factorial.lua -lua-5.1/test/fib.lua -lua-5.1/test/fibfor.lua -lua-5.1/test/globals.lua -lua-5.1/test/hello.lua -lua-5.1/test/life.lua -lua-5.1/test/luac.lua -lua-5.1/test/printf.lua -lua-5.1/test/readonly.lua -lua-5.1/test/sieve.lua -lua-5.1/test/sort.lua -lua-5.1/test/table.lua -lua-5.1/test/trace-calls.lua -lua-5.1/test/trace-globals.lua -lua-5.1/test/xd.lua -END OF MANIFEST diff --git a/Makefile b/Makefile index 56a9b665dd..6a586e5bb5 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp TO_LIB= liblua.a TO_MAN= lua.1 luac.1 -# Lua version. Currently used only for messages. +# Lua version. V= 5.1 all: $(PLAT) diff --git a/doc/contents.html b/doc/contents.html index 564377c942..96a2dfabc3 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -2,14 +2,20 @@ Lua 5.1 reference manual - contents + - +

    Lua -Lua 5.1 Reference Manual +Reference manual for Lua 5.1

    @@ -19,7 +25,7 @@


    Contents

    - @@ -156,31 +170,33 @@

    Functions

    math.abs
    math.acos
    math.asin
    -math.atan2
    math.atan
    +math.atan2
    math.ceil
    -math.cosh
    math.cos
    +math.cosh
    math.deg
    math.exp
    math.floor
    math.fmod
    math.frexp
    +math.huge
    math.ldexp
    -math.log10
    math.log
    +math.log10
    math.max
    math.min
    math.modf
    +math.pi
    math.pow
    math.rad
    math.random
    math.randomseed
    -math.sinh
    math.sin
    +math.sinh
    math.sqrt
    -math.tanh
    math.tan
    +math.tanh
    module
    next
    os.clock
    @@ -236,7 +252,7 @@

    Functions

    xpcall
    - +

    API

    lua_Alloc
    lua_CFunction
    @@ -337,6 +353,7 @@

    API

    lua_touserdata
    lua_type
    lua_typename
    +lua_upvalueindex
    lua_xmove
    lua_yield
    @@ -365,6 +382,8 @@

    Auxiliary library

    luaL_checkstring
    luaL_checktype
    luaL_checkudata
    +luaL_dofile
    +luaL_dostring
    luaL_error
    luaL_getmetafield
    luaL_getmetatable
    @@ -398,8 +417,11 @@

    Auxiliary library


    Last update: -Fri Feb 10 17:15:37 BRST 2006 +Wed May 31 10:11:21 BRT 2006 + diff --git a/doc/lua.css b/doc/lua.css index 90f62312d0..f007211009 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -6,6 +6,13 @@ body { a:link { color: #000080 ; + background-color: #FFFFFF ; + text-decoration: none ; +} + +a:visited { + background-color: #FFFFFF ; + text-decoration: none ; } a:link:hover, a:visited:hover { diff --git a/doc/manual.html b/doc/manual.html index a44d2e8ea3..b220222f97 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -6,11 +6,11 @@ - + -
    +

    -[Lua logo] + Lua 5.1 Reference Manual

    @@ -20,16 +20,19 @@

    Copyright © 2006 Lua.org, PUC-Rio. All rights reserved. -
    +
    -

    -

    +

    + -

    1 - Introduction

    -

    Lua is an extension programming language designed to support + +

    1 - Introduction

    + +

    +Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, @@ -37,56 +40,68 @@

    Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. Lua is implemented as a library, written in clean C -(that is, in the common subset of ANSI C and C++). +(that is, in the common subset of ANSI C and C++). + -

    Being an extension language, Lua has no notion of a "main" program: +

    +Being an extension language, Lua has no notion of a "main" program: it only works embedded in a host client, called the embedding program or simply the host. This host program can invoke functions to execute a piece of Lua code, can write and read Lua variables, -and can register C functions to be called by Lua code. -Through the use of C functions, Lua can be augmented to cope with +and can register C functions to be called by Lua code. +Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. The Lua distribution includes a sample host program called lua, which uses the Lua library to offer a complete, stand-alone Lua interpreter. -

    Lua is free software, + +

    +Lua is free software, and is provided as usual with no guarantees, as stated in its license. The implementation described in this manual is available at Lua's official web site, www.lua.org. -

    Like any other reference manual, + +

    +Like any other reference manual, this document is dry in places. For a discussion of the decisions behind the design of Lua, see the technical papers available at Lua's web site. For a detailed introduction to programming in Lua, see Roberto's book, Programming in Lua. -

    -

    2 - The Language

    -

    This section describes the lexis, the syntax, and the semantics of Lua. + +

    2 - The Language

    + +

    +This section describes the lexis, the syntax, and the semantics of Lua. In other words, this section describes which tokens are valid, how they can be combined, and what their combinations mean. -

    The language constructs will be explained using the usual extended BNF notation, + +

    +The language constructs will be explained using the usual extended BNF notation, in which -{a} means 0 or more a's, and -[a] means an optional a. -Non-terminals are shown in italics, -keywords are shown in bold, -and other terminal symbols are shown in typewriter font, -enclosed in single quotes. +{a} means 0 or more a's, and +[a] means an optional a. +Non-terminals are shown like non-terminal, +keywords are shown like kword, +and other terminal symbols are shown like `=´. The complete syntax of Lua can be found at the end of this manual. -

    2.1 - Lexical Conventions

    -

    Names + +

    2.1 - Lexical Conventions

    + +

    +Names (also called identifiers) in Lua can be any string of letters, digits, and underscores, @@ -97,58 +112,65 @@

    can be used in an identifier.) Identifiers are used to name variables and table fields. -

    The following keywords are reserved + +

    +The following keywords are reserved and cannot be used as names: +

    -       and       break     do        else      elseif
    -       end       false     for       function  if
    -       in        local     nil       not       or
    -       repeat    return    then      true      until     while
    +     and       break     do        else      elseif
    +     end       false     for       function  if
    +     in        local     nil       not       or
    +     repeat    return    then      true      until     while
     
    -

    Lua is a case-sensitive language: +

    +Lua is a case-sensitive language: and is a reserved word, but And and AND are two different, valid names. As a convention, names starting with an underscore followed by -uppercase letters (such as _VERSION) +uppercase letters (such as _VERSION) are reserved for internal global variables used by Lua. -

    The following strings denote other tokens: + +

    +The following strings denote other tokens: +

    -       +     -     *     /     %     ^     #
    -       ==    ~=    <=    >=    <     >     =
    -       (     )     {     }     [     ]
    -       ;     :     ,     .     ..    ...
    +     +     -     *     /     %     ^     #
    +     ==    ~=    <=    >=    <     >     =
    +     (     )     {     }     [     ]
    +     ;     :     ,     .     ..    ...
     
    -

    Literal strings +

    +Literal strings can be delimited by matching single or double quotes, and can contain the following C-like escape sequences: -

      -
    • \a --- bell -
    • \b --- backspace -
    • \f --- form feed -
    • \n --- newline -
    • \r --- carriage return -
    • \t --- horizontal tab -
    • \v --- vertical tab -
    • \\ --- backslash -
    • \" --- quotation mark (double quote) -
    • \' --- apostrophe (single quote) -
    -Moreover, a `\newline´ -(that is, a backslash followed by a real newline) +'\a' (bell), +'\b' (backspace), +'\f' (form feed), +'\n' (newline), +'\r' (carriage return), +'\t' (horizontal tab), +'\v' (vertical tab), +'\\' (backslash), +'\"' (quotation mark [double quote]), +and '\'' (apostrophe [single quote]). +Moreover, a backslash followed by a real newline results in a newline in the string. A character in a string may also be specified by its numerical value -using the escape sequence `\ddd´, +using the escape sequence \ddd, where ddd is a sequence of up to three decimal digits. (Note that if a numerical escape is to be followed by a digit, it must be expressed using exactly three digits.) Strings in Lua may contain any 8-bit value, including embedded zeros, -which can be specified as `\0´. +which can be specified as '\0'. -

    To put a double (single) quote, a newline, a backslash, + +

    +To put a double (single) quote, a newline, a backslash, or an embedded zero inside a literal string enclosed by double (single) quotes you must use an escape sequence. @@ -156,52 +178,59 @@

    (Some control characters may cause problems for the file system, but Lua has no problem with them.) -

    Literal strings can also be defined using a long format + +

    +Literal strings can also be defined using a long format enclosed by long brackets. We define an opening long bracket of level n as an opening square bracket followed by n equal signs followed by another opening square bracket. -So, an opening long bracket of level 0 is written as [[, -an opening long bracket of level 1 is written as [=[, +So, an opening long bracket of level 0 is written as [[, +an opening long bracket of level 1 is written as [=[, and so on. A closing long bracket is defined similarly; -for instance, a closing long bracket of level 4 is written as ]====]. +for instance, a closing long bracket of level 4 is written as ]====]. A long string starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. Literals in this bracketed form may run for several lines, do not interpret any escape sequences, and ignore long brackets of any other level. -They may contain anything except a closing bracket of the proper level -or embedded zeros. +They may contain anything except a closing bracket of the proper level. -

    For convenience, + +

    +For convenience, when the opening long bracket is immediately followed by a newline, the newline is not included in the string. As an example, in a system using ASCII -(in which `a´ is coded as 97, -newline is coded as 10, and `1´ is coded as 49), -the four literals below denote the same string: +(in which 'a' is coded as 97, +newline is coded as 10, and '1' is coded as 49), +the five literals below denote the same string: +

    -      (1)   'alo\n123"'
    -      (2)   "alo\n123\""
    -      (3)   '\97lo\10\04923"'
    -      (4)   [[alo
    -            123"]]
    -      (5)   [==[
    -            alo
    -            123"]==]
    +     a = 'alo\n123"'
    +     a = "alo\n123\""
    +     a = '\97lo\10\04923"'
    +     a = [[alo
    +     123"]]
    +     a = [==[
    +     alo
    +     123"]==]
     
    -

    Numerical constants may be written with an optional decimal part +

    +A numerical constant may be written with an optional decimal part and an optional decimal exponent. Lua also accepts integer hexadecimal constants, by prefixing them with 0x. Examples of valid numerical constants are +

    -       3       3.0     3.1416  314.16e-2   0.31416E1  0xff  0x56
    +     3   3.0   3.1416   314.16e-2   0.31416E1   0xff   0x56
     
    -

    Comments start with a double hyphen (--) +

    +A comment starts with a double hyphen (--) anywhere outside a string. If the text immediately after -- is not an opening long bracket, the comment is a short comment, @@ -210,19 +239,28 @@

    which runs until the corresponding closing long bracket. Long comments are frequently used to disable code temporarily. -

    2.2 - Values and Types

    -

    Lua is a dynamically typed language. + + + +

    2.2 - Values and Types

    + +

    +Lua is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type. -

    All values in Lua are first-class values. + +

    +All values in Lua are first-class values. This means that all values can be stored in variables, passed as arguments to other functions, and returned as results. -

    There are eight basic types in Lua: + +

    +There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table. @@ -235,37 +273,45 @@

    Number represents real (double-precision floating-point) numbers. (It is easy to build Lua interpreters that use other internal representations for numbers, -such as single-precision float or long integers. -See file luaconf.h.) +such as single-precision float or long integers; +see file luaconf.h.) String represents arrays of characters. Lua is 8-bit clean: -Strings may contain any 8-bit character, -including embedded zeros (`\0´) (see 2.1). +strings may contain any 8-bit character, +including embedded zeros ('\0') (see §2.1). + -

    Lua can call (and manipulate) functions written in Lua and +

    +Lua can call (and manipulate) functions written in Lua and functions written in C -(see 2.5.8). +(see §2.5.8). + -

    The type userdata is provided to allow arbitrary C data to +

    +The type userdata is provided to allow arbitrary C data to be stored in Lua variables. This type corresponds to a block of raw memory and has no pre-defined operations in Lua, except assignment and identity test. However, by using metatables, the programmer can define operations for userdata values -(see 2.8). +(see §2.8). Userdata values cannot be created or modified in Lua, -only through the C API. +only through the C API. This guarantees the integrity of data owned by the host program. -

    The type thread represents independent threads of execution -and it is used to implement coroutines (see 2.11). + +

    +The type thread represents independent threads of execution +and it is used to implement coroutines (see §2.11). Do not confuse Lua threads with operating-system threads. Lua supports coroutines on all systems, even those that do not support threads. -

    The type table implements associative arrays, + +

    +The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, but with any value (except nil). Tables can be heterogeneous; @@ -277,28 +323,37 @@

    The language supports this representation by providing a.name as syntactic sugar for a["name"]. There are several convenient ways to create tables in Lua -(see 2.5.7). +(see §2.5.7). + -

    Like indices, +

    +Like indices, the value of a table field can be of any type (except nil). In particular, because functions are first-class values, table fields may contain functions. -Thus tables may also carry methods (see 2.5.9). +Thus tables may also carry methods (see §2.5.9). + -

    Tables, functions, threads, and (full) userdata values are objects: +

    +Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy. -

    The library function type returns a string describing the type + +

    +The library function type returns a string describing the type of a given value. -

    2.2.1 - Coercion

    -

    Lua provides automatic conversion between + +

    2.2.1 - Coercion

    + +

    +Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert this string to a number, following the usual conversion rules. @@ -308,57 +363,80 @@

    use the format function from the string library (see string.format). -

    2.3 - Variables

    -

    Variables are places that store values. + + + + + +

    2.3 - Variables

    + +

    +Variables are places that store values. There are three kinds of variables in Lua: global variables, local variables, and table fields. -

    A single name can denote a global variable or a local variable + +

    +A single name can denote a global variable or a local variable (or a function's formal parameter, which is a particular kind of local variable): +

     	var ::= Name
    -
    -Name denotes identifiers, as defined in (see 2.1). +
  • +Name denotes identifiers, as defined in §2.1. + -

    Variables are assumed to be global unless explicitly declared local -(see 2.4.7). +

    +Variables are assumed to be global unless explicitly declared local +(see §2.4.7). Local variables are lexically scoped: -Local variables can be freely accessed by functions -defined inside their scope (see 2.6). +local variables can be freely accessed by functions +defined inside their scope (see §2.6). + + +

    +Before the first assignment to a variable, its value is nil. + -

    Before the first assignment to a variable, its value is nil. +

    +Square brackets are used to index a table: -

    Square brackets are used to index a table:

     	var ::= prefixexp `[´ exp `]´
    -
    +
  • The first expression (prefixexp) should result in a table value; the second expression (exp) identifies a specific entry in this table. The expression denoting the table to be indexed has a restricted syntax; -see 2.5 for details. +see §2.5 for details. -

    The syntax var.Name is just syntactic sugar for + +

    +The syntax var.Name is just syntactic sugar for var["Name"] and is used to denote table fields: +

     	var ::= prefixexp `.´ Name
     
    -

    The meaning of accesses to global variables +

    +The meaning of accesses to global variables and table fields can be changed via metatables. An access to an indexed variable t[i] is equivalent to a call gettable_event(t,i). -(See 2.8 for a complete description of the +(See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.) -

    All global variables live as fields in ordinary Lua tables, + +

    +All global variables live as fields in ordinary Lua tables, called environment tables or simply -environments (see 2.9). +environments (see §2.9). Each function has its own reference to an environment, so that all global variables in this function will refer to this environment table. @@ -368,92 +446,124 @@

    you call getfenv. To replace it, you call setfenv. -(You can only manipulate the environment of C functions -through the debug library; (see 5.9).) +(You can only manipulate the environment of C functions +through the debug library; (see §5.9).) -

    An access to a global variable x + +

    +An access to a global variable x is equivalent to _env.x, which in turn is equivalent to +

    -       gettable_event(_env, "x")
    -
    + gettable_event(_env, "x") +

    where _env is the environment of the running function. -(See 2.8 for a complete description of the +(See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. Similarly, the _env variable is not defined in Lua. We use them here only for explanatory purposes.) -

    2.4 - Statements

    -

    Lua supports an almost conventional set of statements, + + + +

    2.4 - Statements

    + +

    +Lua supports an almost conventional set of statements, similar to those in Pascal or C. This set includes assignment, control structures, function calls, -table constructors, and variable declarations. +and variable declarations. + -

    2.4.1 - Chunks

    -

    The unit of execution of Lua is called a chunk. +

    2.4.1 - Chunks

    + +

    +The unit of execution of Lua is called a chunk. A chunk is simply a sequence of statements, which are executed sequentially. Each statement can be optionally followed by a semicolon: +

     	chunk ::= {stat [`;´]}
    -
    -There are no empty statements and thus `;;´ is not legal. +

    +There are no empty statements and thus ';;' is not legal. -

    Lua handles a chunk as the body of an anonymous function + +

    +Lua handles a chunk as the body of an anonymous function with a variable number of arguments -(see 2.5.9). +(see §2.5.9). As such, chunks can define local variables, receive arguments, and return values. -

    A chunk may be stored in a file or in a string inside the host program. + +

    +A chunk may be stored in a file or in a string inside the host program. When a chunk is executed, first it is pre-compiled into instructions for a virtual machine, and then the compiled code is executed by an interpreter for the virtual machine. -

    Chunks may also be pre-compiled into binary form; + +

    +Chunks may also be pre-compiled into binary form; see program luac for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly. -

    2.4.2 - Blocks

    + + + + +

    2.4.2 - Blocks

    A block is a list of statements; syntactically, a block is the same as a chunk: +

     	block ::= chunk
     
    -

    A block may be explicitly delimited to produce a single statement: +

    +A block may be explicitly delimited to produce a single statement: +

     	stat ::= do block end
    -
    +
  • Explicit blocks are useful to control the scope of variable declarations. Explicit blocks are also sometimes used to add a return or break statement in the middle -of another block (see 2.4.4). +of another block (see §2.4.4). + + -

    2.4.3 - Assignment

    -

    Lua allows multiple assignment. +

    2.4.3 - Assignment

    + +

    +Lua allows multiple assignment. Therefore, the syntax for assignment defines a list of variables on the left side and a list of expressions on the right side. The elements in both lists are separated by commas: +

     	stat ::= varlist1 `=´ explist1
     	varlist1 ::= var {`,´ var}
     	explist1 ::= exp {`,´ exp}
    -
    -Expressions are discussed in 2.5. +

    +Expressions are discussed in §2.5. -

    Before the assignment, + +

    +Before the assignment, the list of values is adjusted to the length of the list of variables. If there are more values than needed, @@ -463,217 +573,306 @@

    If the list of expressions ends with a function call, then all values returned by this call enter in the list of values, before the adjustment -(except when the call is enclosed in parentheses; see 2.5). +(except when the call is enclosed in parentheses; see §2.5). -

    The assignment statement first evaluates all its expressions + +

    +The assignment statement first evaluates all its expressions and only then are the assignments performed. Thus the code +

    -       i = 3
    -       i, a[i] = i+1, 20
    -
    + i = 3 + i, a[i] = i+1, 20 +

    sets a[3] to 20, without affecting a[4] because the i in a[i] is evaluated (to 3) -before it is assigned 4. +before it is assigned 4. Similarly, the line +

    -       x, y = y, x
    -
    + x, y = y, x +

    exchanges the values of x and y. -

    The meaning of assignments to global variables + +

    +The meaning of assignments to global variables and table fields can be changed via metatables. An assignment to an indexed variable t[i] = val is equivalent to settable_event(t,i,val). -(See 2.8 for a complete description of the +(See §2.8 for a complete description of the settable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.) -

    An assignment to a global variable x = val + +

    +An assignment to a global variable x = val is equivalent to the assignment _env.x = val, which in turn is equivalent to +

    -       settable_event(_env, "x", val)
    -
    + settable_event(_env, "x", val) +

    where _env is the environment of the running function. (The _env variable is not defined in Lua. We use it here only for explanatory purposes.) -

    2.4.4 - Control Structures

    + + + + +

    2.4.4 - Control Structures

    The control structures if, while, and repeat have the usual meaning and familiar syntax: +

     	stat ::= while exp do block end
     	stat ::= repeat block until exp
     	stat ::= if exp then block {elseif exp then block} [else block] end
    -
    -Lua also has a for statement, in two flavors (see 2.4.5). +

    +Lua also has a for statement, in two flavors (see §2.4.5). -

    The condition expression of a + +

    +The condition expression of a control structure may return any value. Both false and nil are considered false. All values different from nil and false are considered true (in particular, the number 0 and the empty string are also true). -

    In the repeat--until loop, + +

    +In the repeatuntil loop, the inner block does not end at the until keyword, but only after the condition. So, the condition can refer to local variables declared inside the loop block. -

    The return statement is used to return values + +

    +The return statement is used to return values from a function or a chunk (which is just a function). Functions and chunks may return more than one value, so the syntax for the return statement is +

     	stat ::= return [explist1]
     
    -

    The break statement is used to terminate the execution of a +

    +The break statement is used to terminate the execution of a while, repeat, or for loop, skipping to the next statement after the loop: +

     	stat ::= break
    -
    +

    A break ends the innermost enclosing loop. -

    The return and break + +

    +The return and break statements can only be written as the last statement of a block. If it is really necessary to return or break in the middle of a block, then an explicit inner block can be used, as in the idioms -`do return end´ and -`do break end´, +do return end and do break end, because now return and break are the last statements in their (inner) blocks. -

    2.4.5 - For Statement

    -

    The for statement has two forms: + + + +

    2.4.5 - For Statement

    + +

    + +The for statement has two forms: one numeric and one generic. -

    The numeric for loop repeats a block of code while a +

    +The numeric for loop repeats a block of code while a control variable runs through an arithmetic progression. It has the following syntax: +

     	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end
    -
    +

    The block is repeated for name starting at the value of the first exp, until it passes the second exp by steps of the third exp. More precisely, a for statement like +

    -       for var = e1, e2, e3 do block end
    -
    + for var = e1, e2, e3 do block end +

    is equivalent to the code: +

    -       do
    -         local _var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
    -         if not (_var and _limit and _step) then error() end
    -         while (_step>0 and _var<=_limit) or (_step<=0 and _var>=_limit) do
    -           local var = _var
    -           block
    -           _var = _var + _step
    -         end
    +     do
    +       local _var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
    +       if not (_var and _limit and _step) then error() end
    +       while (_step>0 and _var<=_limit) or (_step<=0 and _var>=_limit) do
    +         local var = _var
    +         block
    +         _var = _var + _step
            end
    -
    + end +

    Note the following: +

      -
    • All three control expressions are evaluated only once, + +
    • +All three control expressions are evaluated only once, before the loop starts. They must all result in numbers. -
    • _var, _limit, and _step are invisible variables. +
    • + +
    • +_var, _limit, and _step are invisible variables. The names are here for explanatory purposes only. -
    • If the third expression (the step) is absent, -then a step of 1 is used. -
    • You can use break to exit a for loop. -
    • The loop variable var is local to the loop; +
    • + +
    • +If the third expression (the step) is absent, +then a step of 1 is used. +
    • + +
    • +You can use break to exit a for loop. +
    • + +
    • +The loop variable var is local to the loop; you cannot use its value after the for ends or is broken. If you need the value of the loop variable var, then assign it to another variable before breaking or exiting the loop. +
    • +
    -

    The generic for statement works over functions, +

    +The generic for statement works over functions, called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil. The generic for loop has the following syntax: +

     	stat ::= for namelist in explist1 do block end
     	namelist ::= Name {`,´ Name}
    -
    +

    A for statement like +

    -       for var_1, ..., var_n in explist do block end
    -
    + for var_1, ···, var_n in explist do block end +

    is equivalent to the code: +

    -       do
    -         local _f, _s, _var = explist
    -         while true do
    -           local var_1, ... , var_n = _f(_s, _var)
    -           _var = var_1
    -           if _var == nil then break end
    -           block
    -         end
    +     do
    +       local _f, _s, _var = explist
    +       while true do
    +         local var_1, ···, var_n = _f(_s, _var)
    +         _var = var_1
    +         if _var == nil then break end
    +         block
            end
    -
    + end +

    Note the following: +

      -
    • explist is evaluated only once. + +
    • +explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable. -
    • _f, _s, and _var are invisible variables. +
    • + +
    • +_f, _s, and _var are invisible variables. The names are here for explanatory purposes only. -
    • You can use break to exit a for loop. -
    • The loop variables var_i are local to the loop; +
    • + +
    • +You can use break to exit a for loop. +
    • + +
    • +The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop. +
    • +
    -

    2.4.6 - Function Calls as Statements

    + + + +

    2.4.6 - Function Calls as Statements

    To allow possible side-effects, function calls can be executed as statements: +

     	stat ::= functioncall
    -
    +

    In this case, all returned values are thrown away. -Function calls are explained in 2.5.8. +Function calls are explained in §2.5.8. + -

    2.4.7 - Local Declarations

    + + + +

    2.4.7 - Local Declarations

    Local variables may be declared anywhere inside a block. The declaration may include an initial assignment: +

     	stat ::= local namelist [`=´ explist1]
    -
    +

    If present, an initial assignment has the same semantics -of a multiple assignment (see 2.4.3). +of a multiple assignment (see §2.4.3). Otherwise, all variables are initialized with nil. -

    A chunk is also a block (see 2.4.1), + +

    +A chunk is also a block (see §2.4.1), and so local variables can be declared in a chunk outside any explicit block. The scope of such local variables extends until the end of the chunk. -

    The visibility rules for local variables are explained in 2.6. -

    2.5 - Expressions

    +

    +The visibility rules for local variables are explained in §2.6. + + + + + + + +

    2.5 - Expressions

    The basic expressions in Lua are the following: +

     	exp ::= prefixexp
    -	exp ::= nil  |  false  |  true
    +	exp ::= nil | false | true
     	exp ::= Number
     	exp ::= String
     	exp ::= function
    @@ -681,28 +880,33 @@ 

    exp ::= `...´ exp ::= exp binop exp exp ::= unop exp - prefixexp ::= var | functioncall | `(´ exp `)´ + prefixexp ::= var | functioncall | `(´ exp `)´

    -

    Numbers and literal strings are explained in 2.1; -variables are explained in 2.3; -function definitions are explained in 2.5.9; -function calls are explained in 2.5.8; -table constructors are explained in 2.5.7. +

    +Numbers and literal strings are explained in §2.1; +variables are explained in §2.3; +function definitions are explained in §2.5.9; +function calls are explained in §2.5.8; +table constructors are explained in §2.5.7. Vararg expressions, -denoted by three dots (`...´), can only be used inside +denoted by three dots ('...'), can only be used inside vararg functions; -they are explained in 2.5.9. +they are explained in §2.5.9. + +

    +Binary operators comprise arithmetic operators (see §2.5.1), +relational operators (see §2.5.2), logical operators (see §2.5.3), +and the concatenation operator (see §2.5.4). +Unary operators comprise the unary minus (see §2.5.1), +the unary not (see §2.5.3), +and the unary length operator (see §2.5.5). -

    Binary operators comprise arithmetic operators (see 2.5.1), -relational operators (see 2.5.2), and logical operators (see 2.5.3). -Unary operators comprise the unary minus (see 2.5.1), -the unary not (see 2.5.3), -and the unary length operator (see 2.5.5). -

    Both function calls and vararg expressions may result in multiple values. -If the expression is used as a statement (see 2.4.6) +

    +Both function calls and vararg expressions may result in multiple values. +If the expression is used as a statement (see §2.4.6) (only possible for function calls), then its return list is adjusted to zero elements, thus discarding all returned values. @@ -714,99 +918,122 @@

    then no adjustment is made, unless the call is enclosed in parentheses. -

    Here are some examples: + +

    +Here are some examples: +

    -       f()                -- adjusted to 0 results
    -       g(f(), x)          -- f() is adjusted to 1 result
    -       g(x, f())          -- g gets x plus all values returned by f()
    -       a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
    -       a,b = ...          -- a gets the first vararg parameter, b gets
    -                          -- the second (both a and b may get nil if there is
    -                          -- no corresponding vararg parameter)
    -       a,b,c = x, f()     -- f() is adjusted to 2 results
    -       a,b,c = f()        -- f() is adjusted to 3 results
    -       return f()         -- returns all values returned by f()
    -       return ...         -- returns all received vararg parameters
    -       return x,y,f()     -- returns x, y, and all values returned by f()
    -       {f()}              -- creates a list with all values returned by f()
    -       {...}              -- creates a list with all vararg parameters
    -       {f(), nil}         -- f() is adjusted to 1 result
    +     f()                -- adjusted to 0 results
    +     g(f(), x)          -- f() is adjusted to 1 result
    +     g(x, f())          -- g gets x plus all values returned by f()
    +     a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
    +     a,b = ...          -- a gets the first vararg parameter, b gets
    +                        -- the second (both a and b may get nil if there is
    +                        -- no corresponding vararg parameter)
    +     a,b,c = x, f()     -- f() is adjusted to 2 results
    +     a,b,c = f()        -- f() is adjusted to 3 results
    +     return f()         -- returns all values returned by f()
    +     return ...         -- returns all received vararg parameters
    +     return x,y,f()     -- returns x, y, and all values returned by f()
    +     {f()}              -- creates a list with all values returned by f()
    +     {...}              -- creates a list with all vararg parameters
    +     {f(), nil}         -- f() is adjusted to 1 result
     
    -

    An expression enclosed in parentheses always results in only one value. +

    +An expression enclosed in parentheses always results in only one value. Thus, (f(x,y,z)) is always a single value, even if f returns several values. (The value of (f(x,y,z)) is the first value returned by f or nil if f does not return any values.) -

    2.5.1 - Arithmetic Operators

    + + +

    2.5.1 - Arithmetic Operators

    Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), / (division), % (modulo), and ^ (exponentiation); and unary - (negation). If the operands are numbers, or strings that can be converted to -numbers (see 2.2.1), +numbers (see §2.2.1), then all operations have the usual meaning. Exponentiation works for any exponent. For instance, x^(-0.5) computes the inverse of the square root of x. -Modulus is defined as +Modulo is defined as +

    -       a % b == a - math.floor(a/b)*b
    -
    + a % b == a - math.floor(a/b)*b +

    That is, it is the remainder of a division that rounds the quotient towards minus infinity. -

    2.5.2 - Relational Operators

    + + + + +

    2.5.2 - Relational Operators

    The relational operators in Lua are +

    -       ==    ~=    <     >     <=    >=
    -
    + == ~= < > <= >= +

    These operators always result in false or true. -

    Equality (==) first compares the type of its operands. + +

    +Equality (==) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. Objects (tables, userdata, threads, and functions) are compared by reference: -Two objects are considered equal only if they are the same object. +two objects are considered equal only if they are the same object. Every time you create a new object (a table, userdata, thread, or function), this new object is different from any previously existing object. -

    You can change the way that Lua compares tables and userdata -by using the "eq" metamethod (see 2.8). -

    The conversion rules of 2.2.1 +

    +You can change the way that Lua compares tables and userdata +by using the "eq" metamethod (see §2.8). + + +

    +The conversion rules of §2.2.1 do not apply to equality comparisons. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table. -

    The operator ~= is exactly the negation of equality (==). +

    +The operator ~= is exactly the negation of equality (==). + -

    The order operators work as follows. +

    +The order operators work as follows. If both arguments are numbers, then they are compared as such. Otherwise, if both arguments are strings, then their values are compared according to the current locale. Otherwise, Lua tries to call the "lt" or the "le" -metamethod (see 2.8). +metamethod (see §2.8). -

    2.5.3 - Logical Operators

    -The logical operators in Lua are -
    -       and   or    not
    -
    -Like the control structures (see 2.4.4), + + + +

    2.5.3 - Logical Operators

    +The logical operators in Lua are +and, or, and not. +Like the control structures (see §2.4.4), all logical operators consider both false and nil as false and anything else as true. -

    The negation operator not always returns false or true. +

    +The negation operator not always returns false or true. The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument. @@ -817,34 +1044,46 @@

    that is, the second operand is evaluated only if necessary. Here are some examples: +
    -       10 or 20            --> 10
    -       10 or error()       --> 10
    -       nil or "a"          --> "a"
    -       nil and 10          --> nil
    -       false and error()   --> false
    -       false and nil       --> false
    -       false or nil        --> nil
    -       10 and 20           --> 20
    -
    + 10 or 20 --> 10 + 10 or error() --> 10 + nil or "a" --> "a" + nil and 10 --> nil + false and error() --> false + false and nil --> false + false or nil --> nil + 10 and 20 --> 20 +

    (In this manual, -`-->´ indicates the result of the preceding expression.) +--> indicates the result of the preceding expression.) + + -

    2.5.4 - Concatenation

    + + +

    2.5.4 - Concatenation

    The string concatenation operator in Lua is -denoted by two dots (`..´). +denoted by two dots ('..'). If both operands are strings or numbers, then they are converted to -strings according to the rules mentioned in 2.2.1. -Otherwise, the "concat" metamethod is called (see 2.8). +strings according to the rules mentioned in §2.2.1. +Otherwise, the "concat" metamethod is called (see §2.8). + + -

    2.5.5 - The Length Operator

    -

    The length operator is denoted by the unary operator #. + +

    2.5.5 - The Length Operator

    + +

    +The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte). -

    The length of a table t is defined to be any + +

    +The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n may be zero. @@ -858,39 +1097,50 @@

    (that is, it may consider any such nil value as the end of the array). -

    2.5.6 - Precedence

    + + + + +

    2.5.6 - Precedence

    Operator precedence in Lua follows the table below, from lower to higher priority: +

    -       or
    -       and
    -       <     >     <=    >=    ~=    ==
    -       ..
    -       +     -
    -       *     /     %
    -       not   #     - (unary)
    -       ^
    -
    + or + and + < > <= >= ~= == + .. + + - + * / % + not # - (unary) + ^ +

    As usual, you can use parentheses to change the precedences of an expression. -The concatenation (`..´) and exponentiation (`^´) +The concatenation ('..') and exponentiation ('^') operators are right associative. All other binary operators are left associative. -

    2.5.7 - Table Constructors

    + + + + +

    2.5.7 - Table Constructors

    Table constructors are expressions that create tables. Every time a constructor is evaluated, a new table is created. Constructors can be used to create empty tables, or to create a table and initialize some of its fields. The general syntax for constructors is +

     	tableconstructor ::= `{´ [fieldlist] `}´
     	fieldlist ::= field {fieldsep field} [fieldsep]
    -	field ::= `[´ exp `]´ `=´ exp  |  Name `=´ exp  |  exp
    -	fieldsep ::= `,´  |  `;´
    +	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
    +	fieldsep ::= `,´ | `;´
     
    -

    Each field of the form [exp1] = exp2 adds to the new table an entry +

    +Each field of the form [exp1] = exp2 adds to the new table an entry with key exp1 and value exp2. A field of the form name = exp is equivalent to ["name"] = exp. @@ -899,90 +1149,113 @@

    starting with 1. Fields in the other formats do not affect this counting. For example, +
    -       a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
    -
    + a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 } +

    is equivalent to +

    -       do
    -         local t = {}
    -         t[f(1)] = g
    -         t[1] = "x"         -- 1st exp
    -         t[2] = "y"         -- 2nd exp
    -         t.x = 1            -- t["x"] = 1
    -         t[3] = f(x)        -- 3rd exp
    -         t[30] = 23
    -         t[4] = 45          -- 4th exp
    -         a = t
    -       end
    +     do
    +       local t = {}
    +       t[f(1)] = g
    +       t[1] = "x"         -- 1st exp
    +       t[2] = "y"         -- 2nd exp
    +       t.x = 1            -- t["x"] = 1
    +       t[3] = f(x)        -- 3rd exp
    +       t[30] = 23
    +       t[4] = 45          -- 4th exp
    +       a = t
    +     end
     
    -

    If the last field in the list has the form exp +

    +If the last field in the list has the form exp and the expression is a function call or a vararg expression, then all values returned by this expression enter the list consecutively -(see 2.5.8). +(see §2.5.8). To avoid this, enclose the function call (or the vararg expression) -in parentheses (see 2.5). +in parentheses (see §2.5). + -

    The field list may have an optional trailing separator, +

    +The field list may have an optional trailing separator, as a convenience for machine-generated code. -

    2.5.8 - Function Calls

    + + + + +

    2.5.8 - Function Calls

    A function call in Lua has the following syntax: +

     	functioncall ::= prefixexp args
    -
    +

    In a function call, -first prefixexp and args are evaluated. -If the value of prefixexp has type function, +first prefixexp and args are evaluated. +If the value of prefixexp has type function, then this function is called with the given arguments. -Otherwise, the prefixexp "call" metamethod is called, -having as first parameter the value of prefixexp, +Otherwise, the prefixexp "call" metamethod is called, +having as first parameter the value of prefixexp, followed by the original call arguments -(see 2.8). +(see §2.8). + + +

    +The form -

    The form

     	functioncall ::= prefixexp `:´ Name args
    -
    +

    can be used to call "methods". -A call v:name(...) -is syntactic sugar for v.name(v,...), +A call v:name(args) +is syntactic sugar for v.name(v,args), except that v is evaluated only once. -

    Arguments have the following syntax: + +

    +Arguments have the following syntax: +

     	args ::= `(´ [explist1] `)´
     	args ::= tableconstructor
     	args ::= String
    -
    +

    All argument expressions are evaluated before the call. -A call of the form f{...} is syntactic sugar for f({...}); +A call of the form f{fields} is +syntactic sugar for f({fields}); that is, the argument list is a single new table. -A call of the form f'...' -(or f"..." or f[[...]]) is syntactic sugar for f('...'); +A call of the form f'string' +(or f"string" or f[[string]]) +is syntactic sugar for f('string'); that is, the argument list is a single literal string. -

    As an exception to the free-format syntax of Lua, -you cannot put a line break before the `(´ in a function call. + +

    +As an exception to the free-format syntax of Lua, +you cannot put a line break before the '(' in a function call. This restriction avoids some ambiguities in the language. If you write +

    -       a = f
    -       (g).x(a)
    -
    + a = f + (g).x(a) +

    Lua would see that as a single statement, a = f(g).x(a). So, if you want two statements, you must add a semi-colon between them. If you actually want to call f, you must remove the line break before (g). -

    A call of the form return functioncall is called + +

    +A call of the form return functioncall is called a tail call. Lua implements proper tail calls (or proper tail recursion): -In a tail call, +in a tail call, the called function reuses the stack entry of the calling function. Therefore, there is no limit on the number of nested tail calls that a program can execute. @@ -993,60 +1266,77 @@

    this syntax makes the calling function return exactly the returns of the called function. So, none of the following examples are tail calls: +
    -       return (f(x))        -- results adjusted to 1
    -       return 2 * f(x)
    -       return x, f(x)       -- additional results
    -       f(x); return         -- results discarded
    -       return x or f(x)     -- results adjusted to 1
    +     return (f(x))        -- results adjusted to 1
    +     return 2 * f(x)
    +     return x, f(x)       -- additional results
    +     f(x); return         -- results discarded
    +     return x or f(x)     -- results adjusted to 1
     
    -

    2.5.9 - Function Definitions

    -

    The syntax for function definition is + + +

    2.5.9 - Function Definitions

    + +

    +The syntax for function definition is +

     	function ::= function funcbody
     	funcbody ::= `(´ [parlist1] `)´ block end
     
    -

    The following syntactic sugar simplifies function definitions: +

    +The following syntactic sugar simplifies function definitions: +

     	stat ::= function funcname funcbody
     	stat ::= local function Name funcbody
     	funcname ::= Name {`.´ Name} [`:´ Name]
    -
    +

    The statement +

    -       function f () ... end
    -
    + function f () body end +

    translates to +

    -       f = function () ... end
    -
    + f = function () body end +

    The statement +

    -       function t.a.b.c.f () ... end
    -
    + function t.a.b.c.f () body end +

    translates to +

    -       t.a.b.c.f = function () ... end
    -
    + t.a.b.c.f = function () body end +

    The statement +

    -       local function f () ... end
    -
    + local function f () body end +

    translates to +

    -       local f; f = function () ... end
    -
    -not this: + local f; f = function () body end +

    +not to +

    -       local f = function () ... end
    -
    + local f = function () body end +

    (This only makes a difference when the body of the function contains references to f.) -

    A function definition is an executable expression, + +

    +A function definition is an executable expression, whose value has type function. When Lua pre-compiles a chunk, all its function bodies are pre-compiled too. @@ -1058,17 +1348,20 @@

    may refer to different external local variables and may have different environment tables. -

    Parameters act as local variables that are + +

    +Parameters act as local variables that are initialized with the argument values: +

    -	parlist1 ::= namelist [`,´ `...´]  |  `...´
    -
    + parlist1 ::= namelist [`,´ `...´] | `...´ +

    When a function is called, the list of arguments is adjusted to the length of the list of parameters, unless the function is a variadic or vararg function, which is -indicated by three dots (`...´) at the end of its parameter list. +indicated by three dots ('...') at the end of its parameter list. A vararg function does not adjust its argument list; instead, it collects all extra arguments and supplies them to the function through a vararg expression, @@ -1082,114 +1375,148 @@

    then no adjustment is made (unless the call is enclosed in parentheses). -

    As an example, consider the following definitions: + +

    +As an example, consider the following definitions: +

    -       function f(a, b) end
    -       function g(a, b, ...) end
    -       function r() return 1,2,3 end
    -
    + function f(a, b) end + function g(a, b, ...) end + function r() return 1,2,3 end +

    Then, we have the following mapping from arguments to parameters and to the vararg expression: +

    -       CALL            PARAMETERS
    -
    -       f(3)             a=3, b=nil
    -       f(3, 4)          a=3, b=4
    -       f(3, 4, 5)       a=3, b=4
    -       f(r(), 10)       a=1, b=10
    -       f(r())           a=1, b=2
    -
    -       g(3)             a=3, b=nil, ... -->  (nothing)
    -       g(3, 4)          a=3, b=4,   ... -->  (nothing)
    -       g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
    -       g(5, r())        a=5, b=1,   ... -->  2  3
    +     CALL            PARAMETERS
    +     
    +     f(3)             a=3, b=nil
    +     f(3, 4)          a=3, b=4
    +     f(3, 4, 5)       a=3, b=4
    +     f(r(), 10)       a=1, b=10
    +     f(r())           a=1, b=2
    +     
    +     g(3)             a=3, b=nil, ... -->  (nothing)
    +     g(3, 4)          a=3, b=4,   ... -->  (nothing)
    +     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
    +     g(5, r())        a=5, b=1,   ... -->  2  3
     
    -

    Results are returned using the return statement (see 2.4.4). +

    +Results are returned using the return statement (see §2.4.4). If control reaches the end of a function without encountering a return statement, then the function returns with no results. -

    The colon syntax + +

    +The colon syntax is used for defining methods, that is, functions that have an implicit extra parameter self. Thus, the statement +

    -       function t.a.b.c:f (...) ... end
    -
    + function t.a.b.c:f (params) body end +

    is syntactic sugar for +

    -       t.a.b.c.f = function (self, ...) ... end
    +     t.a.b.c.f = function (self, params) body end
     
    -

    2.6 - Visibility Rules

    -

    Lua is a lexically scoped language. + + + +

    2.6 - Visibility Rules

    + +

    + +Lua is a lexically scoped language. The scope of variables begins at the first statement after their declaration and lasts until the end of the innermost block that includes the declaration. Consider the following example: +

    -       x = 10                -- global variable
    -       do                    -- new block
    -         local x = x         -- new `x', with value 10
    -         print(x)            --> 10
    -         x = x+1
    -         do                  -- another block
    -           local x = x+1     -- another `x'
    -           print(x)          --> 12
    -         end
    -         print(x)            --> 11
    +     x = 10                -- global variable
    +     do                    -- new block
    +       local x = x         -- new 'x', with value 10
    +       print(x)            --> 10
    +       x = x+1
    +       do                  -- another block
    +         local x = x+1     -- another 'x'
    +         print(x)          --> 12
            end
    -       print(x)              --> 10  (the global one)
    +       print(x)            --> 11
    +     end
    +     print(x)              --> 10  (the global one)
     
    -

    Notice that, in a declaration like local x = x, +

    +Notice that, in a declaration like local x = x, the new x being declared is not in scope yet, and so the second x refers to the outside variable. -

    Because of the lexical scoping rules, + +

    +Because of the lexical scoping rules, local variables can be freely accessed by functions defined inside their scope. A local variable used by an inner function is called an upvalue, or external local variable, inside the inner function. -

    Notice that each execution of a local statement + +

    +Notice that each execution of a local statement defines new local variables. Consider the following example: +

    -       a = {}
    -       local x = 20
    -       for i=1,10 do
    -         local y = 0
    -         a[i] = function () y=y+1; return x+y end
    -       end
    -
    + a = {} + local x = 20 + for i=1,10 do + local y = 0 + a[i] = function () y=y+1; return x+y end + end +

    The loop creates ten closures (that is, ten instances of the anonymous function). Each of these closures uses a different y variable, while all of them share the same x. -

    2.7 - Error Handling

    -

    Because Lua is an embedded extension language, -all Lua actions start from C code in the host program + + + +

    2.7 - Error Handling

    + +

    +Because Lua is an embedded extension language, +all Lua actions start from C code in the host program calling a function from the Lua library (see lua_pcall). Whenever an error occurs during Lua compilation or execution, control returns to C, which can take appropriate measures (such as printing an error message). -

    Lua code can explicitly generate an error by calling the + +

    +Lua code can explicitly generate an error by calling the error function. If you need to catch errors in Lua, you can use the pcall function. -

    2.8 - Metatables

    -

    Every value in Lua may have a metatable. + + + +

    2.8 - Metatables

    + +

    +Every value in Lua may have a metatable. This metatable is an ordinary Lua table that defines the behavior of the original value under certain special operations. @@ -1200,29 +1527,39 @@

    If it finds one, Lua calls this function to perform the addition. -

    We call the keys in a metatable events + +

    +We call the keys in a metatable events and the values metamethods. In the previous example, the event is "add" and the metamethod is the function that performs the addition. -

    You can query the metatable of any value + +

    +You can query the metatable of any value through the getmetatable function. -

    You can replace the metatable of tables + +

    +You can replace the metatable of tables through the setmetatable function. You cannot change the metatable of other types from Lua (except using the debug library); -you must use the C API for that. +you must use the C API for that. + -

    Tables and userdata have individual metatables +

    +Tables and userdata have individual metatables (although multiple tables and userdata can share a same table as their metatable); values of all other types share one single metatable per type. So, there is one single metatable for all numbers, and for all strings, etc. -

    A metatable may control how an object behaves in arithmetic operations, + +

    +A metatable may control how an object behaves in arithmetic operations, order comparisons, concatenation, length operation, and indexing. A metatable can also define a function to be called when a userdata is garbage collected. @@ -1230,342 +1567,414 @@

    called an event. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. -If so, the value associated with that key (the metamethod) +If so, the value associated with that key (the metamethod) controls how Lua will perform the operation. -

    Metatables control the operations listed next. + +

    +Metatables control the operations listed next. Each operation is identified by its corresponding name. The key for each operation is a string with its name prefixed by -two underscores, `__´; +two underscores, '__'; for instance, the key for operation "add" is the string "__add". The semantics of these operations is better explained by a Lua function describing how the interpreter executes the operation. -

    The code shown here in Lua is only illustrative; + +

    +The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter and it is much more efficient than this simulation. All functions used in these descriptions (rawget, tonumber, etc.) -are described in 5.1. +are described in §5.1. In particular, to retrieve the metamethod of a given object, we use the expression +

    -       metatable(obj)[event]
    -
    + metatable(obj)[event] +

    This should be read as +

    -       rawget(getmetatable(obj) or {}, event)
    -
    + rawget(getmetatable(obj) or {}, event) +

    That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail (it simply results in nil). -

      + + +
        +
      • "add": the + operation. -

        The function getbinhandler below defines how Lua chooses a handler + + +

        +The function getbinhandler below defines how Lua chooses a handler for a binary operation. First, Lua tries the first operand. If its type does not define a handler for the operation, then Lua tries the second operand. +

        - function getbinhandler (op1, op2, event)
        -   return metatable(op1)[event] or metatable(op2)[event]
        - end
        -
        -Using this function, + function getbinhandler (op1, op2, event) + return metatable(op1)[event] or metatable(op2)[event] + end +

        +By ysing this function, the behavior of the op1 + op2 is +

        - function add_event (op1, op2)
        -   local o1, o2 = tonumber(op1), tonumber(op2)
        -   if o1 and o2 then  -- both operands are numeric?
        -     return o1 + o2   -- `+' here is the primitive `add'
        -   else  -- at least one of the operands is not numeric
        -     local h = getbinhandler(op1, op2, "__add")
        -     if h then
        -       -- call the handler with both operands
        -       return h(op1, op2)
        -     else  -- no handler available: default behavior
        -       error("...")
        +     function add_event (op1, op2)
        +       local o1, o2 = tonumber(op1), tonumber(op2)
        +       if o1 and o2 then  -- both operands are numeric?
        +         return o1 + o2   -- '+' here is the primitive 'add'
        +       else  -- at least one of the operands is not numeric
        +         local h = getbinhandler(op1, op2, "__add")
        +         if h then
        +           -- call the handler with both operands
        +           return h(op1, op2)
        +         else  -- no handler available: default behavior
        +           error(···)
        +         end
        +       end
              end
        -   end
        - end
        -
        +

        +

      • -

      • "sub": +
      • "sub": the - operation. + Behavior similar to the "add" operation. +
      • -

      • "mul": +
      • "mul": the * operation. + Behavior similar to the "add" operation. +
      • -

      • "div": +
      • "div": the / operation. + Behavior similar to the "add" operation. +
      • -

      • "mod": +
      • "mod": the % operation. + Behavior similar to the "add" operation, with the operation o1 - floor(o1/o2)*o2 as the primitive operation. +
      • -

      • "pow": +
      • "pow": the ^ (exponentiation) operation. + Behavior similar to the "add" operation, -with the function pow (from the C math library) +with the function pow (from the C math library) as the primitive operation. +
      • -

      • "unm": +
      • "unm": the unary - operation. + +
        - function unm_event (op)
        -   local o = tonumber(op)
        -   if o then  -- operand is numeric?
        -     return -o  -- `-' here is the primitive `unm'
        -   else  -- the operand is not numeric.
        -     -- Try to get a handler from the operand
        -     local h = metatable(op).__unm
        -     if h then
        -       -- call the handler with the operand
        -       return h(op)
        -     else  -- no handler available: default behavior
        -       error("...")
        +     function unm_event (op)
        +       local o = tonumber(op)
        +       if o then  -- operand is numeric?
        +         return -o  -- '-' here is the primitive 'unm'
        +       else  -- the operand is not numeric.
        +         -- Try to get a handler from the operand
        +         local h = metatable(op).__unm
        +         if h then
        +           -- call the handler with the operand
        +           return h(op)
        +         else  -- no handler available: default behavior
        +           error(···)
        +         end
        +       end
              end
        -   end
        - end
        -
        +

        +

      • -

      • "concat": +
      • "concat": the .. (concatenation) operation. + +
        - function concat_event (op1, op2)
        -   if (type(op1) == "string" or type(op1) == "number") and
        -      (type(op2) == "string" or type(op2) == "number") then
        -     return op1 .. op2  -- primitive string concatenation
        -   else
        -     local h = getbinhandler(op1, op2, "__concat")
        -     if h then
        -       return h(op1, op2)
        -     else
        -       error("...")
        +     function concat_event (op1, op2)
        +       if (type(op1) == "string" or type(op1) == "number") and
        +          (type(op2) == "string" or type(op2) == "number") then
        +         return op1 .. op2  -- primitive string concatenation
        +       else
        +         local h = getbinhandler(op1, op2, "__concat")
        +         if h then
        +           return h(op1, op2)
        +         else
        +           error(···)
        +         end
        +       end
              end
        -   end
        - end
        -
        +

        +

      • -

      • "len": +
      • "len": the # operation. + +
        - function len_event (op)
        -   if type(op) == "string" then
        -     return strlen(op)         -- primitive string length
        -   elseif type(op) == "table" then
        -     return #op                -- primitive table length
        -   else
        -     local h = metatable(op).__len
        -     if h then
        -       -- call the handler with the operand
        -       return h(op)
        -     else  -- no handler available: default behavior
        -       error("...")
        +     function len_event (op)
        +       if type(op) == "string" then
        +         return strlen(op)         -- primitive string length
        +       elseif type(op) == "table" then
        +         return #op                -- primitive table length
        +       else
        +         local h = metatable(op).__len
        +         if h then
        +           -- call the handler with the operand
        +           return h(op)
        +         else  -- no handler available: default behavior
        +           error(···)
        +         end
        +       end
              end
        -   end
        - end
        -
        -See 2.5.5 for a description of the length of a table. +

        +See §2.5.5 for a description of the length of a table. +

      • -

      • "eq": +
      • "eq": the == operation. + The function getcomphandler defines how Lua chooses a metamethod for comparison operators. A metamethod only is selected when both objects being compared have the same type and the same metamethod for the selected operation. +
        - function getcomphandler (op1, op2, event)
        -   if type(op1) ~= type(op2) then return nil end
        -   local mm1 = metatable(op1)[event]
        -   local mm2 = metatable(op2)[event]
        -   if mm1 == mm2 then return mm1 else return nil end
        - end
        -
        + function getcomphandler (op1, op2, event) + if type(op1) ~= type(op2) then return nil end + local mm1 = metatable(op1)[event] + local mm2 = metatable(op2)[event] + if mm1 == mm2 then return mm1 else return nil end + end +

        The "eq" event is defined as follows: +

        - function eq_event (op1, op2)
        -   if type(op1) ~= type(op2) then  -- different types?
        -     return false   -- different objects
        -   end
        -   if op1 == op2 then   -- primitive equal?
        -     return true   -- objects are equal
        -   end
        -   -- try metamethod
        -   local h = getcomphandler(op1, op2, "__eq")
        -   if h then
        -     return h(op1, op2)
        -   else
        -     return false
        -   end
        - end
        -
        + function eq_event (op1, op2) + if type(op1) ~= type(op2) then -- different types? + return false -- different objects + end + if op1 == op2 then -- primitive equal? + return true -- objects are equal + end + -- try metamethod + local h = getcomphandler(op1, op2, "__eq") + if h then + return h(op1, op2) + else + return false + end + end +

        a ~= b is equivalent to not (a == b). +

      • + +
      • "lt": +the < operation. + -

      • "lt": -the < operation.
        - function lt_event (op1, op2)
        -   if type(op1) == "number" and type(op2) == "number" then
        -     return op1 < op2   -- numeric comparison
        -   elseif type(op1) == "string" and type(op2) == "string" then
        -     return op1 < op2   -- lexicographic comparison
        -   else
        -     local h = getcomphandler(op1, op2, "__lt")
        -     if h then
        -       return h(op1, op2)
        -     else
        -       error("...");
        +     function lt_event (op1, op2)
        +       if type(op1) == "number" and type(op2) == "number" then
        +         return op1 < op2   -- numeric comparison
        +       elseif type(op1) == "string" and type(op2) == "string" then
        +         return op1 < op2   -- lexicographic comparison
        +       else
        +         local h = getcomphandler(op1, op2, "__lt")
        +         if h then
        +           return h(op1, op2)
        +         else
        +           error(···);
        +         end
        +       end
              end
        -   end
        - end
        -
        -a > b is equivalent to b < a. +

        +a > b is equivalent to b < a. +

      • + +
      • "le": +the <= operation. + -

      • "le": -the <= operation.
        - function le_event (op1, op2)
        -   if type(op1) == "number" and type(op2) == "number" then
        -     return op1 <= op2   -- numeric comparison
        -   elseif type(op1) == "string" and type(op2) == "string" then
        -     return op1 <= op2   -- lexicographic comparison
        -   else
        -     local h = getcomphandler(op1, op2, "__le")
        -     if h then
        -       return h(op1, op2)
        -     else
        -       h = getcomphandler(op1, op2, "__lt")
        -       if h then
        -         return not h(op2, op1)
        +     function le_event (op1, op2)
        +       if type(op1) == "number" and type(op2) == "number" then
        +         return op1 <= op2   -- numeric comparison
        +       elseif type(op1) == "string" and type(op2) == "string" then
        +         return op1 <= op2   -- lexicographic comparison
                else
        -         error("...");
        +         local h = getcomphandler(op1, op2, "__le")
        +         if h then
        +           return h(op1, op2)
        +         else
        +           h = getcomphandler(op1, op2, "__lt")
        +           if h then
        +             return not h(op2, op1)
        +           else
        +             error(···);
        +           end
        +         end
                end
              end
        -   end
        - end
        -
        -a >= b is equivalent to b <= a. +

        +a >= b is equivalent to b <= a. Note that, in the absence of a "le" metamethod, -Lua tries the "lt", assuming that a <= b is -equivalent to not (b < a). +Lua tries the "lt", assuming that a <= b is +equivalent to not (b < a). +

      • -

      • "index": +
      • "index": The indexing access table[key]. + +
        - function gettable_event (table, key)
        -   local h
        -   if type(table) == "table" then
        -     local v = rawget(table, key)
        -     if v ~= nil then return v end
        -     h = metatable(table).__index
        -     if h == nil then return nil end
        -   else
        -     h = metatable(table).__index
        -     if h == nil then
        -       error("...");
        +     function gettable_event (table, key)
        +       local h
        +       if type(table) == "table" then
        +         local v = rawget(table, key)
        +         if v ~= nil then return v end
        +         h = metatable(table).__index
        +         if h == nil then return nil end
        +       else
        +         h = metatable(table).__index
        +         if h == nil then
        +           error(···);
        +         end
        +       end
        +       if type(h) == "function" then
        +         return h(table, key)      -- call the handler
        +       else return h[key]          -- or repeat operation on it
        +       end
              end
        -   end
        -   if type(h) == "function" then
        -     return h(table, key)      -- call the handler
        -   else return h[key]          -- or repeat operation on it
        -   end
        - end
        -
        +

        +

      • -

      • "newindex": +
      • "newindex": The indexing assignment table[key] = value. + +
        - function settable_event (table, key, value)
        -   local h
        -   if type(table) == "table" then
        -     local v = rawget(table, key)
        -     if v ~= nil then rawset(table, key, value); return end
        -     h = metatable(table).__newindex
        -     if h == nil then rawset(table, key, value); return end
        -   else
        -     h = metatable(table).__newindex
        -     if h == nil then
        -       error("...");
        +     function settable_event (table, key, value)
        +       local h
        +       if type(table) == "table" then
        +         local v = rawget(table, key)
        +         if v ~= nil then rawset(table, key, value); return end
        +         h = metatable(table).__newindex
        +         if h == nil then rawset(table, key, value); return end
        +       else
        +         h = metatable(table).__newindex
        +         if h == nil then
        +           error(···);
        +         end
        +       end
        +       if type(h) == "function" then
        +         return h(table, key,value)    -- call the handler
        +       else h[key] = value             -- or repeat operation on it
        +       end
              end
        -   end
        -   if type(h) == "function" then
        -     return h(table, key,value)    -- call the handler
        -   else h[key] = value             -- or repeat operation on it
        -   end
        - end
        -
        +

        +

      • -

      • "call": +
      • "call": called when Lua calls a value. + +
        - function function_event (func, ...)
        -   if type(func) == "function" then
        -     return func(...)   -- primitive call
        -   else
        -     local h = metatable(func).__call
        -     if h then
        -       return h(func, ...)
        -     else
        -       error("...")
        +     function function_event (func, ...)
        +       if type(func) == "function" then
        +         return func(...)   -- primitive call
        +       else
        +         local h = metatable(func).__call
        +         if h then
        +           return h(func, ...)
        +         else
        +           error(···)
        +         end
        +       end
              end
        -   end
        - end
        -
        +

        +

      • + +
      + + -

    -

    2.9 - Environments

    +

    2.9 - Environments

    -

    Besides metatables, +

    +Besides metatables, objects of types thread, function, and userdata have another table associated with them, called their environment. Like metatables, environments are regular tables and multiple objects can share the same environment. -

    Environments associated with userdata have no meaning for Lua. -It is only a feature for programmers to associate a table to + +

    +Environments associated with userdata have no meaning for Lua. +It is only a convenience feature for programmers to associate a table to a userdata. -

    Environments associated with threads are called + +

    +Environments associated with threads are called global environments. -They are used as the default environment for threads and +They are used as the default environment for their threads and non-nested functions created by the thread (through loadfile, loadstring or load) -and can be directly accessed by C code (see 3.3). +and can be directly accessed by C code (see §3.3). + -

    Environments associated with C functions can be directly -accessed by C code (see 3.3). -They are used as the default environment for other C functions +

    +Environments associated with C functions can be directly +accessed by C code (see §3.3). +They are used as the default environment for other C functions created by the function. -

    Environments associated with Lua functions are used to resolve -all accesses to global variables within the function (see 2.3). + +

    +Environments associated with Lua functions are used to resolve +all accesses to global variables within the function (see §2.3). They are used as the default environment for other Lua functions created by the function. -

    You can change the environment of a Lua function or the + +

    +You can change the environment of a Lua function or the running thread by calling setfenv. You can get the environment of a Lua function or the running thread by calling getfenv. To manipulate the environment of other objects -(userdata, C functions, other threads) you must -use the C API. +(userdata, C functions, other threads) you must +use the C API. + -

    2.10 - Garbage Collection

    -

    Lua performs automatic memory management. + + +

    2.10 - Garbage Collection

    + +

    +Lua performs automatic memory management. This means that you have to worry neither about allocating memory for new objects nor about freeing it when the objects are no longer needed. @@ -1576,12 +1985,16 @@

    All objects in Lua are subject to automatic management: tables, userdata, functions, threads, and strings. -

    Lua implements an incremental mark-and-sweep collector. + +

    +Lua implements an incremental mark-and-sweep collector. It uses two numbers to control its garbage-collection cycles: the garbage-collector pause and the garbage-collector step multiplier. -

    The garbage-collector pause + +

    +The garbage-collector pause controls how long the collector waits before starting a new cycle. Larger values make the collector less aggressive. Values smaller than 1 mean the collector will not wait to @@ -1589,65 +2002,83 @@

    A value of 2 means that the collector waits for the total memory in use to double before starting a new cycle. -

    The step multiplier + +

    +The step multiplier controls the relative speed of the collector relative to memory allocation. -Larger values make the collector more aggressive but also increases +Larger values make the collector more aggressive but also increase the size of each incremental step. Values smaller than 1 make the collector too slow and may result in the collector never finishing a cycle. The default, 2, means that the collector runs at "twice" the speed of memory allocation. -

    You can change these numbers by calling lua_gc in C + +

    +You can change these numbers by calling lua_gc in C or collectgarbage in Lua. -Both get as arguments percentage points -(so an argument 100 means a real value of 1). +Both get percentage points as arguments +(so an argument of 100 means a real value of 1). With these functions you can also control the collector directly (e.g., stop and restart it). -

    2.10.1 - Garbage-Collection Metamethods

    -

    Using the C API, -you can set garbage-collector metamethods for userdata (see 2.8). + +

    2.10.1 - Garbage-Collection Metamethods

    + +

    +Using the C API, +you can set garbage-collector metamethods for userdata (see §2.8). These metamethods are also called finalizers. Finalizers allow you to coordinate Lua's garbage collection with external resource management (such as closing files, network or database connections, or freeing your own memory). -

    Garbage userdata with a field __gc in their metatables are not + +

    +Garbage userdata with a field __gc in their metatables are not collected immediately by the garbage collector. Instead, Lua puts them in a list. After the collection, Lua does the equivalent of the following function for each userdata in that list: +

    - function gc_event (udata)
    -   local h = metatable(udata).__gc
    -   if h then
    -     h(udata)
    -   end
    - end
    +     function gc_event (udata)
    +       local h = metatable(udata).__gc
    +       if h then
    +         h(udata)
    +       end
    +     end
     
    -

    At the end of each garbage-collection cycle, +

    +At the end of each garbage-collection cycle, the finalizers for userdata are called in reverse order of their creation, among those collected in that cycle. That is, the first finalizer to be called is the one associated with the userdata created last in the program. -

    2.10.2 - Weak Tables

    -

    A weak table is a table whose elements are + + + +

    2.10.2 - Weak Tables

    + +

    +A weak table is a table whose elements are weak references. A weak reference is ignored by the garbage collector. In other words, if the only references to an object are weak references, then the garbage collector will collect this object. -

    A weak table can have weak keys, weak values, or both. + +

    +A weak table can have weak keys, weak values, or both. A table with weak keys allows the collection of its keys, but prevents the collection of its values. A table with both weak keys and weak values allows the collection of @@ -1656,33 +2087,46 @@

    the whole pair is removed from the table. The weakness of a table is controlled by the value of the __mode field of its metatable. -If the __mode field is a string containing the character `k´, +If the __mode field is a string containing the character 'k', the keys in the table are weak. -If __mode contains `v´, +If __mode contains 'v', the values in the table are weak. -

    After you use a table as a metatable, + +

    +After you use a table as a metatable, you should not change the value of its field __mode. Otherwise, the weak behavior of the tables controlled by this metatable is undefined. -

    2.11 - Coroutines

    -

    Lua supports coroutines, + + + + + +

    2.11 - Coroutines

    + +

    +Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function. -

    You create a coroutine with a call to coroutine.create. + +

    +You create a coroutine with a call to coroutine.create. Its sole argument is a function that is the main function of the coroutine. The create function only creates a new coroutine and returns a handle to it (an object of type thread); it does not start the coroutine execution. -

    When you first call coroutine.resume, + +

    +When you first call coroutine.resume, passing as its first argument the thread returned by coroutine.create, the coroutine starts its execution, @@ -1692,8 +2136,10 @@

    After the coroutine starts running, it runs until it terminates or yields. -

    A coroutine can terminate its execution in two ways: -Normally, when its main function returns + +

    +A coroutine can terminate its execution in two ways: +normally, when its main function returns (explicitly or implicitly, after the last instruction); and abnormally, if there is an unprotected error. In the first case, coroutine.resume returns true, @@ -1701,7 +2147,9 @@

    In case of errors, coroutine.resume returns false plus an error message. -

    A coroutine yields by calling coroutine.yield. + +

    +A coroutine yields by calling coroutine.yield. When a coroutine yields, the corresponding coroutine.resume returns immediately, even if the yield happens inside nested function calls @@ -1714,170 +2162,217 @@

    with the call to coroutine.yield returning any extra arguments passed to coroutine.resume. -

    The coroutine.wrap function creates a coroutine, + +

    +The coroutine.wrap function creates a coroutine, just like coroutine.create, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. Any arguments passed to this function go as extra arguments to coroutine.resume. -coroutine.wrap returns all the values returned by coroutine.resume, +coroutine.wrap returns all the values returned by coroutine.resume, except the first one (the boolean error code). Unlike coroutine.resume, -coroutine.wrap does not catch errors; +coroutine.wrap does not catch errors; any error is propagated to the caller. -

    As an example, -consider the next code: + +

    +As an example, +consider the following code: +

    -function foo (a)
    -  print("foo", a)
    -  return coroutine.yield(2*a)
    -end
    -
    -co = coroutine.create(function (a,b)
    -      print("co-body", a, b)
    -      local r = foo(a+1)
    -      print("co-body", r)
    -      local r, s = coroutine.yield(a+b, a-b)
    -      print("co-body", r, s)
    -      return b, "end"
    -end)
    -       
    -print("main", coroutine.resume(co, 1, 10))
    -print("main", coroutine.resume(co, "r"))
    -print("main", coroutine.resume(co, "x", "y"))
    -print("main", coroutine.resume(co, "x", "y"))
    -
    + function foo (a) + print("foo", a) + return coroutine.yield(2*a) + end + + co = coroutine.create(function (a,b) + print("co-body", a, b) + local r = foo(a+1) + print("co-body", r) + local r, s = coroutine.yield(a+b, a-b) + print("co-body", r, s) + return b, "end" + end) + + print("main", coroutine.resume(co, 1, 10)) + print("main", coroutine.resume(co, "r")) + print("main", coroutine.resume(co, "x", "y")) + print("main", coroutine.resume(co, "x", "y")) +

    When you run it, it produces the following output: +

    -co-body 1       10
    -foo     2
    -main    true    4
    -co-body r
    -main    true    11      -9
    -co-body x       y
    -main    true    10      end
    -main    false   cannot resume dead coroutine
    +     co-body 1       10
    +     foo     2
    +     main    true    4
    +     co-body r
    +     main    true    11      -9
    +     co-body x       y
    +     main    true    10      end
    +     main    false   cannot resume dead coroutine
     
    -

    -

    3 - The Application Program Interface

    -

    This section describes the C API for Lua, that is, -the set of C functions available to the host program to communicate + +

    3 - The Application Program Interface

    + +

    + +This section describes the C API for Lua, that is, +the set of C functions available to the host program to communicate with Lua. All API functions and related types and constants -are declared in the header file lua.h. +are declared in the header file lua.h. + -

    Even when we use the term "function", +

    +Even when we use the term "function", any facility in the API may be provided as a macro instead. -All such macros use each of its arguments exactly once +All such macros use each of their arguments exactly once (except for the first argument, which is always a Lua state), and so do not generate any hidden side-effects. -

    As in most C libraries, + +

    +As in most C libraries, the Lua API functions do not check their arguments for validity or consistency. However, you can change this behavior by compiling Lua -with a proper definition for the macro luai_apicheck, +with a proper definition for the macro luai_apicheck, in file luaconf.h. -

    3.1 - The Stack

    -

    Lua uses a virtual stack to pass values to and from C. + +

    3.1 - The Stack

    + +

    +Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value (nil, number, string, etc.). -

    Whenever Lua calls C, the called function gets a new stack, + +

    +Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of -C functions that are still active. -This stack initially contains any arguments to the C function -and it is where the C function pushes its results +C functions that are still active. +This stack initially contains any arguments to the C function +and it is where the C function pushes its results to be returned to the caller (see lua_CFunction). -

    For convenience, + +

    +For convenience, most query operations in the API do not follow a strict stack discipline. Instead, they can refer to any element in the stack by using an index: A positive index represents an absolute stack position -(starting at 1); +(starting at 1); a negative index represents an offset relative to the top of the stack. More specifically, if the stack has n elements, -then index 1 represents the first element +then index 1 represents the first element (that is, the element that was pushed onto the stack first) and -index n represents the last element; -index -1 also represents the last element +index n represents the last element; +index -1 also represents the last element (that is, the element at the top) and index -n represents the first element. We say that an index is valid -if it lies between 1 and the stack top -(that is, if 1 <= abs(index) <= top). +if it lies between 1 and the stack top +(that is, if 1 ≤ abs(index) ≤ top). -

    3.2 - Stack Size

    -

    When you interact with Lua API, + + + +

    3.2 - Stack Size

    + +

    +When you interact with Lua API, you are responsible for ensuring consistency. In particular, you are responsible for controlling stack overflow. You can use the function lua_checkstack to grow the stack size. -

    Whenever Lua calls C, + +

    +Whenever Lua calls C, LUA_MINSTACK it ensures that at least LUA_MINSTACK stack positions are available. LUA_MINSTACK is defined as 20, so that usually you do not have to worry about stack space unless your code has loops pushing elements onto the stack. -

    Most query functions accept as indices any value inside the + +

    +Most query functions accept as indices any value inside the available stack space, that is, indices up to the maximum stack size you have set through lua_checkstack. Such indices are called acceptable indices. More formally, we define an acceptable index as follows: +

    -       (index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
    -
    + (index < 0 && abs(index) <= top) || + (index > 0 && index <= stackspace) +

    Note that 0 is never an acceptable index. -

    3.3 - Pseudo-Indices

    -

    Unless otherwise noted, + + + +

    3.3 - Pseudo-Indices

    + +

    +Unless otherwise noted, any function that accepts valid indices can also be called with pseudo-indices, -which represent some Lua values that are accessible to C code +which represent some Lua values that are accessible to C code but which are not in the stack. Pseudo-indices are used to access the thread environment, the function environment, the registry, -and the upvalues of a C function (see 3.4). +and the upvalues of a C function (see §3.4). + + +

    +The thread environment (where global variables live) is +always at pseudo-index LUA_GLOBALSINDEX. +The environment of the running C function is always +at pseudo-index LUA_ENVIRONINDEX. -

    The thread environment (where global variables live) is -always at pseudo-index LUA_GLOBALSINDEX. -The environment of the running C function is always -at pseudo-index LUA_ENVIRONINDEX. -

    To access and change the value of global variables, +

    +To access and change the value of global variables, you can use regular table operations over an environment table. For instance, to access the value of a global variable, do +

    -       lua_getfield(L, LUA_GLOBALSINDEX, varname);
    +     lua_getfield(L, LUA_GLOBALSINDEX, varname);
     
    -

    3.4 - C Closures

    -

    When a C function is created, + + +

    3.4 - C Closures

    + +

    +When a C function is created, it is possible to associate some values with it, -thus creating a C closure; +thus creating a C closure; these values are called upvalues and are accessible to the function whenever it is called (see lua_pushcclosure). -

    Whenever a C function is called, + +

    +Whenever a C function is called, its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro -lua_upvalueindex. +lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), @@ -1885,28 +2380,40 @@

    current function, produces an acceptable (but invalid) index. -

    3.5 - Registry

    -

    Lua provides a registry, -a pre-defined table that can be used by any C code to + + + +

    3.5 - Registry

    + +

    +Lua provides a registry, +a pre-defined table that can be used by any C code to store whatever Lua value it needs to store. This table is always located at pseudo-index -LUA_REGISTRYINDEX. -Any C library can store data into this table, +LUA_REGISTRYINDEX. +Any C library can store data into this table, but it should take care to choose keys different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name -or a light userdata with the address of a C object in your code. +or a light userdata with the address of a C object in your code. -

    The integer keys in the registry are used by the reference mechanism, + +

    +The integer keys in the registry are used by the reference mechanism, implemented by the auxiliary library, and therefore should not be used for other purposes. -

    3.6 - Error Handling in C

    -

    Internally, Lua uses the C longjmp facility to handle errors. + + + +

    3.6 - Error Handling in C

    + +

    +Internally, Lua uses the C longjmp facility to handle errors. (You can also choose to use exceptions if you use C++; -See file luaconf.h.) +see file luaconf.h.) When Lua faces any error (such as memory allocation errors, type errors, syntax errors, and runtime errors) @@ -1916,7 +2423,9 @@

    to set a recover point; any error jumps to the most recent active recover point. -

    Almost any function in the API may raise an error, + +

    +Almost any function in the API may raise an error, for instance due to a memory allocation error. The following functions run in protected mode (that is, they create a protected environment to run), @@ -1924,25 +2433,30 @@

    lua_newstate, lua_close, lua_load, lua_pcall, and lua_cpcall. -

    Inside a C function you can raise an error by calling lua_error. -

    3.7 - Functions and Types

    +

    +Inside a C function you can raise an error by calling lua_error. + + + + -

    Here we list all functions and types from the C API in +

    3.7 - Functions and Types

    + +

    +Here we list all functions and types from the C API in alphabetical order. -

    -


    lua_Alloc

    -
    -          typedef void * (*lua_Alloc) (void *ud,
    -                                       void *ptr,
    -                                       size_t osize,
    -                                       size_t nsize);
     
    -
    +

    lua_Alloc

    +
    typedef void * (*lua_Alloc) (void *ud,
    +                             void *ptr,
    +                             size_t osize,
    +                             size_t nsize);
    -

    The type of the memory allocation function used by Lua states. +

    +The type of the memory-allocation function used by Lua states. The allocator function must provide a functionality similar to realloc, but not exactly the same. @@ -1962,53 +2476,63 @@

    When nsize and osize are not zero, the allocator behaves like realloc. Lua assumes that the allocator never fails when -osize >= nsize. +osize >= nsize. + -

    Here is a simple implementation for the allocator function. +

    +Here is a simple implementation for the allocator function. It is used in the auxiliary library by lua_newstate. -

    -static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
    -  (void)ud;     /* not used */
    -  (void)osize;  /* not used */
    -  if (nsize == 0) {
    -    free(ptr);  /* ANSI requires that free(NULL) has no effect */
    -    return NULL;
    -  }
    -  else
    -    /* ANSI requires that realloc(NULL, size) == malloc(size) */
    -    return realloc(ptr, nsize);
    -}
    -
    -

    -


    lua_atpanic

    -          lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
    +     static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
    +       (void)ud;     /* not used */
    +       (void)osize;  /* not used */
    +       if (nsize == 0) {
    +         free(ptr);  /* ANSI requires that free(NULL) has no effect */
    +         return NULL;
    +       }
    +       else
    +         /* ANSI requires that realloc(NULL, size) == malloc(size) */
    +         return realloc(ptr, nsize);
    +     }
     
    -

    Sets a new panic function and returns the old one. -

    If an error happens outside any protected environment, + +


    lua_atpanic

    +
    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
    + +

    +Sets a new panic function and returns the old one. + + +

    +If an error happens outside any protected environment, Lua calls a panic function and then calls exit(EXIT_FAILURE), thus exiting the host application. Your panic function may avoid this exit by never returning (e.g., doing a long jump). -

    The panic function can access the error message at the top of the stack. -

    -


    lua_call

    -
    -          void lua_call (lua_State *L, int nargs, int nresults);
    -
    +

    +The panic function can access the error message at the top of the stack. + + + + +


    lua_call

    +
    void lua_call (lua_State *L, int nargs, int nresults);
    + +

    +Calls a function. -

    Calls a function. -

    To call a function you must use the following protocol: -First, the function to be called is pushed onto the stack; +

    +To call a function you must use the following protocol: +first, the function to be called is pushed onto the stack; then, the arguments to the function are pushed in direct order; that is, the first argument is pushed first. @@ -2018,103 +2542,116 @@

    when the function is called. The function results are pushed onto the stack when the function returns. The number of results is adjusted to nresults, -unless nresults is LUA_MULTRET. +unless nresults is LUA_MULTRET. In this case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), so that after the call the last result is on the top of the stack. -

    Any error inside the called function is propagated upwards + +

    +Any error inside the called function is propagated upwards (with a longjmp). -

    The following example shows how the host program may do the + +

    +The following example shows how the host program may do the equivalent to this Lua code: +

    -       a = f("how", t.x, 14)
    -
    -Here it is in C: + a = f("how", t.x, 14) +

    +Here it is in C: +

    -    lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* function to be called */
    -    lua_pushstring(L, "how");                                 /* 1st argument */
    -    lua_getfield(L, LUA_GLOBALSINDEX, "t");            /* table to be indexed */
    -    lua_getfield(L, -1, "x");                 /* push result of t.x (2nd arg) */
    -    lua_remove(L, -2);                           /* remove `t' from the stack */
    -    lua_pushinteger(L, 14);                                   /* 3rd argument */
    -    lua_call(L, 3, 1);         /* call function with 3 arguments and 1 result */
    -    lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global variable `a' */
    -
    + lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */ + lua_pushstring(L, "how"); /* 1st argument */ + lua_getfield(L, LUA_GLOBALSINDEX, "t"); /* table to be indexed */ + lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */ + lua_remove(L, -2); /* remove 't' from the stack */ + lua_pushinteger(L, 14); /* 3rd argument */ + lua_call(L, 3, 1); /* call function with 3 arguments and 1 result */ + lua_setfield(L, LUA_GLOBALSINDEX, "a"); /* set global variable 'a' */ +

    Note that the code above is "balanced": at its end, the stack is back to its original configuration. This is considered good programming practice. -

    -


    lua_CFunction

    -
    -          typedef int (*lua_CFunction) (lua_State *L);
    -
    -

    Type for C functions. -

    In order to communicate properly with Lua, -a C function must use the following protocol, + +


    lua_CFunction

    +
    typedef int (*lua_CFunction) (lua_State *L);
    + +

    +Type for C functions. + + +

    +In order to communicate properly with Lua, +a C function must use the following protocol, which defines the way parameters and results are passed: -A C function receives its arguments from Lua in its stack +a C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first). So, when the function starts, -lua_gettop(L) returns the number of arguments received by the function. +lua_gettop(L) returns the number of arguments received by the function. The first argument (if any) is at index 1 -and its last argument is at index lua_gettop(L). -To return values to Lua, a C function just pushes them onto the stack, +and its last argument is at index lua_gettop(L). +To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results. Any other value in the stack below the results will be properly discarded by Lua. -Like a Lua function, a C function called by Lua can also return +Like a Lua function, a C function called by Lua can also return many results. -

    As an example, the following function receives a variable number + +

    +As an example, the following function receives a variable number of numerical arguments and returns their average and sum: +

    -       static int foo (lua_State *L) {
    -         int n = lua_gettop(L);    /* number of arguments */
    -         lua_Number sum = 0;
    -         int i;
    -         for (i = 1; i <= n; i++) {
    -           if (!lua_isnumber(L, i)) {
    -             lua_pushstring(L, "incorrect argument to function `average'");
    -             lua_error(L);
    -           }
    -           sum += lua_tonumber(L, i);
    +     static int foo (lua_State *L) {
    +       int n = lua_gettop(L);    /* number of arguments */
    +       lua_Number sum = 0;
    +       int i;
    +       for (i = 1; i <= n; i++) {
    +         if (!lua_isnumber(L, i)) {
    +           lua_pushstring(L, "incorrect argument to function 'average'");
    +           lua_error(L);
              }
    -         lua_pushnumber(L, sum/n);        /* first result */
    -         lua_pushnumber(L, sum);         /* second result */
    -         return 2;                   /* number of results */
    +         sum += lua_tonumber(L, i);
            }
    +       lua_pushnumber(L, sum/n);        /* first result */
    +       lua_pushnumber(L, sum);         /* second result */
    +       return 2;                   /* number of results */
    +     }
     
    -

    -


    lua_checkstack

    -
    -          int lua_checkstack (lua_State *L, int extra);
    -
    -

    Ensures that there are at least extra free stack slots in the stack. + +


    lua_checkstack

    +
    int lua_checkstack (lua_State *L, int extra);
    + +

    +Ensures that there are at least extra free stack slots in the stack. It returns false if it cannot grow the stack to that size. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged. -

    -


    lua_close

    -
    -          void lua_close (lua_State *L);
    -
    -

    Destroys all objects in the given Lua state + + +


    lua_close

    +
    void lua_close (lua_State *L);
    + +

    +Destroys all objects in the given Lua state (calling the corresponding garbage-collection metamethods, if any) and frees all dynamic memory used by this state. On several platforms, you may not need to call this function, @@ -2124,29 +2661,31 @@

    might need to release states as soon as they are not needed, to avoid growing too large. -

    -


    lua_concat

    -
    -          void lua_concat (lua_State *L, int n);
    -
    -

    Concatenates the n values at the top of the stack, + + +


    lua_concat

    +
    void lua_concat (lua_State *L, int n);
    + +

    +Concatenates the n values at the top of the stack, pops them, and leaves the result at the top. -If n is 1, the result is the single string on the stack +If n is 1, the result is the single string on the stack (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is done following the usual semantics of Lua -(see 2.5.4). +(see §2.5.4). + + + -

    -


    lua_cpcall

    -
    -          int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
    -
    +

    lua_cpcall

    +
    int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
    -

    Calls the C function func in protected mode. +

    +Calls the C function func in protected mode. func starts with only one element in its stack, a light userdata containing ud. In case of errors, @@ -2155,28 +2694,30 @@

    otherwise, it returns zero, and does not change the stack. All values returned by func are discarded. -

    -


    lua_createtable

    -
    -          void lua_createtable (lua_State *L, int narr, int nrec);
    -
    -

    Creates a new empty table and pushes it onto the stack. + + +


    lua_createtable

    +
    void lua_createtable (lua_State *L, int narr, int nrec);
    + +

    +Creates a new empty table and pushes it onto the stack. The new table has space pre-allocated for narr array elements and nrec non-array elements. This pre-allocation is useful when you know exactly how many elements the table will have. Otherwise you can use the function lua_newtable. -

    -


    lua_dump

    -
    -          int lua_dump (lua_State *L, lua_Writer writer, void *data);
    -
    -

    Dumps a function as a binary chunk. + + +


    lua_dump

    +
    int lua_dump (lua_State *L, lua_Writer writer, void *data);
    + +

    +Dumps a function as a binary chunk. Receives a Lua function on the top of the stack and produces a binary chunk that, if loaded again, @@ -2186,347 +2727,418 @@

    with the given data to write them. -

    The value returned is the error code returned by the last + +

    +The value returned is the error code returned by the last call to the writer; 0 means no errors. -

    This function does not pop the Lua function from the stack. -

    -


    lua_equal

    -
    -          int lua_equal (lua_State *L, int index1, int index2);
    -
    +

    +This function does not pop the Lua function from the stack. + + -

    Returns 1 if the two values in acceptable indices index1 and + +


    lua_equal

    +
    int lua_equal (lua_State *L, int index1, int index2);
    + +

    +Returns 1 if the two values in acceptable indices index1 and index2 are equal, following the semantics of the Lua == operator (that is, may call metamethods). -Otherwise returns 0. -Also returns 0 if any of the indices is non valid. +Otherwise returns 0. +Also returns 0 if any of the indices is non valid. + + + -

    -


    lua_error

    -
    -          int lua_error (lua_State *L);
    -
    +

    lua_error

    +
    int lua_error (lua_State *L);
    -

    Generates a Lua error. +

    +Generates a Lua error. The error message (which can actually be a Lua value of any type) must be on the stack top. This function does a long jump, and therefore never returns. -(see luaL_error). +(see luaL_error). + -

    -


    lua_gc

    -
    -          int lua_gc (lua_State *L, int what, int data);
    -
    -

    Controls the garbage collector. -

    This function performs several tasks, +


    lua_gc

    +
    int lua_gc (lua_State *L, int what, int data);
    + +

    +Controls the garbage collector. + + +

    +This function performs several tasks, according to the value of the parameter what: +

      -
    • LUA_GCSTOP--- stops the garbage collector. -
    • LUA_GCRESTART--- restarts the garbage collector. -
    • LUA_GCCOLLECT--- performs a full garbage-collection cycle. -
    • LUA_GCCOUNT--- returns the current -amount of memory (in Kbytes) in use by Lua. -
    • LUA_GCCOUNTB--- returns the remainder of -dividing the current amount of bytes of memory in use by Lua -by 1024. -
    • LUA_GCSTEP--- performs an incremental step of -garbage collection. + +
    • LUA_GCSTOP: +stops the garbage collector. +
    • + +
    • LUA_GCRESTART: +restarts the garbage collector. +
    • + +
    • LUA_GCCOLLECT: +performs a full garbage-collection cycle. +
    • + +
    • LUA_GCCOUNT: +returns the current amount of memory (in Kbytes) in use by Lua. +
    • + +
    • LUA_GCCOUNTB: +returns the remainder of dividing the current amount of bytes of +memory in use by Lua by 1024. +
    • + +
    • LUA_GCSTEP: +performs an incremental step of garbage collection. The step "size" is controlled by data (larger values mean more steps) in a non-specified way. If you want to control the step size -you must tune experimentally the value of data. +you must experimentally tune the value of data. The function returns 1 if the step finished a garbage-collection cycle. -
    • LUA_GCSETPAUSE--- +
    • + +
    • LUA_GCSETPAUSE: sets data/100 as the new value -for the pause of the collector (see 2.10). +for the pause of the collector (see §2.10). The function returns the previous value of the pause. -
    • LUA_GCSETSTEPMUL--- +
    • + +
    • LUA_GCSETSTEPMUL: sets arg/100 as the new value for the step multiplier of -the collector (see 2.10). +the collector (see §2.10). The function returns the previous value of the step multiplier. +
    • +
    -

    -


    lua_getallocf

    -
    -          lua_Alloc lua_getallocf (lua_State *L, void **ud);
    -
    -

    Returns the memory allocator function of a given state. + +


    lua_getallocf

    +
    lua_Alloc lua_getallocf (lua_State *L, void **ud);
    + +

    +Returns the memory-allocation function of a given state. If ud is not NULL, Lua stores in *ud the opaque pointer passed to lua_newstate. -

    -


    lua_getfenv

    -
    -          void lua_getfenv (lua_State *L, int index);
    -
    -

    Pushes on the stack the environment table of + + +


    lua_getfenv

    +
    void lua_getfenv (lua_State *L, int index);
    + +

    +Pushes onto the stack the environment table of the value at the given index. -

    -


    lua_getfield

    -
    -          void lua_getfield (lua_State *L, int index, const char *k);
    -
    -

    Pushes onto the stack the value t[k], + + +


    lua_getfield

    +
    void lua_getfield (lua_State *L, int index, const char *k);
    + +

    +Pushes onto the stack the value t[k], where t is the value at the given valid index index. As in Lua, this function may trigger a metamethod -for the "index" event (see 2.8). +for the "index" event (see §2.8). + + -

    -


    lua_getglobal

    -
    -          void lua_getglobal (lua_State *L, const char *name);
    -
    -

    Pushes onto the stack the value of the global name. +


    lua_getglobal

    +
    void lua_getglobal (lua_State *L, const char *name);
    + +

    +Pushes onto the stack the value of the global name. It is defined as a macro: -

    -#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
    -
    -

    -


    lua_getmetatable

    -          int lua_getmetatable (lua_State *L, int index);
    +     #define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
     
    -

    Pushes onto the stack the metatable of the value at the given + + +


    lua_getmetatable

    +
    int lua_getmetatable (lua_State *L, int index);
    + +

    +Pushes onto the stack the metatable of the value at the given acceptable index. If the index is not valid, or if the value does not have a metatable, -the function returns 0 and pushes nothing on the stack. +the function returns 0 and pushes nothing on the stack. + + -

    -


    lua_gettable

    -
    -          void lua_gettable (lua_State *L, int index);
    -
    -

    Pushes onto the stack the value t[k], +


    lua_gettable

    +
    void lua_gettable (lua_State *L, int index);
    + +

    +Pushes onto the stack the value t[k], where t is the value at the given valid index index and k is the value at the top of the stack. -

    This function pops the key from the stack + +

    +This function pops the key from the stack (putting the resulting value in its place). As in Lua, this function may trigger a metamethod -for the "index" event (see 2.8). +for the "index" event (see §2.8). + + -

    -


    lua_gettop

    -
    -          int lua_gettop (lua_State *L);
    -
    -

    Returns the index of the top element in the stack. -Because indices start at 1, +


    lua_gettop

    +
    int lua_gettop (lua_State *L);
    + +

    +Returns the index of the top element in the stack. +Because indices start at 1, this result is equal to the number of elements in the stack -(and so 0 means an empty stack). +(and so 0 means an empty stack). -

    -


    lua_insert

    -
    -          void lua_insert (lua_State *L, int index);
    -
    -

    Moves the top element into the given valid index, + + +


    lua_insert

    +
    void lua_insert (lua_State *L, int index);
    + +

    +Moves the top element into the given valid index, shifting up the elements above this index to open space. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. -

    -


    lua_Integer

    -
    -          typedef ptrdiff_t lua_Integer;
    -
    -

    The type used by the Lua API to represent integral values. -

    By default it is a ptrdiff_t, + +


    lua_Integer

    +
    typedef ptrdiff_t lua_Integer;
    + +

    +The type used by the Lua API to represent integral values. + + +

    +By default it is a ptrdiff_t, which is usually the largest integral type the machine handles "comfortably". -

    -


    lua_isboolean

    -
    -          int lua_isboolean (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index has type boolean, + + +


    lua_isboolean

    +
    int lua_isboolean (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index has type boolean, and 0 otherwise. -

    -


    lua_iscfunction

    -
    -          int lua_iscfunction (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a C function, + + +


    lua_iscfunction

    +
    int lua_iscfunction (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a C function, and 0 otherwise. -

    -


    lua_isfunction

    -
    -          int lua_isfunction (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a function + + +


    lua_isfunction

    +
    int lua_isfunction (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a function (either C or Lua), and 0 otherwise. -

    -


    lua_islightuserdata

    -
    -          int lua_islightuserdata (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a light userdata, + + +


    lua_islightuserdata

    +
    int lua_islightuserdata (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a light userdata, and 0 otherwise. -

    -


    lua_isnil

    -
    -          int lua_isnil (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is nil, + + +


    lua_isnil

    +
    int lua_isnil (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is nil, and 0 otherwise. -

    -


    lua_isnumber

    -
    -          int lua_isnumber (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a number + + +


    lua_isnumber

    +
    int lua_isnumber (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a number or a string convertible to a number, and 0 otherwise. -

    -


    lua_isstring

    -
    -          int lua_isstring (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a string + + +


    lua_isstring

    +
    int lua_isstring (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a string or a number (which is always convertible to a string), and 0 otherwise. -

    -


    lua_istable

    -
    -          int lua_istable (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a table, + + +


    lua_istable

    +
    int lua_istable (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a table, and 0 otherwise. -

    -


    lua_isthread

    -
    -          int lua_isthread (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a thread, + + +


    lua_isthread

    +
    int lua_isthread (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a thread, and 0 otherwise. -

    -


    lua_isuserdata

    -
    -          int lua_isuserdata (lua_State *L, int index);
    -
    -

    Returns 1 if the value at the given acceptable index is a userdata + + +


    lua_isuserdata

    +
    int lua_isuserdata (lua_State *L, int index);
    + +

    +Returns 1 if the value at the given acceptable index is a userdata (either full or light), and 0 otherwise. -

    -


    lua_lessthan

    -
    -          int lua_lessthan (lua_State *L, int index1, int index2);
    -
    -

    Returns 1 if the value at acceptable index index1 is smaller + + +


    lua_lessthan

    +
    int lua_lessthan (lua_State *L, int index1, int index2);
    + +

    +Returns 1 if the value at acceptable index index1 is smaller than the value at acceptable index index2, -following the semantics of the Lua < operator +following the semantics of the Lua < operator (that is, may call metamethods). -Otherwise returns 0. -Also returns 0 if any of the indices is non valid. +Otherwise returns 0. +Also returns 0 if any of the indices is non valid. -

    -


    lua_load

    -
    -          int lua_load (lua_State *L, lua_Reader reader, void *data,
    -                                      const char *chunkname);
     
    -
    -

    Loads a Lua chunk. + +


    lua_load

    +
    int lua_load (lua_State *L,
    +              lua_Reader reader,
    +              void *data,
    +              const char *chunkname);
    + +

    +Loads a Lua chunk. If there are no errors, lua_load pushes the compiled chunk as a Lua function on top of the stack. Otherwise, it pushes an error message. The return values of lua_load are: +

      -
    • 0 --- no errors; -
    • LUA_ERRSYNTAX --- -syntax error during pre-compilation. -
    • LUA_ERRMEM --- -memory allocation error. + +
    • 0: no errors;
    • + +
    • LUA_ERRSYNTAX: +syntax error during pre-compilation;
    • + +
    • LUA_ERRMEM: +memory allocation error.
    • +
    -

    lua_load automatically detects whether the chunk is text or binary, +

    +This function only loads a chunk; +it does not run it. + + +

    +lua_load automatically detects whether the chunk is text or binary, and loads it accordingly (see program luac). -

    lua_load uses a user-supplied reader function to read the chunk + +

    +lua_load uses a user-supplied reader function to read the chunk (see lua_Reader). The data argument is an opaque value passed to the reader function. -

    The chunkname argument gives a name to the chunk, -which is used for error messages and in debug information (see 3.8). -

    -


    lua_newstate

    -
    -          lua_State *lua_newstate (lua_Alloc f, void *ud);
    -
    +

    +The chunkname argument gives a name to the chunk, +which is used for error messages and in debug information (see §3.8). + + -

    Creates a new, independent state. + +


    lua_newstate

    +
    lua_State *lua_newstate (lua_Alloc f, void *ud);
    + +

    +Creates a new, independent state. Returns NULL if cannot create the state (due to lack of memory). The argument f is the allocator function; @@ -2534,125 +3146,146 @@

    The second argument, ud, is an opaque pointer that Lua simply passes to the allocator in every call. -

    -


    lua_newtable

    -
    -          void lua_newtable (lua_State *L);
    -
    -

    Creates a new empty table and pushes it onto the stack. -Equivalent to lua_createtable(L, 0, 0). -

    -


    lua_newthread

    -
    -          lua_State *lua_newthread (lua_State *L);
    -
    + +

    lua_newtable

    +
    void lua_newtable (lua_State *L);
    + +

    +Creates a new empty table and pushes it onto the stack. +It is equivalent to lua_createtable(L, 0, 0). + + -

    Creates a new thread, pushes it on the stack, + +


    lua_newthread

    +
    lua_State *lua_newthread (lua_State *L);
    + +

    +Creates a new thread, pushes it on the stack, and returns a pointer to a lua_State that represents this new thread. The new state returned by this function shares with the original state all global objects (such as tables), but has an independent execution stack. -

    There is no explicit function to close or to destroy a thread. + +

    +There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object. -

    -


    lua_newuserdata

    -
    -          void *lua_newuserdata (lua_State *L, size_t size);
    -
    -

    This function allocates a new block of memory with the given size, -pushes on the stack a new full userdata with the block address, + + +


    lua_newuserdata

    +
    void *lua_newuserdata (lua_State *L, size_t size);
    + +

    +This function allocates a new block of memory with the given size, +pushes onto the stack a new full userdata with the block address, and returns this address. -

    Userdata represents C values in Lua. + +

    +Userdata represents C values in Lua. A full userdata represents a block of memory. It is an object (like a table): -You must create it, it can have its own metatable, +you must create it, it can have its own metatable, and you can detect when it is being collected. A full userdata is only equal to itself (under raw equality). -

    When Lua collects a full userdata with a gc metamethod, + +

    +When Lua collects a full userdata with a gc metamethod, Lua calls the metamethod and marks the userdata as finalized. When this userdata is collected again then Lua frees its corresponding memory. -

    -


    lua_next

    -
    -          int lua_next (lua_State *L, int index);
    -
    -

    Pops a key from the stack, + + +


    lua_next

    +
    int lua_next (lua_State *L, int index);
    + +

    +Pops a key from the stack, and pushes a key-value pair from the table at the given index (the "next" pair after the given key). If there are no more elements in the table, then lua_next returns 0 (and pushes nothing). -

    A typical traversal looks like this: + +

    +A typical traversal looks like this: +

    -       /* table is in the stack at index `t' */
    -       lua_pushnil(L);  /* first key */
    -       while (lua_next(L, t) != 0) {
    -         /* `key' is at index -2 and `value' at index -1 */
    -         printf("%s - %s\n",
    -           lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
    -         lua_pop(L, 1);  /* removes `value'; keeps `key' for next iteration */
    -       }
    +     /* table is in the stack at index 't' */
    +     lua_pushnil(L);  /* first key */
    +     while (lua_next(L, t) != 0) {
    +       /* 'key' is at index -2 and 'value' at index -1 */
    +       printf("%s - %s\n",
    +         lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
    +       lua_pop(L, 1);  /* removes 'value'; keeps 'key' for next iteration */
    +     }
     
    -

    While traversing a table, +

    +While traversing a table, do not call lua_tolstring directly on a key, unless you know that the key is actually a string. Recall that lua_tolstring changes the value at the given index; this confuses the next call to lua_next. -

    -


    lua_Number

    -
    -          typedef double lua_Number;
    -
    -

    The type of numbers in Lua. + + +


    lua_Number

    +
    typedef double lua_Number;
    + +

    +The type of numbers in Lua. By default, it is double, but that can be changed in luaconf.h. -

    Through the configuration file you can change + +

    +Through the configuration file you can change Lua to operate with another type for numbers (e.g., float or long). -

    -


    lua_objlen

    -
    -          size_t lua_objlen (lua_State *L, int index);
    -
    -

    Returns the "length" of the value at the given acceptable index: + + +


    lua_objlen

    +
    size_t lua_objlen (lua_State *L, int index);
    + +

    +Returns the "length" of the value at the given acceptable index: for strings, this is the string length; -for tables, this is the result of the length operator (`#´); +for tables, this is the result of the length operator ('#'); for userdata, this is the size of the block of memory allocated for the userdata; -for other values, it is 0. +for other values, it is 0. + + -

    -


    lua_pcall

    -
    -          lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
    -
    -

    Calls a function in protected mode. +


    lua_pcall

    +
    lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
    -

    Both nargs and nresults have the same meaning as +

    +Calls a function in protected mode. + + +

    +Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call, lua_pcall behaves exactly like lua_call. @@ -2664,7 +3297,9 @@

    lua_pcall always removes the function and its arguments from the stack. -

    If errfunc is 0, + +

    +If errfunc is 0, then the error message returned on the stack is exactly the original error message. Otherwise, errfunc is the stack index of an @@ -2674,279 +3309,332 @@

    this function will be called with the error message and its return value will be the message returned on the stack by lua_pcall. -

    Typically, the error handler function is used to add more debug + +

    +Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound. -

    The lua_pcall function returns 0 in case of success + +

    +The lua_pcall function returns 0 in case of success or one of the following error codes (defined in lua.h): +

      -
    • LUA_ERRRUN --- a runtime error. -
    • LUA_ERRMEM --- memory allocation error. + +
    • LUA_ERRRUN: +a runtime error. +
    • + +
    • LUA_ERRMEM: +memory allocation error. For such errors, Lua does not call the error handler function. -
    • LUA_ERRERR --- +
    • + +
    • LUA_ERRERR: error while running the error handler function. +
    • +
    -

    -


    lua_pop

    -
    -          void lua_pop (lua_State *L, int n);
    -
    -

    Pops n elements from the stack. -

    -


    lua_pushboolean

    -
    -          void lua_pushboolean (lua_State *L, int b);
    -
    +

    lua_pop

    +
    void lua_pop (lua_State *L, int n);
    +

    +Pops n elements from the stack. -

    Pushes a boolean value with value b onto the stack. -

    -


    lua_pushcclosure

    -
    -          void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
    -
    -

    Pushes a new C closure onto the stack. -

    When a C function is created, +


    lua_pushboolean

    +
    void lua_pushboolean (lua_State *L, int b);
    + +

    +Pushes a boolean value with value b onto the stack. + + + + + +


    lua_pushcclosure

    +
    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
    + +

    +Pushes a new C closure onto the stack. + + +

    +When a C function is created, it is possible to associate some values with it, -thus creating a C closure (see 3.4); +thus creating a C closure (see §3.4); these values are then accessible to the function whenever it is called. -To associate values with a C function, +To associate values with a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). Then lua_pushcclosure -is called to create and push the C function onto the stack, +is called to create and push the C function onto the stack, with the argument n telling how many values should be associated with the function. lua_pushcclosure also pops these values from the stack. -

    -


    lua_pushcfunction

    -
    -          void lua_pushcfunction (lua_State *L, lua_CFunction f);
    -
    -

    Pushes a C function onto the stack. + + +


    lua_pushcfunction

    +
    void lua_pushcfunction (lua_State *L, lua_CFunction f);
    + +

    +Pushes a C function onto the stack. This function receives a pointer to a C function -and pushes on the stack a Lua value of type function that, -when called, invokes the corresponding C function. +and pushes onto the stack a Lua value of type function that, +when called, invokes the corresponding C function. + -

    Any function to be registered in Lua must +

    +Any function to be registered in Lua must follow the correct protocol to receive its parameters and return its results (see lua_CFunction). -

    The call lua_pushcfunction(L, f) is equivalent to + +

    +The call lua_pushcfunction(L, f) is equivalent to lua_pushcclosure(L, f, 0). -

    -


    lua_pushfstring

    -
    -          const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
    -
    -

    Pushes onto the stack a formatted string + + +


    lua_pushfstring

    +
    const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
    + +

    +Pushes onto the stack a formatted string and returns a pointer to this string. -It is similar to the C function sprintf, +It is similar to the C function sprintf, but has some important differences: +

      -
    • You do not have to allocate space for the result: -The result is a Lua string and Lua takes care of memory allocation + +
    • +You do not have to allocate space for the result: +the result is a Lua string and Lua takes care of memory allocation (and deallocation, through garbage collection). -
    • The conversion specifiers are quite restricted. +
    • + +
    • +The conversion specifiers are quite restricted. There are no flags, widths, or precisions. The conversion specifiers can only be -`%%´ (inserts a `%´ in the string), -`%s´ (inserts a zero-terminated string, with no size restrictions), -`%f´ (inserts a lua_Number), -`%p´ (inserts a pointer as a hexadecimal numeral), -`%d´ (inserts an int), and -`%c´ (inserts an int as a character). +'%%' (inserts a '%' in the string), +'%s' (inserts a zero-terminated string, with no size restrictions), +'%f' (inserts a lua_Number), +'%p' (inserts a pointer as a hexadecimal numeral), +'%d' (inserts an int), and +'%c' (inserts an int as a character). +
    • +
    -

    -


    lua_pushinteger

    -
    -          void lua_pushinteger (lua_State *L, lua_Integer n);
    -
    -

    Pushes a number with value n onto the stack. -

    -


    lua_pushlightuserdata

    -
    -          void lua_pushlightuserdata (lua_State *L, void *p);
    -
    +

    lua_pushinteger

    +
    void lua_pushinteger (lua_State *L, lua_Integer n);
    + +

    +Pushes a number with value n onto the stack. + + + + + +


    lua_pushlightuserdata

    +
    void lua_pushlightuserdata (lua_State *L, void *p);
    +

    +Pushes a light userdata onto the stack. -

    Pushes a light userdata onto the stack. -

    Userdata represents C values in Lua. +

    +Userdata represents C values in Lua. A light userdata represents a pointer. It is a value (like a number): -You do not create it, it has no metatables, -it is not collected (as it was never created). +you do not create it, it has no individual metatable, +and it is not collected (as it was never created). A light userdata is equal to "any" -light userdata with the same C address. +light userdata with the same C address. -

    -


    lua_pushlstring

    -
    -          void lua_pushlstring (lua_State *L, const char *s, size_t len);
    -
    -

    Pushes the string pointed to by s with size len + + +


    lua_pushlstring

    +
    void lua_pushlstring (lua_State *L, const char *s, size_t len);
    + +

    +Pushes the string pointed to by s with size len onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. The string can contain embedded zeros. -

    -


    lua_pushnil

    -
    -          void lua_pushnil (lua_State *L);
    -
    -

    Pushes a nil value onto the stack. -

    -


    lua_pushnumber

    -
    -          void lua_pushnumber (lua_State *L, lua_Number n);
    -
    +

    lua_pushnil

    +
    void lua_pushnil (lua_State *L);
    -

    Pushes a number with value n onto the stack. +

    +Pushes a nil value onto the stack. -

    -


    lua_pushstring

    -
    -          void lua_pushstring (lua_State *L, const char *s);
    -
    -

    Pushes the zero-terminated string pointed to by s -onto the stack. -Lua makes (or reuses) an internal copy of the given string, -so the memory at s can be freed or reused immediately after -the function returns. -The string cannot contain embedded zeros; -it is assumed to end at the first zero. -

    -


    lua_pushthread

    -
    -          void lua_pushthread (lua_State *L);
    -
    + +

    lua_pushnumber

    +
    void lua_pushnumber (lua_State *L, lua_Number n);
    + +

    +Pushes a number with value n onto the stack. -

    Pushes the thread represented by L onto the stack. -

    -


    lua_pushvalue

    -
    -          void lua_pushvalue (lua_State *L, int index);
    -
    -

    Pushes a copy of the element at the given valid index +


    lua_pushstring

    +
    void lua_pushstring (lua_State *L, const char *s);
    + +

    +Pushes the zero-terminated string pointed to by s onto the stack. +Lua makes (or reuses) an internal copy of the given string, +so the memory at s can be freed or reused immediately after +the function returns. +The string cannot contain embedded zeros; +it is assumed to end at the first zero. + + + -

    -


    lua_pushvfstring

    -
    -          const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
    -
    +

    lua_pushthread

    +
    int lua_pushthread (lua_State *L);
    -

    Equivalent to lua_pushfstring, except that it receives a va_list +

    +Pushes the thread represented by L onto the stack. +Returns 1 if this thread is the main thread of its state. + + + + + +


    lua_pushvalue

    +
    void lua_pushvalue (lua_State *L, int index);
    + +

    +Pushes a copy of the element at the given valid index +onto the stack. + + + + + +


    lua_pushvfstring

    +
    const char *lua_pushvfstring (lua_State *L,
    +                              const char *fmt,
    +                              va_list argp);
    + +

    +Equivalent to lua_pushfstring, except that it receives a va_list instead of a variable number of arguments. -

    -


    lua_rawequal

    -
    -          int lua_rawequal (lua_State *L, int index1, int index2);
    -
    -

    Returns 1 if the two values in acceptable indices index1 and + + +


    lua_rawequal

    +
    int lua_rawequal (lua_State *L, int index1, int index2);
    + +

    +Returns 1 if the two values in acceptable indices index1 and index2 are primitively equal (that is, without calling metamethods). -Otherwise returns 0. -Also returns 0 if any of the indices are non valid. +Otherwise returns 0. +Also returns 0 if any of the indices are non valid. -

    -


    lua_rawget

    -
    -          void lua_rawget (lua_State *L, int index);
    -
    -

    Similar to lua_gettable, but does a raw access + + +


    lua_rawget

    +
    void lua_rawget (lua_State *L, int index);
    + +

    +Similar to lua_gettable, but does a raw access (i.e., without metamethods). -

    -


    lua_rawgeti

    -
    -          void lua_rawgeti (lua_State *L, int index, int n);
    -
    -

    Pushes onto the stack the value t[n], + + +


    lua_rawgeti

    +
    void lua_rawgeti (lua_State *L, int index, int n);
    + +

    +Pushes onto the stack the value t[n], where t is the value at the given valid index index. The access is raw; that is, it does not invoke metamethods. -

    -


    lua_rawset

    -
    -          void lua_rawset (lua_State *L, int index);
    -
    -

    Similar to lua_settable, but does a raw assignment + + +


    lua_rawset

    +
    void lua_rawset (lua_State *L, int index);
    + +

    +Similar to lua_settable, but does a raw assignment (i.e., without metamethods). -

    -


    lua_rawseti

    -
    -          void lua_rawseti (lua_State *L, int index, int n);
    -
    -

    Does the equivalent of t[n] = v, + + +


    lua_rawseti

    +
    void lua_rawseti (lua_State *L, int index, int n);
    + +

    +Does the equivalent of t[n] = v, where t is the value at the given valid index index and v is the value at the top of the stack, -

    This function pops the value from the stack. + +

    +This function pops the value from the stack. The assignment is raw; that is, it does not invoke metamethods. -

    -


    lua_Reader

    -
    -          typedef const char * (*lua_Reader)
    -                               (lua_State *L, void *data, size_t *size);
     
    -
    -

    The reader function used by lua_load. + +


    lua_Reader

    +
    typedef const char * (*lua_Reader) (lua_State *L,
    +                                    void *data,
    +                                    size_t *size);
    + +

    +The reader function used by lua_load. Every time it needs another piece of the chunk, lua_load calls the reader, passing along its data parameter. @@ -2957,54 +3645,60 @@

    To signal the end of the chunk, the reader must return NULL. The reader function may return pieces of any size greater than zero. -

    -


    lua_register

    -
    -          void lua_register (lua_State *L, const char *name, lua_CFunction f);
    -
    -

    Sets the C function f as the new value of global name. + + +


    lua_register

    +
    void lua_register (lua_State *L, const char *name, lua_CFunction f);
    + +

    +Sets the C function f as the new value of global name. It is defined as a macro: -

    -#define lua_register(L,n,f)  (lua_pushcfunction(L, f), lua_setglobal(L, n))
    -
    -

    -


    lua_remove

    -          void lua_remove (lua_State *L, int index);
    +     #define lua_register(L,n,f)  (lua_pushcfunction(L, f), lua_setglobal(L, n))
     
    -

    Removes the element at the given valid index, + + +


    lua_remove

    +
    void lua_remove (lua_State *L, int index);
    + +

    +Removes the element at the given valid index, shifting down the elements above this index to fill the gap. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. -

    -


    lua_replace

    -
    -          void lua_replace (lua_State *L, int index);
    -
    -

    Moves the top element into the given position (and pops it), + + +


    lua_replace

    +
    void lua_replace (lua_State *L, int index);
    + +

    +Moves the top element into the given position (and pops it), without shifting any element (therefore replacing the value at the given position). -

    -


    lua_resume

    -
    -          int lua_resume (lua_State *L, int narg);
    -
    -

    Starts and resumes a coroutine in a given thread. -

    To start a coroutine, you first create a new thread + +


    lua_resume

    +
    int lua_resume (lua_State *L, int narg);
    + +

    +Starts and resumes a coroutine in a given thread. + + +

    +To start a coroutine, you first create a new thread (see lua_newthread); -then you push on its stack the main function plus any eventual arguments; +then you push onto its stack the main function plus any arguments; then you call lua_resume, with narg being the number of arguments. This call returns when the coroutine suspends or finishes its execution. @@ -3023,137 +3717,155 @@

    be passed as results from yield, and then call lua_resume. -

    -


    lua_setallocf

    -
    -          void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
    -
    -

    Changes the allocator function of a given state to f + + +


    lua_setallocf

    +
    void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
    + +

    +Changes the allocator function of a given state to f with user data ud. -

    -


    lua_setfenv

    -
    -          int lua_setfenv (lua_State *L, int index);
    -
    -

    Pops a table from the stack and sets it as + + +


    lua_setfenv

    +
    int lua_setfenv (lua_State *L, int index);
    + +

    +Pops a table from the stack and sets it as the new environment for the value at the given index. If the value at the given index is neither a function nor a thread nor a userdata, lua_setfenv returns 0. Otherwise it returns 1. -

    -


    lua_setfield

    -
    -          void lua_setfield (lua_State *L, int index, const char *k);
    -
    -

    Does the equivalent to t[k] = v, + + +


    lua_setfield

    +
    void lua_setfield (lua_State *L, int index, const char *k);
    + +

    +Does the equivalent to t[k] = v, where t is the value at the given valid index index and v is the value at the top of the stack, -

    This function pops the value from the stack. + +

    +This function pops the value from the stack. As in Lua, this function may trigger a metamethod -for the "newindex" event (see 2.8). +for the "newindex" event (see §2.8). + + + -

    -


    lua_setglobal

    -
    -          void lua_setglobal (lua_State *L, const char *name);
    -
    +

    lua_setglobal

    +
    void lua_setglobal (lua_State *L, const char *name);
    -

    Pops a value from the stack and +

    +Pops a value from the stack and sets it as the new value of global name. It is defined as a macro: -

    -#define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
    -
    -

    -


    lua_setmetatable

    -          int lua_setmetatable (lua_State *L, int index);
    +     #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
     
    -

    Pops a table from the stack and + + +


    lua_setmetatable

    +
    int lua_setmetatable (lua_State *L, int index);
    + +

    +Pops a table from the stack and sets it as the new metatable for the value at the given acceptable index. -

    -


    lua_settable

    -
    -          void lua_settable (lua_State *L, int index);
    -
    -

    Does the equivalent to t[k] = v, + + +


    lua_settable

    +
    void lua_settable (lua_State *L, int index);
    + +

    +Does the equivalent to t[k] = v, where t is the value at the given valid index index, v is the value at the top of the stack, and k is the value just below the top. -

    This function pops both the key and the value from the stack. + +

    +This function pops both the key and the value from the stack. As in Lua, this function may trigger a metamethod -for the "newindex" event (see 2.8). +for the "newindex" event (see §2.8). + + + -

    -


    lua_settop

    -
    -          void lua_settop (lua_State *L, int index);
    -
    +

    lua_settop

    +
    void lua_settop (lua_State *L, int index);
    -

    Accepts any acceptable index, or 0, +

    +Accepts any acceptable index, or 0, and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. -If index is 0, then all stack elements are removed. +If index is 0, then all stack elements are removed. + -

    -


    lua_State

    -
    -          typedef struct lua_State lua_State;
    -
    -

    Opaque structure that keeps the whole state of a Lua interpreter. + +


    lua_State

    +
    typedef struct lua_State lua_State;
    + +

    +Opaque structure that keeps the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. All information about a state is kept in this structure. -

    A pointer to this state must be passed as the first argument to + +

    +A pointer to this state must be passed as the first argument to every function in the library, except to lua_newstate, which creates a Lua state from scratch. -

    -


    lua_status

    -
    -          int lua_status (lua_State *L);
    -
    -

    Returns the status of the thread L. -

    The status can be 0 for a normal thread, + +


    lua_status

    +
    int lua_status (lua_State *L);
    + +

    +Returns the status of the thread L. + + +

    +The status can be 0 for a normal thread, an error code if the thread finished its execution with an error, -or LUA_YIELD if the thread is suspended. +or LUA_YIELD if the thread is suspended. + -

    -


    lua_toboolean

    -
    -          int lua_toboolean (lua_State *L, int index);
    -
    -

    Converts the Lua value at the given acceptable index to a C boolean -value (0 or 1). + +


    lua_toboolean

    +
    int lua_toboolean (lua_State *L, int index);
    + +

    +Converts the Lua value at the given acceptable index to a C boolean +value (0 or 1). Like all tests in Lua, lua_toboolean returns 1 for any Lua value different from false and nil; @@ -3162,41 +3874,46 @@

    (If you want to accept only actual boolean values, use lua_isboolean to test the value's type.) -

    -


    lua_tocfunction

    -
    -          lua_CFunction lua_tocfunction (lua_State *L, int index);
    -
    -

    Converts a value at the given acceptable index to a C function. -That value must be a C function; + + +


    lua_tocfunction

    +
    lua_CFunction lua_tocfunction (lua_State *L, int index);
    + +

    +Converts a value at the given acceptable index to a C function. +That value must be a C function; otherwise, returns NULL. -

    -


    lua_tointeger

    -
    -          lua_Integer lua_tointeger (lua_State *L, int idx);
    -
    -

    Converts the Lua value at the given acceptable index + + +


    lua_tointeger

    +
    lua_Integer lua_tointeger (lua_State *L, int idx);
    + +

    +Converts the Lua value at the given acceptable index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number -(see 2.2.1); -otherwise, lua_tointeger returns 0. +(see §2.2.1); +otherwise, lua_tointeger returns 0. + -

    If the number is not an integer, +

    +If the number is not an integer, it is truncated in some non-specified way. -

    -


    lua_tolstring

    -
    -          const char *lua_tolstring (lua_State *L, int index, size_t *len);
    -
    -

    Converts the Lua value at the given acceptable index to a string + + +


    lua_tolstring

    +
    const char *lua_tolstring (lua_State *L, int index, size_t *len);
    + +

    +Converts the Lua value at the given acceptable index to a string (const char*). If len is not NULL, it also sets *len with the string length. @@ -3208,86 +3925,96 @@

    (This change confuses lua_next when lua_tolstring is applied to keys during a table traversal.) -

    lua_tolstring returns a fully aligned pointer + +

    +lua_tolstring returns a fully aligned pointer to a string inside the Lua state. -This string always has a zero (`\0´) -after its last character (as in C), +This string always has a zero ('\0') +after its last character (as in C), but may contain other zeros in its body. Because Lua has garbage collection, there is no guarantee that the pointer returned by lua_tolstring will be valid after the corresponding value is removed from the stack. -

    -


    lua_tonumber

    -
    -          lua_Number lua_tonumber (lua_State *L, int index);
    -
    -

    Converts the Lua value at the given acceptable index + + +


    lua_tonumber

    +
    lua_Number lua_tonumber (lua_State *L, int index);
    + +

    +Converts the Lua value at the given acceptable index to a number (see lua_Number). The Lua value must be a number or a string convertible to a number -(see 2.2.1); -otherwise, lua_tonumber returns 0. +(see §2.2.1); +otherwise, lua_tonumber returns 0. + + + -

    -


    lua_topointer

    -
    -          const void *lua_topointer (lua_State *L, int index);
    -
    +

    lua_topointer

    +
    const void *lua_topointer (lua_State *L, int index);
    -

    Converts the value at the given acceptable index to a generic -C pointer (void*). +

    +Converts the value at the given acceptable index to a generic +C pointer (void*). The value may be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. -Lua ensures that different objects return different pointers. -There is no direct way to convert the pointer back to its original value. +Different objects will give different pointers. +There is no way to convert the pointer back to its original value. -

    Typically this function is used only for debug information. -

    -


    lua_tostring

    -
    -          const char *lua_tostring (lua_State *L, int index);
    -
    +

    +Typically this function is used only for debug information. -

    Equivalent to lua_tolstring with len equal to NULL. -

    -


    lua_tothread

    -
    -          lua_State *lua_tothread (lua_State *L, int index);
    -
    -

    Converts the value at the given acceptable index to a Lua thread +


    lua_tostring

    +
    const char *lua_tostring (lua_State *L, int index);
    + +

    +Equivalent to lua_tolstring with len equal to NULL. + + + + + +


    lua_tothread

    +
    lua_State *lua_tothread (lua_State *L, int index);
    + +

    +Converts the value at the given acceptable index to a Lua thread (represented as lua_State*). This value must be a thread; otherwise, the function returns NULL. -

    -


    lua_touserdata

    -
    -          void *lua_touserdata (lua_State *L, int index);
    -
    -

    If the value at the given acceptable index is a full userdata, + + +


    lua_touserdata

    +
    void *lua_touserdata (lua_State *L, int index);
    + +

    +If the value at the given acceptable index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. Otherwise, returns NULL. -

    -


    lua_type

    -
    -          int lua_type (lua_State *L, int index);
    -
    -

    Returns the type of the value in the given acceptable index, + + +


    lua_type

    +
    int lua_type (lua_State *L, int index);
    + +

    +Returns the type of the value in the given acceptable index, or LUA_TNONE for a non-valid index (that is, an index to an "empty" stack position). The types returned by lua_type are coded by the following constants @@ -3303,230 +4030,301 @@

    and LUA_TLIGHTUSERDATA. -

    -


    lua_typename

    -
    -          const char *lua_typename  (lua_State *L, int tp);
    -
    -

    Returns the name of the type encoded by the value tp, + + +


    lua_typename

    +
    const char *lua_typename  (lua_State *L, int tp);
    + +

    +Returns the name of the type encoded by the value tp, which must be one the values returned by lua_type. -

    -


    lua_Writer

    -
    -          typedef int (*lua_Writer)
    -                          (lua_State *L, const void* p, size_t sz, void* ud);
     
    -
    -

    The writer function used by lua_dump. + +


    lua_Writer

    +
    typedef int (*lua_Writer) (lua_State *L,
    +                           const void* p,
    +                           size_t sz,
    +                           void* ud);
    + +

    +The writer function used by lua_dump. Every time it produces another piece of chunk, lua_dump calls the writer, passing along the buffer to be written (p), its size (sz), and the data parameter supplied to lua_dump. -

    The writer returns an error code: + +

    +The writer returns an error code: 0 means no errors; any other value means an error and stops lua_dump from calling the writer again. -

    -


    lua_xmove

    -
    -          void lua_xmove (lua_State *from, lua_State *to, int n);
    -
    -

    Exchange values between different threads of the same global state. -

    This function pops n values from the stack from, + +


    lua_xmove

    +
    void lua_xmove (lua_State *from, lua_State *to, int n);
    + +

    +Exchange values between different threads of the same global state. + + +

    +This function pops n values from the stack from, and pushes them onto the stack to. -

    -


    lua_yield

    -
    -          int lua_yield  (lua_State *L, int nresults);
    -
    -

    Yields a coroutine. -

    This function should only be called as the -return expression of a C function, as follows: + +


    lua_yield

    +
    int lua_yield  (lua_State *L, int nresults);
    + +

    +Yields a coroutine. + + +

    +This function should only be called as the +return expression of a C function, as follows: +

    -       return lua_yield (L, nresults);
    -
    -When a C function calls lua_yield in that way, + return lua_yield (L, nresults); +

    +When a C function calls lua_yield in that way, the running coroutine suspends its execution, and the call to lua_resume that started this coroutine returns. The parameter nresults is the number of values from the stack that are passed as results to lua_resume. -

    -

    3.8 - The Debug Interface

    -

    Lua has no built-in debugging facilities. -Instead, it offers a special interface + + + + + +

    3.8 - The Debug Interface

    + +

    +Lua has no built-in debugging facilities. +Instead, it offers a special interface by means of functions and hooks. This interface allows the construction of different kinds of debuggers, profilers, and other tools that need "inside information" from the interpreter. -

    -


    lua_Debug

    -
    -          typedef struct lua_Debug {
    -            int event;
    -            const char *name;           /* (n) */
    -            const char *namewhat;       /* (n) */
    -            const char *what;           /* (S) */
    -            const char *source;         /* (S) */
    -            int currentline;            /* (l) */
    -            int nups;                   /* (u) number of upvalues */
    -            int linedefined;            /* (S) */
    -            int lastlinedefined;        /* (S) */
    -            char short_src[LUA_IDSIZE]; /* (S) */
    -            /* private part */
    -            ...
    -          } lua_Debug;
     
    -
    +

    lua_Debug

    +
    typedef struct lua_Debug {
    +  int event;
    +  const char *name;           /* (n) */
    +  const char *namewhat;       /* (n) */
    +  const char *what;           /* (S) */
    +  const char *source;         /* (S) */
    +  int currentline;            /* (l) */
    +  int nups;                   /* (u) number of upvalues */
    +  int linedefined;            /* (S) */
    +  int lastlinedefined;        /* (S) */
    +  char short_src[LUA_IDSIZE]; /* (S) */
    +  /* private part */
    +  other fields
    +} lua_Debug;
    -

    A structure used to carry different pieces of +

    +A structure used to carry different pieces of information about an active function. lua_getstack fills only the private part of this structure, for later use. To fill the other fields of lua_Debug with useful information, call lua_getinfo. -

    The fields of lua_Debug have the following meaning: + +

    +The fields of lua_Debug have the following meaning: +

      -
    • source --- + +
    • source: If the function was defined in a string, then source is that string. If the function was defined in a file, -then source starts with a `@´ followed by the file name. +then source starts with a '@' followed by the file name. +
    • -

    • short_src --- +
    • short_src: a "printable" version of source, to be used in error messages. +
    • -

    • linedefined --- +
    • linedefined: the line number where the definition of the function starts. +
    • -

    • lastlinedefined --- +
    • lastlinedefined: the line number where the definition of the function ends. +
    • -

    • what --- +
    • what: the string "Lua" if the function is a Lua function, -"C" if it is a C function, +"C" if it is a C function, "main" if it is the main part of a chunk, and "tail" if it was a function that did a tail call. In the latter case, Lua has no other information about the function. +
    • -

    • currentline --- +
    • currentline: the current line where the given function is executing. When no line information is available, -currentline is set to -1. +currentline is set to -1. +
    • -

    • name --- +
    • name: a reasonable name for the given function. Because functions in Lua are first-class values, they do not have a fixed name: -Some functions may be the value of multiple global variables, +some functions may be the value of multiple global variables, while others may be stored only in a table field. The lua_getinfo function checks how the function was called to find a suitable name. If it cannot find a name, then name is set to NULL. +
    • -

    • namewhat --- +
    • namewhat: explains the name field. The value of namewhat can be "global", "local", "method", "field", "upvalue", or "" (the empty string), according to how the function was called. (Lua uses the empty string when no other option seems to apply.) +
    • -

    • nups --- +
    • nups: the number of upvalues of the function. +
    • + +
    -

    -

    -


    lua_gethook

    -
    -          lua_Hook lua_gethook (lua_State *L);
    -
    -

    Returns the current hook function. +


    lua_gethook

    +
    lua_Hook lua_gethook (lua_State *L);
    -

    -


    lua_gethookcount

    -
    -          int lua_gethookcount (lua_State *L);
    -
    +

    +Returns the current hook function. -

    Returns the current hook count. -

    -


    lua_gethookmask

    -
    -          int lua_gethookmask (lua_State *L);
    -
    -

    Returns the current hook mask. +


    lua_gethookcount

    +
    int lua_gethookcount (lua_State *L);
    -

    -


    lua_getinfo

    -
    -          int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
    -
    +

    +Returns the current hook count. -

    Fills the fields of lua_Debug with useful information. -

    This function returns 0 on error -(for instance, an invalid option in what). -Each character in the string what -selects some fields of the structure ar to be filled, -as indicated by the letter in parentheses in the definition of lua_Debug: -`S´ fills in the fields source, linedefined, -lastlinedefined, -and what; -`l´ fills in the field currentline, etc. -Moreover, `f´ pushes onto the stack the function that is -running at the given level. - -

    To get information about a function that is not active -(that is, not in the stack), -you push it onto the stack -and start the what string with the character `>´. + + +


    lua_gethookmask

    +
    int lua_gethookmask (lua_State *L);
    + +

    +Returns the current hook mask. + + + + + +


    lua_getinfo

    +
    int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
    + +

    +Returns information about a specific function or function invocation. + + +

    +To get information about a function invocation, +the parameter ar must be a valid activation record that was +filled by a previous call to lua_getstack or +given as argument to a hook (see lua_Hook). + + +

    +To get information about a function you push it onto the stack +and start the what string with the character '>'. +(In that case, +lua_getinfo pops the function in the top of the stack.) For instance, to know in which line a function f was defined, you can write the following code: -

    -       lua_Debug ar;
    -       lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* get global `f' */
    -       lua_getinfo(L, ">S", &ar);
    -       printf("%d\n", ar.linedefined);
    -
    -

    -


    lua_getlocal

    -          const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
    +     lua_Debug ar;
    +     lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* get global 'f' */
    +     lua_getinfo(L, ">S", &ar);
    +     printf("%d\n", ar.linedefined);
     
    +

    +Each character in the string what +selects some fields of the structure ar to be filled or +a value to be pushed on the stack: + +

      + +
    • 'n': fills in the field name and namewhat; +
    • + +
    • 'S': +fills in the fields source, linedefined, +lastlinedefined, what, and short_src; +
    • + +
    • 'l': fills in the field currentline; +
    • + +
    • 'u': fills in the field nups; +
    • + +
    • 'f': +pushes onto the stack the function that is +running at the given level; +
    • + +
    • 'L': +pushes onto the stack a table whose indices are the +numbers of the lines that are valid on the function. +(A valid line is a line with some associated code, +that is, a line where you can put a break point. +Non-valid lines include empty lines and comments.) +
    • + +
    + +

    +This function returns 0 on error +(for instance, an invalid option in what). + + + -

    Gets information about a local variable of a given activation record. + +


    lua_getlocal

    +
    const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
    + +

    +Gets information about a local variable of a given activation record. The parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook). @@ -3536,40 +4334,48 @@

    lua_getlocal pushes the variable's value onto the stack and returns its name. -

    Variable names starting with `(´ (open parentheses) + +

    +Variable names starting with '(' (open parentheses) represent internal variables -(loop control variables, temporaries, and C function locals). +(loop control variables, temporaries, and C function locals). + -

    Returns NULL (and pushes nothing) +

    +Returns NULL (and pushes nothing) when the index is greater than the number of active local variables. -

    -


    lua_getstack

    -
    -          int lua_getstack (lua_State *L, int level, lua_Debug *ar);
    -
    -

    Get information about the interpreter runtime stack. -

    This function fills parts of a lua_Debug structure with + +


    lua_getstack

    +
    int lua_getstack (lua_State *L, int level, lua_Debug *ar);
    + +

    +Get information about the interpreter runtime stack. + + +

    +This function fills parts of a lua_Debug structure with an identification of the activation record of the function executing at a given level. -Level 0 is the current running function, +Level 0 is the current running function, whereas level n+1 is the function that has called level n. When there are no errors, lua_getstack returns 1; when called with a level greater than the stack depth, it returns 0. -

    -


    lua_getupvalue

    -
    -          const char *lua_getupvalue (lua_State *L, int funcindex, int n);
    -
    -

    Gets information about a closure's upvalue. + + +


    lua_getupvalue

    +
    const char *lua_getupvalue (lua_State *L, int funcindex, int n);
    + +

    +Gets information about a closure's upvalue. (For Lua functions, upvalues are the external local variables that the function uses, and that are consequently included in its closure.) @@ -3581,26 +4387,31 @@

    as they are active through the whole function. So, they are numbered in an arbitrary order.) -

    Returns NULL (and pushes nothing) + +

    +Returns NULL (and pushes nothing) when the index is greater than the number of upvalues. -For C functions, this function uses the empty string "" +For C functions, this function uses the empty string "" as a name for all upvalues. -

    -


    lua_Hook

    -
    -          typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
    -
    -

    Type for debugging hook functions. -

    Whenever a hook is called, its ar argument has its field + +


    lua_Hook

    +
    typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
    + +

    +Type for debugging hook functions. + + +

    +Whenever a hook is called, its ar argument has its field event set to the specific event that triggered the hook. Lua identifies these events with the following constants: -LUA_HOOKCALL, LUA_HOOKRET, -LUA_HOOKTAILRET, LUA_HOOKLINE, -and LUA_HOOKCOUNT. +LUA_HOOKCALL, LUA_HOOKRET, +LUA_HOOKTAILRET, LUA_HOOKLINE, +and LUA_HOOKCOUNT. Moreover, for line events, the field currentline is also set. To get the value of any other field in ar, the hook must call lua_getinfo. @@ -3610,86 +4421,114 @@

    a function that did a tail call; in this case, it is useless to call lua_getinfo. -

    While Lua is running a hook, it disables other calls to hooks. + +

    +While Lua is running a hook, it disables other calls to hooks. Therefore, if a hook calls back Lua to execute a function or a chunk, this execution occurs without any calls to hooks. -

    -


    lua_sethook

    -
    -          int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
    -
    -

    Sets the debugging hook function. -

    func is the hook function. + +


    lua_sethook

    +
    int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
    + +

    +Sets the debugging hook function. + + +

    +func is the hook function. mask specifies on which events the hook will be called: -It is formed by a bitwise or of the constants -LUA_MASKCALL, -LUA_MASKRET, -LUA_MASKLINE, -and LUA_MASKCOUNT. +it is formed by a bitwise or of the constants +LUA_MASKCALL, +LUA_MASKRET, +LUA_MASKLINE, +and LUA_MASKCOUNT. The count argument is only meaningful when the mask includes LUA_MASKCOUNT. For each event, the hook is called as explained below: +

      -
    • The call hook is called when the interpreter calls a function. + +
    • The call hook: is called when the interpreter calls a function. The hook is called just after Lua enters the new function, before the function gets its arguments. -
    • The return hook is called when the interpreter returns from a function. +
    • + +
    • The return hook: is called when the interpreter returns from a function. The hook is called just before Lua leaves the function. You have no access to the values to be returned by the function. -
    • The line hook is called when the interpreter is about to +
    • + +
    • The line hook: is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.) -
    • The count hook is called after the interpreter executes every +
    • + +
    • The count hook: is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.) +
    • +
    -

    A hook is disabled by setting mask to zero. +

    +A hook is disabled by setting mask to zero. + + -

    -


    lua_setlocal

    -
    -          const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
    -
    -

    Sets the value of a local variable of a given activation record. +


    lua_setlocal

    +
    const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
    + +

    +Sets the value of a local variable of a given activation record. Parameters ar and n are as in lua_getlocal (see lua_getlocal). lua_setlocal assigns the value at the top of the stack to the variable and returns its name. It also pops the value from the stack. -

    Returns NULL (and pops nothing) + +

    +Returns NULL (and pops nothing) when the index is greater than the number of active local variables. -

    -


    lua_setupvalue

    -
    -          const char *lua_setupvalue (lua_State *L, int funcindex, int n);
    -
    -

    Sets the value of a closure's upvalue. + + +


    lua_setupvalue

    +
    const char *lua_setupvalue (lua_State *L, int funcindex, int n);
    + +

    +Sets the value of a closure's upvalue. Parameters funcindex and n are as in lua_getupvalue (see lua_getupvalue). It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. -

    Returns NULL (and pops nothing) -when the index is greater than the number of upvalues.

    -

    4 - The Auxiliary Library

    +Returns NULL (and pops nothing) +when the index is greater than the number of upvalues. + + + + + + + +

    4 - The Auxiliary Library

    + The auxiliary library provides several convenient functions to interface C with Lua. While the basic API provides the primitive functions for all @@ -3697,137 +4536,175 @@

    the auxiliary library provides higher-level functions for some common tasks. -

    All functions from the auxiliary library + +

    +All functions from the auxiliary library are defined in header file lauxlib.h and have a prefix luaL_. -

    All functions in the auxiliary library are built on + +

    +All functions in the auxiliary library are built on top of the basic API, and so they provide nothing that cannot be done with this API. -

    Several functions in the auxiliary library are used to -check C function arguments. + +

    +Several functions in the auxiliary library are used to +check C function arguments. Their names are always luaL_check* or luaL_opt*. All of these functions raise an error if the check is not satisfied. Because the error message is formatted for arguments -(e.g., "bad argument #1"), +(e.g., "bad argument #1"), you should not use these functions for other stack values. -

    4.1 - Functions and Types

    -

    Here we list all functions and types from the auxiliary library + +

    4.1 - Functions and Types

    + +

    +Here we list all functions and types from the auxiliary library in alphabetical order. -

    -


    luaL_addchar

    -
    -          void luaL_addchar (luaL_Buffer B, char c);
    -
    -

    Adds the character c to the buffer B +


    luaL_addchar

    +
    void luaL_addchar (luaL_Buffer *B, char c);
    + +

    +Adds the character c to the buffer B (see luaL_Buffer). -

    -


    luaL_addlstring

    -
    -          void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
    -
    -

    Adds the string pointed to by s with length l to + + +


    luaL_addlstring

    +
    void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
    + +

    +Adds the string pointed to by s with length l to the buffer B (see luaL_Buffer). The string may contain embedded zeros. -

    -


    luaL_addsize

    -
    -          void luaL_addsize (luaL_Buffer B, size_t n);
    -
    -

    Adds a string of length n previously copied to the + + +


    luaL_addsize

    +
    void luaL_addsize (luaL_Buffer *B, size_t n);
    + +

    +Adds a string of length n previously copied to the buffer area (see luaL_prepbuffer) to the buffer B (see luaL_Buffer). -

    -


    luaL_addstring

    -
    -          void luaL_addstring (luaL_Buffer *B, const char *s);
    -
    -

    Adds the zero-terminated string pointed to by s + + +


    luaL_addstring

    +
    void luaL_addstring (luaL_Buffer *B, const char *s);
    + +

    +Adds the zero-terminated string pointed to by s to the buffer B (see luaL_Buffer). The string may not contain embedded zeros. -

    -


    luaL_addvalue

    -
    -          void luaL_addvalue (luaL_Buffer *B);
    -
    -

    Adds the value at the top of the stack + + +


    luaL_addvalue

    +
    void luaL_addvalue (luaL_Buffer *B);
    + +

    +Adds the value at the top of the stack to the buffer B (see luaL_Buffer). Pops the value. -

    This is the only function on string buffers that can (and must) + +

    +This is the only function on string buffers that can (and must) be called with an extra element on the stack, which is the value to be added to the buffer. -

    -


    luaL_argcheck

    -
    -          void luaL_argcheck (lua_State *L, int cond, int numarg,
    -                              const char *extramsg);
    -
    -

    Checks whether cond is true. -If not, raises an error with message -"bad argument #<numarg> to <func> (<extramsg>)", -where func is retrieved from the call stack. -

    -


    luaL_argerror

    + +

    luaL_argcheck

    +
    void luaL_argcheck (lua_State *L,
    +                    int cond,
    +                    int numarg,
    +                    const char *extramsg);
    + +

    +Checks whether cond is true. +If not, raises an error with the following message, +where func is retrieved from the call stack: +

    -          int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
    +     bad argument #<numarg> to <func> (<extramsg>)
     
    -

    Raises an error with message -"bad argument #<numarg> to <func> (<extramsg>)", -where func is retrieved from the call stack. -

    This function never returns, -but it is an idiom to use it as return luaL_argerror ... -in C functions. -

    -


    luaL_Buffer

    +

    luaL_argerror

    +
    int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
    + +

    +Raises an error with the following message, +where func is retrieved from the call stack: +

    -          typedef struct luaL_Buffer luaL_Buffer;
    +     bad argument #<numarg> to <func> (<extramsg>)
     
    +

    +This function never returns, +but it is an idiom to use it in C functions +as return luaL_argerror(args). + + + -

    Type for a string buffer. -

    A string buffer allows C code to build Lua strings piecemeal. +


    luaL_Buffer

    +
    typedef struct luaL_Buffer luaL_Buffer;
    + +

    +Type for a string buffer. + + +

    +A string buffer allows C code to build Lua strings piecemeal. Its pattern of use is as follows: +

      -
    • First you declare a variable b of type luaL_Buffer. -
    • Then you initialize it with a call luaL_buffinit(L, &b). -
    • Then you add string pieces to the buffer calling any of + +
    • First you declare a variable b of type luaL_Buffer.
    • + +
    • Then you initialize it with a call luaL_buffinit(L, &b).
    • + +
    • +Then you add string pieces to the buffer calling any of the luaL_add* functions. -
    • You finish by calling luaL_pushresult(&b). +
    • + +
    • +You finish by calling luaL_pushresult(&b). This call leaves the final string on the top of the stack. +
    • +
    -

    During its normal operation, +

    +During its normal operation, a string buffer uses a variable number of stack slots. So, while using a buffer, you cannot assume that you know where the top of the stack is. @@ -3842,168 +4719,224 @@

    level when the buffer was initialized, plus the final string on its top. -

    -


    luaL_buffinit

    -
    -          void luaL_buffinit (lua_State *L, luaL_Buffer *B);
    -
    -

    Initializes a buffer B. + + +


    luaL_buffinit

    +
    void luaL_buffinit (lua_State *L, luaL_Buffer *B);
    + +

    +Initializes a buffer B. This function does not allocate any space; the buffer must be declared as a variable (see luaL_Buffer). -

    -


    luaL_callmeta

    -
    -          int luaL_callmeta (lua_State *L, int obj, const char *e);
    -
    -

    Calls a metamethod. -

    If the object at index obj has a metatable and this + +


    luaL_callmeta

    +
    int luaL_callmeta (lua_State *L, int obj, const char *e);
    + +

    +Calls a metamethod. + + +

    +If the object at index obj has a metatable and this metatable has a field e, this function calls this field and passes the object as its only argument. -In this case this function returns 1 and pushes on the +In this case this function returns 1 and pushes onto the stack the value returned by the call. If there is no metatable or no metamethod, this function returns 0 (without pushing any value on the stack). -

    -


    luaL_checkany

    -
    -          void luaL_checkany (lua_State *L, int narg);
    -
    -

    Checks whether the function has an argument + + +


    luaL_checkany

    +
    void luaL_checkany (lua_State *L, int narg);
    + +

    +Checks whether the function has an argument of any type (including nil) at position narg. -

    -


    luaL_checkint

    -
    -          int luaL_checkint (lua_State *L, int narg);
    -
    -

    Checks whether the function argument narg is a number + + +


    luaL_checkint

    +
    int luaL_checkint (lua_State *L, int narg);
    + +

    +Checks whether the function argument narg is a number and returns this number cast to an int. -

    -


    luaL_checkinteger

    -
    -          lua_Integer luaL_checkinteger (lua_State *L, int narg);
    -
    -

    Checks whether the function argument narg is a number + + +


    luaL_checkinteger

    +
    lua_Integer luaL_checkinteger (lua_State *L, int narg);
    + +

    +Checks whether the function argument narg is a number and returns this number cast to a lua_Integer. -

    -


    luaL_checklong

    -
    -          long luaL_checklong (lua_State *L, int narg);
    -
    -

    Checks whether the function argument narg is a number + + +


    luaL_checklong

    +
    long luaL_checklong (lua_State *L, int narg);
    + +

    +Checks whether the function argument narg is a number and returns this number cast to a long. -

    -


    luaL_checklstring

    -
    -          const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
    -
    -

    Checks whether the function argument narg is a string + + +


    luaL_checklstring

    +
    const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
    + +

    +Checks whether the function argument narg is a string and returns this string; if l is not NULL fills *l with the string's length. -

    -


    luaL_checknumber

    -
    -          lua_Number luaL_checknumber (lua_State *L, int narg);
    -
    -

    Checks whether the function argument narg is a number -and returns this number. -

    -


    luaL_checkoption

    -
    -          int luaL_checkoption (lua_State *L, int narg, const char *def,
    -                                const char *const lst[]);
    -
    + +

    luaL_checknumber

    +
    lua_Number luaL_checknumber (lua_State *L, int narg);
    + +

    +Checks whether the function argument narg is a number +and returns this number. + + -

    Checks whether the function argument narg is a string and -searches for this string in the array lst -(which must be NULL-terminated). -If def is not NULL, -uses def as a default value when -the function has no argument narg or if this argument is nil. -

    Returns the index in the array where the string was found. +


    luaL_checkoption

    +
    int luaL_checkoption (lua_State *L,
    +                      int narg,
    +                      const char *def,
    +                      const char *const lst[]);
    + +

    +Checks whether the function argument narg is a string and +searches for this string in the array lst +(which must be NULL-terminated). +Returns the index in the array where the string was found. Raises an error if the argument is not a string or if the string cannot be found. -

    This is a useful function for mapping strings to C enums. -The usual convention in Lua libraries is to use strings instead of numbers -to select options. -

    -


    luaL_checkstack

    -
    -          void luaL_checkstack (lua_State *L, int sz, const char *msg);
    -
    +

    +If def is not NULL, +the function uses def as a default value when +there is no argument narg or if this argument is nil. -

    Grows the stack size to top + sz elements, +

    +This is a useful function for mapping strings to C enums. +(The usual convention in Lua libraries is +to use strings instead of numbers to select options.) + + + + + +


    luaL_checkstack

    +
    void luaL_checkstack (lua_State *L, int sz, const char *msg);
    + +

    +Grows the stack size to top + sz elements, raising an error if the stack cannot grow to that size. msg is an additional text to go into the error message. -

    -


    luaL_checkstring

    -
    -          const char *luaL_checkstring (lua_State *L, int narg);
    -
    -

    Checks whether the function argument narg is a string + + +


    luaL_checkstring

    +
    const char *luaL_checkstring (lua_State *L, int narg);
    + +

    +Checks whether the function argument narg is a string and returns this string. -

    -


    luaL_checktype

    -
    -          void luaL_checktype (lua_State *L, int narg, int t);
    -
    -

    Checks whether the function argument narg has type t. -

    -


    luaL_checkudata

    -
    -          void *luaL_checkudata (lua_State *L, int narg, const char *tname);
    -
    + +

    luaL_checktype

    +
    void luaL_checktype (lua_State *L, int narg, int t);
    + +

    +Checks whether the function argument narg has type t. + + + -

    Checks whether the function argument narg is a userdata +


    luaL_checkudata

    +
    void *luaL_checkudata (lua_State *L, int narg, const char *tname);
    + +

    +Checks whether the function argument narg is a userdata of the type tname (see luaL_newmetatable). -

    -


    luaL_error

    + + + + +

    luaL_dofile

    +
    int luaL_dofile (lua_State *L, const char *filename);
    + +

    +Loads and runs the given file. +It is defined as the following macro: +

    -          int luaL_error (lua_State *L, const char *fmt, ...);
    -
    + (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0)) +

    +It returns 0 if there are no errors +or 1 in case of errors. + + + + + +


    luaL_dostring

    +
    int luaL_dostring (lua_State *L, const char *str);
    + +

    +Loads and runs the given string. +It is defined as the following macro: + +

    +     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
    +

    +It returns 0 if there are no errors +or 1 in case of errors. + -

    Raises an error. + + +


    luaL_error

    +
    int luaL_error (lua_State *L, const char *fmt, ...);
    + +

    +Raises an error. The error message format is given by fmt plus any extra arguments, following the same rules of lua_pushfstring. @@ -4011,297 +4944,355 @@

    the line number where the error occurred, if this information is available. -

    This function never returns, -but it is an idiom to use it as return luaL_error ... -in C functions. -

    -


    luaL_getmetafield

    -
    -          int luaL_getmetafield (lua_State *L, int obj, const char *e);
    -
    +

    +This function never returns, +but it is an idiom to use it in C functions +as return luaL_error(args). + -

    Pushes on the stack the field e from the metatable + + +


    luaL_getmetafield

    +
    int luaL_getmetafield (lua_State *L, int obj, const char *e);
    + +

    +Pushes onto the stack the field e from the metatable of the object at index obj. If the object does not have a metatable, or if the metatable does not have this field, returns 0 and pushes nothing. -

    -


    luaL_getmetatable

    -
    -          void luaL_getmetatable (lua_State *L, const char *tname);
    -
    -

    Pushes on the stack the metatable associated with name tname + + +


    luaL_getmetatable

    +
    void luaL_getmetatable (lua_State *L, const char *tname);
    + +

    +Pushes onto the stack the metatable associated with name tname in the registry (see luaL_newmetatable). -

    -


    luaL_gsub

    -
    -          const char *luaL_gsub (lua_State *L, const char *s,
    -                                 const char *p, const char *r);
    -
    -

    Creates a copy of string s by replacing + + +


    luaL_gsub

    +
    const char *luaL_gsub (lua_State *L,
    +                       const char *s,
    +                       const char *p,
    +                       const char *r);
    + +

    +Creates a copy of string s by replacing any occurrence of the string p with the string r. Pushes the resulting string on the stack and returns it. -

    -


    luaL_loadbuffer

    -
    -          int luaL_loadbuffer (lua_State *L, const char *buff,
    -                               size_t sz, const char *name);
    -
    -

    Loads a buffer as a Lua chunk. + + +


    luaL_loadbuffer

    +
    int luaL_loadbuffer (lua_State *L,
    +                     const char *buff,
    +                     size_t sz,
    +                     const char *name);
    + +

    +Loads a buffer as a Lua chunk. This function uses lua_load to load the chunk in the buffer pointed to by buff with size sz. -

    This function returns the same results as lua_load. + +

    +This function returns the same results as lua_load. name is the chunk name, used for debug information and error messages. -

    -


    luaL_loadfile

    -
    -          int luaL_loadfile (lua_State *L, const char *filename);
    -
    -

    Loads a file as a Lua chunk. + + +


    luaL_loadfile

    +
    int luaL_loadfile (lua_State *L, const char *filename);
    + +

    +Loads a file as a Lua chunk. This function uses lua_load to load the chunk in the file named filename. If filename is NULL, then it loads from the standard input. The first line in the file is ignored if it starts with a #. -

    This function returns the same results as lua_load, -but it has an extra error code LUA_ERRFILE + +

    +This function returns the same results as lua_load, +but it has an extra error code LUA_ERRFILE if it cannot open/read the file. -

    -


    luaL_loadstring

    -
    -          int luaL_loadstring (lua_State *L, const char *s);
    -
    + +

    +As lua_load, this function only loads the chunk; +it does not run it. -

    Loads a string as a Lua chunk. + + + +


    luaL_loadstring

    +
    int luaL_loadstring (lua_State *L, const char *s);
    + +

    +Loads a string as a Lua chunk. This function uses lua_load to load the chunk in the zero-terminated string s. -

    This function returns the same results as lua_load. -

    -


    luaL_newmetatable

    -
    -          int luaL_newmetatable (lua_State *L, const char *tname);
    -
    +

    +This function returns the same results as lua_load. -

    If the registry already has the key tname, +

    +Also as lua_load, this function only loads the chunk; +it does not run it. + + + + + +


    luaL_newmetatable

    +
    int luaL_newmetatable (lua_State *L, const char *tname);
    + +

    +If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used as a metatable for userdata, adds it to the registry with key tname, and returns 1. -

    In both cases pushes on the stack the final value associated + +

    +In both cases pushes onto the stack the final value associated with tname in the registry. -

    -


    luaL_newstate

    -
    -          lua_State *luaL_newstate (void);
    -
    -

    Creates a new Lua state, calling lua_newstate with an -allocation function based on the standard C realloc function + + +


    luaL_newstate

    +
    lua_State *luaL_newstate (void);
    + +

    +Creates a new Lua state, calling lua_newstate with an +allocation function based on the standard C realloc function and setting a panic function (see lua_atpanic) that prints an error message to the standard error output in case of fatal errors. -

    Returns the new state, + +

    +Returns the new state, or NULL if there is a memory allocation error. -

    -


    luaL_openlibs

    -
    -          void luaL_openlibs (lua_State *L);
    -
    -

    Opens all standard Lua libraries into the given state. -

    -


    luaL_optint

    -
    -          int luaL_optint (lua_State *L, int narg, int d);
    -
    + +

    luaL_openlibs

    +
    void luaL_openlibs (lua_State *L);
    + +

    +Opens all standard Lua libraries into the given state. + + + -

    If the function argument narg is a number, +


    luaL_optint

    +
    int luaL_optint (lua_State *L, int narg, int d);
    + +

    +If the function argument narg is a number, returns this number cast to an int. If this argument is absent or is nil, returns d. Otherwise, raises an error. -

    -


    luaL_optinteger

    -
    -          lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer d);
    -
    -

    If the function argument narg is a number, + + +


    luaL_optinteger

    +
    lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer d);
    + +

    +If the function argument narg is a number, returns this number cast to a lua_Integer. If this argument is absent or is nil, returns d. Otherwise, raises an error. -

    -


    luaL_optlong

    -
    -          long luaL_optlong (lua_State *L, int narg, long d);
    -
    -

    If the function argument narg is a number, + + +


    luaL_optlong

    +
    long luaL_optlong (lua_State *L, int narg, long d);
    + +

    +If the function argument narg is a number, returns this number cast to a long. If this argument is absent or is nil, returns d. Otherwise, raises an error. -

    -


    luaL_optlstring

    -
    -          const char *luaL_optlstring (lua_State *L, int narg,
    -                                       const char *d, size_t *l);
    -
    -

    If the function argument narg is a string, + + +


    luaL_optlstring

    +
    const char *luaL_optlstring (lua_State *L,
    +                             int narg,
    +                             const char *d,
    +                             size_t *l);
    + +

    +If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error. -

    If l is not NULL, + +

    +If l is not NULL, fills the position *l with the results's length. -

    -


    luaL_optnumber

    -
    -          lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
    -
    -

    If the function argument narg is a number, + + +


    luaL_optnumber

    +
    lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
    + +

    +If the function argument narg is a number, returns this number. If this argument is absent or is nil, returns d. Otherwise, raises an error. -

    -


    luaL_optstring

    -
    -          const char *luaL_optstring (lua_State *L, int narg, const char *d);
    -
    -

    If the function argument narg is a string, + + +


    luaL_optstring

    +
    const char *luaL_optstring (lua_State *L, int narg, const char *d);
    + +

    +If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error. -

    -


    luaL_prepbuffer

    -
    -          char *luaL_prepbuffer (luaL_Buffer *B);
    -
    -

    Returns an address to a space of size LUAL_BUFFERSIZE + + +


    luaL_prepbuffer

    +
    char *luaL_prepbuffer (luaL_Buffer *B);
    + +

    +Returns an address to a space of size LUAL_BUFFERSIZE where you can copy a string to be added to buffer B (see luaL_Buffer). After copying the string into this space you must call luaL_addsize with the size of the string to actually add it to the buffer. -

    -


    luaL_pushresult

    -
    -          void luaL_pushresult (luaL_Buffer *B);
    -
    -

    Finishes the use of buffer B leaving the final string on + + +


    luaL_pushresult

    +
    void luaL_pushresult (luaL_Buffer *B);
    + +

    +Finishes the use of buffer B leaving the final string on the top of the stack. -

    -


    luaL_ref

    -
    -          int luaL_ref (lua_State *L, int t);
    -
    -

    Creates and returns a reference, + + +


    luaL_ref

    +
    int luaL_ref (lua_State *L, int t);
    + +

    +Creates and returns a reference, in the table at index t, for the object at the top of the stack (and pops the object). -

    A reference is a unique integer key. + +

    +A reference is a unique integer key. As long as you do not manually add integer keys into table t, luaL_ref ensures the uniqueness of the key it returns. You can retrieve an object referred by reference r by calling lua_rawgeti(L, t, r). Function luaL_unref frees a reference and its associated object. -

    If the object at the top of the stack is nil, -luaL_ref returns the constant LUA_REFNIL. -The constant LUA_NOREF is guaranteed to be different + +

    +If the object at the top of the stack is nil, +luaL_ref returns the constant LUA_REFNIL. +The constant LUA_NOREF is guaranteed to be different from any reference returned by luaL_ref. -

    -


    luaL_Reg

    -
    -          typedef struct luaL_Reg {
    -            const char *name;
    -            lua_CFunction func;
    -          } luaL_Reg;
     
    -
    -

    Type for arrays of functions to be registered by + +


    luaL_Reg

    +
    typedef struct luaL_Reg {
    +  const char *name;
    +  lua_CFunction func;
    +} luaL_Reg;
    + +

    +Type for arrays of functions to be registered by luaL_register. name is the function name and func is a pointer to the function. Any array of luaL_Reg must end with an sentinel entry in which both name and func are NULL. -

    -


    luaL_register

    -
    -          void luaL_register (lua_State *L, const char *libname,
    -                              const luaL_Reg *l);
    -
    -

    Opens a library. -

    When called with libname equal to NULL, -simply registers all functions in the list l + +


    luaL_register

    +
    void luaL_register (lua_State *L,
    +                    const char *libname,
    +                    const luaL_Reg *l);
    + +

    +Opens a library. + + +

    +When called with libname equal to NULL, +it simply registers all functions in the list l (see luaL_Reg) into the table on the top of the stack. -

    When called with a non-null libname, + +

    +When called with a non-null libname, creates a new table t, sets it as the value of the global variable libname, sets it as the value of package.loaded[libname], @@ -4310,70 +5301,87 @@

    variable libname, reuses this table instead of creating a new one. -

    In any case the function leaves the table + +

    +In any case the function leaves the table on the top of the stack. -

    -


    luaL_typename

    -
    -          const char *luaL_typename (lua_State *L, int idx);
    -
    -

    Returns the name of the type of the value at index idx. -

    -


    luaL_typerror

    -
    -          int luaL_typerror (lua_State *L, int narg, const char *tname);
    -
    + +

    luaL_typename

    +
    const char *luaL_typename (lua_State *L, int idx);
    + +

    +Returns the name of the type of the value at index idx. + + -

    Generates an error with a message like -

    -<location>: bad argument <narg> to <function> (<tname> expected, got <realt>)
    -
    -where <location> is produced by luaL_where, -<function> is the name of the current function, -and <realt> is the type name of the actual argument. -

    -


    luaL_unref

    +

    luaL_typerror

    +
    int luaL_typerror (lua_State *L, int narg, const char *tname);
    + +

    +Generates an error with a message like +

    -          void luaL_unref (lua_State *L, int t, int ref);
    -
    + <location>: bad argument <narg> to <function> (<tname> expected, got <realt>) +

    +where <location> is produced by luaL_where, +<function> is the name of the current function, +and <realt> is the type name of the actual argument. + + + + +


    luaL_unref

    +
    void luaL_unref (lua_State *L, int t, int ref);
    -

    Releases reference ref from the table at index t +

    +Releases reference ref from the table at index t (see luaL_ref). The entry is removed from the table, so that the referred object can be collected. The reference ref is also freed to be used again. -

    If ref is LUA_NOREF or LUA_REFNIL, + +

    +If ref is LUA_NOREF or LUA_REFNIL, luaL_unref does nothing. -

    -


    luaL_where

    -
    -          void luaL_where (lua_State *L, int lvl);
    -
    -

    Pushes on the stack a string identifying the current position + + +


    luaL_where

    +
    void luaL_where (lua_State *L, int lvl);
    + +

    +Pushes onto the stack a string identifying the current position of the control at level lvl in the call stack. -Typically this string has the format <chunkname>:<currentline>:. -Level 0 is the running function, -level 1 is the function that called the running function, +Typically this string has the format <chunkname>:<currentline>:. +Level 0 is the running function, +level 1 is the function that called the running function, etc. -

    This function is used to build a prefix for error messages.

    -

    5 - Standard Libraries

    +This function is used to build a prefix for error messages. + + + + + + + +

    5 - Standard Libraries

    -

    The standard Lua libraries provide useful functions -that are implemented directly through the C API. +

    +The standard Lua libraries provide useful functions +that are implemented directly through the C API. Some of these functions provide essential services to the language (e.g., type and getmetatable); others provide access to "outside" services (e.g., I/O); @@ -4381,79 +5389,128 @@

    but are quite useful or have critical performance requirements that deserve an implementation in C (e.g., sort). -

    All libraries are implemented through the official C API -and are provided as separate C modules. + +

    +All libraries are implemented through the official C API +and are provided as separate C modules. Currently, Lua has the following standard libraries: +

      -
    • basic library; -
    • package library; -
    • string manipulation; -
    • table manipulation; -
    • mathematical functions (sin, log, etc.); -
    • input and output; -
    • operating system facilities; -
    • debug facilities. -
    -Except for the basic and package libraries, -each library provides all its functions as fields of a global table -or as methods of its objects. -

    To have access to these libraries, -the C host program must call -luaL_openlibs, +

  • basic library;
  • + +
  • package library;
  • + +
  • string manipulation;
  • + +
  • table manipulation;
  • + +
  • mathematical functions (sin, log, etc.);
  • + +
  • input and output;
  • + +
  • operating system facilities;
  • + +
  • debug facilities.
  • + +

    +Except for the basic and package libraries, +each library provides all its functions as fields of a global table +or as methods of its objects. + + +

    +To have access to these libraries, +the C host program must call +luaL_openlibs, which open all standard libraries. Alternatively, it can open them individually by calling -luaopen_base (for the basic library), -luaopen_package (for the package library), -luaopen_string (for the string library), -luaopen_table (for the table library), -luaopen_math (for the mathematical library), -luaopen_io (for the I/O and the Operating System libraries), -and luaopen_debug (for the debug library). -These functions are declared in lualib.h +luaopen_base (for the basic library), +luaopen_package (for the package library), +luaopen_string (for the string library), +luaopen_table (for the table library), +luaopen_math (for the mathematical library), +luaopen_io (for the I/O and the Operating System libraries), +and luaopen_debug (for the debug library). +These functions are declared in lualib.h and should not be called directly: -you must call them like any other Lua C function, -e.g., by using lua_call. +you must call them like any other Lua C function, +e.g., by using lua_call. + + -

    5.1 - Basic Functions

    +

    5.1 - Basic Functions

    -

    The basic library provides some core functions to Lua. +

    +The basic library provides some core functions to Lua. If you do not include this library in your application, you should check carefully whether you need to provide implementations for some of its facilities. -


    assert (v [, message])

    + +

    +


    assert (v [, message])

    Issues an error when the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!" -


    collectgarbage (opt [, arg])

    -

    This function is a generic interface to the garbage collector. + + +

    +


    collectgarbage (opt [, arg])

    + + +

    +This function is a generic interface to the garbage collector. It performs different functions according to its first argument, opt: +

      -
    • "stop" --- stops the garbage collector. -
    • "restart" --- restarts the garbage collector. -
    • "collect" --- performs a full garbage-collection cycle. -
    • "count" --- returns the total memory in use by Lua (in Kbytes). -
    • "step" --- performs a garbage-collection step. + +
    • "stop": +stops the garbage collector. +
    • + +
    • "restart": +restarts the garbage collector. +
    • + +
    • "collect": +performs a full garbage-collection cycle. +
    • + +
    • "count": +returns the total memory in use by Lua (in Kbytes). +
    • + +
    • "step": +performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. If you want to control the step size -you must tune experimentally the value of arg. +you must experimentally tune the value of arg. Returns true if the step finished a collection cycle. -
    • "steppause" --- +
    • + +
    • "setpause": sets arg/100 as the new value for the pause of -the collector (see 2.10). -
    • "setstepmul" --- +the collector (see §2.10). +
    • + +
    • "setstepmul": sets arg/100 as the new value for the step multiplier of -the collector (see 2.10). +the collector (see §2.10). +
    • +
    -


    dofile (filename)

    + + +

    +


    dofile (filename)

    Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). @@ -4461,22 +5518,32 @@

    In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode). -


    error (message [, level])

    + + + +

    +


    error (message [, level])

    Terminates the last protected function called and returns message as the error message. Function error never returns. -

    Usually, error adds some information about the error position + +

    +Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. -With level 1 (the default), the error position is where the +With level 1 (the default), the error position is where the error function was called. -Level 2 points the error to where the function +Level 2 points the error to where the function that called error was called; and so on. -Passing a level 0 avoids the addition of error position information +Passing a level 0 avoids the addition of error position information to the message. -


    _G

    + + + +

    +


    _G

    A global variable (not a function) that holds the global environment (that is, _G._G = _G). Lua itself does not use this variable; @@ -4484,71 +5551,120 @@

    nor vice-versa. (Use setfenv to change environments.) -


    getfenv (f)

    + + + +

    +


    getfenv (f)

    Returns the current environment in use by the function. f can be a Lua function or a number that specifies the function at that stack level: -Level 1 is the function calling getfenv. +Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, getfenv returns the global environment. The default for f is 1. -


    getmetatable (object)

    -

    If object does not have a metatable, returns nil. + + +

    +


    getmetatable (object)

    + + +

    +If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a "__metatable" field, returns the associated value. Otherwise, returns the metatable of the given object. -


    ipairs (t)

    -

    Returns three values: an iterator function, the table t, and 0, + + +

    +


    ipairs (t)

    + + +

    +Returns three values: an iterator function, the table t, and 0, so that the construction +

    -       for i,v in ipairs(t) do ... end
    -
    -will iterate over the pairs (1,t[1]), (2,t[2]), ..., -up to the first integer key with a nil value in the table. + for i,v in ipairs(t) do body end +

    +will iterate over the pairs (1,t[1]), (2,t[2]), ···, +up to the first integer key absent from the table. + + +

    +See next for the caveats of modifying the table during its traversal. -

    See next for the caveats of modifying the table during its traversal. -


    load (func [, chunkname])

    -

    Loads a chunk using function func to get its pieces. + +

    +


    load (func [, chunkname])

    + + +

    +Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates with previous results. A return of nil (or no value) signals the end of the chunk. -

    If there are no errors, + +

    +If there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. The environment of the returned function is the global environment. -

    chunkname is used as the chunk name for error messages + +

    +chunkname is used as the chunk name for error messages and debug information. -


    loadfile ([filename])

    -

    Similar to load, + + +

    +


    loadfile ([filename])

    + + +

    +Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given. -


    loadstring (string [, chunkname])

    -

    Similar to load, + + +

    +


    loadstring (string [, chunkname])

    + + +

    +Similar to load, but gets the chunk from the given string. -

    To load and run a given string, use the idiom + +

    +To load and run a given string, use the idiom +

    -      assert(loadstring(s))()
    +     assert(loadstring(s))()
     
    -


    next (table [, index])

    -

    Allows a program to traverse all fields of a table. + +

    +


    next (table [, index])

    + + +

    +Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. next returns the next index of the table @@ -4563,37 +5679,52 @@

    In particular, you can use next(t) to check whether a table is empty. -

    Lua has no declaration of fields. -There is no difference between a -field not present in a table or a field with value nil. -Therefore, next only considers fields with non-nil values. + +

    The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.) -

    The behavior of next is undefined if, + +

    +The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields. -


    pairs (t)

    -

    Returns three values: the next function, the table t, and nil, + + +

    +


    pairs (t)

    + + +

    +Returns three values: the next function, the table t, and nil, so that the construction +

    -       for k,v in pairs(t) do ... end
    -
    -will iterate over all key--value pairs of table t. + for k,v in pairs(t) do body end +

    +will iterate over all key–value pairs of table t. + + +

    +See next for the caveats of modifying the table during its traversal. -

    See next for the caveats of modifying the table during its traversal. -


    pcall (f, arg1, arg2, ...)

    -

    Calls function f with -the given arguments in protected mode. -This means that any error inside f is not propagated; + +

    +


    pcall (f, arg1, ···)

    + + +

    +Calls function f with +the given arguments in protected mode. +This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), @@ -4602,7 +5733,11 @@

    after this first result. In case of any error, pcall returns false plus the error message. -


    print (e1, e2, ...)

    + + + +

    +


    print (···)

    Receives any number of arguments, and prints their values to stdout, using the tostring function to convert them to strings. @@ -4611,114 +5746,181 @@

    typically for debugging. For formatted output, use string.format. -


    rawequal (v1, v2)

    + + + +

    +


    rawequal (v1, v2)

    Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean. -


    rawget (table, index)

    + + + +

    +


    rawget (table, index)

    Gets the real value of table[index], without invoking any metamethod. -table must be a table and -index any value different from nil. +table must be a table; +index may be any value. + + + -


    rawset (table, index, value)

    +

    +


    rawset (table, index, value)

    Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil, and value any Lua value. -


    select (index, ...)

    -

    If index is a number, + + +

    +


    select (index, ···)

    + + +

    +If index is a number, returns all arguments after argument number index. Otherwise, index must be the string "#", and select returns the total number of extra arguments it received. -


    setfenv (f, table)

    -

    Sets the environment to be used by the given function. + + +

    +


    setfenv (f, table)

    + + +

    +Sets the environment to be used by the given function. f can be a Lua function or a number that specifies the function at that stack level: -Level 1 is the function calling setfenv. +Level 1 is the function calling setfenv. setfenv returns the given function. -

    As a special case, when f is 0 setfenv changes + +

    +As a special case, when f is 0 setfenv changes the environment of the running thread. In this case, setfenv returns no values. -


    setmetatable (table, metatable)

    -

    Sets the metatable for the given table. -(You cannot change the metatable of other types from Lua, only from C.) + + +

    +


    setmetatable (table, metatable)

    + + +

    +Sets the metatable for the given table. +(You cannot change the metatable of other types from Lua, only from C.) If metatable is nil, removes the metatable of the given table. If the original metatable has a "__metatable" field, raises an error. -

    This function returns table. -


    tonumber (e [, base])

    +

    +This function returns table. + + + + +

    +


    tonumber (e [, base])

    Tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns this number; otherwise, it returns nil. -

    An optional argument specifies the base to interpret the numeral. + +

    +An optional argument specifies the base to interpret the numeral. The base may be any integer between 2 and 36, inclusive. -In bases above 10, the letter `A´ (in either upper or lower case) -represents 10, `B´ represents 11, and so forth, -with `Z´ representing 35. +In bases above 10, the letter 'A' (in either upper or lower case) +represents 10, 'B' represents 11, and so forth, +with 'Z' representing 35. In base 10 (the default), the number may have a decimal part, -as well as an optional exponent part (see 2.1). +as well as an optional exponent part (see §2.1). In other bases, only unsigned integers are accepted. -


    tostring (e)

    + + + +

    +


    tostring (e)

    Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, use string.format. -

    If the metatable of e has a "__tostring" field, + +

    +If the metatable of e has a "__tostring" field, then tostring calls the corresponding value with e as argument, and uses the result of the call as its result. -


    type (v)

    + + + +

    +


    type (v)

    Returns the type of its only argument, coded as a string. The possible results of this function are -"nil" (a string, not the value nil), -"number", -"string", -"boolean, -"table", -"function", -"thread", -and "userdata". - -


    unpack (list [, i [, j]])

    +"nil" (a string, not the value nil), +"number", +"string", +"boolean", +"table", +"function", +"thread", +and "userdata". + + + + +

    +


    unpack (list [, i [, j]])

    Returns the elements from the given table. This function is equivalent to +
    -  return list[i], list[i+1], ..., list[j]
    -
    + return list[i], list[i+1], ···, list[j] +

    except that the above code can be written only for a fixed number of elements. -By default, i is 1 and j is the length of the list, -as defined by the length operator (see 2.5.5). +By default, i is 1 and j is the length of the list, +as defined by the length operator (see §2.5.5). + + -


    _VERSION

    + +

    +


    _VERSION

    A global variable (not a function) that holds a string containing the current interpreter version. -The current contents of this variable is "Lua 5.1". +The current contents of this variable is "Lua 5.1". + + -


    xpcall (f, err)

    -

    This function is similar to pcall, +

    +


    xpcall (f, err)

    + + +

    +This function is similar to pcall, except that you can set a new error handler. -

    xpcall calls function f in protected mode, + +

    +xpcall calls function f in protected mode, using err as the error handler. Any error inside f is not propagated; instead, xpcall catches the error, @@ -4731,46 +5933,77 @@

    In case of any error, xpcall returns false plus the result from err. -

    5.2 - Coroutine Manipulation

    -

    The operations related to coroutines comprise a sub-library of -the basic library and come inside the table coroutine. -See 2.11 for a general description of coroutines. -


    coroutine.create (f)

    -

    Creates a new coroutine, with body f. + + + +

    5.2 - Coroutine Manipulation

    + +

    +The operations related to coroutines comprise a sub-library of +the basic library and come inside the table coroutine. +See §2.11 for a general description of coroutines. + + +

    +


    coroutine.create (f)

    + + +

    +Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". -


    coroutine.resume (co [, val1, ..., valn])

    -

    Starts or continues the execution of coroutine co. + + +

    +


    coroutine.resume (co [, val1, ···])

    + + +

    +Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. -The values val1, ..., valn are passed +The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; -the values val1, ..., valn are passed +the values val1, ··· are passed as the results from the yield. -

    If the coroutine runs without any errors, + +

    +If the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message. -


    coroutine.running ()

    -

    Returns the running coroutine, + + +

    +


    coroutine.running ()

    + + +

    +Returns the running coroutine, or nil when called by the main thread. -


    coroutine.status (co)

    -

    Returns the status of coroutine co, as a string: + + +

    +


    coroutine.status (co)

    + + +

    +Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, @@ -4780,9 +6013,15 @@

    and "dead" if the coroutine has finished its body function, or if it has stopped with an error. -


    coroutine.wrap (f)

    -

    Creates a new coroutine, with body f. + + +

    +


    coroutine.wrap (f)

    + + +

    +Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the @@ -4791,24 +6030,41 @@

    except the first boolean. In case of error, propagates the error. -


    coroutine.yield ([val1, ..., valn])

    -

    Suspends the execution of the calling coroutine. -The coroutine cannot be running a C function, + + +

    +


    coroutine.yield (···)

    + + +

    +Suspends the execution of the calling coroutine. +The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume. -

    5.3 - Modules

    -

    The package library provides basic + + + + + +

    5.3 - Modules

    + +

    +The package library provides basic facilities for loading and building modules in Lua. It exports two of its functions directly in the global environment: require and module. -Everything else is exported in a table package. +Everything else is exported in a table package. -


    module (name [, ...])

    -

    Creates a module. +

    +


    module (name [, ···])

    + + +

    +Creates a module. If there is a table in package.loaded[name], this table is the module. Otherwise, if there is a global table t with the given name, @@ -4824,7 +6080,9 @@

    of the current function and the new value of package.loaded[name], so that require returns t. -

    If name is a compound name + +

    +If name is a compound name (that is, one with components separated by dots), module creates (or reuses, if they already exist) tables for each component. @@ -4832,36 +6090,48 @@

    then module stores the module table in field c of field b of global a. -

    This function may receive optional options after + +

    +This function may receive optional options after the module name, where each option is a function to be applied over the module. -


    require (modname)

    -

    Loads the given module. -The function starts by looking into the table package.loaded + + +

    +


    require (modname)

    + + +

    +Loads the given module. +The function starts by looking into the table package.loaded to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module. -

    To find a loader, + +

    +To find a loader, first require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the -path stored in package.path. -If that also fails, it searches for a C loader using the -path stored in package.cpath. +path stored in package.path. +If that also fails, it searches for a C loader using the +path stored in package.cpath. If that also fails, it tries an all-in-one loader (see below). -

    When loading a C library, + +

    +When loading a C library, require first uses a dynamic link facility to link the application with the library. -Then it tries to find a C function inside this library to +Then it tries to find a C function inside this library to be used as the loader. -The name of this C function is the string "luaopen_" +The name of this C function is the string "luaopen_" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, @@ -4869,21 +6139,25 @@

    For instance, if the module name is a.v1-b.c, the function name will be luaopen_b_c. -

    If require finds neither a Lua library nor a -C library for a module, + +

    +If require finds neither a Lua library nor a +C library for a module, it calls the all-in-one loader. -This loader searches the C path for a library for +This loader searches the C path for a library for the root name of the given module. For instance, when requiring a.b.c, -it will search for a C library for a. +it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. -With this facility, a package can pack several C submodules +With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function. -

    Once a loader is found, + +

    +Once a loader is found, require calls the loader with a single argument, modname. If the loader returns any value, require assigns it to package.loaded[modname]. @@ -4893,210 +6167,312 @@

    In any case, require returns the final value of package.loaded[modname]. -

    If there is any error loading or running the module, + +

    +If there is any error loading or running the module, or if it cannot find any loader for the module, then require signals an error. -


    package.cpath

    -

    The path used by require to search for a C loader. -

    Lua initializes the C path package.cpath in the same way + +

    +


    package.cpath

    + + +

    +The path used by require to search for a C loader. + + +

    +Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, -using the environment variable LUA_CPATH +using the environment variable LUA_CPATH (plus another default path defined in luaconf.h). -


    package.loaded

    -

    A table used by require to control which + + +

    +


    package.loaded

    + + +

    +A table used by require to control which modules are already loaded. When you require a module modname and package.loaded[modname] is not false, require simply returns the value stored there. -


    package.loadlib (libname, funcname)

    -

    Dynamically links the host program with the C library libname. + + +

    +


    package.loadlib (libname, funcname)

    + + +

    +Dynamically links the host program with the C library libname. Inside this library, looks for a function funcname -and returns this function as a C function. +and returns this function as a C function. (So, funcname must follow the protocol (see lua_CFunction)). -

    This is a low-level function. + +

    +This is a low-level function. It completely bypasses the package and module system. Unlike require, it does not perform any path searching and does not automatically adds extensions. -libname must be the complete file name of the C library, +libname must be the complete file name of the C library, including if necessary a path and extension. -funcname must be the exact name exported by the C library -(which may depend on the C compiler and linker used). +funcname must be the exact name exported by the C library +(which may depend on the C compiler and linker used). -

    This function is not supported by ANSI C. + +

    +This function is not supported by ANSI C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard). -


    package.path

    -

    The path used by require to search for a Lua loader. -

    At start-up, Lua initializes this variable with -the value of the environment variable LUA_PATH or + +

    +


    package.path

    + + +

    +The path used by require to search for a Lua loader. + + +

    +At start-up, Lua initializes this variable with +the value of the environment variable LUA_PATH or with a default path defined in luaconf.h, if the environment variable is not defined. -Any ";;" in the value of the environment variable +Any ";;" in the value of the environment variable is replaced by the default path. -

    A path is a sequence of templates separated by semicolons. + +

    +A path is a sequence of templates separated by semicolons. For each template, require will change each interrogation mark in the template by filename, which is modname with each dot replaced by a -"directory separator" (such as "/" in Unix); +"directory separator" (such as "/" in Unix); then it will try to load the resulting file name. So, for instance, if the Lua path is +

    -  "./?.lua;./?.lc;/usr/local/?/init.lua"
    -
    + "./?.lua;./?.lc;/usr/local/?/init.lua" +

    the search for a Lua loader for module foo will try to load the files ./foo.lua, ./foo.lc, and /usr/local/foo/init.lua, in that order. -


    package.preload

    -

    A table to store loaders for specific modules + + +

    +


    package.preload

    + + +

    +A table to store loaders for specific modules (see require). -


    package.seeall (module)

    -

    Sets a metatable for module with + + +

    +


    package.seeall (module)

    + + +

    +Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module. -

    5.4 - String Manipulation

    -

    This library provides generic functions for string manipulation, + + + + + +

    5.4 - String Manipulation

    + +

    +This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching. -When indexing a string in Lua, the first character is at position 1 -(not at 0, as in C). +When indexing a string in Lua, the first character is at position 1 +(not at 0, as in C). Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. -Thus, the last character is at position -1, and so on. +Thus, the last character is at position -1, and so on. + -

    The string library provides all its functions inside the table -string. +

    +The string library provides all its functions inside the table +string. It also sets a metatable for strings -where the __index field points to the metatable itself. +where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s, i) can be written as s:byte(i). -


    string.byte (s [, i [, j]])

    + +

    +


    string.byte (s [, i [, j]])

    Returns the internal numerical codes of the characters s[i], -s[i+1], ..., s[j]. -The default value for i is 1; -the default value for j is i. +s[i+1], ···, s[j]. +The default value for i is 1; +the default value for j is i. + + +

    +Note that numerical codes are not necessarily portable across platforms. + + -

    Note that numerical codes are not necessarily portable across platforms. -


    string.char (i1, i2, ...)

    -Receives 0 or more integers. +

    +


    string.char (···)

    +Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument. -

    Note that numerical codes are not necessarily portable across platforms. -


    string.dump (function)

    +

    +Note that numerical codes are not necessarily portable across platforms. + + + + +

    +


    string.dump (function)

    + -

    Returns a string containing a binary representation of the given function, +

    +Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues. -


    string.find (s, pattern [, init [, plain]])

    + + + +

    +


    string.find (s, pattern [, init [, plain]])

    Looks for the first match of pattern in the string s. -If it finds a match, then find returns the indices of s +If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; -its default value is 1 and may be negative. +its default value is 1 and may be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then init must be given as well. -

    If the pattern has captures, + +

    +If the pattern has captures, then in a successful match the captured values are also returned, after the two indices. -


    string.format (formatstring, e1, e2, ...)

    + + + +

    +


    string.format (formatstring, ···)

    Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of -standard C functions. +standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: -The string is written between double quotes, +the string is written between double quotes, and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly escaped when written. For instance, the call +
    -       string.format('%q', 'a string with "quotes" and \n new line')
    -
    + string.format('%q', 'a string with "quotes" and \n new line') +

    will produce the string: +

    -"a string with \"quotes\" and \
    - new line"
    +     "a string with \"quotes\" and \
    +      new line"
     
    -

    The options c, d, E, e, f, +

    +The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string. -

    This function does not accept string values + +

    +This function does not accept string values containing embedded zeros. -


    string.gmatch (s, pattern)

    + + + +

    +


    string.gmatch (s, pattern)

    Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. -

    If pattern specifies no captures, + +

    +If pattern specifies no captures, then the whole match is produced in each call. -

    As an example, the following loop + +

    +As an example, the following loop +

    -  s = "hello world from Lua"
    -  for w in string.gmatch(s, "%a+") do
    -    print(w)
    -  end
    -
    + s = "hello world from Lua" + for w in string.gmatch(s, "%a+") do + print(w) + end +

    will iterate over all the words from string s, printing one per line. The next example collects all pairs key=value from the given string into a table: +

    -  t = {}
    -  s = "from=world, to=Lua"
    -  for k, v in string.gmatch(s, "(%w+)=(%w+)") do
    -    t[k] = v
    -  end
    +     t = {}
    +     s = "from=world, to=Lua"
    +     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
    +       t[k] = v
    +     end
     
    -


    string.gsub (s, pattern, repl [, n])

    + + +

    +


    string.gsub (s, pattern, repl [, n])

    Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, @@ -5104,74 +6480,98 @@

    gsub also returns, as its second value, the total number of substitutions made. -

    If repl is a string, then its value is used for replacement. -The character % works as an escape character: -Any sequence in repl of the form %n, + +

    +If repl is a string, then its value is used for replacement. +The character % works as an escape character: +any sequence in repl of the form %n, with n between 1 and 9, stands for the value of the n-th captured substring (see below). The sequence %0 stands for the whole match. -The sequence %% stands for a single %. +The sequence %% stands for a single %. -

    If repl is a table, then the table is queried for every match, + +

    +If repl is a table, then the table is queried for every match, using the first capture as the key; if the pattern specifies no captures, then the whole match is used as the key. -

    If repl is a function, then this function is called every time a + +

    +If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order; if the pattern specifies no captures, then the whole match is passed as a sole argument. -

    If the value returned by the table query or by the function call + +

    +If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement (that is, the original match is kept in the string). -

    The optional last parameter n limits + +

    +The optional last parameter n limits the maximum number of substitutions to occur. For instance, when n is 1 only the first occurrence of pattern is replaced. -

    Here are some examples: -

    -   x = string.gsub("hello world", "(%w+)", "%1 %1")
    -   --> x="hello hello world world"
    -
    -   x = string.gsub("hello world", "%w+", "%0 %0", 1)
    -   --> x="hello hello world"
     
    -   x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
    -   --> x="world hello Lua from"
    +

    +Here are some examples: - x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) - --> x="home = /home/roberto, user = roberto" +

    +     x = string.gsub("hello world", "(%w+)", "%1 %1")
    +     --> x="hello hello world world"
    +     
    +     x = string.gsub("hello world", "%w+", "%0 %0", 1)
    +     --> x="hello hello world"
    +     
    +     x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
    +     --> x="world hello Lua from"
    +     
    +     x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
    +     --> x="home = /home/roberto, user = roberto"
    +     
    +     x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
    +           return loadstring(s)()
    +         end)
    +     --> x="4+5 = 9"
    +     
    +     local t = {name="lua", version="5.1"}
    +     x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t)
    +     --> x="lua-5.1.tar.gz"
    +
    - x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) - return loadstring(s)() - end) - --> x="4+5 = 9" - local t = {name="lua", version="5.1"} - x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t) - --> x="lua-5.1.tar.gz" -
    -


    string.len (s)

    +

    +


    string.len (s)

    Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5. -


    string.lower (s)

    + + + +

    +


    string.lower (s)

    Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. -


    string.match (s, pattern [, init])

    + + + +

    +


    string.match (s, pattern [, init])

    Looks for the first match of pattern in the string s. If it finds one, then match returns @@ -5181,20 +6581,32 @@

    then the whole match is returned. A third, optional numerical argument init specifies where to start the search; -its default value is 1 and may be negative. +its default value is 1 and may be negative. -


    string.rep (s, n)

    + + + +

    +


    string.rep (s, n)

    Returns a string that is the concatenation of n copies of the string s. -


    string.reverse (s)

    + + + +

    +


    string.reverse (s)

    Returns a string that is the string s reversed. -


    string.sub (s, i [, j])

    + + + +

    +


    string.sub (s, i [, j])

    Returns the substring of s that starts at i and continues until j; i and j may be negative. -If j is absent, then it is assumed to be equal to -1 +If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s @@ -5202,44 +6614,68 @@

    and string.sub(s, -i) returns a suffix of s with length i. -


    string.upper (s)

    + + + +

    +


    string.upper (s)

    Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. -

    Patterns

    -

    + +

    5.4.1 - Patterns

    + + +

    Character Class:

    A character class is used to represent a set of characters. The following combinations are allowed in describing a character class: +

      -
    • x (where x is not one of the magic characters + +
    • x: +(where x is not one of the magic characters ^$()%.[]*+-?) ---- represents the character x itself. -
    • . --- (a dot) represents all characters. -
    • %a --- represents all letters. -
    • %c --- represents all control characters. -
    • %d --- represents all digits. -
    • %l --- represents all lowercase letters. -
    • %p --- represents all punctuation characters. -
    • %s --- represents all space characters. -
    • %u --- represents all uppercase letters. -
    • %w --- represents all alphanumeric characters. -
    • %x --- represents all hexadecimal digits. -
    • %z --- represents the character with representation 0. -
    • %x (where x is any non-alphanumeric character) --- +represents the character x itself. +
    • + +
    • .: (a dot) represents all characters.
    • + +
    • %a: represents all letters.
    • + +
    • %c: represents all control characters.
    • + +
    • %d: represents all digits.
    • + +
    • %l: represents all lowercase letters.
    • + +
    • %p: represents all punctuation characters.
    • + +
    • %s: represents all space characters.
    • + +
    • %u: represents all uppercase letters.
    • + +
    • %w: represents all alphanumeric characters.
    • + +
    • %x: represents all hexadecimal digits.
    • + +
    • %z: represents the character with representation 0.
    • + +
    • %x: (where x is any non-alphanumeric character) represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic) -can be preceded by a `%´ +can be preceded by a '%' when used to represent itself in a pattern. +
    • -

    • [set] --- +
    • [set]: represents the class which is the union of all characters in set. A range of characters may be specified by -separating the end characters of the range with a `-´. +separating the end characters of the range with a '-'. All classes %x described above may also be used as components in set. All other characters in set represent themselves. @@ -5247,71 +6683,105 @@

      represents all alphanumeric characters plus the underscore, [0-7] represents the octal digits, and [0-7%l%-] represents the octal digits plus -the lowercase letters plus the `-´ character. +the lowercase letters plus the '-' character. + -

      The interaction between ranges and classes is not defined. +

      +The interaction between ranges and classes is not defined. Therefore, patterns like [%a-z] or [a-%%] have no meaning. +

    • -

    • [^set] --- +
    • [^set]: represents the complement of set, where set is interpreted as above. -
    +
  • + +

    For all classes represented by single letters (%a, %c, etc.), the corresponding uppercase letter represents the complement of the class. For instance, %S represents all non-space characters. -

    The definitions of letter, space, and other character groups + +

    +The definitions of letter, space, and other character groups depend on the current locale. In particular, the class [a-z] may not be equivalent to %l. -

    + + + + +

    Pattern Item:

    A pattern item may be +

      -
    • + +
    • a single character class, which matches any single character in the class; -
    • -a single character class followed by `*´, +
    • + +
    • +a single character class followed by '*', which matches 0 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence; -
    • -a single character class followed by `+´, +
    • + +
    • +a single character class followed by '+', which matches 1 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence; -
    • -a single character class followed by `-´, +
    • + +
    • +a single character class followed by '-', which also matches 0 or more repetitions of characters in the class. -Unlike `*´, +Unlike '*', these repetition items will always match the shortest possible sequence; -
    • -a single character class followed by `?´, +
    • + +
    • +a single character class followed by '?', which matches 0 or 1 occurrence of a character in the class; -
    • -%n, for n between 1 and 9; +
    • + +
    • +%n, for n between 1 and 9; such item matches a substring equal to the n-th captured string (see below); -
    • -%bxy, where x and y are two distinct characters; -such item matches strings that start with x, end with y, +
    • + +
    • +%bxy, where x and y are two distinct characters; +such item matches strings that start with x, end with y, and where the x and y are balanced. This means that, if one reads the string from left to right, counting +1 for an x and -1 for a y, the ending y is the first y where the count reaches 0. For instance, the item %b() matches expressions with balanced parentheses. +
    • +
    -

    + + + +

    Pattern:

    A pattern is a sequence of pattern items. -A `^´ at the beginning of a pattern anchors the match at the +A '^' at the beginning of a pattern anchors the match at the beginning of the subject string. -A `$´ at the end of a pattern anchors the match at the +A '$' at the end of a pattern anchors the match at the end of the subject string. At other positions, -`^´ and `$´ have no special meaning and represent themselves. +'^' and '$' have no special meaning and represent themselves. + + -

    + + +

    Captures:

    A pattern may contain sub-patterns enclosed in parentheses; they describe captures. When a match succeeds, the substrings of the subject string @@ -5319,52 +6789,88 @@

    Captures are numbered according to their left parentheses. For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is -stored as the first capture (and therefore has number 1); -the character matching "." is captured with number 2, -and the part matching "%s*" has number 3. +stored as the first capture (and therefore has number 1); +the character matching "." is captured with number 2, +and the part matching "%s*" has number 3. -

    As a special case, the empty capture () captures + +

    +As a special case, the empty capture () captures the current string position (a number). For instance, if we apply the pattern "()aa()" on the -string "flaaap", there will be two captures: 3 and 5. +string "flaaap", there will be two captures: 3 and 5. -

    A pattern cannot contain embedded zeros. Use %z instead. -

    5.5 - Table Manipulation

    +

    +A pattern cannot contain embedded zeros. Use %z instead. + + + + + + + + + + + +

    5.5 - Table Manipulation

    This library provides generic functions for table manipulation. -It provides all its functions inside the table table. +It provides all its functions inside the table table. -

    Most functions in the table library assume that the table + +

    +Most functions in the table library assume that the table represents an array or a list. For these functions, when we talk about the "length" of a table we mean the result of the length operator. -


    table.concat (table [, sep [, i [, j]]])

    -Returns table[i]..sep..table[i+1] ... sep..table[j]. + +

    +


    table.concat (table [, sep [, i [, j]]])

    +Returns table[i]..sep..table[i+1] ··· sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string. -


    table.insert (table, [pos,] value)

    -

    Inserts element value at position pos in table, + + +

    +


    table.insert (table, [pos,] value)

    + + +

    +Inserts element value at position pos in table, shifting up other elements to open space, if necessary. The default value for pos is n+1, -where n is the length of the table (see 2.5.5), +where n is the length of the table (see §2.5.5), so that a call table.insert(t,x) inserts x at the end of table t. -


    table.maxn (table)

    -

    Returns the largest positive numerical index of the given table, + + +

    +


    table.maxn (table)

    + + +

    +Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. (To do its job this function does a linear traversal of the whole table.) -


    table.remove (table [, pos])

    -

    Removes from table the element at position pos, + + +

    +


    table.remove (table [, pos])

    + + +

    +Removes from table the element at position pos, shifting down other elements to close the space, if necessary. Returns the value of the removed element. The default value for pos is n, @@ -5372,7 +6878,11 @@

    so that a call table.remove(t) removes the last element of table t. -


    table.sort (table [, comp])

    + + + +

    +


    table.sort (table [, comp])

    Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. @@ -5382,220 +6892,611 @@

    when the first is less than the second (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given, -then the standard Lua operator < is used instead. +then the standard Lua operator < is used instead. -

    The sort algorithm is not stable; + +

    +The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort. -

    5.6 - Mathematical Functions

    - -

    This library is an interface to the standard C math library. -It provides all its functions inside the table math. -The library provides the following functions: - - - - - - - - -

    -       math.abs     math.acos    math.asin    math.atan    math.atan2
    -       math.ceil    math.cos     math.cosh    math.deg     math.exp
    -       math.floor   math.fmod    math.frexp   math.ldexp   math.log
    -       math.log10   math.max     math.min     math.modf    math.pow
    -       math.rad     math.random  math.randomseed           math.sin
    -       math.sinh    math.sqrt    math.tan     math.tanh
    -
    -plus a variable math.pi and -a variable math.huge, -with the value HUGE_VAL. -Most of these functions -are only interfaces to the corresponding functions in the C library. -All trigonometric functions work in radians. -The functions math.deg and math.rad convert -between radians and degrees. - -

    The function math.max returns the maximum -value of its numeric arguments. -Similarly, math.min computes the minimum. -Both can be used with 1, 2, or more arguments. - -

    The function math.modf corresponds to the modf C function. -It returns two values: -The integral part and the fractional part of its argument. -The function math.frexp also returns 2 values: -The normalized fraction and the exponent of its argument. - -

    The functions math.random and math.randomseed -are interfaces to the simple random generator functions -rand and srand that are provided by ANSI C. -(No guarantees can be given for their statistical properties.) -When called without arguments, -math.random returns a pseudo-random real number -in the range [0,1). -When called with a number n, -math.random returns -a pseudo-random integer in the range [1,n]. -When called with two arguments, -l and u, -math.random returns a pseudo-random -integer in the range [l,u]. -The math.randomseed function sets a "seed" -for the pseudo-random generator: -Equal seeds produce equal sequences of numbers. -

    5.7 - Input and Output Facilities

    -

    The I/O library provides two different styles for file manipulation. -The first one uses implicit file descriptors; + + + + +

    5.6 - Mathematical Functions

    + +

    +This library is an interface to the standard C math library. +It provides all its functions inside the table math. + + +

    +


    math.abs (x)

    + + +

    +Returns the absolute value of x. + + + + +

    +


    math.acos (x)

    + + +

    +Returns the arc cosine of x (in radians). + + + + +

    +


    math.asin (x)

    + + +

    +Returns the arc sine of x (in radians). + + + + +

    +


    math.atan (x)

    + + +

    +Returns the arc tangent of x (in radians). + + + + +

    +


    math.atan2 (x, y)

    + + +

    +Returns the arc tangent of x/y (in radians), +but uses the signs of both parameters to find the +quadrant of the result. +(It also handles correctly the case of y being zero.) + + + + +

    +


    math.ceil (x)

    + + +

    +Returns the smallest integer larger than or equal to x. + + + + +

    +


    math.cos (x)

    + + +

    +Returns the cosine of x (assumed to be in radians). + + + + +

    +


    math.cosh (x)

    + + +

    +Returns the hyperbolic cosine of x. + + + + +

    +


    math.deg (x)

    + + +

    +Returns the angle x (given in radians) in degrees. + + + + +

    +


    math.exp (x)

    + + +

    +Returns the the value ex. + + + + +

    +


    math.floor (x)

    + + +

    +Returns the largest integer smaller than or equal to x. + + + + +

    +


    math.fmod (x, y)

    + + +

    +Returns the remainder of the division of x by y. + + + + +

    +


    math.frexp (x)

    + + +

    +Returns m and e such that x = m2e, +e is an integer and the absolute value of m is +in the range [0.5, 1) +(or zero when x is zero). + + + + +

    +


    math.huge

    + + +

    +The value HUGE_VAL, +a value larger than or equal to any other numerical value. + + + + +

    +


    math.ldexp (m, e)

    + + +

    +Returns m2e (e should be an integer). + + + + +

    +


    math.log (x)

    + + +

    +Returns the natural logarithm of x. + + + + +

    +


    math.log10 (x)

    + + +

    +Returns the base-10 logarithm of x. + + + + +

    +


    math.max (x, ···)

    + + +

    +Returns the maximum value among its arguments. + + + + +

    +


    math.min (x, ···)

    + + +

    +Returns the minimum value among its arguments. + + + + +

    +


    math.modf (x)

    + + +

    +Returns two numbers, +the integral part of x and the fractional part of x. + + + + +

    +


    math.pi

    + + +

    +The value PI. + + + + +

    +


    math.pow (x, y)

    + + +

    +Returns xy. +(You can also use the expression x^y to compute this value.) + + + + +

    +


    math.rad (x)

    + + +

    +Returns the angle x (given in degrees) in radians. + + + + +

    +


    math.random ([m [, n]])

    + + +

    +This function is an interface to the simple +pseudo-random generator function rand provided by ANSI C. +(No guarantees can be given for its statistical properties.) + + +

    +When called without arguments, +returns a pseudo-random real number +in the range [0,1). +When called with a number m, +math.random returns +a pseudo-random integer in the range [1, m]. +When called with two numbers m and n, +math.random returns a pseudo-random +integer in the range [m, n]. + + + + +

    +


    math.randomseed (x)

    + + +

    +Sets x as the "seed" +for the pseudo-random generator: +equal seeds produce equal sequences of numbers. + + + + +

    +


    math.sin (x)

    + + +

    +Returns the sine of x (assumed to be in radians). + + + + +

    +


    math.sinh (x)

    + + +

    +Returns the hyperbolic sine of x. + + + + +

    +


    math.sqrt (x)

    + + +

    +Returns the square root of x. +(You can also use the expression x^0.5 to compute this value.) + + + + +

    +


    math.tan (x)

    + + +

    +Returns the tangent of x (assumed to be in radians). + + + + +

    +


    math.tanh (x)

    + + +

    +Returns the hyperbolic tangent of x. + + + + + + + +

    5.7 - Input and Output Facilities

    + +

    +The I/O library provides two different styles for file manipulation. +The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors. -

    When using implicit file descriptors, -all operations are supplied by table io. + +

    +When using implicit file descriptors, +all operations are supplied by table io. When using explicit file descriptors, the operation io.open returns a file descriptor and then all operations are supplied as methods of the file descriptor. -

    The table io also provides + +

    +The table io also provides three predefined file descriptors with their usual meanings from C: -io.stdin, io.stdout, and io.stderr. +io.stdin, io.stdout, and io.stderr. -

    Unless otherwise stated, + +

    +Unless otherwise stated, all I/O functions return nil on failure (plus an error message as a second result) and some value different from nil on success. -


    io.close ([file])

    -

    Equivalent to file:close(). +

    +


    io.close ([file])

    + + +

    +Equivalent to file:close(). Without a file, closes the default output file. -


    io.flush ()

    -

    Equivalent to file:flush over the default output file. -


    io.input ([file])

    -

    When called with a file name, it opens the named file (in text mode), +

    +


    io.flush ()

    + + +

    +Equivalent to file:flush over the default output file. + + + + +

    +


    io.input ([file])

    + + +

    +When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file. -

    In case of errors this function raises the error, + +

    +In case of errors this function raises the error, instead of returning an error code. -


    io.lines ([filename])

    -

    Opens the given file name in read mode + + +

    +


    io.lines ([filename])

    + + +

    +Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction +

    -       for line in io.lines(filename) do ... end
    -
    + for line in io.lines(filename) do body end +

    will iterate over all lines of the file. When the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file. -

    The call io.lines() (without a file name) is equivalent + +

    +The call io.lines() (without a file name) is equivalent to io.input():lines(); that is, it iterates over the lines of the default input file. In this case it does not close the file when the loop ends. -


    io.open (filename [, mode])

    -

    This function opens a file, + + +

    +


    io.open (filename [, mode])

    + + +

    +This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message. -

    The mode string can be any of the following: + +

    +The mode string can be any of the following: +

      -
    • "r" --- read mode (the default); -
    • "w" --- write mode; -
    • "a" --- append mode; -
    • "r+" --- update mode, all previous data is preserved; -
    • "w+" --- update mode, all previous data is erased; -
    • "a+" --- append update mode, previous data is preserved, - writing is only allowed at the end of file. -
    -The mode string may also have a `b´ at the end, +
  • "r": read mode (the default);
  • +
  • "w": write mode;
  • +
  • "a": append mode;
  • +
  • "r+": update mode, all previous data is preserved;
  • +
  • "w+": update mode, all previous data is erased;
  • +
  • "a+": append update mode, previous data is preserved, + writing is only allowed at the end of file.
  • +

    +The mode string may also have a 'b' at the end, which is needed in some systems to open the file in binary mode. This string is exactly what is used in the -standard C function fopen. +standard C function fopen. + + + + +

    +


    io.output ([file])

    + + +

    +Similar to io.input, but operates over the default output file. -


    io.output ([file])

    -

    Similar to io.input, but operates over the default output file. -


    io.popen ([prog [, mode]])

    -

    Starts program prog in a separated process and returns +

    +


    io.popen ([prog [, mode]])

    + + +

    +Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w"). -

    This function is system dependent and is not available + +

    +This function is system dependent and is not available on all platforms. -


    io.read (format1, ...)

    -

    Equivalent to io.input():read. -


    io.tmpfile ()

    -

    Returns a handle for a temporary file. +

    +


    io.read (···)

    + + +

    +Equivalent to io.input():read. + + + + +

    +


    io.tmpfile ()

    + + +

    +Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. -


    io.type (obj)

    -

    Checks whether obj is a valid file handle. + + +

    +


    io.type (obj)

    + + +

    +Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle. -


    io.write (value1, ...)

    -

    Equivalent to io.output():write. -


    file:close ()

    -

    Closes file. +

    +


    io.write (···)

    + + +

    +Equivalent to io.output():write. + + + + +

    +


    file:close ()

    + + +

    +Closes file. Note that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen. -


    file:flush ()

    -

    Saves any written data to file. -


    file:lines ()

    -

    Returns an iterator function that, +

    +


    file:flush ()

    + + +

    +Saves any written data to file. + + + + +

    +


    file:lines ()

    + + +

    +Returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction +

    -       for line in file:lines() do ... end
    -
    + for line in file:lines() do body end +

    will iterate over all lines of the file. (Unlike io.lines, this function does not close the file when the loop ends.) -


    file:read (format1, ...)

    -

    Reads the file file, + + +

    +


    file:read (···)

    + + +

    +Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, @@ -5604,39 +7505,63 @@

    it uses a default format that reads the entire next line (see below). -

    The available formats are + +

    +The available formats are +

      -
    • "*n" reads a number; + +
    • "*n": +reads a number; this is the only format that returns a number instead of a string. -
    • "*a" reads the whole file, starting at the current position. +
    • + +
    • "*a": +reads the whole file, starting at the current position. On end of file, it returns the empty string. -
    • "*l" reads the next line (skipping the end of line), +
    • + +
    • "*l": +reads the next line (skipping the end of line), returning nil on end of file. This is the default format. -
    • number reads a string with up to this number of characters, +
    • + +
    • number: +reads a string with up to this number of characters, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, or nil on end of file. +
    • +
    -


    file:seek ([whence] [, offset])

    -

    Sets and gets the file position, + +

    +


    file:seek ([whence] [, offset])

    + + +

    +Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows: +

      -
    • "set" --- base is position 0 (beginning of the file); -
    • "cur" --- base is current position; -
    • "end" --- base is end of file; -
    +
  • "set": base is position 0 (beginning of the file);
  • +
  • "cur": base is current position;
  • +
  • "end": base is end of file;
  • +

    In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. If this function fails, it returns nil, plus a string describing the error. -

    The default value for whence is "cur", + +

    +The default value for whence is "cur", and for offset is 0. Therefore, the call file:seek() returns the current file position, without changing it; @@ -5645,114 +7570,202 @@

    and the call file:seek("end") sets the position to the end of the file, and returns its size. -


    file:setvbuf (mode [, size])

    -

    Sets the buffering mode for an output file. + + +

    +


    file:setvbuf (mode [, size])

    + + +

    +Sets the buffering mode for an output file. There are three available modes: +

      -
    • "no" --- + +
    • "no": no buffering; the result of any output operation appears immediately. -
    • "full" --- +
    • + +
    • "full": full buffering; output operation is performed only -when the buffer is full (or when you explicitly flush the file (see 5.7)). -
    • "line" --- +when the buffer is full (or when you explicitly flush the file +(see io.flush)). +
    • + +
    • "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device). -
    + + +

    For the last two cases, sizes specifies the size of the buffer, in bytes. The default is an appropriate size. -


    file:write (value1, ...)

    -

    Writes the value of each of its arguments to + + +

    +


    file:write (···)

    + + +

    +Writes the value of each of its arguments to the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write. -

    5.8 - Operating System Facilities

    -

    This library is implemented through table os. -


    os.clock ()

    -

    Returns an approximation of the amount in seconds of CPU time -used by the program. -


    os.date ([format [, time]])

    -

    Returns a string or a table containing date and time, + +

    5.8 - Operating System Facilities

    + +

    +This library is implemented through table os. + + +

    +


    os.clock ()

    + + +

    +Returns an approximation of the amount in seconds of CPU time +used by the program. + + + + +

    +


    os.date ([format [, time]])

    + + +

    +Returns a string or a table containing date and time, formatted according to the given string format. -

    If the time argument is present, + +

    +If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time. -

    If format starts with `!´, + +

    +If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is *t, then date returns a table with the following fields: year (four digits), month (1--12), day (1--31), hour (0--23), min (0--59), sec (0--61), -wday (weekday, Sunday is 1), +wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean). -

    If format is not *t, + +

    +If format is not *t, then date returns the date as a string, -formatted according to the same rules as the C function strftime. +formatted according to the same rules as the C function strftime. + -

    When called without arguments, +

    +When called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")). -


    os.difftime (t2, t1)

    -

    Returns the number of seconds from time t1 to time t2. + + +

    +


    os.difftime (t2, t1)

    + + +

    +Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1. -


    os.execute ([command])

    -

    This function is equivalent to the C function system. + + +

    +


    os.execute ([command])

    + + +

    +This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise. -


    os.exit ([code])

    -

    Calls the C function exit, + + +

    +


    os.exit ([code])

    + + +

    +Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. -


    os.getenv (varname)

    -

    Returns the value of the process environment variable varname, + + +

    +


    os.getenv (varname)

    + + +

    +Returns the value of the process environment variable varname, or nil if the variable is not defined. -


    os.remove (filename)

    -

    Deletes the file or directory with the given name. + + +

    +


    os.remove (filename)

    + + +

    +Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error. -


    os.rename (oldname, newname)

    -

    Renames file or directory named oldname to newname. + + +

    +


    os.rename (oldname, newname)

    + + +

    +Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error. -


    os.setlocale (locale [, category])

    -

    Sets the current locale of the program. + + +

    +


    os.setlocale (locale [, category])

    + + +

    +Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", @@ -5761,38 +7774,65 @@

    The function returns the name of the new locale, or nil if the request cannot be honored. -


    os.time ([table])

    -

    Returns the current time when called without arguments, +

    +When called with nil as the first argument, +this function only returns the name of the current locale +for the given category. + + + + +

    +


    os.time ([table])

    + + +

    +Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function). -

    The returned value is a number, whose meaning depends on your system. + +

    +The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to date and difftime. -


    os.tmpname ()

    -

    Returns a string with a file name that can + + +

    +


    os.tmpname ()

    + + +

    +Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed. -

    5.9 - The Debug Library

    -

    This library provides + + + + + +

    5.9 - The Debug Library

    + +

    +This library provides the functionality of the debug interface to Lua programs. You should exert care when using this library. The functions provided here should be used exclusively for debugging and similar tasks, such as profiling. Please resist the temptation to use them as a usual programming tool: -They can be very slow. +they can be very slow. Moreover, several of its functions violate some assumptions about Lua code (e.g., that variables local to a function @@ -5800,12 +7840,22 @@

    that userdata metatables cannot be changed by Lua code) and therefore can compromise otherwise secure code. -

    All functions in this library are provided -inside the debug table. -


    debug.debug ()

    +

    +All functions in this library are provided +inside the debug table. +All functions that operate over a thread +have an optional first argument which is the +thread to operate over. +The default is always the current thread. + + +

    +


    debug.debug ()

    + -

    Enters an interactive mode with the user, +

    +Enters an interactive mode with the user, running each string that the user enters. Using simple commands and other debug facilities, the user can inspect global and local variables, @@ -5813,113 +7863,185 @@

    A line containing only the word cont finishes this function, so that the caller continues its execution. -

    Note that commands for debug.debug are not lexically nested + +

    +Note that commands for debug.debug are not lexically nested within any function, and so have no direct access to local variables. -


    debug.getfenv (o)

    + + + +

    +


    debug.getfenv (o)

    Returns the environment of object o. -


    debug.gethook ()

    -

    Returns the current hook settings, as three values: + + +

    +


    debug.gethook ([thread])

    + + +

    +Returns the current hook settings of the thread, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function). -


    debug.getinfo (function [, what])

    -

    Returns a table with information about a function. + + +

    +


    debug.getinfo ([thread,] function [, what])

    + + +

    +Returns a table with information about a function. You can give the function directly, or you can give a number as the value of function, -which means the function running at level function of the call stack: -Level 0 is the current function (getinfo itself); -level 1 is the function that called getinfo; +which means the function running at level function of the call stack +of the given thread: +level 0 is the current function (getinfo itself); +level 1 is the function that called getinfo; and so on. If function is a number larger than the number of active functions, then getinfo returns nil. -

    The returned table contains all the fields returned by lua_getinfo, + +

    +The returned table contains all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available. If present, -the option `f´ +the option 'f' adds a field named func with the function itself. -

    For instance, the expression debug.getinfo(1,"n").name returns + +

    +For instance, the expression debug.getinfo(1,"n").name returns a name of the current function, if a reasonable name can be found, and debug.getinfo(print) returns a table with all available information about the print function. -


    debug.getlocal (level, local)

    -

    This function returns the name and the value of the local variable + + +

    +


    debug.getlocal ([thread,] level, local)

    + + +

    +This function returns the name and the value of the local variable with index local of the function at level level of the stack. -(The first parameter or local variable has index 1, and so on, +(The first parameter or local variable has index 1, and so on, until the last active local variable.) The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.) -

    Variable names starting with `(´ (open parentheses) + +

    +Variable names starting with '(' (open parentheses) represent internal variables -(loop control variables, temporaries, and C function locals). +(loop control variables, temporaries, and C function locals). + + -


    debug.getmetatable (object)

    -

    Returns the metatable of the given object +

    +


    debug.getmetatable (object)

    + + +

    +Returns the metatable of the given object or nil if it does not have a metatable. -


    debug.getregistry ()

    -

    Returns the registry table (see 3.5). -


    debug.getupvalue (func, up)

    -

    This function returns the name and the value of the upvalue +

    +


    debug.getregistry ()

    + + +

    +Returns the registry table (see §3.5). + + + + +

    +


    debug.getupvalue (func, up)

    + + +

    +This function returns the name and the value of the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index. -


    debug.setfenv (object, table)

    -

    Sets the environment of the given object to the given table. -


    debug.sethook (hook, mask [, count])

    -

    Sets the given function as a hook. +

    +


    debug.setfenv (object, table)

    + + +

    +Sets the environment of the given object to the given table. + + + + +

    +


    debug.sethook ([thread,] hook, mask [, count])

    + + +

    +Sets the given function as a hook. The string mask and the number count describe when the hook will be called. The string mask may have the following characters, with the given meaning: +

      -
    • "c" --- The hook is called every time Lua calls a function; -
    • "r" --- The hook is called every time Lua returns from a function; -
    • "l" --- The hook is called every time Lua enters a new line of code. -
    +
  • "c": The hook is called every time Lua calls a function;
  • +
  • "r": The hook is called every time Lua returns from a function;
  • +
  • "l": The hook is called every time Lua enters a new line of code.
  • +

    With a count different from zero, the hook is called after every count instructions. -

    When called without arguments, + +

    +When called without arguments, debug.sethook turns off the hook. -

    When the hook is called, its first parameter is a string + +

    +When the hook is called, its first parameter is a string describing the event that has triggered its call: "call", "return" (or "tail return"), "line", and "count". For line events, the hook also gets the new line number as its second parameter. Inside a hook, -you can call getinfo with level 2 to get more information about +you can call getinfo with level 2 to get more information about the running function -(level 0 is the getinfo function, -and level 1 is the hook function), +(level 0 is the getinfo function, +and level 1 is the hook function), unless the event is "tail return". In this case, Lua is only simulating the return, and a call to getinfo will return invalid data. -


    debug.setlocal (level, local, value)

    -

    This function assigns the value value to the local variable + + +

    +


    debug.setlocal ([thread,] level, local, value)

    + + +

    +This function assigns the value value to the local variable with index local of the function at level level of the stack. The function returns nil if there is no local variable with the given index, @@ -5927,32 +8049,56 @@

    (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable. -


    debug.setmetatable (object, table)

    -

    Sets the metatable for the given object to the given table + + +

    +


    debug.setmetatable (object, table)

    + + +

    +Sets the metatable for the given object to the given table (which can be nil). -


    debug.setupvalue (func, up, value)

    -

    This function assigns the value value to the upvalue + + +

    +


    debug.setupvalue (func, up, value)

    + + +

    +This function assigns the value value to the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue. -


    debug.traceback ([message])

    -

    Returns a string with a traceback of the call stack. + + +

    +


    debug.traceback ([thread,] [message])

    + + +

    +Returns a string with a traceback of the call stack. An optional message string is appended at the beginning of the traceback. This function is typically used with xpcall to produce better error messages. -

    -

    6 - Lua Stand-alone

    -

    Although Lua has been designed as an extension language, -to be embedded in a host C program, + + + + + +

    6 - Lua Stand-alone

    + +

    +Although Lua has been designed as an extension language, +to be embedded in a host C program, it is also frequently used as a stand-alone language. An interpreter for Lua as a stand-alone language, called simply lua, @@ -5960,18 +8106,20 @@

    The stand-alone interpreter includes all standard libraries, including the debug library. Its usage is: +
    -      lua [options] [script [args]]
    -
    + lua [options] [script [args]] +

    The options are: +

      -
    • -e stat executes string stat; -
    • -l mod "requires" mod; -
    • -i enters interactive mode after running script; -
    • -v prints version information; -
    • -- stops handling options; -
    • - executes stdin as a file and stops handling options. -
    +
  • -e stat: executes string stat;
  • +
  • -l mod: "requires" mod;
  • +
  • -i: enters interactive mode after running script;
  • +
  • -v: prints version information;
  • +
  • --: stops handling options;
  • +
  • -: executes stdin as a file and stops handling options.
  • +

    After handling its options, lua runs the given script, passing to it the given args as string arguments. When called without arguments, @@ -5979,22 +8127,29 @@

    when the standard input (stdin) is a terminal, and as lua - otherwise. -

    Before running any argument, -the interpreter checks for an environment variable LUA_INIT. -If its format is @filename, + +

    +Before running any argument, +the interpreter checks for an environment variable LUA_INIT. +If its format is @filename, then lua executes the file. Otherwise, lua executes the string itself. -

    All options are handled in order, except -i. + +

    +All options are handled in order, except -i. For instance, an invocation like +

    -       $ lua -e'a=1' -e 'print(a)' script.lua
    -
    -will first set a to 1, then print the value of a (which is `1´), + $ lua -e'a=1' -e 'print(a)' script.lua +

    +will first set a to 1, then print the value of a (which is '1'), and finally run the file script.lua with no arguments. (Here $ is the shell prompt. Your prompt may be different.) -

    Before starting to run the script, + +

    +Before starting to run the script, lua collects all arguments in the command line in a global table called arg. The script name is stored at index 0, @@ -6004,244 +8159,295 @@

    (that is, the interpreter name plus the options) go to negative indices. For instance, in the call +
    -       $ lua -la b.lua t1 t2
    -
    + $ lua -la b.lua t1 t2 +

    the interpreter first runs the file a.lua, then creates a table +

    -       arg = { [-2] = "lua", [-1] = "-la",
    -               [0] = "b.lua",
    -               [1] = "t1", [2] = "t2" }
    -
    + arg = { [-2] = "lua", [-1] = "-la", + [0] = "b.lua", + [1] = "t1", [2] = "t2" } +

    and finally runs the file b.lua. -The script is called with arg[1], arg[2], ... +The script is called with arg[1], arg[2], ··· as arguments; -it can also access these arguments with the vararg expression `...´. +it can also access these arguments with the vararg expression '...'. + -

    In interactive mode, +

    +In interactive mode, if you write an incomplete statement, the interpreter waits for its completion by issuing a different prompt. -

    If the global variable _PROMPT contains a string, + +

    +If the global variable _PROMPT contains a string, then its value is used as the prompt. -Similarly, if the global variable _PROMPT2 contains a string, +Similarly, if the global variable _PROMPT2 contains a string, its value is used as the secondary prompt (issued during incomplete statements). Therefore, both prompts can be changed directly on the command line. For instance, +

    -       $ lua -e"_PROMPT='myprompt> '" -i
    -
    + $ lua -e"_PROMPT='myprompt> '" -i +

    (the outer pair of quotes is for the shell, the inner pair is for Lua), or in any Lua programs by assigning to _PROMPT. Note the use of -i to enter interactive mode; otherwise, the program would just end silently right after the assignment to _PROMPT. -

    To allow the use of Lua as a + +

    +To allow the use of Lua as a script interpreter in Unix systems, the stand-alone interpreter skips the first line of a chunk if it starts with #. Therefore, Lua scripts can be made into executable programs -by using chmod +x and the #! form, +by using chmod +x and the #! form, as in +

    -#!/usr/local/bin/lua
    -
    + #!/usr/local/bin/lua +

    (Of course, the location of the Lua interpreter may be different in your machine. If lua is in your PATH, then +

    -#!/usr/bin/env lua
    -
    + #!/usr/bin/env lua +

    is a more portable solution.) -


    -

    Incompatibilities with the Previous Version

    +

    7 - Incompatibilities with the Previous Version

    -

    Here we list the incompatibilities that may be found when moving a program -from Lua 5.0 to Lua 5.1. +

    +Here we list the incompatibilities that may be found when moving a program +from Lua 5.0 to Lua 5.1. You can avoid most of the incompatibilities compiling Lua with appropriate options (see file luaconf.h). However, all these compatibility options will be removed in the next version of Lua. -

    Incompatibilities with version 5.0

    -

    Changes in the Language

    + +

    7.1 - Changes in the Language

      +
    • The vararg system changed from the pseudo-argument arg with a table with the extra arguments to the vararg expression. (Option LUA_COMPAT_VARARG in luaconf.h.) +
    • -

    • +
    • There was a subtle change in the scope of the implicit variables of the for statement and for the repeat statement. +
    • -

    • -The long string/long comment syntax ([[...]]) does not allow nesting. -You can use the new syntax ([=[...]=]) in these cases. +
    • +The long string/long comment syntax ([[string]]) +does not allow nesting. +You can use the new syntax ([=[string]=]) in these cases. (Option LUA_COMPAT_LSTR in luaconf.h.) +
    • + +
    + + -

    -

    Changes in the Libraries

    +

    7.2 - Changes in the Libraries

      -

    • +
    • Function string.gfind was renamed string.gmatch. (Option LUA_COMPAT_GFIND) +
    • -

    • +
    • When string.gsub is called with a function as its third argument, whenever this function returns nil or false the replacement string is the whole match, instead of the empty string. +
    • -

    • +
    • Function table.setn was deprecated. Function table.getn corresponds to the new length operator (#); use the operator instead of the function. (Option LUA_COMPAT_GETN) +
    • -

    • +
    • Function loadlib was renamed package.loadlib. (Option LUA_COMPAT_LOADLIB) +
    • -

    • +
    • Function math.mod was renamed math.fmod. (Option LUA_COMPAT_MOD) +
    • -

    • +
    • Functions table.foreach and table.foreachi are deprecated. You can use a for loop with pairs or ipairs instead. +
    • -

    • +
    • There were substantial changes in function require due to the new module system. However, the new behavior is mostly compatible with the old, but require gets the path from package.path instead of from LUA_PATH. +
    • -

    • +
    • Function collectgarbage has different arguments. Function gcinfo is deprecated; use collectgarbage("count") instead. +
    • + +
    + + -

    -

    Changes in the API

    +

    7.3 - Changes in the API

      -

    • +
    • The luaopen_* functions (to open libraries) cannot be called directly, like a regular C function. They must be called through Lua, like a Lua function. +
    • -

    • +
    • Function lua_open was replaced by lua_newstate to -allow the user to set a memory allocation function. +allow the user to set a memory-allocation function. You can use luaL_newstate from the standard library to create a state with a standard allocation function (based on realloc). +
    • -

    • +
    • Functions luaL_getn and luaL_setn (from the auxiliary library) are deprecated. Use lua_objlen instead of luaL_getn and nothing instead of luaL_setn. +
    • -

    • +
    • Function luaL_openlib was replaced by luaL_register. +
    • -

    +
  • +Function luaL_checkudata now throws an error when the given value +is not a userdata of the expected type. +(In Lua 5.0 it returned NULL.) +
  • + + -

    -

    The Complete Syntax of Lua

    -

    Here is the complete syntax of Lua in extended BNF. +

    8 - The Complete Syntax of Lua

    + +

    +Here is the complete syntax of Lua in extended BNF. It does not describe operator priorities or some syntactical restrictions, such as return and break statements can only appear as the last statement of a block. -

    -

     
    -	chunk ::= {stat [`;´]} [laststat[`;´]]
    +
    +
    +
    +	chunk ::= {stat [`;´]} [laststat [`;´]]
     
     	block ::= chunk
     
    -	stat ::=  varlist1 `=´ explist1  | 
    -		 functioncall  | 
    -		 do block end  | 
    -		 while exp do block end  | 
    -		 repeat block until exp  | 
    -		 if exp then block {elseif exp then block} [else block] end  | 
    -		 for Name `=´ exp `,´ exp [`,´ exp] do block end  | 
    -		 for namelist in explist1 do block end  | 
    -		 function funcname funcbody  | 
    -		 local function Name funcbody  | 
    +	stat ::=  varlist1 `=´ explist1 | 
    +		 functioncall | 
    +		 do block end | 
    +		 while exp do block end | 
    +		 repeat block until exp | 
    +		 if exp then block {elseif exp then block} [else block] end | 
    +		 for Name `=´ exp `,´ exp [`,´ exp] do block end | 
    +		 for namelist in explist1 do block end | 
    +		 function funcname funcbody | 
    +		 local function Name funcbody | 
     		 local namelist [`=´ explist1] 
     
    -	laststat ::= return [explist1]  |  break
    +	laststat ::= return [explist1] | break
     
     	funcname ::= Name {`.´ Name} [`:´ Name]
     
     	varlist1 ::= var {`,´ var}
     
    -	var ::=  Name  |  prefixexp `[´ exp `]´  |  prefixexp `.´ Name 
    +	var ::=  Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name 
     
     	namelist ::= Name {`,´ Name}
     
     	explist1 ::= {exp `,´} exp
     
    -	exp ::=  nil  |  false  |  true  |  Number  |  String  |  `...´  | 
    -		 function  |  prefixexp  |  tableconstructor  |  exp binop exp  |  unop exp 
    +	exp ::=  nil | false | true | Number | String | `...´ | function | 
    +		 prefixexp | tableconstructor | exp binop exp | unop exp 
     
    -	prefixexp ::= var  |  functioncall  |  `(´ exp `)´
    +	prefixexp ::= var | functioncall | `(´ exp `)´
     
    -	functioncall ::=  prefixexp args  |  prefixexp `:´ Name args 
    +	functioncall ::=  prefixexp args | prefixexp `:´ Name args 
     
    -	args ::=  `(´ [explist1] `)´  |  tableconstructor  |  String 
    +	args ::=  `(´ [explist1] `)´ | tableconstructor | String 
     
     	function ::= function funcbody
     
     	funcbody ::= `(´ [parlist1] `)´ block end
     
    -	parlist1 ::= namelist [`,´ `...´]  |  `...´
    +	parlist1 ::= namelist [`,´ `...´] | `...´
     
     	tableconstructor ::= `{´ [fieldlist] `}´
     
     	fieldlist ::= field {fieldsep field} [fieldsep]
     
    -	field ::= `[´ exp `]´ `=´ exp  |  Name `=´ exp  |  exp
    +	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
     
    -	fieldsep ::= `,´  |  `;´
    +	fieldsep ::= `,´ | `;´
     
    -	binop ::= `+´  |  `-´  |  `*´  |  `/´  |  `^´  |  `%´  |  `..´  | 
    -		 `<´  |  `<=´  |  `>´  |  `>=´  |  `==´  |  `~=´  | 
    -		 and  |  or
    +	binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | 
    +		 `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | 
    +		 and | or
     
    -	unop ::= `-´  |  not  |  `#´
    +	unop ::= `-´ | not | `#´
     
     

    -

    + + + + + +


    + +Last update: +Wed May 31 21:31:40 BRT 2006 + diff --git a/src/Makefile b/src/Makefile index 1d46d3423a..0708ac479f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -80,7 +80,7 @@ none: @echo "Please choose a platform: $(PLATS)" aix: - $(MAKE) all CC="xlc" CFLAGS="-O2" MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" ansi: $(MAKE) all MYCFLAGS=-DLUA_ANSI @@ -121,15 +121,15 @@ lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ - lzio.h lmem.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h \ - ldo.h lgc.h + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ + ltable.h ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ - llex.h lzio.h lmem.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h \ - ltm.h ldo.h lfunc.h lstring.h lgc.h lvm.h + llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ + lfunc.h lstring.h lgc.h ltable.h lvm.h ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ - lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h ltable.h \ - lstring.h lundump.h lvm.h + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ + ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h lundump.h lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ @@ -139,7 +139,7 @@ lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ - lzio.h lmem.h llex.h lparser.h ltable.h lstring.h lgc.h + lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h @@ -150,8 +150,8 @@ lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ - lzio.h lmem.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h \ - ldo.h lfunc.h lstring.h lgc.h + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ + lfunc.h lstring.h lgc.h ltable.h lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ diff --git a/src/lauxlib.c b/src/lauxlib.c index 317a48d108..96a6b85237 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.158 2006/01/16 12:42:21 roberto Exp $ +** $Id: lauxlib.c,v 1.159 2006/03/21 19:31:09 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -123,11 +123,17 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); - lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ - if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2)) - luaL_typerror(L, ud, tname); - lua_pop(L, 2); /* remove both metatables */ - return p; + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + } + luaL_typerror(L, ud, tname); /* else error */ + return NULL; /* to avoid warnings */ } diff --git a/src/lauxlib.h b/src/lauxlib.h index 1bba1c04f8..1f3430863e 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.87 2005/12/29 15:32:11 roberto Exp $ +** $Id: lauxlib.h,v 1.88 2006/04/12 20:31:15 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -108,9 +108,11 @@ LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) -#define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0)) +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) -#define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, 0, 0)) +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) diff --git a/src/lbaselib.c b/src/lbaselib.c index 1d922a8105..778e393a9d 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.189 2006/01/18 11:49:12 roberto Exp $ +** $Id: lbaselib.c,v 1.190 2006/05/31 16:50:40 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -619,7 +619,7 @@ static void base_open (lua_State *L) { lua_setglobal(L, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); - lua_pushliteral(L, LUA_VERSION); + lua_pushlstring(L, LUA_VERSION, 7); lua_setglobal(L, "_VERSION"); /* set global _VERSION */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */ auxopen(L, "ipairs", luaB_ipairs, ipairsaux); diff --git a/src/lcode.c b/src/lcode.c index dd3e37e78c..b71acd8429 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.24 2005/12/22 16:19:56 roberto Exp $ +** $Id: lcode.c,v 2.25 2006/03/21 19:28:49 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -731,17 +731,15 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); - luaK_concat(fs, &e1->f, e2->f); - e1->k = e2->k; e1->u.s.info = e2->u.s.info; - e1->u.s.aux = e2->u.s.aux; e1->t = e2->t; + luaK_concat(fs, &e2->f, e1->f); + *e1 = *e2; break; } case OPR_OR: { lua_assert(e1->f == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); - luaK_concat(fs, &e1->t, e2->t); - e1->k = e2->k; e1->u.s.info = e2->u.s.info; - e1->u.s.aux = e2->u.s.aux; e1->f = e2->f; + luaK_concat(fs, &e2->t, e1->t); + *e1 = *e2; break; } case OPR_CONCAT: { @@ -750,7 +748,7 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); SETARG_B(getcode(fs, e2), e1->u.s.info); - e1->k = e2->k; e1->u.s.info = e2->u.s.info; + e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ diff --git a/src/lcode.h b/src/lcode.h index b5668f22a6..c02cb2b726 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.47 2005/11/08 19:44:31 roberto Exp $ +** $Id: lcode.h,v 1.48 2006/03/21 19:28:03 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -32,7 +32,6 @@ typedef enum BinOpr { OPR_NOBINOPR } BinOpr; -#define binopistest(op) ((op) >= OPR_NE) typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; diff --git a/src/lgc.c b/src/lgc.c index 691565db49..2d24a127ac 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.37 2005/12/22 16:19:56 roberto Exp $ +** $Id: lgc.c,v 2.38 2006/05/24 14:34:06 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -320,8 +320,10 @@ static l_mem propagatemark (global_State *g) { } -static void propagateall (global_State *g) { - while (g->gray) propagatemark(g); +static size_t propagateall (global_State *g) { + size_t m = 0; + while (g->gray) m += propagatemark(g); + return m; } @@ -540,7 +542,7 @@ static void atomic (lua_State *L) { propagateall(g); udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ marktmu(g); /* mark `preserved' userdata */ - propagateall(g); /* remark, to propagate `preserveness' */ + udsize += propagateall(g); /* remark, to propagate `preserveness' */ cleartable(g->weak); /* remove collected objects from weak tables */ /* flip current white */ g->currentwhite = cast_byte(otherwhite(g)); @@ -590,6 +592,8 @@ static l_mem singlestep (lua_State *L) { case GCSfinalize: { if (g->tmudata) { GCTM(L); + if (g->estimate > GCFINALIZECOST) + g->estimate -= GCFINALIZECOST; return GCFINALIZECOST; } else { diff --git a/src/liolib.c b/src/liolib.c index bb3b5194d9..be60972ca8 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.72 2006/01/28 12:59:13 roberto Exp $ +** $Id: liolib.c,v 2.73 2006/05/08 20:14:16 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -99,7 +99,7 @@ static FILE **newfile (lua_State *L) { static int io_pclose (lua_State *L) { FILE **p = topfile(L); int ok = lua_pclose(L, *p); - if (ok) *p = NULL; + *p = NULL; return pushresult(L, ok, NULL); } @@ -107,7 +107,7 @@ static int io_pclose (lua_State *L) { static int io_fclose (lua_State *L) { FILE **p = topfile(L); int ok = (fclose(*p) == 0); - if (ok) *p = NULL; + *p = NULL; return pushresult(L, ok, NULL); } diff --git a/src/llex.c b/src/llex.c index f3022df596..1c07cad9bb 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.19 2006/02/06 18:28:16 roberto Exp $ +** $Id: llex.c,v 2.20 2006/03/09 18:14:31 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -20,6 +20,7 @@ #include "lparser.h" #include "lstate.h" #include "lstring.h" +#include "ltable.h" #include "lzio.h" diff --git a/src/llex.h b/src/llex.h index d4ca7f20e1..ff07e83d31 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.57 2005/12/07 15:43:05 roberto Exp $ +** $Id: llex.h,v 1.58 2006/03/23 18:23:32 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -68,9 +68,9 @@ typedef struct LexState { LUAI_FUNC void luaX_init (lua_State *L); -LUAI_FUNC void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, +LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source); -LUAI_FUNC TString *luaX_newstring (LexState *LS, const char *str, size_t l); +LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); LUAI_FUNC void luaX_lookahead (LexState *ls); LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); diff --git a/src/loadlib.c b/src/loadlib.c index 19edaca0fd..08722e1855 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.51 2005/12/29 15:32:11 roberto Exp $ +** $Id: loadlib.c,v 1.52 2006/04/10 18:27:23 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -22,10 +22,6 @@ #include "lualib.h" -/* environment variables that hold the search path for packages */ -#define LUA_PATH "LUA_PATH" -#define LUA_CPATH "LUA_CPATH" - /* prefix for open functions in C libraries */ #define LUA_POF "luaopen_" diff --git a/src/lopcodes.h b/src/lopcodes.h index 2834b1d74d..48105f1e72 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.124 2005/12/02 18:42:08 roberto Exp $ +** $Id: lopcodes.h,v 1.125 2006/03/14 19:04:44 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -197,8 +197,8 @@ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) =) R(A)*/ diff --git a/src/loslib.c b/src/loslib.c index 509d7b72e4..7c6c5d6168 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.17 2006/01/27 13:54:31 roberto Exp $ +** $Id: loslib.c,v 1.19 2006/04/26 18:19:49 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -28,10 +28,7 @@ static int os_pushresult (lua_State *L, int i, const char *filename) { } else { lua_pushnil(L); - if (filename) - lua_pushfstring(L, "%s: %s", filename, strerror(en)); - else - lua_pushfstring(L, "%s", strerror(en)); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); lua_pushinteger(L, en); return 3; } @@ -126,8 +123,7 @@ static int getfield (lua_State *L, const char *key, int d) { static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - time_t t = lua_isnoneornil(L, 2) ? time(NULL) : - (time_t)luaL_checknumber(L, 2); + time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); struct tm *stm; if (*s == '!') { /* UTC? */ stm = gmtime(&t); @@ -199,9 +195,8 @@ static int os_setlocale (lua_State *L) { LC_NUMERIC, LC_TIME}; static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; - const char *l = lua_tostring(L, 1); + const char *l = luaL_optstring(L, 1, NULL); int op = luaL_checkoption(L, 2, "all", catnames); - luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); lua_pushstring(L, setlocale(cat[op], l)); return 1; } diff --git a/src/lparser.c b/src/lparser.c index b40ee794fe..6d30ebad6d 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.40 2005/12/22 16:19:56 roberto Exp $ +** $Id: lparser.c,v 2.41 2006/03/09 18:15:48 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,7 +23,7 @@ #include "lparser.h" #include "lstate.h" #include "lstring.h" - +#include "ltable.h" diff --git a/src/lparser.h b/src/lparser.h index d5e6e81d0d..e5b5b57e85 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.56 2005/10/03 14:02:40 roberto Exp $ +** $Id: lparser.h,v 1.57 2006/03/09 18:14:31 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -9,7 +9,6 @@ #include "llimits.h" #include "lobject.h" -#include "ltable.h" #include "lzio.h" diff --git a/src/lstate.c b/src/lstate.c index 77e93fbdfa..4bcb7594ce 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.35 2005/10/06 20:46:25 roberto Exp $ +** $Id: lstate.c,v 2.36 2006/05/24 14:15:50 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -198,7 +198,6 @@ static void callallgcTM (lua_State *L, void *ud) { LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ - luai_userstateclose(L); lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ @@ -209,6 +208,7 @@ LUA_API void lua_close (lua_State *L) { L->nCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); + luai_userstateclose(L); close_state(L); } diff --git a/src/lstrlib.c b/src/lstrlib.c index 84478fd106..f93a8af09c 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.130 2005/12/29 15:32:11 roberto Exp $ +** $Id: lstrlib.c,v 1.132 2006/04/26 20:41:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -703,6 +703,10 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { luaL_addchar(b, *s); break; } + case '\r': { + luaL_addlstring(b, "\\r", 2); + break; + } case '\0': { luaL_addlstring(b, "\\000", 4); break; @@ -805,7 +809,8 @@ static int str_format (lua_State *L) { } } default: { /* also treat cases `pnLlh' */ - return luaL_error(L, "invalid option to " LUA_QL("format")); + return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " + LUA_QL("format"), *(strfrmt - 1)); } } luaL_addlstring(&b, buff, strlen(buff)); diff --git a/src/lua.c b/src/lua.c index 6df527db30..991a74b8aa 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.157 2005/12/29 16:23:32 roberto Exp $ +** $Id: lua.c,v 1.159 2006/05/24 14:16:39 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -252,17 +252,30 @@ static int handle_script (lua_State *L, char **argv, int n) { } +/* check that argument has no extra characters at the end */ +#define notail(x) {if ((x)[2] != '\0') return -1;} + + static int collectargs (char **argv, int *pi, int *pv, int *pe) { int i; for (i = 1; argv[i] != NULL; i++) { if (argv[i][0] != '-') /* not an option? */ return i; switch (argv[i][1]) { /* option */ - case '-': return (argv[i+1] != NULL ? i+1 : 0); - case '\0': return i; - case 'i': *pi = 1; /* go through */ - case 'v': *pv = 1; break; - case 'e': *pe = 1; /* go through */ + case '-': + notail(argv[i]); + return (argv[i+1] != NULL ? i+1 : 0); + case '\0': + return i; + case 'i': + notail(argv[i]); + *pi = 1; /* go through */ + case 'v': + notail(argv[i]); + *pv = 1; + break; + case 'e': + *pe = 1; /* go through */ case 'l': if (argv[i][2] == '\0') { i++; @@ -306,12 +319,12 @@ static int runargs (lua_State *L, char **argv, int n) { static int handle_luainit (lua_State *L) { - const char *init = getenv("LUA_INIT"); + const char *init = getenv(LUA_INIT); if (init == NULL) return 0; /* status OK */ else if (init[0] == '@') return dofile(L, init+1); else - return dostring(L, init, "=LUA_INIT"); + return dostring(L, init, "=" LUA_INIT); } diff --git a/src/lua.h b/src/lua.h index 881f834555..b2162d5eb2 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.216 2006/01/10 12:50:13 roberto Exp $ +** $Id: lua.h,v 1.217 2006/05/31 16:50:40 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -16,7 +16,7 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1" +#define LUA_VERSION "Lua 5.1.1" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2006 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" diff --git a/src/luac.c b/src/luac.c index 2dd76b7653..03f3bc7508 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.52 2005/11/11 14:03:13 lhf Exp $ +** $Id: luac.c,v 1.53 2006/05/31 13:30:05 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -70,6 +70,7 @@ static void usage(const char* message) static int doargs(int argc, char* argv[]) { int i; + int version=0; if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; for (i=1; itop+(i))->l.p) -static Proto* combine(lua_State* L, int n) +static const Proto* combine(lua_State* L, int n) { if (n==1) return toproto(L,-1); @@ -156,7 +160,7 @@ static int pmain(lua_State* L) struct Smain* s = (struct Smain*)lua_touserdata(L, 1); int argc=s->argc; char** argv=s->argv; - Proto* f; + const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; ik[n]); + const char* s=getstr(ts); + int n=ts->tsv.len; + int i; putchar('"'); - for (; *s; s++) + for (i=0; i Date: Fri, 2 Jun 2006 12:00:00 +0000 Subject: [PATCH 32/97] Lua 5.1.1-rc2 --- Makefile | 11 +++++++---- doc/manual.html | 46 ++++++++++++++++++++++++---------------------- etc/lua.pc | 6 +++++- src/lapi.c | 4 ++-- src/lbaselib.c | 4 ++-- src/lua.c | 4 ++-- src/lua.h | 5 +++-- src/luac.c | 4 ++-- 8 files changed, 47 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index 6a586e5bb5..b3678b10bd 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,9 @@ TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp TO_LIB= liblua.a TO_MAN= lua.1 luac.1 -# Lua version. +# Lua version and release. V= 5.1 +R= 5.1.1 all: $(PLAT) @@ -80,11 +81,11 @@ dummy: # echo config parameters echo: @echo "" - @echo "These are the parameters currently set in src/Makefile to build Lua $V:" + @echo "These are the parameters currently set in src/Makefile to build Lua $R:" @echo "" @cd src && $(MAKE) -s echo @echo "" - @echo "These are the parameters currently set in Makefile to install Lua $V:" + @echo "These are the parameters currently set in Makefile to install Lua $R:" @echo "" @echo "PLAT = $(PLAT)" @echo "INSTALL_TOP = $(INSTALL_TOP)" @@ -103,6 +104,7 @@ echo: # echo private config parameters pecho: @echo "V = $(V)" + @echo "R = $(R)" @echo "TO_BIN = $(TO_BIN)" @echo "TO_INC = $(TO_INC)" @echo "TO_LIB = $(TO_LIB)" @@ -111,8 +113,9 @@ pecho: # echo config parameters as Lua code # uncomment the last sed expression if you want nil instead of empty strings lecho: - @echo "-- installation parameters for Lua $V" + @echo "-- installation parameters for Lua $R" @echo "VERSION = '$V'" + @echo "RELEASE = '$R'" @$(MAKE) echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' @echo "-- EOF" diff --git a/doc/manual.html b/doc/manual.html index b220222f97..f2de71318d 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -407,22 +407,6 @@

    2.3 - Variables

     	var ::= prefixexp `[´ exp `]´
     

    -The first expression (prefixexp) should result in a table value; -the second expression (exp) -identifies a specific entry in this table. -The expression denoting the table to be indexed has a restricted syntax; -see §2.5 for details. - - -

    -The syntax var.Name is just syntactic sugar for -var["Name"] and is used to denote table fields: - -

    -	var ::= prefixexp `.´ Name
    -
    - -

    The meaning of accesses to global variables and table fields can be changed via metatables. An access to an indexed variable t[i] is equivalent to @@ -433,6 +417,14 @@

    2.3 - Variables

    We use it here only for explanatory purposes.) +

    +The syntax var.Name is just syntactic sugar for +var["Name"]: + +

    +	var ::= prefixexp `.´ Name
    +
    +

    All global variables live as fields in ordinary Lua tables, called environment tables or simply @@ -1625,7 +1617,7 @@

    2.8 - Metatables

    return metatable(op1)[event] or metatable(op2)[event] end

    -By ysing this function, +By using this function, the behavior of the op1 + op2 is

    @@ -2299,8 +2291,8 @@ 

    3.2 - Stack Size

    -Whenever Lua calls C, LUA_MINSTACK -it ensures that at least LUA_MINSTACK stack positions are available. +Whenever Lua calls C, +it ensures that at least LUA_MINSTACK stack positions are available. LUA_MINSTACK is defined as 20, so that usually you do not have to worry about stack space unless your code has loops pushing elements onto the stack. @@ -5777,6 +5769,10 @@

    5.1 - Basic Functions

    and value any Lua value. +

    +This function returns table. + +

    @@ -7909,12 +7905,17 @@

    5.9 - The Debug Library

    -The returned table contains all the fields returned by lua_getinfo, +The returned table my contain all the fields returned by lua_getinfo, with the string what describing which fields to fill in. -The default for what is to get all information available. +The default for what is to get all information available, +except the table of valid lines. If present, the option 'f' adds a field named func with the function itself. +If present, +the option 'L' +adds a field named activelines with the table of +valid lines.

    @@ -7988,6 +7989,7 @@

    5.9 - The Debug Library

    Sets the environment of the given object to the given table. +Returns object. @@ -8446,7 +8448,7 @@

    8 - The Complete Syntax of Lua


    Last update: -Wed May 31 21:31:40 BRT 2006 +Fri Jun 2 14:33:44 BRT 2006 diff --git a/etc/lua.pc b/etc/lua.pc index 5fd2b1ed1f..21a16bad73 100644 --- a/etc/lua.pc +++ b/etc/lua.pc @@ -4,6 +4,8 @@ # grep '^V=' ../Makefile V= 5.1 +# grep '^R=' ../Makefile +R= 5.1.1 # grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' prefix= /usr/local @@ -14,14 +16,16 @@ INSTALL_MAN= ${prefix}/man/man1 INSTALL_LMOD= ${prefix}/share/lua/${V} INSTALL_CMOD= ${prefix}/lib/lua/${V} +# canonical vars exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Lua Description: An Extensible Extension Language -Version: ${V} +Version: ${R} Requires: Libs: -L${libdir} -llua -lm Cflags: -I${includedir} +# (end of lua.pc) diff --git a/src/lapi.c b/src/lapi.c index ce7bcf6f3a..68e86f2ef0 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.53 2006/01/10 12:50:00 roberto Exp $ +** $Id: lapi.c,v 2.54 2006/06/02 15:34:00 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -32,7 +32,7 @@ const char lua_ident[] = - "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" + "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" "$Authors: " LUA_AUTHORS " $\n" "$URL: www.lua.org $\n"; diff --git a/src/lbaselib.c b/src/lbaselib.c index 778e393a9d..2df437b018 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.190 2006/05/31 16:50:40 roberto Exp $ +** $Id: lbaselib.c,v 1.191 2006/06/02 15:34:00 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -619,7 +619,7 @@ static void base_open (lua_State *L) { lua_setglobal(L, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); - lua_pushlstring(L, LUA_VERSION, 7); + lua_pushliteral(L, LUA_VERSION); lua_setglobal(L, "_VERSION"); /* set global _VERSION */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */ auxopen(L, "ipairs", luaB_ipairs, ipairsaux); diff --git a/src/lua.c b/src/lua.c index 991a74b8aa..5cee7fa9f0 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.159 2006/05/24 14:16:39 roberto Exp $ +** $Id: lua.c,v 1.160 2006/06/02 15:34:00 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -107,7 +107,7 @@ static int docall (lua_State *L, int narg, int clear) { static void print_version (void) { - l_message(NULL, LUA_VERSION " " LUA_COPYRIGHT); + l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); } diff --git a/src/lua.h b/src/lua.h index b2162d5eb2..064ff6fb35 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.217 2006/05/31 16:50:40 roberto Exp $ +** $Id: lua.h,v 1.218 2006/06/02 15:34:00 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -16,7 +16,8 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1.1" +#define LUA_VERSION "Lua 5.1" +#define LUA_RELEASE "Lua 5.1.1" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2006 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" diff --git a/src/luac.c b/src/luac.c index 03f3bc7508..d07017391b 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.53 2006/05/31 13:30:05 lhf Exp $ +** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -108,7 +108,7 @@ static int doargs(int argc, char* argv[]) } if (version) { - printf("%s %s\n",LUA_VERSION,LUA_COPYRIGHT); + printf("%s %s\n",LUA_RELEASE,LUA_COPYRIGHT); if (version==argc-1) exit(EXIT_SUCCESS); } return i; From fc48fbdd7b265a381002c76dcf79584b919104a0 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Mon, 5 Jun 2006 12:00:00 +0000 Subject: [PATCH 33/97] Lua 5.1.1-rc3 --- doc/manual.html | 11 ++++++----- src/ldo.c | 7 ++++--- src/lparser.c | 11 ++++++----- src/lvm.c | 3 ++- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index f2de71318d..16fbb36ef0 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -7905,7 +7905,7 @@

    5.9 - The Debug Library

    -The returned table my contain all the fields returned by lua_getinfo, +The returned table may contain all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available, except the table of valid lines. @@ -8370,9 +8370,7 @@

    8 - The Complete Syntax of Lua

    Here is the complete syntax of Lua in extended BNF. -It does not describe operator priorities or some syntactical restrictions, -such as return and break statements -can only appear as the last statement of a block. +(It does not describe operator precedences.) @@ -8448,8 +8446,11 @@

    8 - The Complete Syntax of Lua


    Last update: -Fri Jun 2 14:33:44 BRT 2006 +Mon Jun 5 17:05:27 BRT 2006 + diff --git a/src/ldo.c b/src/ldo.c index b8eb1a8a59..ab86fb70e8 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.37 2005/12/22 16:19:56 roberto Exp $ +** $Id: ldo.c,v 2.38 2006/06/05 19:36:14 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -383,12 +383,14 @@ void luaD_call (lua_State *L, StkId func, int nResults) { static void resume (lua_State *L, void *ud) { StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; - if (L->status != LUA_YIELD) { /* start coroutine */ + if (L->status == 0) { /* start coroutine? */ lua_assert(ci == L->base_ci && firstArg > L->base); if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) return; } else { /* resuming from previous yield */ + lua_assert(L->status == LUA_YIELD); + L->status = 0; if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || @@ -399,7 +401,6 @@ static void resume (lua_State *L, void *ud) { else /* yielded inside a hook: just continue its execution */ L->base = L->ci->base; } - L->status = 0; luaV_execute(L, cast_int(L->ci - L->base_ci)); } diff --git a/src/lparser.c b/src/lparser.c index 6d30ebad6d..a9be740e99 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.41 2006/03/09 18:15:48 roberto Exp $ +** $Id: lparser.c,v 2.42 2006/06/05 15:57:59 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -299,7 +299,8 @@ static void leaveblock (FuncState *fs) { removevars(fs->ls, bl->nactvar); if (bl->upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); - lua_assert(!bl->isbreakable || !bl->upval); /* loops have no body */ + /* a block either controls scope or breaks (never both) */ + lua_assert(!bl->isbreakable || !bl->upval); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ luaK_patchtohere(fs, bl->breaklist); @@ -444,6 +445,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; + int rkkey; if (ls->t.token == TK_NAME) { luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); @@ -452,10 +454,9 @@ static void recfield (LexState *ls, struct ConsControl *cc) { yindex(ls, &key); cc->nh++; checknext(ls, '='); - luaK_exp2RK(fs, &key); + rkkey = luaK_exp2RK(fs, &key); expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, luaK_exp2RK(fs, &key), - luaK_exp2RK(fs, &val)); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } diff --git a/src/lvm.c b/src/lvm.c index 6f4c0291c9..1e3ea4c89b 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.62 2006/01/23 19:51:43 roberto Exp $ +** $Id: lvm.c,v 2.63 2006/06/05 15:58:59 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -376,6 +376,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { TValue *k; const Instruction *pc; reentry: /* entry point */ + lua_assert(isLua(L->ci)); pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; From 72847ae02f73ea86c1a0d5778a9bc982cdccb821 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Wed, 7 Jun 2006 12:00:00 +0000 Subject: [PATCH 34/97] Lua 5.1.1 --- doc/contents.html | 92 ++++++++++++++++++++++++----------------------- src/lapi.c | 5 ++- 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/doc/contents.html b/doc/contents.html index 96a2dfabc3..c1e4a99ddb 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -18,16 +18,14 @@

    Reference manual for Lua 5.1

    - -Copyright -© 2006 Lua.org, PUC-Rio. All rights reserved. - +contents +· +index
    +

    -

    Contents

    +

    Contents

    -

    Quick index

    +

    Index

    - + -
    -

    Functions

    +
    +

    Lua functions

    _G
    _VERSION
    assert
    collectgarbage
    +dofile
    +error
    +getfenv
    +getmetatable
    +ipairs
    +load
    +loadfile
    +loadstring
    +module
    +next
    +pairs
    +pcall
    +print
    +rawequal
    +rawget
    +rawset
    +require
    +select
    +setfenv
    +setmetatable
    +tonumber
    +tostring
    +type
    +unpack
    +xpcall
    + +
    +

     

    coroutine.create
    coroutine.resume
    coroutine.running
    @@ -141,8 +168,6 @@

    Functions

    debug.setmetatable
    debug.setupvalue
    debug.traceback
    -dofile
    -error
    file:close
    file:flush
    file:lines
    @@ -150,8 +175,6 @@

    Functions

    file:seek
    file:setvbuf
    file:write
    -getfenv
    -getmetatable
    io.close
    io.flush
    io.input
    @@ -163,18 +186,14 @@

    Functions

    io.tmpfile
    io.type
    io.write
    -ipairs
    -load
    -loadfile
    -loadstring
    math.abs
    math.acos
    math.asin
    -math.atan
    math.atan2
    +math.atan
    math.ceil
    -math.cos
    math.cosh
    +math.cos
    math.deg
    math.exp
    math.floor
    @@ -182,8 +201,8 @@

    Functions

    math.frexp
    math.huge
    math.ldexp
    -math.log
    math.log10
    +math.log
    math.max
    math.min
    math.modf
    @@ -192,13 +211,11 @@

    Functions

    math.rad
    math.random
    math.randomseed
    -math.sin
    math.sinh
    +math.sin
    math.sqrt
    -math.tan
    math.tanh
    -module
    -next
    +math.tan
    os.clock
    os.date
    os.difftime
    @@ -216,16 +233,6 @@

    Functions

    package.path
    package.preload
    package.seeall
    -pairs
    -pcall
    -print
    -rawequal
    -rawget
    -rawset
    -require
    -select
    -setfenv
    -setmetatable
    string.byte
    string.char
    string.dump
    @@ -245,15 +252,10 @@

    Functions

    table.maxn
    table.remove
    table.sort
    -tonumber
    -tostring
    -type
    -unpack
    -xpcall
    -

    API

    +
    +

    C API

    lua_Alloc
    lua_CFunction
    lua_Debug
    @@ -359,7 +361,7 @@

    API

    -

    Auxiliary library

    +

    auxiliary library

    luaL_Buffer
    luaL_Reg
    luaL_addchar
    @@ -417,10 +419,10 @@

    Auxiliary library


    Last update: -Wed May 31 10:11:21 BRT 2006 +Tue Jun 6 14:55:31 BRT 2006 diff --git a/src/lapi.c b/src/lapi.c index 68e86f2ef0..7c532b8b1b 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.54 2006/06/02 15:34:00 roberto Exp $ +** $Id: lapi.c,v 2.55 2006/06/07 12:37:17 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -199,6 +199,9 @@ LUA_API void lua_insert (lua_State *L, int idx) { LUA_API void lua_replace (lua_State *L, int idx) { StkId o; lua_lock(L); + /* explicit test for incompatible code */ + if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) + luaG_runerror(L, "no calling environment"); api_checknelems(L, 1); o = index2adr(L, idx); api_checkvalidindex(L, o); From 7e7bc7c7c7f3301a5f837579b81bcac4a2f9cccc Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 23 Mar 2007 12:00:00 +0000 Subject: [PATCH 35/97] Lua 5.1.2-rc1 --- doc/amazon.gif | Bin 0 -> 797 bytes doc/contents.html | 51 +++++-- doc/cover.png | Bin 0 -> 3305 bytes doc/lua.css | 23 ++- doc/manual.css | 7 + doc/manual.html | 371 +++++++++++++++++++++++++++------------------- doc/readme.html | 14 +- src/lbaselib.c | 10 +- src/lcode.c | 44 ++++-- src/ldebug.c | 10 +- src/loslib.c | 23 ++- src/lparser.c | 4 +- src/lstrlib.c | 4 +- src/lua.h | 8 +- src/print.c | 3 +- 15 files changed, 364 insertions(+), 208 deletions(-) create mode 100644 doc/amazon.gif create mode 100644 doc/cover.png create mode 100644 doc/manual.css diff --git a/doc/amazon.gif b/doc/amazon.gif new file mode 100644 index 0000000000000000000000000000000000000000..f2586d5765361bb8a33a72401449f3abdefe4e16 GIT binary patch literal 797 zcmV+&1LFKgNk%w1VOjtj0K^&q@9)h50%r{k3;+NBK0Y<5t#HiDnQw1j_x9wkua=aQ zf8O4{J3ExYz@^dAvgzr__o-L@ehvGQF7LT?@$1I#;Ij3_g2%_+^3u}mmw|9dEECm0Kc!X!@|#@3&?4Fr)=|m57&HqxlCDW&_KZ+1;`8vSj33YC_e@b zLW(B90kQ_n9Ds8N3z4jU4HiAyWz9`JYknO6suY&Mn*c`+`V13=EEIuKH*uwDKrGlz zo{tDTNaHR5yf%>5cyj}g-^zXgiM@QV=g%Gh303A)7B84EpbPvE-6X=O$DmxJ`b(9|4E82-m%Ds!U< zI=HL8TMx@{~>s4%C(a0wK8Wjd@n+|5vxOvSr(vuAh- z5-e0mzlK5u3lKm6pnB`22G3HYpfaDDC`;MbMg*4 b)M@9Pc;4WH3w-wJ=bwNED(Iksh5!INDePJ9 literal 0 HcmV?d00001 diff --git a/doc/contents.html b/doc/contents.html index c1e4a99ddb..01b069f7ac 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -2,31 +2,59 @@ Lua 5.1 reference manual - contents - +

    -Lua -Reference manual for Lua 5.1 + +Lua 5.1 Reference Manual

    +This is an online version of +
    + + + +Lua 5.1 Reference Manual +
    by R. Ierusalimschy, L. H. de Figueiredo, W. Celes +
    Lua.org, August 2006 +
    ISBN 85-903798-3-3 +
    +[Buy from Amazon] +
    +
    +

    + +Buy a paper copy and +help to support +the Lua project. +

    + +startcontents · index +· +errata


    + +Copyright © 2006-2007 Lua.org, PUC-Rio. +Freely available under the terms of the +Lua license. +

    Contents

    Index

    - +
    - - - - +
    +

    Lua functions

    _G
    _VERSION
    @@ -146,7 +173,7 @@

    Lua functions

    xpcall
    +

     

    coroutine.create
    coroutine.resume
    @@ -254,7 +281,7 @@

     

    table.sort
    +

    C API

    lua_Alloc
    lua_CFunction
    @@ -419,10 +446,10 @@

    auxiliary library


    Last update: -Tue Jun 6 14:55:31 BRT 2006 +Fri Mar 23 08:33:19 BRT 2007 diff --git a/doc/cover.png b/doc/cover.png new file mode 100644 index 0000000000000000000000000000000000000000..2dbb198123f03a7250bfa57c8253739962d69afb GIT binary patch literal 3305 zcmVNc=P)V>IGcGYOVIUw=dB=aTYv^*htKxL4xjCf9X{I|EBQ!hu?+M>5oT>TE}0ye97P9R7S8qXycMFZ&6rBQl2xq6d5z1RT?1tMWggH(oGfxZ3MRwMW* zhWcm<0o+gGDNJLnwySJIYqTbnA(cT&JjHAh%b?&;aM%-PVunbF`4oU{acLCOU~~ed z=Xys9YZpo#i8bMPc#43D)u4sMGKqI^_da6LW&~0K*cO4+ z_PRNFEtj+pK65RYy#Eh+iK_)|A>ml%LRW(G?uWEPuP@)V__gB&q{E^1Drx0`;n)|1&{JZ#-e7eMcd1S~0(ChdB8 zS0!Ap-8R#X^0X5R7@pQ0wmH~jKhYj`l%C2tznfmz5?4vXD&s9-{r%L{8o|B1n{hn> zX-7F)1C|g{Fjw^QO3xSEM8WF{nF8))ijLB@AziK0j<-dAU&NHQAw-4j8oelO%2Dg_ z37hiyuBd>qbbcrr0xb~*rLW9q2cyBcq8kgCW9j_Jd}=!9R2g|I=9{KHXtr2}hFHKH zPZ!2Bg|$47mFu;Duqg$YQfQ4vD~-}9t!+atHYg~SbM=?ElxgB&vnLeLny@Jo1@}ra zw-%pO_5&GLRc)GAp8w;^w0pr+)}6{$xN2*=h1(z&s0B5@zOQ2Cj<++EgPm6D*KdLp^Jc$%i(A&wq1mn{*M;Pu$%2I-|s;8_q`68Jd zLJ$dITeas|8_h>+9GB??ksz(jj7@SsNq-j_f;Mf@l8W*L-v0vui)W9N64OhM7aV?n zo{!IxNC9-U@zPPgc8EYtsn)ggZ<}BOc#01{#gH6*gjm!cMXYMFiJ5! z$8SI7^a#mxl?1n2Bwr+veIkV`2fdd@*by0Naq>o!4A;Y!nrTV7gj#l-OAs* zvT_zQj8DKsyvuDrVn7=m8 z&;O0T{VN_DroW5Nu5jxvQZU%ZlLv@3)#xH@icfQd{R930nH<0P?=qQ<5s3ufc;l~s z^rLTdbhJn*9LK$Q@z$Gf{__VPoYQ~*AN<{S=xOJbXHXg;Sjdpd5Nq1FU!ZP(bkV*K z5BX<_uE(!VaN&B59T#f)0@ixmc3_}Kkful!<-+AYa=bk&rr9RA^GG2#cH|o2Jo3*;M^C0Z#I`l`S@(jjq^e|^t7&J*rAXei$y>%zrcxe zzKVokW{ylvDyoN%5F8rxOC(&6ljrfOA4aT&iHZA4RiB-iOg@n)*W;YNOgdZoU&C~Q zYvZ-d>YDjzn4Be*DQQDPBE@KZ$^kz7@cjMzsnv(*TI*A%M(*BC03b*t8J+ZR_jR(6 zttGy#T|b&jH^^6g-e(O?=xBjqSdb8D)Kd$tjjQa}6Izo*l=AOHBZzP@%TWj?-Z2yYmt`$ryp=SGWT>kg8zlLgEEs(4iVm;4Q>56I~!I5E_!W;Hjvwox?Uqoq) z@&EyI&Dg6UFbzN8)tb&2Y&=@c`Y|NW9`Pe8A!)AFN8A)Nk)Urp8ZM1e+_>zsWuw3Gwz#h*<|ZTYWyBV&rD^+OOrPXFnaE_T4H3gMI7NJvIPCeSU~lbZRURtjFJ3 zOtR_n9@p1NEV@-WX*<9pdwg@TE&lANPj7A1!>6YW%k<@shB-1^pOm#iGtfhChrf42 zsVsLR)XYafILOn7Dzbrs7oH##T<@vPK}ueH!cSN`F26lfqvKnrf9<;5xmTWYf?eG_ zeX!9}PBYlclLvflOw3@&T9Q?4=KSZAi+(6#NWSqr9j%R{qzT%*cARj9+M7Z={YZ`Z zkUIHTCXWs=UG`IipsSVd{5f`@zJAseNAl`14({FT2Xbx{9&lM)RVZ}_{lVes;w@a^N+fz49V zNXZM2^W9f`Rcp=JFX(8gt1f+0`B4G4?=d#PKzC_k7?Qz0y4x6=B$uz#sndjmeCtJC zJ5DgL%uYf!d*Z&jYQX0B2)f!R6lrVmT}CPC?c~T_GI?g_YxBM}hQWc|eD9k)^C*Fe z?D1?8AQoMD2D71Pn?G+{G@(R_)@FY(T|5yQo#5loxID%}wj5$qei{Hm5DK!lj~Ach z@X#`~XwB_uPF>*Z&(R#ISEvU#FA)Nz`TQED$+JgFvs?%)ll=n>_cNbnY=Y|(+?{11 zL&3o^iG=8GW2ldzK00F6PjxbRUOh&1<7lUfP!D<@?6{2FWT>x{XIvqi2CY#FPoWf2 zVo0P!tZu2v=D9u1zJZdTwyAHS9=M*uGC8uBNRUK|GgrvwmU;C8q`)+=EkZW7g=ru~ z6RQpkqkiq>Ru+?vAkXbSVK7dSLn?*gy_ zjjN{!SUh^+iEFRr=;K9At8qQ=c=~M}HT#)sT^Fg(`nT>?C{y%_^R>wBb&6$ nh%8`n`v3p{2XskIMF-Xh6%#iZwFs;u00000NkvXXu0mjfd@Wp4 literal 0 HcmV?d00001 diff --git a/doc/lua.css b/doc/lua.css index f007211009..039cf11698 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -2,16 +2,24 @@ body { color: #000000 ; background-color: #FFFFFF ; font-family: sans-serif ; + text-align: justify ; + margin-right: 20px ; + margin-left: 20px ; +} + +h1, h2, h3, h4 { + font-weight: normal ; + font-style: italic ; } a:link { color: #000080 ; - background-color: #FFFFFF ; + background-color: inherit ; text-decoration: none ; } a:visited { - background-color: #FFFFFF ; + background-color: inherit ; text-decoration: none ; } @@ -20,3 +28,14 @@ a:link:hover, a:visited:hover { background-color: #E0E0FF ; } +a:link:active, a:visited:active { + color: #FF0000 ; +} + +hr { + border: 0 ; + height: 1px ; + color: #a0a0a0 ; + background-color: #a0a0a0 ; +} + diff --git a/doc/manual.css b/doc/manual.css new file mode 100644 index 0000000000..93f1ab2dc8 --- /dev/null +++ b/doc/manual.css @@ -0,0 +1,7 @@ +h3 code { + font-family: inherit ; +} + +pre { + font-size: 105% ; +} diff --git a/doc/manual.html b/doc/manual.html index 16fbb36ef0..6203f824b6 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -4,6 +4,7 @@ Lua 5.1 Reference Manual + @@ -17,10 +18,16 @@

    by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    -Copyright -© 2006 Lua.org, PUC-Rio. All rights reserved. +Copyright © 2006-2007 Lua.org, PUC-Rio. +Freely available under the terms of the +Lua license.


    +

    + +contents +· +index

    @@ -71,7 +78,7 @@

    1 - Introduction

    For a discussion of the decisions behind the design of Lua, see the technical papers available at Lua's web site. For a detailed introduction to programming in Lua, -see Roberto's book, Programming in Lua. +see Roberto's book, Programming in Lua (Second Edition). @@ -390,8 +397,8 @@

    2.3 - Variables

    -Variables are assumed to be global unless explicitly declared local -(see §2.4.7). +Any variable is assumed to be global unless explicitly declared +as a local (see §2.4.7). Local variables are lexically scoped: local variables can be freely accessed by functions defined inside their scope (see §2.6). @@ -708,18 +715,18 @@

    2.4.5 - For Statement

    More precisely, a for statement like
    -     for var = e1, e2, e3 do block end
    +     for v = e1, e2, e3 do block end
     

    is equivalent to the code:

          do
    -       local _var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)
    -       if not (_var and _limit and _step) then error() end
    -       while (_step>0 and _var<=_limit) or (_step<=0 and _var>=_limit) do
    -         local var = _var
    +       local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
    +       if not (var and limit and step) then error() end
    +       while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
    +         local v = var
              block
    -         _var = _var + _step
    +         var = var + step
            end
          end
     

    @@ -734,7 +741,7 @@

    2.4.5 - For Statement

  • -_var, _limit, and _step are invisible variables. +var, limit, and step are invisible variables. The names are here for explanatory purposes only.
  • @@ -748,10 +755,10 @@

    2.4.5 - For Statement

  • -The loop variable var is local to the loop; +The loop variable v is local to the loop; you cannot use its value after the for ends or is broken. -If you need the value of the loop variable var, -then assign it to another variable before breaking or exiting the loop. +If you need this value, +assign it to another variable before breaking or exiting the loop.
  • @@ -770,18 +777,18 @@

    2.4.5 - For Statement

    A for statement like
    -     for var_1, ···, var_n in explist do block end
    +     for var_1, ···, var_n in explist do block end
     

    is equivalent to the code:

          do
    -       local _f, _s, _var = explist
    +       local f, s, var = explist
            while true do
    -         local var_1, ···, var_n = _f(_s, _var)
    -         _var = var_1
    -         if _var == nil then break end
    -         block
    +         local var_1, ···, var_n = f(s, var)
    +         var = var_1
    +         if var == nil then break end
    +         block
            end
          end
     

    @@ -790,13 +797,14 @@

    2.4.5 - For Statement

    • -explist is evaluated only once. +explist is evaluated only once. Its results are an iterator function, -a state, and an initial value for the first iterator variable. +a state, +and an initial value for the first iterator variable.
    • -_f, _s, and _var are invisible variables. +f, s, and var are invisible variables. The names are here for explanatory purposes only.
    • @@ -805,7 +813,7 @@

      2.4.5 - For Statement

    • -The loop variables var_i are local to the loop; +The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop. @@ -902,13 +910,13 @@

      2.5 - Expressions

      (only possible for function calls), then its return list is adjusted to zero elements, thus discarding all returned values. -If the expression is used inside another expression -or in the middle of a list of expressions, -then its result list is adjusted to one element, -thus discarding all values except the first one. -If the expression is used as the last element of a list of expressions, -then no adjustment is made, -unless the call is enclosed in parentheses. +If the expression is used as the last (or the only) element +of a list of expressions, +then no adjustment is made +(unless the call is enclosed in parentheses). +In all other contexts, +Lua adjusts the result list to one element, +discarding all values except the first one.

      @@ -917,17 +925,18 @@

      2.5 - Expressions

            f()                -- adjusted to 0 results
            g(f(), x)          -- f() is adjusted to 1 result
      -     g(x, f())          -- g gets x plus all values returned by f()
      +     g(x, f())          -- g gets x plus all results from f()
            a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
            a,b = ...          -- a gets the first vararg parameter, b gets
      -                        -- the second (both a and b may get nil if there is
      -                        -- no corresponding vararg parameter)
      +                        -- the second (both a and b may get nil if there
      +                        -- is no corresponding vararg parameter)
      +     
            a,b,c = x, f()     -- f() is adjusted to 2 results
            a,b,c = f()        -- f() is adjusted to 3 results
      -     return f()         -- returns all values returned by f()
      +     return f()         -- returns all results from f()
            return ...         -- returns all received vararg parameters
      -     return x,y,f()     -- returns x, y, and all values returned by f()
      -     {f()}              -- creates a list with all values returned by f()
      +     return x,y,f()     -- returns x, y, and all results from f()
      +     {f()}              -- creates a list with all results from f()
            {...}              -- creates a list with all vararg parameters
            {f(), nil}         -- f() is adjusted to 1 result
       
      @@ -1543,8 +1552,7 @@

      2.8 - Metatables

      Tables and userdata have individual metatables -(although multiple tables and userdata can share -a same table as their metatable); +(although multiple tables and userdata can share their metatables); values of all other types share one single metatable per type. So, there is one single metatable for all numbers, and for all strings, etc. @@ -1592,6 +1600,7 @@

      2.8 - Metatables

            rawget(getmetatable(obj) or {}, event)
       

      + That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail (it simply results in nil). @@ -2077,7 +2086,7 @@

      2.10.2 - Weak Tables

      both keys and values. In any case, if either the key or the value is collected, the whole pair is removed from the table. -The weakness of a table is controlled by the value of the +The weakness of a table is controlled by the __mode field of its metatable. If the __mode field is a string containing the character 'k', the keys in the table are weak. @@ -2156,8 +2165,8 @@

      2.11 - Coroutines

      -The coroutine.wrap function creates a coroutine, -just like coroutine.create, +Like coroutine.create, +the coroutine.wrap function also creates a coroutine, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. Any arguments passed to this function @@ -2198,6 +2207,7 @@

      2.11 - Coroutines

            co-body 1       10
            foo     2
      +     
            main    true    4
            co-body r
            main    true    11      -9
      @@ -2268,7 +2278,7 @@ 

      3.1 - The Stack

      and index n represents the last element; index -1 also represents the last element -(that is, the element at the top) +(that is, the element at the top) and index -n represents the first element. We say that an index is valid if it lies between 1 and the stack top @@ -2473,21 +2483,25 @@

      3.7 - Functions and Types

      Here is a simple implementation for the allocator function. -It is used in the auxiliary library by lua_newstate. +It is used in the auxiliary library by luaL_newstate.

      -     static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
      -       (void)ud;     /* not used */
      -       (void)osize;  /* not used */
      +     static void *l_alloc (void *ud, void *ptr, size_t osize,
      +                                                size_t nsize) {
      +       (void)ud;  (void)osize;  /* not used */
              if (nsize == 0) {
      -         free(ptr);  /* ANSI requires that free(NULL) has no effect */
      +         free(ptr);
                return NULL;
              }
              else
      -         /* ANSI requires that realloc(NULL, size) == malloc(size) */
                return realloc(ptr, nsize);
            }
      -
      +

      +This code assumes +that free(NULL) has no effect and that +realloc(NULL, size) is equivalent to malloc(size). +ANSI C ensures both behaviors. + @@ -2557,14 +2571,14 @@

      3.7 - Functions and Types

      Here it is in C:
      -     lua_getfield(L, LUA_GLOBALSINDEX, "f");          /* function to be called */
      -     lua_pushstring(L, "how");                                 /* 1st argument */
      -     lua_getfield(L, LUA_GLOBALSINDEX, "t");            /* table to be indexed */
      -     lua_getfield(L, -1, "x");                 /* push result of t.x (2nd arg) */
      -     lua_remove(L, -2);                           /* remove 't' from the stack */
      -     lua_pushinteger(L, 14);                                   /* 3rd argument */
      -     lua_call(L, 3, 1);         /* call function with 3 arguments and 1 result */
      -     lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global variable 'a' */
      +     lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */
      +     lua_pushstring(L, "how");                        /* 1st argument */
      +     lua_getfield(L, LUA_GLOBALSINDEX, "t");   /* table to be indexed */
      +     lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
      +     lua_remove(L, -2);                  /* remove 't' from the stack */
      +     lua_pushinteger(L, 14);                          /* 3rd argument */
      +     lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
      +     lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global 'a' */
       

      Note that the code above is "balanced": at its end, the stack is back to its original configuration. @@ -2611,7 +2625,7 @@

      3.7 - Functions and Types

      int i; for (i = 1; i <= n; i++) { if (!lua_isnumber(L, i)) { - lua_pushstring(L, "incorrect argument to function 'average'"); + lua_pushstring(L, "incorrect argument"); lua_error(L); } sum += lua_tonumber(L, i); @@ -2723,7 +2737,7 @@

      3.7 - Functions and Types

      The value returned is the error code returned by the last call to the writer; -0 means no errors. +0 means no errors.

      @@ -2814,7 +2828,7 @@

      3.7 - Functions and Types

    • LUA_GCSETSTEPMUL: -sets arg/100 as the new value for the step multiplier of +sets data/100 as the new value for the step multiplier of the collector (see §2.10). The function returns the previous value of the step multiplier.
    • @@ -2942,7 +2956,7 @@

      3.7 - Functions and Types

      By default it is a ptrdiff_t, -which is usually the largest integral type the machine handles +which is usually the largest signed integral type the machine handles "comfortably". @@ -2954,7 +2968,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index has type boolean, -and 0 otherwise. +and 0 otherwise. @@ -2965,7 +2979,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a C function, -and 0 otherwise. +and 0 otherwise. @@ -2976,7 +2990,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a function -(either C or Lua), and 0 otherwise. +(either C or Lua), and 0 otherwise. @@ -2987,7 +3001,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a light userdata, -and 0 otherwise. +and 0 otherwise. @@ -2998,7 +3012,32 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is nil, -and 0 otherwise. +and 0 otherwise. + + + + + +


      lua_isnone

      +
      int lua_isnone (lua_State *L, int index);
      + +

      +Returns 1 if the the given acceptable index is not valid +(that is, it refers to an element outside the current stack), +and 0 otherwise. + + + + + +


      lua_isnoneornil

      +
      int lua_isnoneornil (lua_State *L, int index);
      + +

      +Returns 1 if the the given acceptable index is not valid +(that is, it refers to an element outside the current stack) +or if the value at this index is nil, +and 0 otherwise. @@ -3010,7 +3049,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a number or a string convertible to a number, -and 0 otherwise. +and 0 otherwise. @@ -3022,7 +3061,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a string or a number (which is always convertible to a string), -and 0 otherwise. +and 0 otherwise. @@ -3033,7 +3072,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a table, -and 0 otherwise. +and 0 otherwise. @@ -3044,7 +3083,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a thread, -and 0 otherwise. +and 0 otherwise. @@ -3055,7 +3094,7 @@

      3.7 - Functions and Types

      Returns 1 if the value at the given acceptable index is a userdata -(either full or light), and 0 otherwise. +(either full or light), and 0 otherwise. @@ -3113,8 +3152,8 @@

      3.7 - Functions and Types

      -lua_load uses a user-supplied reader function to read the chunk -(see lua_Reader). +The lua_load function uses a user-supplied reader function +to read the chunk (see lua_Reader). The data argument is an opaque value passed to the reader function. @@ -3219,10 +3258,12 @@

      3.7 - Functions and Types

      /* table is in the stack at index 't' */ lua_pushnil(L); /* first key */ while (lua_next(L, t) != 0) { - /* 'key' is at index -2 and 'value' at index -1 */ + /* uses 'key' (at index -2) and 'value' (at index -1) */ printf("%s - %s\n", - lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1))); - lua_pop(L, 1); /* removes 'value'; keeps 'key' for next iteration */ + lua_typename(L, lua_type(L, -2)), + lua_typename(L, lua_type(L, -1))); + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 1); } @@ -3270,7 +3311,7 @@

      3.7 - Functions and Types


      lua_pcall

      -
      lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
      +
      int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

      Calls a function in protected mode. @@ -3396,9 +3437,11 @@

      3.7 - Functions and Types

      -The call lua_pushcfunction(L, f) is equivalent to -lua_pushcclosure(L, f, 0). +lua_pushcfunction is defined as a macro: +

      +     #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
      +
      @@ -3642,14 +3685,17 @@

      3.7 - Functions and Types


      lua_register

      -
      void lua_register (lua_State *L, const char *name, lua_CFunction f);
      +
      void lua_register (lua_State *L,
      +                   const char *name,
      +                   lua_CFunction f);

      Sets the C function f as the new value of global name. It is defined as a macro:

      -     #define lua_register(L,n,f)  (lua_pushcfunction(L, f), lua_setglobal(L, n))
      +     #define lua_register(L,n,f) \
      +            (lua_pushcfunction(L, f), lua_setglobal(L, n))
       
      @@ -3905,8 +3951,7 @@

      3.7 - Functions and Types

      const char *lua_tolstring (lua_State *L, int index, size_t *len);

      -Converts the Lua value at the given acceptable index to a string -(const char*). +Converts the Lua value at the given acceptable index to a C string. If len is not NULL, it also sets *len with the string length. The Lua value must be a string or a number; @@ -3937,7 +3982,7 @@

      3.7 - Functions and Types

      Converts the Lua value at the given acceptable index -to a number (see lua_Number). +to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number (see §2.2.1); otherwise, lua_tonumber returns 0. @@ -4054,7 +4099,7 @@

      3.7 - Functions and Types

      The writer returns an error code: -0 means no errors; +0 means no errors; any other value means an error and stops lua_dump from calling the writer again. @@ -4279,8 +4324,8 @@

      3.8 - The Debug Interface

    • 'S': -fills in the fields source, linedefined, -lastlinedefined, what, and short_src; +fills in the fields source, short_src, +linedefined, lastlinedefined, and what;
    • 'l': fills in the field currentline; @@ -4313,7 +4358,7 @@

      3.8 - The Debug Interface


      lua_getlocal

      -
      const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
      +
      const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);

      Gets information about a local variable of a given activation record. @@ -4424,14 +4469,14 @@

      3.8 - The Debug Interface


      lua_sethook

      -
      int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
      +
      int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

      Sets the debugging hook function.

      -func is the hook function. +Argument f is the hook function. mask specifies on which events the hook will be called: it is formed by a bitwise or of the constants LUA_MASKCALL, @@ -4475,7 +4520,7 @@

      3.8 - The Debug Interface


      lua_setlocal

      -
      const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
      +
      const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);

      Sets the value of a local variable of a given activation record. @@ -4500,11 +4545,11 @@

      3.8 - The Debug Interface

      Sets the value of a closure's upvalue. -Parameters funcindex and n are as in lua_getupvalue -(see lua_getupvalue). It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. +Parameters funcindex and n are as in the lua_getupvalue +(see lua_getupvalue).

      @@ -4588,9 +4633,9 @@

      4.1 - Functions and Types

      void luaL_addsize (luaL_Buffer *B, size_t n);

      -Adds a string of length n previously copied to the -buffer area (see luaL_prepbuffer) to the buffer B -(see luaL_Buffer). +Adds to the buffer B (see luaL_Buffer) +a string of length n previously copied to the +buffer area (see luaL_prepbuffer). @@ -4631,7 +4676,7 @@

      4.1 - Functions and Types


      luaL_argcheck

      void luaL_argcheck (lua_State *L,
                           int cond,
      -                    int numarg,
      +                    int narg,
                           const char *extramsg);

      @@ -4640,21 +4685,21 @@

      4.1 - Functions and Types

      where func is retrieved from the call stack:
      -     bad argument #<numarg> to <func> (<extramsg>)
      +     bad argument #<narg> to <func> (<extramsg>)
       

      luaL_argerror

      -
      int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
      +
      int luaL_argerror (lua_State *L, int narg, const char *extramsg);

      Raises an error with the following message, where func is retrieved from the call stack:

      -     bad argument #<numarg> to <func> (<extramsg>)
      +     bad argument #<narg> to <func> (<extramsg>)
       

      @@ -5079,9 +5124,10 @@

      4.1 - Functions and Types

      lua_State *luaL_newstate (void);

      -Creates a new Lua state, calling lua_newstate with an -allocation function based on the standard C realloc function -and setting a panic function (see lua_atpanic) that prints +Creates a new Lua state. +It calls lua_newstate with an +allocator based on the standard C realloc function +and then sets a panic function (see lua_atpanic) that prints an error message to the standard error output in case of fatal errors. @@ -5119,7 +5165,9 @@

      4.1 - Functions and Types


      luaL_optinteger

      -
      lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer d);
      +
      lua_Integer luaL_optinteger (lua_State *L,
      +                             int narg,
      +                             lua_Integer d);

      If the function argument narg is a number, @@ -5183,7 +5231,9 @@

      4.1 - Functions and Types


      luaL_optstring

      -
      const char *luaL_optstring (lua_State *L, int narg, const char *d);
      +
      const char *luaL_optstring (lua_State *L,
      +                            int narg,
      +                            const char *d);

      If the function argument narg is a string, @@ -5285,7 +5335,7 @@

      4.1 - Functions and Types

      When called with a non-null libname, -creates a new table t, +luaL_register creates a new table t, sets it as the value of the global variable libname, sets it as the value of package.loaded[libname], and registers on it all functions in the list l. @@ -5316,14 +5366,14 @@

      4.1 - Functions and Types

      int luaL_typerror (lua_State *L, int narg, const char *tname);

      -Generates an error with a message like +Generates an error with a message like the following:

      -     <location>: bad argument <narg> to <function> (<tname> expected, got <realt>)
      +     location: bad argument narg to 'func' (tname expected, got rt)
       

      -where <location> is produced by luaL_where, -<function> is the name of the current function, -and <realt> is the type name of the actual argument. +where location is produced by luaL_where, +func is the name of the current function, +and rt is the type name of the actual argument. @@ -5354,7 +5404,11 @@

      4.1 - Functions and Types

      Pushes onto the stack a string identifying the current position of the control at level lvl in the call stack. -Typically this string has the format <chunkname>:<currentline>:. +Typically this string has the following format: + +

      +     chunkname:currentline:
      +

      Level 0 is the running function, level 1 is the function that called the running function, etc. @@ -5413,9 +5467,8 @@

      5 - Standard Libraries

      To have access to these libraries, -the C host program must call -luaL_openlibs, -which open all standard libraries. +the C host program should call the luaL_openlibs function, +which opens all standard libraries. Alternatively, it can open them individually by calling luaopen_base (for the basic library), @@ -5547,7 +5600,7 @@

      5.1 - Basic Functions

      -


      getfenv (f)

      +

      getfenv ([f])

      Returns the current environment in use by the function. f can be a Lua function or a number that specifies the function at that stack level: @@ -5589,10 +5642,6 @@

      5.1 - Basic Functions

      up to the first integer key absent from the table. -

      -See next for the caveats of modifying the table during its traversal. - -

      @@ -5704,7 +5753,8 @@

      5.1 - Basic Functions

      -See next for the caveats of modifying the table during its traversal. +See function next for the caveats of modifying +the table during its traversal. @@ -5911,7 +5961,7 @@

      5.1 - Basic Functions

      -This function is similar to pcall, +This function is similar to pcall, except that you can set a new error handler. @@ -6101,7 +6151,7 @@

      5.3 - Modules

      Loads the given module. -The function starts by looking into the table package.loaded +The function starts by looking into the package.loaded table to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. @@ -6156,7 +6206,7 @@

      5.3 - Modules

      Once a loader is found, require calls the loader with a single argument, modname. If the loader returns any value, -require assigns it to package.loaded[modname]. +require assigns the returned value to package.loaded[modname]. If the loader returns no value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. @@ -6190,6 +6240,7 @@

      5.3 - Modules

      +


      package.loaded

      @@ -6426,7 +6477,8 @@

      5.4 - String Manipulation

      This function does not accept string values -containing embedded zeros. +containing embedded zeros, +except as arguments to the q option. @@ -6436,9 +6488,6 @@

      5.4 - String Manipulation

      Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. - - -

      If pattern specifies no captures, then the whole match is produced in each call. @@ -6465,6 +6514,11 @@

      5.4 - String Manipulation

      end +

      +For this function, a '^' at the start of a pattern does not +work as an anchor, as this would prevent the iteration. + +

      @@ -6540,7 +6594,7 @@

      5.4 - String Manipulation

      --> x="4+5 = 9" local t = {name="lua", version="5.1"} - x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t) + x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.1.tar.gz" @@ -6824,7 +6878,8 @@

      5.5 - Table Manipulation


      table.concat (table [, sep [, i [, j]]])

      -Returns table[i]..sep..table[i+1] ··· sep..table[j]. +Given an array where all elements are strings or numbers, +returns table[i]..sep..table[i+1] ··· sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. @@ -7122,7 +7177,7 @@

      5.6 - Mathematical Functions

      -The value PI. +The value of pi. @@ -7266,7 +7321,8 @@

      5.7 - Input and Output Facilities

      Unless otherwise stated, all I/O functions return nil on failure -(plus an error message as a second result) +(plus an error message as a second result and +a system-dependent error code as a third result) and some value different from nil on success. @@ -7331,7 +7387,7 @@

      5.7 - Input and Output Facilities

      -The call io.lines() (without a file name) is equivalent +The call io.lines() (with no file name) is equivalent to io.input():lines(); that is, it iterates over the lines of the default input file. In this case it does not close the file when the loop ends. @@ -7381,7 +7437,7 @@

      5.7 - Input and Output Facilities

      -


      io.popen ([prog [, mode]])

      +

      io.popen (prog [, mode])

      @@ -7596,7 +7652,7 @@

      5.7 - Input and Output Facilities

    -For the last two cases, sizes +For the last two cases, size specifies the size of the buffer, in bytes. The default is an appropriate size. @@ -7657,7 +7713,7 @@

    5.8 - Operating System Facilities

    If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, -if format is *t, +if format is the string "*t", then date returns a table with the following fields: year (four digits), month (1--12), day (1--31), hour (0--23), min (0--59), sec (0--61), @@ -7667,7 +7723,7 @@

    5.8 - Operating System Facilities

    -If format is not *t, +If format is not "*t", then date returns the date as a string, formatted according to the same rules as the C function strftime. @@ -7771,6 +7827,13 @@

    5.8 - Operating System Facilities

    or nil if the request cannot be honored. +

    +If locale is the empty string, +the current locate is set to an implementation-defined native locale. +If locate is the string "C", +the current locate is set to the standard C locale. + +

    When called with nil as the first argument, this function only returns the name of the current locale @@ -7921,7 +7984,8 @@

    5.9 - The Debug Library

    For instance, the expression debug.getinfo(1,"n").name returns a name of the current function, if a reasonable name can be found, -and debug.getinfo(print) returns a table with all available information +and the expression debug.getinfo(print) +returns a table with all available information about the print function. @@ -8080,15 +8144,16 @@

    5.9 - The Debug Library

    -


    debug.traceback ([thread,] [message])

    +

    debug.traceback ([thread,] [message] [, level])

    Returns a string with a traceback of the call stack. An optional message string is appended -at the beginning of the traceback. -This function is typically used with xpcall to produce -better error messages. +at the beginning of the traceback. +An optional level number tells at which level +to start the traceback +(default is 1, the function calling traceback). @@ -8232,7 +8297,7 @@

    6 - Lua Stand-alone

    7 - Incompatibilities with the Previous Version

    -Here we list the incompatibilities that may be found when moving a program +Here we list the incompatibilities that you may found when moving a program from Lua 5.0 to Lua 5.1. You can avoid most of the incompatibilities compiling Lua with appropriate options (see file luaconf.h). @@ -8247,7 +8312,7 @@

    7.1 - Changes in the Language

  • The vararg system changed from the pseudo-argument arg with a table with the extra arguments to the vararg expression. -(Option LUA_COMPAT_VARARG in luaconf.h.) +(See compile-time option LUA_COMPAT_VARARG in luaconf.h.)
  • @@ -8259,7 +8324,7 @@

    7.1 - Changes in the Language

    The long string/long comment syntax ([[string]]) does not allow nesting. You can use the new syntax ([=[string]=]) in these cases. -(Option LUA_COMPAT_LSTR in luaconf.h.) +(See compile-time option LUA_COMPAT_LSTR in luaconf.h.)
  • @@ -8272,7 +8337,7 @@

    7.2 - Changes in the Libraries

  • Function string.gfind was renamed string.gmatch. -(Option LUA_COMPAT_GFIND) +(See compile-time option LUA_COMPAT_GFIND in luaconf.h.)
  • @@ -8288,17 +8353,17 @@

    7.2 - Changes in the Libraries

    Function table.getn corresponds to the new length operator (#); use the operator instead of the function. -(Option LUA_COMPAT_GETN) +(See compile-time option LUA_COMPAT_GETN in luaconf.h.)
  • Function loadlib was renamed package.loadlib. -(Option LUA_COMPAT_LOADLIB) +(See compile-time option LUA_COMPAT_LOADLIB in luaconf.h.)
  • Function math.mod was renamed math.fmod. -(Option LUA_COMPAT_MOD) +(See compile-time option LUA_COMPAT_MOD in luaconf.h.)
  • @@ -8446,10 +8511,10 @@

    8 - The Complete Syntax of Lua


    Last update: -Mon Jun 5 17:05:27 BRT 2006 +Fri Mar 23 14:37:09 BRT 2007 diff --git a/doc/readme.html b/doc/readme.html index db20a69a00..28b1d1472e 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -4,7 +4,7 @@ - +

    @@ -12,8 +12,9 @@

    Documentation

    +This is the documentation included in the source distribution of Lua 5.1.2. + +Lua's +official web site +contains updated documentation, +especially the +reference manual. +

    +


    Last update: -Wed Sep 7 12:57:50 BRST 2005 +Fri Mar 23 14:19:36 BRT 2007 diff --git a/src/lbaselib.c b/src/lbaselib.c index 2df437b018..147a727e06 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.191 2006/06/02 15:34:00 roberto Exp $ +** $Id: lbaselib.c,v 1.191a 2006/06/02 15:34:00 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -114,11 +114,11 @@ static int luaB_setmetatable (lua_State *L) { } -static void getfunc (lua_State *L) { +static void getfunc (lua_State *L, int opt) { if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); else { lua_Debug ar; - int level = luaL_optint(L, 1, 1); + int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); if (lua_getstack(L, level, &ar) == 0) luaL_argerror(L, 1, "invalid level"); @@ -131,7 +131,7 @@ static void getfunc (lua_State *L) { static int luaB_getfenv (lua_State *L) { - getfunc(L); + getfunc(L, 1); if (lua_iscfunction(L, -1)) /* is a C function? */ lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ else @@ -142,7 +142,7 @@ static int luaB_getfenv (lua_State *L) { static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); - getfunc(L); + getfunc(L, 0); lua_pushvalue(L, 2); if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { /* change environment of current thread */ diff --git a/src/lcode.c b/src/lcode.c index b71acd8429..9ce515ab64 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.25 2006/03/21 19:28:49 roberto Exp $ +** $Id: lcode.c,v 2.25a 2006/03/21 19:28:49 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -35,15 +35,20 @@ static int isnumeral(expdesc *e) { void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ - if (fs->pc == 0) /* function start? */ - return; /* positions are already clean */ - if (GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pto = GETARG_B(*previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(*previous, from+n-1); - return; + if (fs->pc == 0) { /* function start? */ + if (from >= fs->nactvar) + return; /* positions are already clean */ + } + else { + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; + } } } } @@ -657,10 +662,16 @@ static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { if (constfolding(op, e1, e2)) return; else { - int o1 = luaK_exp2RK(fs, e1); int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; - freeexp(fs, e2); - freeexp(fs, e1); + int o1 = luaK_exp2RK(fs, e1); + if (o1 > o2) { + freeexp(fs, e1); + freeexp(fs, e2); + } + else { + freeexp(fs, e2); + freeexp(fs, e1); + } e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); e1->k = VRELOCABLE; } @@ -718,10 +729,15 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ break; } - default: { + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { if (!isnumeral(v)) luaK_exp2RK(fs, v); break; } + default: { + luaK_exp2RK(fs, v); + break; + } } } diff --git a/src/ldebug.c b/src/ldebug.c index 8919a01739..9c8bdf2fb9 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.29 2005/12/22 16:19:56 roberto Exp $ +** $Id: ldebug.c,v 2.29a 2005/12/22 16:19:56 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -432,14 +432,16 @@ static Instruction symbexec (const Proto *pt, int lastpc, int reg) { break; } case OP_CLOSURE: { - int nup; + int nup, j; check(b < pt->sizep); nup = pt->p[b]->nups; check(pc + nup < pt->sizecode); - for (; nup>0; nup--) { - OpCode op1 = GET_OPCODE(pt->code[pc+nup]); + for (j = 1; j <= nup; j++) { + OpCode op1 = GET_OPCODE(pt->code[pc + j]); check(op1 == OP_GETUPVAL || op1 == OP_MOVE); } + if (reg != NO_REG) /* tracing? */ + pc += nup; /* do not 'execute' these pseudo-instructions */ break; } case OP_VARARG: { diff --git a/src/loslib.c b/src/loslib.c index 7c6c5d6168..fdda47414d 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.19 2006/04/26 18:19:49 roberto Exp $ +** $Id: loslib.c,v 1.20 2006/09/19 13:57:08 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -146,11 +146,22 @@ static int os_date (lua_State *L) { setboolfield(L, "isdst", stm->tm_isdst); } else { - char b[256]; - if (strftime(b, sizeof(b), s, stm)) - lua_pushstring(L, b); - else - return luaL_error(L, LUA_QL("date") " format too long"); + char cc[3]; + luaL_Buffer b; + cc[0] = '%'; cc[2] = '\0'; + luaL_buffinit(L, &b); + for (; *s; s++) { + if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ + luaL_addchar(&b, *s); + else { + size_t reslen; + char buff[200]; /* should be big enough for any conversion result */ + cc[1] = *(++s); + reslen = strftime(buff, sizeof(buff), cc, stm); + luaL_addlstring(&b, buff, reslen); + } + } + luaL_pushresult(&b); } return 1; } diff --git a/src/lparser.c b/src/lparser.c index a9be740e99..6c473c41d2 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.42 2006/06/05 15:57:59 roberto Exp $ +** $Id: lparser.c,v 2.42a 2006/06/05 15:57:59 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -489,7 +489,7 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { static void listfield (LexState *ls, struct ConsControl *cc) { expr(ls, &cc->v); - luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor"); + luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } diff --git a/src/lstrlib.c b/src/lstrlib.c index f93a8af09c..fc7ae4894a 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.132 2006/04/26 20:41:19 roberto Exp $ +** $Id: lstrlib.c,v 1.132a 2006/04/26 20:41:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -723,7 +723,7 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; - while (strchr(FLAGS, *p)) p++; /* skip flags */ + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ diff --git a/src/lua.h b/src/lua.h index 064ff6fb35..2865a7fae9 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.218 2006/06/02 15:34:00 roberto Exp $ +** $Id: lua.h,v 1.218a 2006/06/02 15:34:00 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -17,9 +17,9 @@ #define LUA_VERSION "Lua 5.1" -#define LUA_RELEASE "Lua 5.1.1" +#define LUA_RELEASE "Lua 5.1.2" #define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2006 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT "Copyright (C) 1994-2007 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -359,7 +359,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2006 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2007 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/print.c b/src/print.c index 2a4fb3ed32..430af836d3 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.55 2006/05/31 13:30:05 lhf Exp $ +** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -32,6 +32,7 @@ static void PrintString(const TString* ts) switch (c) { case '"': printf("\\\""); break; + case '\\': printf("\\\\"); break; case '\a': printf("\\a"); break; case '\b': printf("\\b"); break; case '\f': printf("\\f"); break; From cf61d326a6adbeb4ea9467af3fe4da1af8784f01 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Sun, 25 Mar 2007 12:00:00 +0000 Subject: [PATCH 36/97] Lua 5.1.2-rc2 --- Makefile | 13 +++++-------- etc/lua.pc | 2 +- etc/strict.lua | 9 +++++++-- src/Makefile | 9 +++++++-- src/luaconf.h | 4 ++-- src/lvm.c | 8 +++++--- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index b3678b10bd..c5ec666af7 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ PLAT= none # Where to install. The installation starts in the src directory, so take care # if INSTALL_TOP is not an absolute path. (Man pages are installed from the -# doc directory.) +# doc directory.) You may want to make these paths consistent with LUA_ROOT, +# LUA_LDIR, and LUA_CDIR in luaconf.h (and also with etc/lua.pc). # INSTALL_TOP= /usr/local INSTALL_BIN= $(INSTALL_TOP)/bin @@ -37,7 +38,7 @@ RANLIB= ranlib # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= # Convenience platforms targets. -PLATS= aix ansi bsd generic linux macosx mingw posix solaris +PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris # What to install. TO_BIN= lua luac @@ -47,7 +48,7 @@ TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.1 -R= 5.1.1 +R= 5.1.2 all: $(PLAT) @@ -119,11 +120,7 @@ lecho: @$(MAKE) echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' @echo "-- EOF" -# show what has changed since we unpacked -newer: - @$(FIND) . -newer MANIFEST -type f - # list targets that do not create files (but not all makes understand .PHONY) -.PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho newer +.PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho # (end of Makefile) diff --git a/etc/lua.pc b/etc/lua.pc index 21a16bad73..03a2e684ad 100644 --- a/etc/lua.pc +++ b/etc/lua.pc @@ -5,7 +5,7 @@ # grep '^V=' ../Makefile V= 5.1 # grep '^R=' ../Makefile -R= 5.1.1 +R= 5.1.2 # grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' prefix= /usr/local diff --git a/etc/strict.lua b/etc/strict.lua index 7c9fa15947..16ee26b429 100644 --- a/etc/strict.lua +++ b/etc/strict.lua @@ -14,9 +14,14 @@ end mt.__declared = {} +local function what () + local d = debug.getinfo(3, "S") + return d and d.what or "C" +end + mt.__newindex = function (t, n, v) if not mt.__declared[n] then - local w = debug.getinfo(2, "S").what + local w = what() if w ~= "main" and w ~= "C" then error("assign to undeclared variable '"..n.."'", 2) end @@ -26,7 +31,7 @@ mt.__newindex = function (t, n, v) end mt.__index = function (t, n) - if not mt.__declared[n] and debug.getinfo(2, "S").what ~= "C" then + if not mt.__declared[n] and what() ~= "C" then error("variable '"..n.."' is not declared", 2) end return rawget(t, n) diff --git a/src/Makefile b/src/Makefile index 0708ac479f..cd7f6ba2ab 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,7 @@ MYLIBS= # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= -PLATS= aix ansi bsd generic linux macosx mingw posix solaris +PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ @@ -77,7 +77,8 @@ echo: # convenience targets for popular platforms none: - @echo "Please choose a platform: $(PLATS)" + @echo "Please choose a platform:" + @echo " $(PLATS)" aix: $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" @@ -88,6 +89,9 @@ ansi: bsd: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" +freebsd: + $(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" + generic: $(MAKE) all MYCFLAGS= @@ -103,6 +107,7 @@ mingw: $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe + $(MAKE) "LUAC_T=luac.exe" luac.exe posix: $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX diff --git a/src/luaconf.h b/src/luaconf.h index f32f1f76af..8be8338f36 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.82 2006/04/10 18:27:23 roberto Exp $ +** $Id: luaconf.h,v 1.82a 2006/04/10 18:27:23 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -360,7 +360,7 @@ /* @@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' @* behavior. -** CHANGE it to undefined as soon as you replace to 'luaL_registry' +** CHANGE it to undefined as soon as you replace to 'luaL_register' ** your uses of 'luaL_openlib' */ #define LUA_COMPAT_OPENLIB diff --git a/src/lvm.c b/src/lvm.c index 1e3ea4c89b..35b9218152 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.63 2006/06/05 15:58:59 roberto Exp $ +** $Id: lvm.c,v 2.63a 2006/06/05 15:58:59 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -281,10 +281,12 @@ void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!tostring(L, top-2) || !tostring(L, top-1)) { + if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ + } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ + tostring(L, top - 2); /* result is first op (as string) */ + else { /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; From d368f86a9d2a03bd5c3c0fae7f626ea8e2e6dc59 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Mon, 26 Mar 2007 12:00:00 +0000 Subject: [PATCH 37/97] Lua 5.1.2-rc3 --- COPYRIGHT | 2 +- HISTORY | 2 +- INSTALL | 9 ++++++--- doc/manual.html | 10 +++++----- src/loadlib.c | 27 ++++++++++++++------------- src/lvm.c | 4 ++-- src/print.c | 3 +-- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 84d401b1e4..a54a16eec2 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 1994-2006 Lua.org, PUC-Rio. +Copyright (C) 1994-2007 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/HISTORY b/HISTORY index d807a53383..ce0c95bc69 100644 --- a/HISTORY +++ b/HISTORY @@ -14,7 +14,7 @@ HISTORY for Lua 5.1 API: + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + user supplies memory allocator (lua_open becomes lua_newstate). - + luaopen_* functionst must be called through Lua. + + luaopen_* functions must be called through Lua. Implementation: + new configuration scheme via luaconf.h. + incremental garbage collection. diff --git a/INSTALL b/INSTALL index 65f6f1eb07..17eb8aee8c 100644 --- a/INSTALL +++ b/INSTALL @@ -8,7 +8,10 @@ INSTALL for Lua 5.1 Building Lua on Unix systems should be very easy. First do "make" and see if your platform is listed. If so, just do "make xxx", where xxx is your platform name. The platforms currently supported are: - ansi bsd generic linux macosx mingw posix solaris + aix ansi bsd freebsd generic linux macosx mingw posix solaris + + If your platform is not listed, try the closest one or posix, generic, + ansi, in this order. See below for customization instructions and for instructions on how to build with other Windows compilers. @@ -81,8 +84,8 @@ INSTALL for Lua 5.1 compiler: library, luac.c print.c - If you use Visual Studio .NET, you can use etc/luavs.bat - in its "Command Prompt". + If you use Visual Studio .NET, you can use etc/luavs.bat in its + "Command Prompt". If all you want is to build the Lua interpreter, you may put all .c files in a single project, except for luac.c and print.c. Or just use etc/all.c. diff --git a/doc/manual.html b/doc/manual.html index 6203f824b6..6b137ff6e6 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -890,8 +890,8 @@

    2.5 - Expressions

    function calls are explained in §2.5.8; table constructors are explained in §2.5.7. Vararg expressions, -denoted by three dots ('...'), can only be used inside -vararg functions; +denoted by three dots ('...'), can only be used when +directly inside a vararg function; they are explained in §2.5.9. @@ -3222,7 +3222,7 @@

    3.7 - Functions and Types

    -Userdata represents C values in Lua. +Userdata represent C values in Lua. A full userdata represents a block of memory. It is an object (like a table): you must create it, it can have its own metatable, @@ -3498,7 +3498,7 @@

    3.7 - Functions and Types

    -Userdata represents C values in Lua. +Userdata represent C values in Lua. A light userdata represents a pointer. It is a value (like a number): you do not create it, it has no individual metatable, @@ -8511,7 +8511,7 @@

    8 - The Complete Syntax of Lua


    Last update: -Fri Mar 23 14:37:09 BRT 2007 +Mon Mar 26 12:59:26 BRT 2007 diff --git a/doc/manual.css b/doc/manual.css index 93f1ab2dc8..eed5afd9ee 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -5,3 +5,9 @@ h3 code { pre { font-size: 105% ; } + +span.apii { + float: right ; + font-family: inherit ; +} + diff --git a/doc/manual.html b/doc/manual.html index 6b137ff6e6..4df4d4beee 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -18,7 +18,7 @@

    by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    -Copyright © 2006-2007 Lua.org, PUC-Rio. +Copyright © 2006-2008 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -32,6 +32,7 @@

    + @@ -554,9 +555,9 @@

    2.4.3 - Assignment

    The elements in both lists are separated by commas:
    -	stat ::= varlist1 `=´ explist1
    -	varlist1 ::= var {`,´ var}
    -	explist1 ::= exp {`,´ exp}
    +	stat ::= varlist `=´ explist
    +	varlist ::= var {`,´ var}
    +	explist ::= exp {`,´ exp}
     

    Expressions are discussed in §2.5. @@ -663,7 +664,7 @@

    2.4.4 - Control Structures

    so the syntax for the return statement is

    -	stat ::= return [explist1]
    +	stat ::= return [explist]
     

    @@ -771,7 +772,7 @@

    2.4.5 - For Statement

    The generic for loop has the following syntax:
    -	stat ::= for namelist in explist1 do block end
    +	stat ::= for namelist in explist do block end
     	namelist ::= Name {`,´ Name}
     

    A for statement like @@ -843,7 +844,7 @@

    2.4.7 - Local Declarations

    The declaration may include an initial assignment:

    -	stat ::= local namelist [`=´ explist1]
    +	stat ::= local namelist [`=´ explist]
     

    If present, an initial assignment has the same semantics of a multiple assignment (see §2.4.3). @@ -1221,7 +1222,7 @@

    2.5.8 - Function Calls

    Arguments have the following syntax:

    -	args ::= `(´ [explist1] `)´
    +	args ::= `(´ [explist] `)´
     	args ::= tableconstructor
     	args ::= String
     

    @@ -1286,7 +1287,7 @@

    2.5.9 - Function Definitions

     	function ::= function funcbody
    -	funcbody ::= `(´ [parlist1] `)´ block end
    +	funcbody ::= `(´ [parlist] `)´ block end
     

    @@ -1355,7 +1356,7 @@

    2.5.9 - Function Definitions

    initialized with the argument values:
    -	parlist1 ::= namelist [`,´ `...´] | `...´
    +	parlist ::= namelist [`,´ `...´] | `...´
     

    When a function is called, the list of arguments is adjusted to @@ -1551,11 +1552,11 @@

    2.8 - Metatables

    -Tables and userdata have individual metatables +Tables and full userdata have individual metatables (although multiple tables and userdata can share their metatables); values of all other types share one single metatable per type. So, there is one single metatable for all numbers, -and for all strings, etc. +one for all strings, etc.

    @@ -1638,7 +1639,7 @@

    2.8 - Metatables

    local h = getbinhandler(op1, op2, "__add") if h then -- call the handler with both operands - return h(op1, op2) + return (h(op1, op2)) else -- no handler available: default behavior error(···) end @@ -1695,7 +1696,7 @@

    2.8 - Metatables

    local h = metatable(op).__unm if h then -- call the handler with the operand - return h(op) + return (h(op)) else -- no handler available: default behavior error(···) end @@ -1716,7 +1717,7 @@

    2.8 - Metatables

    else local h = getbinhandler(op1, op2, "__concat") if h then - return h(op1, op2) + return (h(op1, op2)) else error(···) end @@ -1739,7 +1740,7 @@

    2.8 - Metatables

    local h = metatable(op).__len if h then -- call the handler with the operand - return h(op) + return (h(op)) else -- no handler available: default behavior error(···) end @@ -1779,7 +1780,7 @@

    2.8 - Metatables

    -- try metamethod local h = getcomphandler(op1, op2, "__eq") if h then - return h(op1, op2) + return (h(op1, op2)) else return false end @@ -1801,7 +1802,7 @@

    2.8 - Metatables

    else local h = getcomphandler(op1, op2, "__lt") if h then - return h(op1, op2) + return (h(op1, op2)) else error(···); end @@ -1824,7 +1825,7 @@

    2.8 - Metatables

    else local h = getcomphandler(op1, op2, "__le") if h then - return h(op1, op2) + return (h(op1, op2)) else h = getcomphandler(op1, op2, "__lt") if h then @@ -1861,8 +1862,8 @@

    2.8 - Metatables

    end end if type(h) == "function" then - return h(table, key) -- call the handler - else return h[key] -- or repeat operation on it + return (h(table, key)) -- call the handler + else return h[key] -- or repeat operation on it end end

    @@ -1887,7 +1888,7 @@

    2.8 - Metatables

    end end if type(h) == "function" then - return h(table, key,value) -- call the handler + h(table, key,value) -- call the handler else h[key] = value -- or repeat operation on it end end @@ -2062,6 +2063,7 @@

    2.10.1 - Garbage-Collection Metamethods

    among those collected in that cycle. That is, the first finalizer to be called is the one associated with the userdata created last in the program. +The userdata itself is freed only in the next garbage-collection cycle. @@ -2427,17 +2429,14 @@

    3.6 - Error Handling in C

    -Almost any function in the API may raise an error, +Most functions in the API may throw an error, for instance due to a memory allocation error. -The following functions run in protected mode -(that is, they create a protected environment to run), -so they never raise an error: -lua_newstate, lua_close, lua_load, -lua_pcall, and lua_cpcall. +The documentation for each function indicates whether +it can throw errors.

    -Inside a C function you can raise an error by calling lua_error. +Inside a C function you can throw an error by calling lua_error. @@ -2448,6 +2447,30 @@

    3.7 - Functions and Types

    Here we list all functions and types from the C API in alphabetical order. +Each function has an indicator like this: +[-o, +p, x] + + +

    +The first field, o, +is how many elements the function pops from the stack. +The second field, p, +is how many elements the function pushes onto the stack. +(Any function always pushes its results after popping its arguments.) +A field in the form x|y means the function may push (or pop) +x or y elements, +depending on the situation; +an interrogation mark '?' means that +we cannot know how many elements the function pops/pushes +by looking only at its arguments +(e.g., they may depend on what is on the stack). +The third field, x, +tells whether the function may throw errors: +'-' means the function never throws any error; +'m' means the function may throw an error +only due to not enough memory; +'e' means the function may throw other kinds of errors; +'v' means the function may throw an error on purpose. @@ -2506,7 +2529,8 @@

    3.7 - Functions and Types

    -

    lua_atpanic

    +

    lua_atpanic

    +[-0, +0, -]

    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

    @@ -2529,7 +2553,8 @@

    3.7 - Functions and Types

    -

    lua_call

    +

    lua_call

    +[-(nargs + 1), +nresults, e]

    void lua_call (lua_State *L, int nargs, int nresults);

    @@ -2639,7 +2664,8 @@

    3.7 - Functions and Types

    -

    lua_checkstack

    +

    lua_checkstack

    +[-0, +0, -]

    int lua_checkstack (lua_State *L, int extra);

    @@ -2653,7 +2679,8 @@

    3.7 - Functions and Types

    -

    lua_close

    +

    lua_close

    +[-0, +0, -]

    void lua_close (lua_State *L);

    @@ -2671,23 +2698,25 @@

    3.7 - Functions and Types

    -

    lua_concat

    +

    lua_concat

    +[-n, +1, e]

    void lua_concat (lua_State *L, int n);

    Concatenates the n values at the top of the stack, pops them, and leaves the result at the top. -If n is 1, the result is the single string on the stack +If n is 1, the result is the single value on the stack (that is, the function does nothing); if n is 0, the result is the empty string. -Concatenation is done following the usual semantics of Lua +Concatenation is performed following the usual semantics of Lua (see §2.5.4). -


    lua_cpcall

    +

    lua_cpcall

    +[-0, +(0|1), -]

    int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);

    @@ -2704,7 +2733,8 @@

    3.7 - Functions and Types

    -

    lua_createtable

    +

    lua_createtable

    +[-0, +1, m]

    void lua_createtable (lua_State *L, int narr, int nrec);

    @@ -2719,7 +2749,8 @@

    3.7 - Functions and Types

    -

    lua_dump

    +

    lua_dump

    +[-0, +0, m]

    int lua_dump (lua_State *L, lua_Writer writer, void *data);

    @@ -2747,7 +2778,8 @@

    3.7 - Functions and Types

    -

    lua_equal

    +

    lua_equal

    +[-0, +0, e]

    int lua_equal (lua_State *L, int index1, int index2);

    @@ -2762,7 +2794,8 @@

    3.7 - Functions and Types

    -

    lua_error

    +

    lua_error

    +[-1, +0, v]

    int lua_error (lua_State *L);

    @@ -2777,7 +2810,8 @@

    3.7 - Functions and Types

    -

    lua_gc

    +

    lua_gc

    +[-0, +0, e]

    int lua_gc (lua_State *L, int what, int data);

    @@ -2838,7 +2872,8 @@

    3.7 - Functions and Types

    -

    lua_getallocf

    +

    lua_getallocf

    +[-0, +0, -]

    lua_Alloc lua_getallocf (lua_State *L, void **ud);

    @@ -2850,7 +2885,8 @@

    3.7 - Functions and Types

    -

    lua_getfenv

    +

    lua_getfenv

    +[-0, +1, -]

    void lua_getfenv (lua_State *L, int index);

    @@ -2861,12 +2897,13 @@

    3.7 - Functions and Types

    -

    lua_getfield

    +

    lua_getfield

    +[-0, +1, e]

    void lua_getfield (lua_State *L, int index, const char *k);

    Pushes onto the stack the value t[k], -where t is the value at the given valid index index. +where t is the value at the given valid index. As in Lua, this function may trigger a metamethod for the "index" event (see §2.8). @@ -2874,7 +2911,8 @@

    3.7 - Functions and Types

    -

    lua_getglobal

    +

    lua_getglobal

    +[-0, +1, e]

    void lua_getglobal (lua_State *L, const char *name);

    @@ -2888,7 +2926,8 @@

    3.7 - Functions and Types

    -

    lua_getmetatable

    +

    lua_getmetatable

    +[-0, +(0|1), -]

    int lua_getmetatable (lua_State *L, int index);

    @@ -2902,12 +2941,13 @@

    3.7 - Functions and Types

    -

    lua_gettable

    +

    lua_gettable

    +[-1, +1, e]

    void lua_gettable (lua_State *L, int index);

    Pushes onto the stack the value t[k], -where t is the value at the given valid index index +where t is the value at the given valid index and k is the value at the top of the stack. @@ -2921,7 +2961,8 @@

    3.7 - Functions and Types

    -

    lua_gettop

    +

    lua_gettop

    +[-0, +0, -]

    int lua_gettop (lua_State *L);

    @@ -2934,7 +2975,8 @@

    3.7 - Functions and Types

    -

    lua_insert

    +

    lua_insert

    +[-1, +1, -]

    void lua_insert (lua_State *L, int index);

    @@ -2963,7 +3005,8 @@

    3.7 - Functions and Types

    -

    lua_isboolean

    +

    lua_isboolean

    +[-0, +0, -]

    int lua_isboolean (lua_State *L, int index);

    @@ -2974,7 +3017,8 @@

    3.7 - Functions and Types

    -

    lua_iscfunction

    +

    lua_iscfunction

    +[-0, +0, -]

    int lua_iscfunction (lua_State *L, int index);

    @@ -2985,7 +3029,8 @@

    3.7 - Functions and Types

    -

    lua_isfunction

    +

    lua_isfunction

    +[-0, +0, -]

    int lua_isfunction (lua_State *L, int index);

    @@ -2996,7 +3041,8 @@

    3.7 - Functions and Types

    -

    lua_islightuserdata

    +

    lua_islightuserdata

    +[-0, +0, -]

    int lua_islightuserdata (lua_State *L, int index);

    @@ -3007,7 +3053,8 @@

    3.7 - Functions and Types

    -

    lua_isnil

    +

    lua_isnil

    +[-0, +0, -]

    int lua_isnil (lua_State *L, int index);

    @@ -3018,11 +3065,12 @@

    3.7 - Functions and Types

    -

    lua_isnone

    +

    lua_isnone

    +[-0, +0, -]

    int lua_isnone (lua_State *L, int index);

    -Returns 1 if the the given acceptable index is not valid +Returns 1 if the given acceptable index is not valid (that is, it refers to an element outside the current stack), and 0 otherwise. @@ -3030,11 +3078,12 @@

    3.7 - Functions and Types

    -

    lua_isnoneornil

    +

    lua_isnoneornil

    +[-0, +0, -]

    int lua_isnoneornil (lua_State *L, int index);

    -Returns 1 if the the given acceptable index is not valid +Returns 1 if the given acceptable index is not valid (that is, it refers to an element outside the current stack) or if the value at this index is nil, and 0 otherwise. @@ -3043,7 +3092,8 @@

    3.7 - Functions and Types

    -

    lua_isnumber

    +

    lua_isnumber

    +[-0, +0, -]

    int lua_isnumber (lua_State *L, int index);

    @@ -3055,7 +3105,8 @@

    3.7 - Functions and Types

    -

    lua_isstring

    +

    lua_isstring

    +[-0, +0, m]

    int lua_isstring (lua_State *L, int index);

    @@ -3067,7 +3118,8 @@

    3.7 - Functions and Types

    -

    lua_istable

    +

    lua_istable

    +[-0, +0, -]

    int lua_istable (lua_State *L, int index);

    @@ -3078,7 +3130,8 @@

    3.7 - Functions and Types

    -

    lua_isthread

    +

    lua_isthread

    +[-0, +0, -]

    int lua_isthread (lua_State *L, int index);

    @@ -3089,7 +3142,8 @@

    3.7 - Functions and Types

    -

    lua_isuserdata

    +

    lua_isuserdata

    +[-0, +0, -]

    int lua_isuserdata (lua_State *L, int index);

    @@ -3100,7 +3154,8 @@

    3.7 - Functions and Types

    -

    lua_lessthan

    +

    lua_lessthan

    +[-0, +0, e]

    int lua_lessthan (lua_State *L, int index1, int index2);

    @@ -3115,7 +3170,8 @@

    3.7 - Functions and Types

    -

    lua_load

    +

    lua_load

    +[-0, +1, -]

    int lua_load (lua_State *L,
                   lua_Reader reader,
                   void *data,
    @@ -3165,7 +3221,8 @@ 

    3.7 - Functions and Types

    -

    lua_newstate

    +

    lua_newstate

    +[-0, +0, -]

    lua_State *lua_newstate (lua_Alloc f, void *ud);

    @@ -3181,7 +3238,8 @@

    3.7 - Functions and Types

    -

    lua_newtable

    +

    lua_newtable

    +[-0, +1, m]

    void lua_newtable (lua_State *L);

    @@ -3192,7 +3250,8 @@

    3.7 - Functions and Types

    -

    lua_newthread

    +

    lua_newthread

    +[-0, +1, m]

    lua_State *lua_newthread (lua_State *L);

    @@ -3212,7 +3271,8 @@

    3.7 - Functions and Types

    -

    lua_newuserdata

    +

    lua_newuserdata

    +[-0, +1, m]

    void *lua_newuserdata (lua_State *L, size_t size);

    @@ -3240,7 +3300,8 @@

    3.7 - Functions and Types

    -

    lua_next

    +

    lua_next

    +[-1, +(2|0), e]

    int lua_next (lua_State *L, int index);

    @@ -3295,7 +3356,8 @@

    3.7 - Functions and Types

    -

    lua_objlen

    +

    lua_objlen

    +[-0, +0, -]

    size_t lua_objlen (lua_State *L, int index);

    @@ -3310,7 +3372,8 @@

    3.7 - Functions and Types

    -

    lua_pcall

    +

    lua_pcall

    +[-(nargs + 1), +(nresults|1), -]

    int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

    @@ -3375,7 +3438,8 @@

    3.7 - Functions and Types

    -

    lua_pop

    +

    lua_pop

    +[-n, +0, -]

    void lua_pop (lua_State *L, int n);

    @@ -3385,7 +3449,8 @@

    3.7 - Functions and Types

    -

    lua_pushboolean

    +

    lua_pushboolean

    +[-0, +1, -]

    void lua_pushboolean (lua_State *L, int b);

    @@ -3395,7 +3460,8 @@

    3.7 - Functions and Types

    -

    lua_pushcclosure

    +

    lua_pushcclosure

    +[-n, +1, m]

    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

    @@ -3420,7 +3486,8 @@

    3.7 - Functions and Types

    -

    lua_pushcfunction

    +

    lua_pushcfunction

    +[-0, +1, m]

    void lua_pushcfunction (lua_State *L, lua_CFunction f);

    @@ -3446,7 +3513,8 @@

    3.7 - Functions and Types

    -

    lua_pushfstring

    +

    lua_pushfstring

    +[-0, +1, m]

    const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

    @@ -3480,7 +3548,8 @@

    3.7 - Functions and Types

    -

    lua_pushinteger

    +

    lua_pushinteger

    +[-0, +1, -]

    void lua_pushinteger (lua_State *L, lua_Integer n);

    @@ -3490,7 +3559,8 @@

    3.7 - Functions and Types

    -

    lua_pushlightuserdata

    +

    lua_pushlightuserdata

    +[-0, +1, -]

    void lua_pushlightuserdata (lua_State *L, void *p);

    @@ -3510,7 +3580,8 @@

    3.7 - Functions and Types

    -

    lua_pushlstring

    +

    lua_pushlstring

    +[-0, +1, m]

    void lua_pushlstring (lua_State *L, const char *s, size_t len);

    @@ -3525,7 +3596,8 @@

    3.7 - Functions and Types

    -

    lua_pushnil

    +

    lua_pushnil

    +[-0, +1, -]

    void lua_pushnil (lua_State *L);

    @@ -3535,7 +3607,8 @@

    3.7 - Functions and Types

    -

    lua_pushnumber

    +

    lua_pushnumber

    +[-0, +1, -]

    void lua_pushnumber (lua_State *L, lua_Number n);

    @@ -3545,7 +3618,8 @@

    3.7 - Functions and Types

    -

    lua_pushstring

    +

    lua_pushstring

    +[-0, +1, m]

    void lua_pushstring (lua_State *L, const char *s);

    @@ -3561,7 +3635,8 @@

    3.7 - Functions and Types

    -

    lua_pushthread

    +

    lua_pushthread

    +[-0, +1, -]

    int lua_pushthread (lua_State *L);

    @@ -3572,7 +3647,8 @@

    3.7 - Functions and Types

    -

    lua_pushvalue

    +

    lua_pushvalue

    +[-0, +1, -]

    void lua_pushvalue (lua_State *L, int index);

    @@ -3583,7 +3659,8 @@

    3.7 - Functions and Types

    -

    lua_pushvfstring

    +

    lua_pushvfstring

    +[-0, +1, m]

    const char *lua_pushvfstring (lua_State *L,
                                   const char *fmt,
                                   va_list argp);
    @@ -3596,7 +3673,8 @@

    3.7 - Functions and Types

    -

    lua_rawequal

    +

    lua_rawequal

    +[-0, +0, -]

    int lua_rawequal (lua_State *L, int index1, int index2);

    @@ -3610,7 +3688,8 @@

    3.7 - Functions and Types

    -

    lua_rawget

    +

    lua_rawget

    +[-1, +1, -]

    void lua_rawget (lua_State *L, int index);

    @@ -3621,12 +3700,13 @@

    3.7 - Functions and Types

    -

    lua_rawgeti

    +

    lua_rawgeti

    +[-0, +1, -]

    void lua_rawgeti (lua_State *L, int index, int n);

    Pushes onto the stack the value t[n], -where t is the value at the given valid index index. +where t is the value at the given valid index. The access is raw; that is, it does not invoke metamethods. @@ -3634,7 +3714,8 @@

    3.7 - Functions and Types

    -

    lua_rawset

    +

    lua_rawset

    +[-2, +0, m]

    void lua_rawset (lua_State *L, int index);

    @@ -3645,13 +3726,14 @@

    3.7 - Functions and Types

    -

    lua_rawseti

    +

    lua_rawseti

    +[-1, +0, m]

    void lua_rawseti (lua_State *L, int index, int n);

    Does the equivalent of t[n] = v, -where t is the value at the given valid index index -and v is the value at the top of the stack, +where t is the value at the given valid index +and v is the value at the top of the stack.

    @@ -3684,7 +3766,8 @@

    3.7 - Functions and Types

    -

    lua_register

    +

    lua_register

    +[-0, +0, m]

    void lua_register (lua_State *L,
                        const char *name,
                        lua_CFunction f);
    @@ -3701,7 +3784,8 @@

    3.7 - Functions and Types

    -

    lua_remove

    +

    lua_remove

    +[-1, +0, -]

    void lua_remove (lua_State *L, int index);

    @@ -3714,7 +3798,8 @@

    3.7 - Functions and Types

    -

    lua_replace

    +

    lua_replace

    +[-1, +0, -]

    void lua_replace (lua_State *L, int index);

    @@ -3726,7 +3811,8 @@

    3.7 - Functions and Types

    -

    lua_resume

    +

    lua_resume

    +[-?, +?, -]

    int lua_resume (lua_State *L, int narg);

    @@ -3759,7 +3845,8 @@

    3.7 - Functions and Types

    -

    lua_setallocf

    +

    lua_setallocf

    +[-0, +0, -]

    void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

    @@ -3770,7 +3857,8 @@

    3.7 - Functions and Types

    -

    lua_setfenv

    +

    lua_setfenv

    +[-1, +0, -]

    int lua_setfenv (lua_State *L, int index);

    @@ -3785,13 +3873,14 @@

    3.7 - Functions and Types

    -

    lua_setfield

    +

    lua_setfield

    +[-1, +0, e]

    void lua_setfield (lua_State *L, int index, const char *k);

    Does the equivalent to t[k] = v, -where t is the value at the given valid index index -and v is the value at the top of the stack, +where t is the value at the given valid index +and v is the value at the top of the stack.

    @@ -3803,7 +3892,8 @@

    3.7 - Functions and Types

    -

    lua_setglobal

    +

    lua_setglobal

    +[-1, +0, e]

    void lua_setglobal (lua_State *L, const char *name);

    @@ -3818,7 +3908,8 @@

    3.7 - Functions and Types

    -

    lua_setmetatable

    +

    lua_setmetatable

    +[-1, +0, -]

    int lua_setmetatable (lua_State *L, int index);

    @@ -3830,12 +3921,13 @@

    3.7 - Functions and Types

    -

    lua_settable

    +

    lua_settable

    +[-2, +0, e]

    void lua_settable (lua_State *L, int index);

    Does the equivalent to t[k] = v, -where t is the value at the given valid index index, +where t is the value at the given valid index, v is the value at the top of the stack, and k is the value just below the top. @@ -3849,7 +3941,8 @@

    3.7 - Functions and Types

    -

    lua_settop

    +

    lua_settop

    +[-?, +?, -]

    void lua_settop (lua_State *L, int index);

    @@ -3882,7 +3975,8 @@

    3.7 - Functions and Types

    -

    lua_status

    +

    lua_status

    +[-0, +0, -]

    int lua_status (lua_State *L);

    @@ -3898,7 +3992,8 @@

    3.7 - Functions and Types

    -

    lua_toboolean

    +

    lua_toboolean

    +[-0, +0, -]

    int lua_toboolean (lua_State *L, int index);

    @@ -3916,7 +4011,8 @@

    3.7 - Functions and Types

    -

    lua_tocfunction

    +

    lua_tocfunction

    +[-0, +0, -]

    lua_CFunction lua_tocfunction (lua_State *L, int index);

    @@ -3928,8 +4024,9 @@

    3.7 - Functions and Types

    -

    lua_tointeger

    -
    lua_Integer lua_tointeger (lua_State *L, int idx);
    +

    lua_tointeger

    +[-0, +0, -] +

    lua_Integer lua_tointeger (lua_State *L, int index);

    Converts the Lua value at the given acceptable index @@ -3947,7 +4044,8 @@

    3.7 - Functions and Types

    -

    lua_tolstring

    +

    lua_tolstring

    +[-0, +0, m]

    const char *lua_tolstring (lua_State *L, int index, size_t *len);

    @@ -3977,7 +4075,8 @@

    3.7 - Functions and Types

    -

    lua_tonumber

    +

    lua_tonumber

    +[-0, +0, -]

    lua_Number lua_tonumber (lua_State *L, int index);

    @@ -3991,7 +4090,8 @@

    3.7 - Functions and Types

    -

    lua_topointer

    +

    lua_topointer

    +[-0, +0, -]

    const void *lua_topointer (lua_State *L, int index);

    @@ -4010,7 +4110,8 @@

    3.7 - Functions and Types

    -

    lua_tostring

    +

    lua_tostring

    +[-0, +0, m]

    const char *lua_tostring (lua_State *L, int index);

    @@ -4020,7 +4121,8 @@

    3.7 - Functions and Types

    -

    lua_tothread

    +

    lua_tothread

    +[-0, +0, -]

    lua_State *lua_tothread (lua_State *L, int index);

    @@ -4033,7 +4135,8 @@

    3.7 - Functions and Types

    -

    lua_touserdata

    +

    lua_touserdata

    +[-0, +0, -]

    void *lua_touserdata (lua_State *L, int index);

    @@ -4047,7 +4150,8 @@

    3.7 - Functions and Types

    -

    lua_type

    +

    lua_type

    +[-0, +0, -]

    int lua_type (lua_State *L, int index);

    @@ -4071,7 +4175,8 @@

    3.7 - Functions and Types

    -

    lua_typename

    +

    lua_typename

    +[-0, +0, -]

    const char *lua_typename  (lua_State *L, int tp);

    @@ -4089,7 +4194,7 @@

    3.7 - Functions and Types

    void* ud);

    -The writer function used by lua_dump. +The type of the writer function used by lua_dump. Every time it produces another piece of chunk, lua_dump calls the writer, passing along the buffer to be written (p), @@ -4107,7 +4212,8 @@

    3.7 - Functions and Types

    -

    lua_xmove

    +

    lua_xmove

    +[-?, +?, -]

    void lua_xmove (lua_State *from, lua_State *to, int n);

    @@ -4122,7 +4228,8 @@

    3.7 - Functions and Types

    -

    lua_yield

    +

    lua_yield

    +[-?, +?, -]

    int lua_yield  (lua_State *L, int nresults);

    @@ -4254,7 +4361,8 @@

    3.8 - The Debug Interface

    -

    lua_gethook

    +

    lua_gethook

    +[-0, +0, -]

    lua_Hook lua_gethook (lua_State *L);

    @@ -4264,7 +4372,8 @@

    3.8 - The Debug Interface

    -

    lua_gethookcount

    +

    lua_gethookcount

    +[-0, +0, -]

    int lua_gethookcount (lua_State *L);

    @@ -4274,7 +4383,8 @@

    3.8 - The Debug Interface

    -

    lua_gethookmask

    +

    lua_gethookmask

    +[-0, +0, -]

    int lua_gethookmask (lua_State *L);

    @@ -4284,7 +4394,8 @@

    3.8 - The Debug Interface

    -

    lua_getinfo

    +

    lua_getinfo

    +[-(0|1), +(0|1|2), -]

    int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

    @@ -4357,7 +4468,8 @@

    3.8 - The Debug Interface

    -

    lua_getlocal

    +

    lua_getlocal

    +[-0, +(0|1), -]

    const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);

    @@ -4387,7 +4499,8 @@

    3.8 - The Debug Interface

    -

    lua_getstack

    +

    lua_getstack

    +[-0, +0, -]

    int lua_getstack (lua_State *L, int level, lua_Debug *ar);

    @@ -4408,7 +4521,8 @@

    3.8 - The Debug Interface

    -

    lua_getupvalue

    +

    lua_getupvalue

    +[-0, +(0|1), -]

    const char *lua_getupvalue (lua_State *L, int funcindex, int n);

    @@ -4468,7 +4582,8 @@

    3.8 - The Debug Interface

    -

    lua_sethook

    +

    lua_sethook

    +[-0, +0, -]

    int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

    @@ -4519,7 +4634,8 @@

    3.8 - The Debug Interface

    -

    lua_setlocal

    +

    lua_setlocal

    +[-(0|1), +0, -]

    const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);

    @@ -4540,7 +4656,8 @@

    3.8 - The Debug Interface

    -

    lua_setupvalue

    +

    lua_setupvalue

    +[-(0|1), +0, -]

    const char *lua_setupvalue (lua_State *L, int funcindex, int n);

    @@ -4590,7 +4707,7 @@

    4 - The Auxiliary Library

    Several functions in the auxiliary library are used to check C function arguments. Their names are always luaL_check* or luaL_opt*. -All of these functions raise an error if the check is not satisfied. +All of these functions throw an error if the check is not satisfied. Because the error message is formatted for arguments (e.g., "bad argument #1"), you should not use these functions for other stack values. @@ -4605,7 +4722,8 @@

    4.1 - Functions and Types

    -

    luaL_addchar

    +

    luaL_addchar

    +[-0, +0, m]

    void luaL_addchar (luaL_Buffer *B, char c);

    @@ -4616,7 +4734,8 @@

    4.1 - Functions and Types

    -

    luaL_addlstring

    +

    luaL_addlstring

    +[-0, +0, m]

    void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

    @@ -4629,7 +4748,8 @@

    4.1 - Functions and Types

    -

    luaL_addsize

    +

    luaL_addsize

    +[-0, +0, m]

    void luaL_addsize (luaL_Buffer *B, size_t n);

    @@ -4641,7 +4761,8 @@

    4.1 - Functions and Types

    -

    luaL_addstring

    +

    luaL_addstring

    +[-0, +0, m]

    void luaL_addstring (luaL_Buffer *B, const char *s);

    @@ -4654,7 +4775,8 @@

    4.1 - Functions and Types

    -

    luaL_addvalue

    +

    luaL_addvalue

    +[-1, +0, m]

    void luaL_addvalue (luaL_Buffer *B);

    @@ -4673,7 +4795,8 @@

    4.1 - Functions and Types

    -

    luaL_argcheck

    +

    luaL_argcheck

    +[-0, +0, v]

    void luaL_argcheck (lua_State *L,
                         int cond,
                         int narg,
    @@ -4691,7 +4814,8 @@ 

    4.1 - Functions and Types

    -

    luaL_argerror

    +

    luaL_argerror

    +[-0, +0, v]

    int luaL_argerror (lua_State *L, int narg, const char *extramsg);

    @@ -4760,7 +4884,8 @@

    4.1 - Functions and Types

    -

    luaL_buffinit

    +

    luaL_buffinit

    +[-0, +0, -]

    void luaL_buffinit (lua_State *L, luaL_Buffer *B);

    @@ -4773,7 +4898,8 @@

    4.1 - Functions and Types

    -

    luaL_callmeta

    +

    luaL_callmeta

    +[-0, +(0|1), e]

    int luaL_callmeta (lua_State *L, int obj, const char *e);

    @@ -4793,7 +4919,8 @@

    4.1 - Functions and Types

    -

    luaL_checkany

    +

    luaL_checkany

    +[-0, +0, v]

    void luaL_checkany (lua_State *L, int narg);

    @@ -4804,7 +4931,8 @@

    4.1 - Functions and Types

    -

    luaL_checkint

    +

    luaL_checkint

    +[-0, +0, v]

    int luaL_checkint (lua_State *L, int narg);

    @@ -4815,7 +4943,8 @@

    4.1 - Functions and Types

    -

    luaL_checkinteger

    +

    luaL_checkinteger

    +[-0, +0, v]

    lua_Integer luaL_checkinteger (lua_State *L, int narg);

    @@ -4826,7 +4955,8 @@

    4.1 - Functions and Types

    -

    luaL_checklong

    +

    luaL_checklong

    +[-0, +0, v]

    long luaL_checklong (lua_State *L, int narg);

    @@ -4837,7 +4967,8 @@

    4.1 - Functions and Types

    -

    luaL_checklstring

    +

    luaL_checklstring

    +[-0, +0, v]

    const char *luaL_checklstring (lua_State *L, int narg, size_t *l);

    @@ -4847,10 +4978,16 @@

    4.1 - Functions and Types

    with the string's length. +

    +This function uses lua_tolstring to get its result, +so all conversions and caveats of that function apply here. -


    luaL_checknumber

    + + +

    luaL_checknumber

    +[-0, +0, v]

    lua_Number luaL_checknumber (lua_State *L, int narg);

    @@ -4861,7 +4998,8 @@

    4.1 - Functions and Types

    -

    luaL_checkoption

    +

    luaL_checkoption

    +[-0, +0, v]

    int luaL_checkoption (lua_State *L,
                           int narg,
                           const char *def,
    @@ -4891,7 +5029,8 @@ 

    4.1 - Functions and Types

    -

    luaL_checkstack

    +

    luaL_checkstack

    +[-0, +0, v]

    void luaL_checkstack (lua_State *L, int sz, const char *msg);

    @@ -4903,7 +5042,8 @@

    4.1 - Functions and Types

    -

    luaL_checkstring

    +

    luaL_checkstring

    +[-0, +0, v]

    const char *luaL_checkstring (lua_State *L, int narg);

    @@ -4911,20 +5051,28 @@

    4.1 - Functions and Types

    and returns this string. +

    +This function uses lua_tolstring to get its result, +so all conversions and caveats of that function apply here. + + -


    luaL_checktype

    +

    luaL_checktype

    +[-0, +0, v]

    void luaL_checktype (lua_State *L, int narg, int t);

    Checks whether the function argument narg has type t. +See lua_type for the encoding of types for t. -


    luaL_checkudata

    +

    luaL_checkudata

    +[-0, +0, v]

    void *luaL_checkudata (lua_State *L, int narg, const char *tname);

    @@ -4935,7 +5083,8 @@

    4.1 - Functions and Types

    -

    luaL_dofile

    +

    luaL_dofile

    +[-0, +?, m]

    int luaL_dofile (lua_State *L, const char *filename);

    @@ -4952,7 +5101,8 @@

    4.1 - Functions and Types

    -

    luaL_dostring

    +

    luaL_dostring

    +[-0, +?, m]

    int luaL_dostring (lua_State *L, const char *str);

    @@ -4969,7 +5119,8 @@

    4.1 - Functions and Types

    -

    luaL_error

    +

    luaL_error

    +[-0, +0, v]

    int luaL_error (lua_State *L, const char *fmt, ...);

    @@ -4991,7 +5142,8 @@

    4.1 - Functions and Types

    -

    luaL_getmetafield

    +

    luaL_getmetafield

    +[-0, +(0|1), m]

    int luaL_getmetafield (lua_State *L, int obj, const char *e);

    @@ -5005,7 +5157,8 @@

    4.1 - Functions and Types

    -

    luaL_getmetatable

    +

    luaL_getmetatable

    +[-0, +1, -]

    void luaL_getmetatable (lua_State *L, const char *tname);

    @@ -5016,7 +5169,8 @@

    4.1 - Functions and Types

    -

    luaL_gsub

    +

    luaL_gsub

    +[-0, +1, m]

    const char *luaL_gsub (lua_State *L,
                            const char *s,
                            const char *p,
    @@ -5032,7 +5186,8 @@ 

    4.1 - Functions and Types

    -

    luaL_loadbuffer

    +

    luaL_loadbuffer

    +[-0, +1, m]

    int luaL_loadbuffer (lua_State *L,
                          const char *buff,
                          size_t sz,
    @@ -5053,7 +5208,8 @@ 

    4.1 - Functions and Types

    -

    luaL_loadfile

    +

    luaL_loadfile

    +[-0, +1, m]

    int luaL_loadfile (lua_State *L, const char *filename);

    @@ -5079,7 +5235,8 @@

    4.1 - Functions and Types

    -

    luaL_loadstring

    +

    luaL_loadstring

    +[-0, +1, m]

    int luaL_loadstring (lua_State *L, const char *s);

    @@ -5100,7 +5257,8 @@

    4.1 - Functions and Types

    -

    luaL_newmetatable

    +

    luaL_newmetatable

    +[-0, +1, m]

    int luaL_newmetatable (lua_State *L, const char *tname);

    @@ -5120,7 +5278,8 @@

    4.1 - Functions and Types

    -

    luaL_newstate

    +

    luaL_newstate

    +[-0, +0, -]

    lua_State *luaL_newstate (void);

    @@ -5140,7 +5299,8 @@

    4.1 - Functions and Types

    -

    luaL_openlibs

    +

    luaL_openlibs

    +[-0, +0, m]

    void luaL_openlibs (lua_State *L);

    @@ -5150,7 +5310,8 @@

    4.1 - Functions and Types

    -

    luaL_optint

    +

    luaL_optint

    +[-0, +0, v]

    int luaL_optint (lua_State *L, int narg, int d);

    @@ -5164,7 +5325,8 @@

    4.1 - Functions and Types

    -

    luaL_optinteger

    +

    luaL_optinteger

    +[-0, +0, v]

    lua_Integer luaL_optinteger (lua_State *L,
                                  int narg,
                                  lua_Integer d);
    @@ -5180,7 +5342,8 @@

    4.1 - Functions and Types

    -

    luaL_optlong

    +

    luaL_optlong

    +[-0, +0, v]

    long luaL_optlong (lua_State *L, int narg, long d);

    @@ -5194,7 +5357,8 @@

    4.1 - Functions and Types

    -

    luaL_optlstring

    +

    luaL_optlstring

    +[-0, +0, v]

    const char *luaL_optlstring (lua_State *L,
                                  int narg,
                                  const char *d,
    @@ -5216,7 +5380,8 @@ 

    4.1 - Functions and Types

    -

    luaL_optnumber

    +

    luaL_optnumber

    +[-0, +0, v]

    lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);

    @@ -5230,7 +5395,8 @@

    4.1 - Functions and Types

    -

    luaL_optstring

    +

    luaL_optstring

    +[-0, +0, v]

    const char *luaL_optstring (lua_State *L,
                                 int narg,
                                 const char *d);
    @@ -5246,7 +5412,8 @@

    4.1 - Functions and Types

    -

    luaL_prepbuffer

    +

    luaL_prepbuffer

    +[-0, +0, -]

    char *luaL_prepbuffer (luaL_Buffer *B);

    @@ -5261,7 +5428,8 @@

    4.1 - Functions and Types

    -

    luaL_pushresult

    +

    luaL_pushresult

    +[-?, +1, m]

    void luaL_pushresult (luaL_Buffer *B);

    @@ -5272,7 +5440,8 @@

    4.1 - Functions and Types

    -

    luaL_ref

    +

    luaL_ref

    +[-1, +0, m]

    int luaL_ref (lua_State *L, int t);

    @@ -5318,7 +5487,8 @@

    4.1 - Functions and Types

    -

    luaL_register

    +

    luaL_register

    +[-(0|1), +1, m]

    void luaL_register (lua_State *L,
                         const char *libname,
                         const luaL_Reg *l);
    @@ -5352,17 +5522,19 @@

    4.1 - Functions and Types

    -

    luaL_typename

    -
    const char *luaL_typename (lua_State *L, int idx);
    +

    luaL_typename

    +[-0, +0, -] +

    const char *luaL_typename (lua_State *L, int index);

    -Returns the name of the type of the value at index idx. +Returns the name of the type of the value at the given index. -


    luaL_typerror

    +

    luaL_typerror

    +[-0, +0, v]

    int luaL_typerror (lua_State *L, int narg, const char *tname);

    @@ -5379,7 +5551,8 @@

    4.1 - Functions and Types

    -

    luaL_unref

    +

    luaL_unref

    +[-0, +0, -]

    void luaL_unref (lua_State *L, int t, int ref);

    @@ -5398,7 +5571,8 @@

    4.1 - Functions and Types

    -

    luaL_where

    +

    luaL_where

    +[-0, +1, m]

    void luaL_where (lua_State *L, int lvl);

    @@ -5433,7 +5607,7 @@

    5 - Standard Libraries

    others provide access to "outside" services (e.g., I/O); and others could be implemented in Lua itself, but are quite useful or have critical performance requirements that -deserve an implementation in C (e.g., sort). +deserve an implementation in C (e.g., table.sort).

    @@ -5476,7 +5650,8 @@

    5 - Standard Libraries

    luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), -luaopen_io (for the I/O and the Operating System libraries), +luaopen_io (for the I/O library), +luaopen_os (for the Operating System library), and luaopen_debug (for the debug library). These functions are declared in lualib.h and should not be called directly: @@ -5665,6 +5840,8 @@

    5.1 - Basic Functions

    chunkname is used as the chunk name for error messages and debug information. +When absent, +it defaults to "=(load)". @@ -5698,6 +5875,11 @@

    5.1 - Basic Functions

    assert(loadstring(s))()
    +

    +When absent, +chunkname defaults to the given string. + +

    @@ -6160,7 +6342,15 @@

    5.3 - Modules

    To find a loader, -first require queries package.preload[modname]. +require is guided by the package.loaders array. +By changing this array, +we can change how require looks for a module. +The following explanation is based on the default configuration +for package.loaders. + + +

    +First require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the @@ -6168,38 +6358,7 @@

    5.3 - Modules

    If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, -it tries an all-in-one loader (see below). - - -

    -When loading a C library, -require first uses a dynamic link facility to link the -application with the library. -Then it tries to find a C function inside this library to -be used as the loader. -The name of this C function is the string "luaopen_" -concatenated with a copy of the module name where each dot -is replaced by an underscore. -Moreover, if the module name has a hyphen, -its prefix up to (and including) the first hyphen is removed. -For instance, if the module name is a.v1-b.c, -the function name will be luaopen_b_c. - - -

    -If require finds neither a Lua library nor a -C library for a module, -it calls the all-in-one loader. -This loader searches the C path for a library for -the root name of the given module. -For instance, when requiring a.b.c, -it will search for a C library for a. -If found, it looks into it for an open function for -the submodule; -in our example, that would be luaopen_a_b_c. -With this facility, a package can pack several C submodules -into one single library, -with each submodule keeping its original open function. +it tries an all-in-one loader (see package.loaders).

    @@ -6234,7 +6393,7 @@

    5.3 - Modules

    Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH -(plus another default path defined in luaconf.h). +or a default path defined in luaconf.h. @@ -6254,6 +6413,94 @@

    5.3 - Modules

    +

    +


    package.loaders

    + + +

    +A table used by require to control how to load modules. + + +

    +Each entry in this table is a searcher function. +When looking for a module, +require calls each of these searchers in ascending order, +with the module name (the argument given to require) as its +sole parameter. +The function may return another function (the module loader) +or a string explaining why it did not find that module +(or nil if it has nothing to say). +Lua initializes this table with four functions. + + +

    +The first searcher simply looks for a loader in the +package.preload table. + + +

    +The second searcher looks for a loader as a Lua library, +using the path stored at package.path. +A path is a sequence of templates separated by semicolons. +For each template, +the searcher will change each interrogation +mark in the template by filename, +which is the module name with each dot replaced by a +"directory separator" (such as "/" in Unix); +then it will try to open the resulting file name. +So, for instance, if the Lua path is the string + +

    +     "./?.lua;./?.lc;/usr/local/?/init.lua"
    +

    +the search for a Lua file for module foo +will try to open the files +./foo.lua, ./foo.lc, and +/usr/local/foo/init.lua, in that order. + + +

    +The third searcher looks for a loader as a C library, +using the path given by the variable package.cpath. +For instance, +if the C path is the string + +

    +     "./?.so;./?.dll;/usr/local/?/init.so"
    +

    +the searcher for module foo +will try to open the files ./foo.so, ./foo.dll, +and /usr/local/foo/init.so, in that order. +Once it finds a C library, +this searcher first uses a dynamic link facility to link the +application with the library. +Then it tries to find a C function inside the library to +be used as the loader. +The name of this C function is the string "luaopen_" +concatenated with a copy of the module name where each dot +is replaced by an underscore. +Moreover, if the module name has a hyphen, +its prefix up to (and including) the first hyphen is removed. +For instance, if the module name is a.v1-b.c, +the function name will be luaopen_b_c. + + +

    +The fourth searcher tries an all-in-one loader. +It searches the C path for a library for +the root name of the given module. +For instance, when requiring a.b.c, +it will search for a C library for a. +If found, it looks into it for an open function for +the submodule; +in our example, that would be luaopen_a_b_c. +With this facility, a package can pack several C submodules +into one single library, +with each submodule keeping its original open function. + + + +


    package.loadlib (libname, funcname)

    @@ -6303,24 +6550,6 @@

    5.3 - Modules

    is replaced by the default path. -

    -A path is a sequence of templates separated by semicolons. -For each template, require will change each interrogation -mark in the template by filename, -which is modname with each dot replaced by a -"directory separator" (such as "/" in Unix); -then it will try to load the resulting file name. -So, for instance, if the Lua path is - -

    -     "./?.lua;./?.lc;/usr/local/?/init.lua"
    -

    -the search for a Lua loader for module foo -will try to load the files -./foo.lua, ./foo.lc, and -/usr/local/foo/init.lua, in that order. - -

    @@ -6524,11 +6753,12 @@

    5.4 - String Manipulation


    string.gsub (s, pattern, repl [, n])

    Returns a copy of s -in which all occurrences of the pattern have been +in which all (or the first n, if given) +occurrences of the pattern have been replaced by a replacement string specified by repl, which may be a string, a table, or a function. gsub also returns, as its second value, -the total number of substitutions made. +the total number of matches that occurred.

    @@ -6565,13 +6795,6 @@

    5.4 - String Manipulation

    (that is, the original match is kept in the string). -

    -The optional last parameter n limits -the maximum number of substitutions to occur. -For instance, when n is 1 only the first occurrence of -pattern is replaced. - -

    Here are some examples: @@ -7005,14 +7228,14 @@

    5.6 - Mathematical Functions

    -


    math.atan2 (x, y)

    +

    math.atan2 (y, x)

    -Returns the arc tangent of x/y (in radians), +Returns the arc tangent of y/x (in radians), but uses the signs of both parameters to find the quadrant of the result. -(It also handles correctly the case of y being zero.) +(It also handles correctly the case of x being zero.) @@ -7062,7 +7285,7 @@

    5.6 - Mathematical Functions

    -Returns the the value ex. +Returns the value ex. @@ -7215,13 +7438,13 @@

    5.6 - Mathematical Functions

    When called without arguments, -returns a pseudo-random real number +returns a uniform pseudo-random real number in the range [0,1). -When called with a number m, +When called with an integer number m, math.random returns -a pseudo-random integer in the range [1, m]. -When called with two numbers m and n, -math.random returns a pseudo-random +a uniform pseudo-random integer in the range [1, m]. +When called with two integer numbers m and n, +math.random returns a uniform pseudo-random integer in the range [m, n]. @@ -7316,6 +7539,7 @@

    5.7 - Input and Output Facilities

    The table io also provides three predefined file descriptors with their usual meanings from C: io.stdin, io.stdout, and io.stderr. +The I/O library never closes these files.

    @@ -7829,9 +8053,9 @@

    5.8 - Operating System Facilities

    If locale is the empty string, -the current locate is set to an implementation-defined native locale. -If locate is the string "C", -the current locate is set to the standard C locale. +the current locale is set to an implementation-defined native locale. +If locale is the string "C", +the current locale is set to the standard C locale.

    @@ -7892,7 +8116,7 @@

    5.9 - The Debug Library

    Please resist the temptation to use them as a usual programming tool: they can be very slow. -Moreover, several of its functions +Moreover, several of these functions violate some assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside or @@ -7983,7 +8207,8 @@

    5.9 - The Debug Library

    For instance, the expression debug.getinfo(1,"n").name returns -a name of the current function, if a reasonable name can be found, +a table with a name for the current function, +if a reasonable name can be found, and the expression debug.getinfo(print) returns a table with all available information about the print function. @@ -8070,9 +8295,9 @@

    5.9 - The Debug Library

    with the given meaning:
      -
    • "c": The hook is called every time Lua calls a function;
    • -
    • "r": The hook is called every time Lua returns from a function;
    • -
    • "l": The hook is called every time Lua enters a new line of code.
    • +
    • "c": the hook is called every time Lua calls a function;
    • +
    • "r": the hook is called every time Lua returns from a function;
    • +
    • "l": the hook is called every time Lua enters a new line of code.

    With a count different from zero, the hook is called after every count instructions. @@ -8257,17 +8482,19 @@

    6 - Lua Stand-alone

    Similarly, if the global variable _PROMPT2 contains a string, its value is used as the secondary prompt (issued during incomplete statements). -Therefore, both prompts can be changed directly on the command line. -For instance, +Therefore, both prompts can be changed directly on the command line +or in any Lua programs by assigning to _PROMPT. +See the next example:
          $ lua -e"_PROMPT='myprompt> '" -i
     

    -(the outer pair of quotes is for the shell, -the inner pair is for Lua), -or in any Lua programs by assigning to _PROMPT. -Note the use of -i to enter interactive mode; otherwise, -the program would just end silently right after the assignment to _PROMPT. +(The outer pair of quotes is for the shell, +the inner pair is for Lua.) +Note the use of -i to enter interactive mode; +otherwise, +the program would just end silently +right after the assignment to _PROMPT.

    @@ -8297,7 +8524,7 @@

    6 - Lua Stand-alone

    7 - Incompatibilities with the Previous Version

    -Here we list the incompatibilities that you may found when moving a program +Here we list the incompatibilities that you may find when moving a program from Lua 5.0 to Lua 5.1. You can avoid most of the incompatibilities compiling Lua with appropriate options (see file luaconf.h). @@ -8446,29 +8673,29 @@

    8 - The Complete Syntax of Lua

    block ::= chunk - stat ::= varlist1 `=´ explist1 | + stat ::= varlist `=´ explist | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | for Name `=´ exp `,´ exp [`,´ exp] do block end | - for namelist in explist1 do block end | + for namelist in explist do block end | function funcname funcbody | local function Name funcbody | - local namelist [`=´ explist1] + local namelist [`=´ explist] - laststat ::= return [explist1] | break + laststat ::= return [explist] | break funcname ::= Name {`.´ Name} [`:´ Name] - varlist1 ::= var {`,´ var} + varlist ::= var {`,´ var} var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name namelist ::= Name {`,´ Name} - explist1 ::= {exp `,´} exp + explist ::= {exp `,´} exp exp ::= nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp @@ -8477,13 +8704,13 @@

    8 - The Complete Syntax of Lua

    functioncall ::= prefixexp args | prefixexp `:´ Name args - args ::= `(´ [explist1] `)´ | tableconstructor | String + args ::= `(´ [explist] `)´ | tableconstructor | String function ::= function funcbody - funcbody ::= `(´ [parlist1] `)´ block end + funcbody ::= `(´ [parlist] `)´ block end - parlist1 ::= namelist [`,´ `...´] | `...´ + parlist ::= namelist [`,´ `...´] | `...´ tableconstructor ::= `{´ [fieldlist] `}´ @@ -8508,13 +8735,14 @@

    8 - The Complete Syntax of Lua

    +
    Last update: -Mon Mar 26 12:59:26 BRT 2007 +Thu Jan 17 15:06:18 BRST 2008 diff --git a/doc/readme.html b/doc/readme.html index 28b1d1472e..972faddd97 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -12,7 +12,7 @@

    Documentation

    -This is the documentation included in the source distribution of Lua 5.1.2. +This is the documentation included in the source distribution of Lua 5.1.3.
    • Reference manual @@ -33,7 +33,7 @@


      Last update: -Fri Mar 23 14:19:36 BRT 2007 +Wed Dec 19 13:59:14 BRST 2007 diff --git a/etc/lua.pc b/etc/lua.pc index 03a2e684ad..19a5c91532 100644 --- a/etc/lua.pc +++ b/etc/lua.pc @@ -5,7 +5,7 @@ # grep '^V=' ../Makefile V= 5.1 # grep '^R=' ../Makefile -R= 5.1.2 +R= 5.1.3 # grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' prefix= /usr/local diff --git a/src/Makefile b/src/Makefile index cd7f6ba2ab..748d0f8db7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -148,8 +148,7 @@ llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h -loadlib.o: loadlib.c lauxlib.h lua.h luaconf.h lobject.h llimits.h \ - lualib.h +loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h diff --git a/src/lapi.c b/src/lapi.c index 7c532b8b1b..d7e8931e45 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.55 2006/06/07 12:37:17 roberto Exp $ +** $Id: lapi.c,v 2.55.1.3 2008/01/03 15:20:39 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -123,6 +123,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { } +LUA_API void lua_setlevel (lua_State *from, lua_State *to) { + to->nCcalls = from->nCcalls; +} + + LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { lua_CFunction old; lua_lock(L); @@ -749,7 +754,7 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { res = 0; break; } - luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); + if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); L->top--; lua_unlock(L); return res; diff --git a/src/lapi.h b/src/lapi.h index 9d1d435649..2c3fab244e 100644 --- a/src/lapi.h +++ b/src/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp $ +** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ diff --git a/src/lauxlib.c b/src/lauxlib.c index 96a6b85237..348730f694 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.159 2006/03/21 19:31:09 roberto Exp $ +** $Id: lauxlib.c,v 1.159.1.2 2008/01/17 14:04:41 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -244,7 +244,7 @@ LUALIB_API void luaI_openlib (lua_State *L, const char *libname, if (libname) { int size = libsize(l); /* check whether lib already exists */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); lua_getfield(L, -1, libname); /* get _LOADED[libname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ diff --git a/src/lauxlib.h b/src/lauxlib.h index 1f3430863e..34258235db 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.88 2006/04/12 20:31:15 roberto Exp $ +** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ diff --git a/src/lbaselib.c b/src/lbaselib.c index 147a727e06..cdeb15ca9b 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.191a 2006/06/02 15:34:00 roberto Exp $ +** $Id: lbaselib.c,v 1.191.1.3 2008/01/03 15:20:39 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -477,15 +477,52 @@ static const luaL_Reg base_funcs[] = { ** ======================================================= */ +#define CO_RUN 0 /* running */ +#define CO_SUS 1 /* suspended */ +#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */ +#define CO_DEAD 3 + +static const char *const statnames[] = + {"running", "suspended", "normal", "dead"}; + +static int costatus (lua_State *L, lua_State *co) { + if (L == co) return CO_RUN; + switch (lua_status(co)) { + case LUA_YIELD: + return CO_SUS; + case 0: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + return CO_NOR; /* it is running */ + else if (lua_gettop(co) == 0) + return CO_DEAD; + else + return CO_SUS; /* initial state */ + } + default: /* some error occured */ + return CO_DEAD; + } +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "coroutine expected"); + lua_pushstring(L, statnames[costatus(L, co)]); + return 1; +} + + static int auxresume (lua_State *L, lua_State *co, int narg) { - int status; + int status = costatus(L, co); if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); - if (lua_status(co) == 0 && lua_gettop(co) == 0) { - lua_pushliteral(L, "cannot resume dead coroutine"); + if (status != CO_SUS) { + lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); return -1; /* error flag */ } lua_xmove(L, co, narg); + lua_setlevel(L, co); status = lua_resume(co, narg); if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); @@ -556,34 +593,6 @@ static int luaB_yield (lua_State *L) { } -static int luaB_costatus (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - if (L == co) lua_pushliteral(L, "running"); - else { - switch (lua_status(co)) { - case LUA_YIELD: - lua_pushliteral(L, "suspended"); - break; - case 0: { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ - lua_pushliteral(L, "normal"); /* it is running */ - else if (lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); /* initial state */ - break; - } - default: /* some error occured */ - lua_pushliteral(L, "dead"); - break; - } - } - return 1; -} - - static int luaB_corunning (lua_State *L) { if (lua_pushthread(L)) return 0; /* main thread is not a coroutine */ diff --git a/src/lcode.c b/src/lcode.c index 9ce515ab64..cff626b7fa 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.25a 2006/03/21 19:28:49 roberto Exp $ +** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -699,7 +699,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { case OPR_MINUS: { - if (e->k == VK) + if (!isnumeral(e)) luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ codearith(fs, OP_UNM, e, &e2); break; diff --git a/src/lcode.h b/src/lcode.h index c02cb2b726..b941c60721 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.48 2006/03/21 19:28:03 roberto Exp $ +** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ diff --git a/src/ldblib.c b/src/ldblib.c index 26a19b6a6f..bb47cc722f 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $ +** $Id: ldblib.c,v 1.104.1.1 2007/12/27 13:02:25 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ diff --git a/src/ldebug.c b/src/ldebug.c index 9c8bdf2fb9..9eac4a9b41 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.29a 2005/12/22 16:19:56 roberto Exp $ +** $Id: ldebug.c,v 2.29.1.3 2007/12/28 15:32:23 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -563,8 +563,8 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { - if (ttisstring(p1)) p1 = p2; - lua_assert(!ttisstring(p1)); + if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; + lua_assert(!ttisstring(p1) && !ttisnumber(p1)); luaG_typeerror(L, p1, "concatenate"); } diff --git a/src/ldebug.h b/src/ldebug.h index 9c76aa10f0..ba28a97248 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.3 2005/04/25 19:24:10 roberto Exp $ +** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ diff --git a/src/ldo.c b/src/ldo.c index ab86fb70e8..7ddf633caa 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.38 2006/06/05 19:36:14 roberto Exp $ +** $Id: ldo.c,v 2.38.1.2 2008/01/03 15:20:39 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -83,7 +83,7 @@ static void resetstack (lua_State *L, int status) { L->base = L->ci->base; luaF_close(L, L->base); /* close eventual pending closures */ luaD_seterrorobj(L, status, L->base); - L->nCcalls = 0; + L->nCcalls = L->baseCcalls; L->allowhook = 1; restore_stack_limit(L); L->errfunc = 0; @@ -417,22 +417,24 @@ static int resume_error (lua_State *L, const char *msg) { LUA_API int lua_resume (lua_State *L, int nargs) { int status; lua_lock(L); - if (L->status != LUA_YIELD) { - if (L->status != 0) - return resume_error(L, "cannot resume dead coroutine"); - else if (L->ci != L->base_ci) + if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci)) return resume_error(L, "cannot resume non-suspended coroutine"); - } + if (L->nCcalls >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow"); luai_userstateresume(L, nargs); - lua_assert(L->errfunc == 0 && L->nCcalls == 0); + lua_assert(L->errfunc == 0); + L->baseCcalls = ++L->nCcalls; status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status != 0) { /* error? */ L->status = cast_byte(status); /* mark thread as `dead' */ luaD_seterrorobj(L, status, L->top); L->ci->top = L->top; } - else + else { + lua_assert(L->nCcalls == L->baseCcalls); status = L->status; + } + --L->nCcalls; lua_unlock(L); return status; } @@ -441,7 +443,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { LUA_API int lua_yield (lua_State *L, int nresults) { luai_userstateyield(L, nresults); lua_lock(L); - if (L->nCcalls > 0) + if (L->nCcalls > L->baseCcalls) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); L->base = L->top - nresults; /* protect stack slots below */ L->status = LUA_YIELD; diff --git a/src/ldo.h b/src/ldo.h index b2de92bb80..98fddac59f 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.7 2005/08/24 16:15:49 roberto Exp $ +** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ diff --git a/src/ldump.c b/src/ldump.c index f08277d3ac..c9d3d4870f 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $ +** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ diff --git a/src/lfunc.c b/src/lfunc.c index 05bd5ff50f..813e88f583 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.12a 2005/12/22 16:19:56 roberto Exp $ +** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ diff --git a/src/lfunc.h b/src/lfunc.h index 2e02419bd6..a68cf5151c 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ +** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ diff --git a/src/lgc.c b/src/lgc.c index 2d24a127ac..d9e0b78294 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.38 2006/05/24 14:34:06 roberto Exp $ +** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ diff --git a/src/lgc.h b/src/lgc.h index 5f69acb1e3..5a8dc605b3 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.15 2005/08/24 16:15:49 roberto Exp $ +** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ diff --git a/src/linit.c b/src/linit.c index 483d9c8c28..c1f90dfab7 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.14 2005/12/29 15:32:11 roberto Exp $ +** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $ ** Initialization of libraries for lua.c ** See Copyright Notice in lua.h */ diff --git a/src/liolib.c b/src/liolib.c index be60972ca8..e92984f15a 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.73 2006/05/08 20:14:16 roberto Exp $ +** $Id: liolib.c,v 2.73.1.2 2008/01/02 13:56:00 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -106,8 +106,11 @@ static int io_pclose (lua_State *L) { static int io_fclose (lua_State *L) { FILE **p = topfile(L); - int ok = (fclose(*p) == 0); - *p = NULL; + int ok = 0; + if (*p != stdin && *p != stdout && *p != stderr) { + ok = (fclose(*p) == 0); + *p = NULL; + } return pushresult(L, ok, NULL); } @@ -129,8 +132,7 @@ static int io_close (lua_State *L) { static int io_gc (lua_State *L) { FILE *f = *topfile(L); - /* ignore closed files and standard files */ - if (f != NULL && f != stdin && f != stdout && f != stderr) + if (f != NULL) /* ignore closed files */ aux_close(L); return 0; } diff --git a/src/llex.c b/src/llex.c index 1c07cad9bb..6dc319358c 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.20 2006/03/09 18:14:31 roberto Exp $ +** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ diff --git a/src/llex.h b/src/llex.h index ff07e83d31..a9201cee48 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.58 2006/03/23 18:23:32 roberto Exp $ +** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ diff --git a/src/llimits.h b/src/llimits.h index b03221aeec..ca8dcb7224 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.69 2005/12/27 17:12:00 roberto Exp $ +** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ diff --git a/src/lmathlib.c b/src/lmathlib.c index d181a73194..441fbf736c 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.67 2005/08/26 17:36:32 roberto Exp $ +** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ diff --git a/src/lmem.c b/src/lmem.c index cef2bc5f85..ae7d8c965f 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.70 2005/12/26 13:35:47 roberto Exp $ +** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ diff --git a/src/lmem.h b/src/lmem.h index 19df1fbb6c..7c2dcb3220 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.31 2005/04/25 19:24:10 roberto Exp $ +** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ diff --git a/src/loadlib.c b/src/loadlib.c index 808368ba43..d955f3ef41 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.54a 2006/07/03 20:16:49 roberto Exp $ +** $Id: loadlib.c,v 1.52.1.2 2007/12/28 14:58:43 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** diff --git a/src/lobject.c b/src/lobject.c index acde82ccdf..4ff50732a4 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.22 2006/02/10 17:43:52 roberto Exp $ +** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ diff --git a/src/lobject.h b/src/lobject.h index 8ce4405b6a..e7199dfc68 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.20 2006/01/18 11:37:34 roberto Exp $ +** $Id: lobject.h,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ diff --git a/src/lopcodes.c b/src/lopcodes.c index bf9cd522c2..4cc745230b 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.37 2005/11/08 19:45:36 roberto Exp $ +** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ ** See Copyright Notice in lua.h */ diff --git a/src/lopcodes.h b/src/lopcodes.h index 48105f1e72..41224d6ee1 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.125 2006/03/14 19:04:44 roberto Exp $ +** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ diff --git a/src/loslib.c b/src/loslib.c index fdda47414d..be6e4e80cc 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.20 2006/09/19 13:57:08 roberto Exp $ +** $Id: loslib.c,v 1.19.1.2 2007/12/28 14:58:43 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ diff --git a/src/lparser.c b/src/lparser.c index 6c473c41d2..1e2a9a88b7 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.42a 2006/06/05 15:57:59 roberto Exp $ +** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -938,6 +938,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) check_conflict(ls, lh, &nv.v); + luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, + "variables in assignment"); assignment(ls, &nv, nvars+1); } else { /* assignment -> `=' explist1 */ diff --git a/src/lparser.h b/src/lparser.h index e5b5b57e85..18836afd1c 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.57 2006/03/09 18:14:31 roberto Exp $ +** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ diff --git a/src/lstate.c b/src/lstate.c index 4bcb7594ce..4313b83a0c 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.36 2006/05/24 14:15:50 roberto Exp $ +** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -93,7 +93,7 @@ static void preinit_state (lua_State *L, global_State *g) { resethookcount(L); L->openupval = NULL; L->size_ci = 0; - L->nCcalls = 0; + L->nCcalls = L->baseCcalls = 0; L->status = 0; L->base_ci = L->ci = NULL; L->savedpc = NULL; @@ -205,7 +205,7 @@ LUA_API void lua_close (lua_State *L) { do { /* repeat until no more errors */ L->ci = L->base_ci; L->base = L->top = L->ci->base; - L->nCcalls = 0; + L->nCcalls = L->baseCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); luai_userstateclose(L); diff --git a/src/lstate.h b/src/lstate.h index d296a4cab9..3bc575b6bc 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.24 2006/02/06 18:27:59 roberto Exp $ +** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -112,6 +112,7 @@ struct lua_State { int stacksize; int size_ci; /* size of array `base_ci' */ unsigned short nCcalls; /* number of nested C calls */ + unsigned short baseCcalls; /* nested C calls when resuming coroutine */ lu_byte hookmask; lu_byte allowhook; int basehookcount; diff --git a/src/lstring.c b/src/lstring.c index 4319930c96..49113151cc 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.8 2005/12/22 16:19:56 roberto Exp $ +** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ diff --git a/src/lstring.h b/src/lstring.h index 1d2e91ea13..73a2ff8b38 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ +** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ diff --git a/src/lstrlib.c b/src/lstrlib.c index fc7ae4894a..ca333ba168 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.132a 2006/04/26 20:41:19 roberto Exp $ +** $Id: lstrlib.c,v 1.132.1.3 2007/12/28 15:32:23 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -629,10 +629,6 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, lua_gettable(L, 3); break; } - default: { - luaL_argerror(L, 3, "string/function/table expected"); - return; - } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); @@ -648,11 +644,15 @@ static int str_gsub (lua_State *L) { size_t srcl; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checkstring(L, 2); + int tr = lua_type(L, 3); int max_s = luaL_optint(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; MatchState ms; luaL_Buffer b; + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table expected"); luaL_buffinit(L, &b); ms.L = L; ms.src_init = src; diff --git a/src/ltable.c b/src/ltable.c index bc91cacd63..ec84f4fabc 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.32 2006/01/18 11:49:02 roberto Exp $ +** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -84,8 +84,8 @@ static const Node dummynode_ = { static Node *hashnum (const Table *t, lua_Number n) { unsigned int a[numints]; int i; - n += 1; /* normalize number (avoid -0) */ - lua_assert(sizeof(a) <= sizeof(n)); + if (luai_numeq(n, 0)) /* avoid problems with -0 */ + return gnode(t, 0); memcpy(a, &n, sizeof(a)); for (i = 1; i < numints; i++) a[0] += a[i]; return hashmod(t, a[0]); diff --git a/src/ltable.h b/src/ltable.h index 09193cdbe0..f5b9d5ead0 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.10 2006/01/10 13:13:06 roberto Exp $ +** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ diff --git a/src/ltablib.c b/src/ltablib.c index 453b23b378..06f1c37be1 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.38 2005/10/23 17:38:15 roberto Exp $ +** $Id: ltablib.c,v 1.38.1.2 2007/12/28 15:32:23 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -118,7 +118,8 @@ static int tinsert (lua_State *L) { static int tremove (lua_State *L) { int e = aux_getn(L, 1); int pos = luaL_optint(L, 2, e); - if (e == 0) return 0; /* table is `empty' */ + if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ + return 0; /* nothing to remove */ luaL_setn(L, 1, e - 1); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ;pos SHRT_MAX ? SHRT_MAX : LUAI_MCS_AUX) diff --git a/src/lualib.h b/src/lualib.h index 0c76232c0d..469417f670 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.36 2005/12/27 17:12:00 roberto Exp $ +** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ diff --git a/src/lundump.c b/src/lundump.c index 7fc635eeb7..1f992f24d0 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.60 2006/02/16 15:53:49 lhf Exp $ +** $Id: lundump.c,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ diff --git a/src/lundump.h b/src/lundump.h index 58cca5d190..c80189dbff 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.40 2005/11/11 14:03:13 lhf Exp $ +** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ diff --git a/src/lvm.c b/src/lvm.c index 08802f440f..ee3256ab94 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.63a 2006/06/05 15:58:59 roberto Exp $ +** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -61,11 +61,9 @@ static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; const Instruction *oldpc = L->savedpc; L->savedpc = pc; - if (mask > LUA_MASKLINE) { /* instruction-hook set? */ - if (L->hookcount == 0) { - resethookcount(L); - luaD_callhook(L, LUA_HOOKCOUNT, -1); - } + if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { + resethookcount(L); + luaD_callhook(L, LUA_HOOKCOUNT, -1); } if (mask & LUA_MASKLINE) { Proto *p = ci_func(L->ci)->l.p; diff --git a/src/lvm.h b/src/lvm.h index 788423f8e3..bfe4f5678d 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.5 2005/08/22 18:54:49 roberto Exp $ +** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ diff --git a/src/lzio.c b/src/lzio.c index 5121ada846..293edd59b0 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ +** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ diff --git a/src/lzio.h b/src/lzio.h index 8f403b8e74..51d695d8c1 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.21 2005/05/17 19:49:15 roberto Exp $ +** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ From 5065c5cce2d4c35d65319fede6b8eddc410fb846 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 18 Jan 2008 12:00:00 +0000 Subject: [PATCH 41/97] Lua 5.1.3-rc2 --- COPYRIGHT | 2 +- doc/contents.html | 8 +++++--- doc/manual.html | 14 ++++++++------ etc/min.c | 2 +- etc/strict.lua | 4 +++- src/ldblib.c | 12 +++++++----- src/loslib.c | 3 +-- src/luaconf.h | 4 ++-- src/lundump.c | 6 ++++-- 9 files changed, 32 insertions(+), 23 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index a54a16eec2..3a53e741e0 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html . =============================================================================== -Copyright (C) 1994-2007 Lua.org, PUC-Rio. +Copyright (C) 1994-2008 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/doc/contents.html b/doc/contents.html index 9856256054..4d253e5446 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -1,7 +1,9 @@ + Lua 5.1 Reference Manual - contents + @@ -9,31 +29,324 @@

      Lua -Documentation +Welcome to Lua 5.2

      -This is the documentation included in the source distribution of Lua 5.1.4. +about +· +installation +· +changes +· +license +· +reference manual +
      +

      -

      +

      + +This is a work version of Lua 5.2. +All details may change in the final version. + +

      About Lua

      + +Lua is a powerful, fast, lightweight, embeddable scripting language +developed by a +team +at +PUC-Rio, +the Pontifical Catholic University of Rio de Janeiro in Brazil. +Lua is +free software +used in many products and projects around the world. +

      Lua's official web site -contains updated documentation, +provides complete information +about Lua, +including +an +executive summary +and +updated +documentation, especially the -reference manual. +reference manual, +which may differ slightly from the +local copy +distributed in this package. +

      + +

      Installing Lua

      +
      how much detail?

      + +Lua is distributed in source form. +You need to build it before using it. +This should be straightforward +because +Lua is implemented in pure ANSI C, and compiles unmodified in all known +platforms that have an ANSI C compiler. +Lua also compiles unmodified as C++. +

      + +The instructions below are for Unix-like platforms. +There are also +instructions for other systems. +See below for +customization options. +

      + +

      Building Lua

      + +In most Unix-like platforms, simply do "make" with a suitable target. +Here are the details. +

      + +

        +
      1. +Open a terminal window and move to +the top-level directory, which is named lua-5.2. +The Makefile there controls both the build process and the installation process. +

        +

      2. + Do "make" and see if your platform is listed. + The platforms currently supported are: +
        + aix ansi bsd freebsd generic linux macosx mingw posix solaris +
        +

        + If your platform is listed, just do "make xxx", where xxx + is your platform name. +

        + If your platform is not listed, try the closest one or posix, generic, + ansi, in this order. +

        +

      3. +The compilation takes only a few moments +and produces three files in the src directory: +lua (the interpreter), +luac (the compiler), +and liblua.a (the library). +

        +

      4. + If you want to check that Lua has been built correctly, do "make test" + after building Lua. This will run the interpreter on a "hello world" + Lua program from the test directory. + You may want to try other example programs in that directory. +
      +

      + +

      Installing Lua

      + Once you have built Lua, you may want to install it in an official + place in your system. In this case, do "make install". The official + place and the way to install files are defined in Makefile. You'll + probably need the right permissions to install files. +

      + + If you want to build and install Lua in one step, do "make xxx install", + where xxx is your platform name. +

      + + If you want to install Lua locally, then do "make local". This will + create directories bin, include, lib, man, and install Lua there as + follows: + review! +

      + +

      +
      + bin: +
      + lua luac +
      + include: +
      + lua.h luaconf.h lualib.h lauxlib.h lua.hpp +
      + lib: +
      + liblua.a +
      + man/man1: +
      + lua.1 luac.1 +
      + + These are the only directories you need for development. +

      + + There are man pages for + lua and + luac, in both nroff and html, and a + reference manual in html in doc, some sample code in test, and some + useful stuff in etc. You don't need these directories for development. +

      + + If you want to install Lua locally, but in some other directory, do + "make install INSTALL_TOP=xxx", where xxx is your chosen directory. +

      + +

      Customization

      + Three kinds of things can be customized by editing a file: +
        +
      • Where and how to install Lua – edit Makefile. +
      • How to build Lua – edit src/Makefile. +
      • Lua features – edit src/luaconf.h. +
      +

      + + You don't actually need to edit the Makefiles because you may set the + relevant variables in the command line when invoking make. +

      + + On the other hand, if you need to customize some Lua features, you'll need + to edit src/luaconf.h before building and installing Lua. + The edited file will be the one installed, and + it will be used by any Lua clients that you build, to ensure consistency. +

      + + We strongly recommend that you enable dynamic loading. This is done + automatically for all platforms listed above that have this feature + and also for Windows. +

      + +

      Building Lua on other systems

      + + If you're not using the usual Unix tools, then the instructions for + building Lua depend on the compiler you use. You'll need to create + projects (or whatever your compiler uses) for building the library, + the interpreter, and the compiler, as follows: +

      +

      +
      +library: +
      + lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c + lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c + ltable.c ltm.c lundump.c lvm.c lzio.c + lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c + ltablib.c lstrlib.c loadlib.c linit.c +
      +interpreter: +
      + library, lua.c +
      +compiler: +
      + library, luac.c print.c +
      + + If you use Visual Studio .NET, you can use etc/luavs.bat in its + "Command Prompt". +

      + + If all you want is to build the Lua interpreter, you may put all .c files + in a single project, except for luac.c and print.c. Or just use etc/all.c. +

      + + To use Lua as a library in your own programs you'll need to know how to + create and use libraries with your compiler. Moreover, to dynamically load + C libraries for Lua you'll need to know how to create dynamic libraries + and you'll need to make sure that the Lua API functions are accessible to + those dynamic libraries — but you do not want to link the Lua library + into each dynamic library. For Unix, we recommend that the Lua library + be linked statically into the host program and its symbols exported for + dynamic linking; src/Makefile does this for the Lua interpreter. + For Windows, we recommend that the Lua library be DLL. +

      + + As mentioned above, you may edit src/luaconf.h to customize + some features before building Lua. +

      + +

      Changes since Lua 5.1

      +
      incomplete!

      + +Here are the main changes in Lua since its last release. +The +reference manual +lists the +incompatibilities that had to be introduced. +

      + +

      Language

      +
        +
      • new lexical environments. +
      • hex escapes in strings. +
      • tables and strings honor the __len metamethod. +
      + +

      Libraries

      +
        +
      • new function package.searchpath. +
      • new metamethods __pairs and __ipairs. +
      • arguments for function called through xpcall. +
      + +

      Implementation

      +
        +
      • emergency garbage collector + (core forces a full collection when allocation fails). +
      • ephemeron tables + (tables with weak keys only visit value when key is accessible) +
      • handling of non-string error messages. +
      • udata with finalizers are kept in a separated list for the GC. +relevant? +
      + + +

      License

      + +[osi certified] + + +Lua is free software licensed under the terms of the +MIT license +reproduced below, +and +can be used for any purpose, including commercial purposes, +at absolutely no cost without having to ask us. + +The only requirement is that if you do use Lua, +then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. + +For details and rationale, see +this. +

      + +

      +Copyright © 1994-2010 Lua.org, PUC-Rio. +

      + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +

      + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +

      + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +

      +


      Last update: -Tue Aug 12 14:46:07 BRT 2008 +Fri Jan 8 16:41:16 BRST 2010 diff --git a/etc/README b/etc/README index 5149fc91d4..99cbb5236c 100644 --- a/etc/README +++ b/etc/README @@ -2,22 +2,12 @@ This directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. If any of the makes fail, you're probably not using the same libraries -used to build Lua. Set MYLIBS in Makefile accordingly. +used to build Lua. Set MYLIBS in Makefile or in the command line accordingly. all.c Full Lua interpreter in a single file. Do "make one" for a demo. -lua.hpp - Lua header files for C++ using 'extern "C"'. - -lua.ico - A Lua icon for Windows (and web sites: save as favicon.ico). - Drawn by hand by Markus Gritsch . - -lua.pc - pkg-config data for Lua - luavs.bat Script to build Lua under "Visual Studio .NET Command Prompt". Run it from the toplevel as etc\luavs.bat. diff --git a/etc/all.c b/etc/all.c index dab68fac58..a7f21b7df0 100644 --- a/etc/all.c +++ b/etc/all.c @@ -1,11 +1,31 @@ /* -* all.c -- Lua core, libraries and interpreter in a single file +* all.c -- Lua core, libraries, and interpreter in a single file */ +/* default is to build the full interpreter */ +#ifndef MAKE_LIB +#ifndef MAKE_LUAC +#undef MAKE_LUA +#define MAKE_LUA +#endif +#endif + +/* choose suitable platform-specific features */ +/* some of these may need extra libraries such as -ldl -lreadline -lncurses */ +#if 0 +#define LUA_USE_LINUX +#define LUA_USE_MACOSX +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN +#define LUA_ANSI +#endif + #define luaall_c +/* core -- used by all */ #include "lapi.c" #include "lcode.c" +#include "lctype.c" #include "ldebug.c" #include "ldo.c" #include "ldump.c" @@ -24,15 +44,30 @@ #include "lvm.c" #include "lzio.c" +/* auxiliary library -- used by all */ #include "lauxlib.c" + +/* standard library -- not used by luac */ +#ifndef MAKE_LUAC #include "lbaselib.c" +#include "lbitlib.c" #include "ldblib.c" #include "liolib.c" -#include "linit.c" #include "lmathlib.c" #include "loadlib.c" #include "loslib.c" #include "lstrlib.c" #include "ltablib.c" +#endif +/* lua */ +#ifdef MAKE_LUA +#include "linit.c" #include "lua.c" +#endif + +/* luac */ +#ifdef MAKE_LUAC +#include "print.c" +#include "luac.c" +#endif diff --git a/etc/lua.ico b/etc/lua.ico deleted file mode 100644 index ccbabc4e2004683f29598a991006d7caff6d837d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1078 zcma)5y>7xl4E|D3VJbX9VX7GW1~6FSw!BIQq_T0tNo32b^bxZ4H5fZGR7xh?&v!Y3 zDh3=J`#b+#Yy%W{!g4u>(a#g`Mme7+yefc~5wPOflDr`o81qe{?|t$BfABsDzNw;V z8cH*0{6W<;G9Np#7ik(qoR4aR5-A@{5)}DJ9&}FRBA#X_5+im4-kQSzMF^)-t2(Vi ztw-^|Sn8@O_lM9`oos+0wMZGt&`Bq(aK&XCv1Gfr&Jtd6%lKPdD{s=unqGWyb3%y{X9SS{jB~HMh0oKMISQrDC zJ;K?)>ElnpmN^UNE-rXxtyk{c#rCe~`P=qnFT7 bCxwx*w%~s~=?o*z_6Fk4@7l(poWF`cPpA(! diff --git a/etc/lua.pc b/etc/lua.pc deleted file mode 100644 index f52f55b012..0000000000 --- a/etc/lua.pc +++ /dev/null @@ -1,31 +0,0 @@ -# lua.pc -- pkg-config data for Lua - -# vars from install Makefile - -# grep '^V=' ../Makefile -V= 5.1 -# grep '^R=' ../Makefile -R= 5.1.4 - -# grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' -prefix= /usr/local -INSTALL_BIN= ${prefix}/bin -INSTALL_INC= ${prefix}/include -INSTALL_LIB= ${prefix}/lib -INSTALL_MAN= ${prefix}/man/man1 -INSTALL_LMOD= ${prefix}/share/lua/${V} -INSTALL_CMOD= ${prefix}/lib/lua/${V} - -# canonical vars -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: Lua -Description: An Extensible Extension Language -Version: ${R} -Requires: -Libs: -L${libdir} -llua -lm -Cflags: -I${includedir} - -# (end of lua.pc) diff --git a/etc/min.c b/etc/min.c index 6a85a4d10e..81e3b73d51 100644 --- a/etc/min.c +++ b/etc/min.c @@ -1,39 +1,36 @@ /* * min.c -- a minimal Lua interpreter -* loads stdin only with minimal error handling. -* no interaction, and no standard library, only a "print" function. +* runs one file from the command line or stdin if none given. +* minimal error handling, no traceback, no interaction, no standard library, +* only a "print" function. */ #include #include "lua.h" #include "lauxlib.h" +#include "lualib.h" static int print(lua_State *L) { int n=lua_gettop(L); int i; + const char *s=""; for (i=1; i<=n; i++) { - if (i>1) printf("\t"); - if (lua_isstring(L,i)) - printf("%s",lua_tostring(L,i)); - else if (lua_isnil(L,i)) - printf("%s","nil"); - else if (lua_isboolean(L,i)) - printf("%s",lua_toboolean(L,i) ? "true" : "false"); - else - printf("%s:%p",luaL_typename(L,i),lua_topointer(L,i)); + printf("%s%s",s,luaL_tolstring(L,i,NULL)); + s="\t"; } printf("\n"); return 0; } -int main(void) +int main(int argc, char *argv[]) { lua_State *L=lua_open(); lua_register(L,"print",print); - if (luaL_dofile(L,NULL)!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); + luaL_openlibs(L); + if (luaL_dofile(L,argv[1])!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); lua_close(L); return 0; } diff --git a/etc/noparser.c b/etc/noparser.c index 13ba546239..5e0e203114 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -4,16 +4,24 @@ * You'll only be able to load binary files and strings, precompiled with luac. * (Of course, you'll have to build luac with the original parsing modules!) * -* To use this module, simply compile it ("make noparser" does that) and list -* its object file before the Lua libraries. The linker should then not load -* the parsing modules. To try it, do "make luab". +* To use this module, simply compile it and list its object file before the +* Lua libraries. The linker should then not load the parsing modules. * -* If you also want to avoid the dump module (ldump.o), define NODUMP. -* #define NODUMP +* If you want to avoid the dump module or the undump modules, use the +* corresponding #define below. +* +#define NOPARSER +#define NODUMP +#define NOUNDUMP */ +#define NOPARSER + #define LUA_CORE +#include "lua.h" +/* --------------------------------------------------------------- noparser */ +#ifdef NOPARSER #include "llex.h" #include "lparser.h" #include "lzio.h" @@ -22,7 +30,7 @@ LUAI_FUNC void luaX_init (lua_State *L) { UNUSED(L); } -LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { +LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, const char *name) { UNUSED(z); UNUSED(buff); UNUSED(name); @@ -30,7 +38,9 @@ LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *n lua_error(L); return NULL; } +#endif +/* --------------------------------------------------------------- nodump */ #ifdef NODUMP #include "lundump.h" @@ -39,12 +49,22 @@ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, UNUSED(w); UNUSED(data); UNUSED(strip); -#if 1 - UNUSED(L); - return 0; -#else lua_pushliteral(L,"dumper not loaded"); lua_error(L); + return 0; +} #endif + +/* --------------------------------------------------------------- noundump */ +#ifdef NOUNDUMP +#include "lundump.h" + +LUAI_FUNC Proto *luaU_undump (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { + UNUSED(z); + UNUSED(buff); + UNUSED(name); + lua_pushliteral(L,"cannot load binary chunks"); + lua_error(L); + return NULL; } #endif diff --git a/src/Makefile b/src/Makefile index e4a3cd6108..a3942a5bdd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,5 @@ -# makefile for building Lua -# see ../INSTALL for installation instructions -# see ../Makefile and luaconf.h for further customization +# Makefile for building Lua +# See ../doc/readme.html for installation and customization instructions. # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= @@ -9,25 +8,26 @@ PLAT= none CC= gcc CFLAGS= -O2 -Wall $(MYCFLAGS) +LIBS= -lm $(MYLIBS) + AR= ar rcu RANLIB= ranlib RM= rm -f -LIBS= -lm $(MYLIBS) MYCFLAGS= MYLDFLAGS= MYLIBS= -# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= +# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris LUA_A= liblua.a -CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ - lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ - lundump.o lvm.o lzio.o -LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ - lstrlib.o loadlib.o linit.o +CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ + lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ + ltm.o lundump.o lvm.o lzio.o +LIB_O= lauxlib.o lbaselib.o lbitlib.o ldblib.o liolib.o lmathlib.o loslib.o \ + ltablib.o lstrlib.o loadlib.o linit.o LUA_T= lua LUA_O= lua.o @@ -75,89 +75,90 @@ echo: @echo "MYLIBS = $(MYLIBS)" # convenience targets for popular platforms +ALL= all none: @echo "Please choose a platform:" @echo " $(PLATS)" aix: - $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" + $(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" ansi: - $(MAKE) all MYCFLAGS=-DLUA_ANSI + $(MAKE) $(ALL) MYCFLAGS="-DLUA_ANSI" bsd: - $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" freebsd: - $(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" generic: - $(MAKE) all MYCFLAGS= + $(MAKE) $(ALL) MYCFLAGS= linux: - $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -ldl -lreadline -lncurses" macosx: - $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline" -# use this on Mac OS X 10.3- -# $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_MACOSX" MYLIBS="-lreadline" mingw: $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe - $(MAKE) "LUAC_T=luac.exe" luac.exe posix: - $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_POSIX" solaris: - $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" # list targets that do not create files (but not all makes understand .PHONY) .PHONY: all $(PLATS) default o a clean depend echo none # DO NOT DELETE -lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ - lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ - lundump.h lvm.h +lapi.o: lapi.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ + lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \ + lvm.h lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h +lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ - ltable.h + lstring.h ltable.h +lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h -ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ - llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ +ldebug.o: ldebug.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ + ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h lvm.h -ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ - lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ - ltable.h lundump.h lvm.h +ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ + lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \ + lstring.h ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h lundump.h lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ - lstate.h ltm.h lzio.h + lopcodes.h lstate.h ltm.h lzio.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h -llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ - lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h +llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \ + lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h + ltm.h lzio.h lmem.h ldo.h lgc.h loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h -lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ - ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h +lobject.o: lobject.c lua.h luaconf.h lctype.h llimits.h ldebug.h lstate.h \ + lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h -lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h +lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ + ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \ + ltable.h lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h diff --git a/src/lapi.c b/src/lapi.c index 5d5145d2eb..b822a7259a 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,12 +1,10 @@ /* -** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $ +** $Id: lapi.c,v 2.109 2010/01/08 15:16:56 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ -#include -#include #include #include @@ -32,42 +30,47 @@ const char lua_ident[] = - "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" - "$Authors: " LUA_AUTHORS " $\n" - "$URL: www.lua.org $\n"; + "$LuaVersion: " LUA_COPYRIGHT " $" + "$LuaAuthors: " LUA_AUTHORS " $"; -#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) +#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject, \ + "invalid index") -#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) - -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} +static Table *getcurrenv (lua_State *L) { + if (L->ci->previous == NULL) /* no enclosing function? */ + return G(L)->l_gt; /* use global table as environment */ + else { + Closure *func = curr_func(L); + return func->c.env; + } +} -static TValue *index2adr (lua_State *L, int idx) { +static TValue *index2addr (lua_State *L, int idx) { + CallInfo *ci = L->ci; if (idx > 0) { - TValue *o = L->base + (idx - 1); - api_check(L, idx <= L->ci->top - L->base); + TValue *o = ci->func + idx; + api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); if (o >= L->top) return cast(TValue *, luaO_nilobject); else return o; } else if (idx > LUA_REGISTRYINDEX) { - api_check(L, idx != 0 && -idx <= L->top - L->base); + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } else switch (idx) { /* pseudo-indices */ - case LUA_REGISTRYINDEX: return registry(L); + case LUA_REGISTRYINDEX: return &G(L)->l_registry; case LUA_ENVIRONINDEX: { - Closure *func = curr_func(L); - sethvalue(L, &L->env, func->c.env); + sethvalue(L, &L->env, getcurrenv(L)); return &L->env; } - case LUA_GLOBALSINDEX: return gt(L); default: { Closure *func = curr_func(L); - idx = LUA_GLOBALSINDEX - idx; + idx = LUA_ENVIRONINDEX - idx; + api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large"); return (idx <= func->c.nupvalues) ? &func->c.upvalue[idx-1] : cast(TValue *, luaO_nilobject); @@ -76,32 +79,31 @@ static TValue *index2adr (lua_State *L, int idx) { } -static Table *getcurrenv (lua_State *L) { - if (L->ci == L->base_ci) /* no enclosing function? */ - return hvalue(gt(L)); /* use global table as environment */ - else { - Closure *func = curr_func(L); - return func->c.env; - } -} - - -void luaA_pushobject (lua_State *L, const TValue *o) { - setobj2s(L, L->top, o); - api_incr_top(L); +/* +** to be caled by 'lua_checkstack' in protected mode, to grow stack +** capturing memory errors +*/ +static void growstack (lua_State *L, void *ud) { + int size = *(int *)ud; + luaD_growstack(L, size); } LUA_API int lua_checkstack (lua_State *L, int size) { - int res = 1; + int res; + CallInfo *ci = L->ci; lua_lock(L); - if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) - res = 0; /* stack overflow */ - else if (size > 0) { - luaD_checkstack(L, size); - if (L->ci->top < L->top + size) - L->ci->top = L->top + size; + if (L->stack_last - L->top > size) /* stack large enough? */ + res = 1; /* yes; check is OK */ + else { /* no; need to grow stack */ + int inuse = L->top - L->stack + EXTRA_STACK; + if (inuse > LUAI_MAXSTACK - size) /* can grow without overflow? */ + res = 0; /* no */ + else /* try to grow stack */ + res = (luaD_rawrunprotected(L, &growstack, &size) == LUA_OK); } + if (res && ci->top < L->top + size) + ci->top = L->top + size; /* adjust frame top */ lua_unlock(L); return res; } @@ -112,8 +114,8 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { if (from == to) return; lua_lock(to); api_checknelems(from, n); - api_check(from, G(from) == G(to)); - api_check(from, to->ci->top - to->top >= n); + api_check(from, G(from) == G(to), "moving among independent states"); + api_check(from, to->ci->top - to->top >= n, "not enough elements to move"); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top++, from->top + i); @@ -122,11 +124,6 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { } -LUA_API void lua_setlevel (lua_State *from, lua_State *to) { - to->nCcalls = from->nCcalls; -} - - LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { lua_CFunction old; lua_lock(L); @@ -137,16 +134,10 @@ LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { } -LUA_API lua_State *lua_newthread (lua_State *L) { - lua_State *L1; - lua_lock(L); - luaC_checkGC(L); - L1 = luaE_newthread(L); - setthvalue(L, L->top, L1); - api_incr_top(L); - lua_unlock(L); - luai_userstatethread(L, L1); - return L1; +LUA_API const lua_Number *lua_version (lua_State *L) { + static const lua_Number version = LUA_VERSION_NUM; + if (L == NULL) return &version; + else return G(L)->version; } @@ -157,20 +148,21 @@ LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API int lua_gettop (lua_State *L) { - return cast_int(L->top - L->base); + return cast_int(L->top - (L->ci->func + 1)); } LUA_API void lua_settop (lua_State *L, int idx) { + StkId func = L->ci->func; lua_lock(L); if (idx >= 0) { - api_check(L, idx <= L->stack_last - L->base); - while (L->top < L->base + idx) + api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); + while (L->top < (func + 1) + idx) setnilvalue(L->top++); - L->top = L->base + idx; + L->top = (func + 1) + idx; } else { - api_check(L, -(idx+1) <= (L->top - L->base)); + api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); L->top += idx+1; /* `subtract' index (index is negative) */ } lua_unlock(L); @@ -180,7 +172,7 @@ LUA_API void lua_settop (lua_State *L, int idx) { LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); - p = index2adr(L, idx); + p = index2addr(L, idx); api_checkvalidindex(L, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; @@ -192,7 +184,7 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); - p = index2adr(L, idx); + p = index2addr(L, idx); api_checkvalidindex(L, p); for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); setobjs2s(L, p, L->top); @@ -200,34 +192,50 @@ LUA_API void lua_insert (lua_State *L, int idx) { } -LUA_API void lua_replace (lua_State *L, int idx) { - StkId o; - lua_lock(L); - /* explicit test for incompatible code */ - if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) - luaG_runerror(L, "no calling environment"); - api_checknelems(L, 1); - o = index2adr(L, idx); - api_checkvalidindex(L, o); +static void moveto (lua_State *L, TValue *fr, int idx) { + TValue *to = index2addr(L, idx); + api_checkvalidindex(L, to); if (idx == LUA_ENVIRONINDEX) { Closure *func = curr_func(L); - api_check(L, ttistable(L->top - 1)); - func->c.env = hvalue(L->top - 1); - luaC_barrier(L, func, L->top - 1); + api_check(L, ttistable(fr), "table expected"); + func->c.env = hvalue(fr); + luaC_barrier(L, func, fr); } else { - setobj(L, o, L->top - 1); - if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ - luaC_barrier(L, curr_func(L), L->top - 1); + setobj(L, to, fr); + if (idx < LUA_ENVIRONINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), fr); } + /* LUA_REGISTRYINDEX does not need gc barrier + (collector revisits it before finishing collection) */ +} + + +LUA_API void lua_replace (lua_State *L, int idx) { + lua_lock(L); + /* explicit test for incompatible code */ + if (idx == LUA_ENVIRONINDEX && L->ci->previous == NULL) + luaG_runerror(L, "no calling environment"); + api_checknelems(L, 1); + moveto(L, L->top - 1, idx); L->top--; lua_unlock(L); } +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr; + lua_lock(L); + fr = index2addr(L, fromidx); + api_checkvalidindex(L, fr); + moveto(L, fr, toidx); + lua_unlock(L); +} + + LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); - setobj2s(L, L->top, index2adr(L, idx)); + setobj2s(L, L->top, index2addr(L, idx)); api_incr_top(L); lua_unlock(L); } @@ -240,7 +248,7 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); } @@ -252,14 +260,14 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { TValue n; - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); return tonumber(o, &n); } @@ -271,48 +279,55 @@ LUA_API int lua_isstring (lua_State *L, int idx) { LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = index2adr(L, index1); - StkId o2 = index2adr(L, index2); + StkId o1 = index2addr(L, index1); + StkId o2 = index2addr(L, index2); return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaO_rawequalObj(o1, o2); } -LUA_API int lua_equal (lua_State *L, int index1, int index2) { - StkId o1, o2; - int i; - lua_lock(L); /* may call tag method */ - o1 = index2adr(L, index1); - o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); +LUA_API void lua_arith (lua_State *L, int op) { + lua_lock(L); + api_checknelems(L, 2); + if (ttisnumber(L->top - 2) && ttisnumber(L->top - 1)) { + changenvalue(L->top - 2, + luaO_arith(op, nvalue(L->top - 2), nvalue(L->top - 1))); + } + else + luaV_arith(L, L->top - 2, L->top - 2, L->top - 1, op - LUA_OPADD + TM_ADD); + L->top--; lua_unlock(L); - return i; } -LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { +LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ - o1 = index2adr(L, index1); - o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaV_lessthan(L, o1, o2); + o1 = index2addr(L, index1); + o2 = index2addr(L, index2); + if (o1 == luaO_nilobject || o2 == luaO_nilobject) + i = 0; + else switch (op) { + case LUA_OPEQ: i = equalobj(L, o1, o2); break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; + default: api_check(L, 0, "invalid option"); i = 0; + } lua_unlock(L); return i; } - LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { TValue n; - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) return nvalue(o); else @@ -322,7 +337,7 @@ LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { TValue n; - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { lua_Integer res; lua_Number num = nvalue(o); @@ -335,13 +350,13 @@ LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { LUA_API int lua_toboolean (lua_State *L, int idx) { - const TValue *o = index2adr(L, idx); + const TValue *o = index2addr(L, idx); return !l_isfalse(o); } LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); if (!ttisstring(o)) { lua_lock(L); /* `luaV_tostring' may create a new string */ if (!luaV_tostring(L, o)) { /* conversion failed? */ @@ -350,7 +365,7 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { return NULL; } luaC_checkGC(L); - o = index2adr(L, idx); /* previous call may reallocate the stack */ + o = index2addr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); } if (len != NULL) *len = tsvalue(o)->len; @@ -358,32 +373,25 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { } -LUA_API size_t lua_objlen (lua_State *L, int idx) { - StkId o = index2adr(L, idx); +LUA_API size_t lua_rawlen (lua_State *L, int idx) { + StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TSTRING: return tsvalue(o)->len; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); - case LUA_TNUMBER: { - size_t l; - lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); - lua_unlock(L); - return l; - } default: return 0; } } LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); @@ -393,13 +401,13 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) { LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = index2adr(L, idx); + StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); @@ -442,20 +450,25 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { } -LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { +LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { + TString *ts; lua_lock(L); luaC_checkGC(L); - setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); + ts = luaS_newlstr(L, s, len); + setsvalue2s(L, L->top, ts); api_incr_top(L); lua_unlock(L); + return getstr(ts); } -LUA_API void lua_pushstring (lua_State *L, const char *s) { - if (s == NULL) +LUA_API const char *lua_pushstring (lua_State *L, const char *s) { + if (s == NULL) { lua_pushnil(L); + return NULL; + } else - lua_pushlstring(L, s, strlen(s)); + return lua_pushlstring(L, s, strlen(s)); } @@ -486,8 +499,9 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { Closure *cl; lua_lock(L); - luaC_checkGC(L); api_checknelems(L, n); + api_check(L, n <= UCHAR_MAX, "upvalue index too large"); + luaC_checkGC(L); cl = luaF_newCclosure(L, n, getcurrenv(L)); cl->c.f = fn; L->top -= n; @@ -534,7 +548,7 @@ LUA_API int lua_pushthread (lua_State *L) { LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); @@ -543,13 +557,12 @@ LUA_API void lua_gettable (lua_State *L, int idx) { LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; - TValue key; lua_lock(L); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); - setsvalue(L, &key, luaS_new(L, k)); - luaV_gettable(L, t, &key, L->top); + setsvalue2s(L, L->top, luaS_new(L, k)); api_incr_top(L); + luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } @@ -557,8 +570,8 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { LUA_API void lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); - t = index2adr(L, idx); - api_check(L, ttistable(t)); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } @@ -567,19 +580,23 @@ LUA_API void lua_rawget (lua_State *L, int idx) { LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); - o = index2adr(L, idx); - api_check(L, ttistable(o)); - setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + setobj2s(L, L->top, luaH_getint(hvalue(o), n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { + Table *t; lua_lock(L); luaC_checkGC(L); - sethvalue(L, L->top, luaH_new(L, narray, nrec)); + t = luaH_new(L); + sethvalue(L, L->top, t); api_incr_top(L); + if (narray > 0 || nrec > 0) + luaH_resize(L, t, narray, nrec); lua_unlock(L); } @@ -589,7 +606,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { Table *mt = NULL; int res; lua_lock(L); - obj = index2adr(L, objindex); + obj = index2addr(L, objindex); switch (ttype(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; @@ -616,7 +633,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); - o = index2adr(L, idx); + o = index2addr(L, idx); api_checkvalidindex(L, o); switch (ttype(o)) { case LUA_TFUNCTION: @@ -625,9 +642,6 @@ LUA_API void lua_getfenv (lua_State *L, int idx) { case LUA_TUSERDATA: sethvalue(L, L->top, uvalue(o)->env); break; - case LUA_TTHREAD: - setobj2s(L, L->top, gt(thvalue(o))); - break; default: setnilvalue(L->top); break; @@ -646,7 +660,7 @@ LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ @@ -656,14 +670,13 @@ LUA_API void lua_settable (lua_State *L, int idx) { LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { StkId t; - TValue key; lua_lock(L); api_checknelems(L, 1); - t = index2adr(L, idx); + t = index2addr(L, idx); api_checkvalidindex(L, t); - setsvalue(L, &key, luaS_new(L, k)); - luaV_settable(L, t, &key, L->top - 1); - L->top--; /* pop value */ + setsvalue2s(L, L->top++, luaS_new(L, k)); + luaV_settable(L, t, L->top - 1, L->top - 2); + L->top -= 2; /* pop value and key */ lua_unlock(L); } @@ -672,8 +685,8 @@ LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); - t = index2adr(L, idx); - api_check(L, ttistable(t)); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); luaC_barriert(L, hvalue(t), L->top-1); L->top -= 2; @@ -685,9 +698,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); api_checknelems(L, 1); - o = index2adr(L, idx); - api_check(L, ttistable(o)); - setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1); luaC_barriert(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); @@ -699,12 +712,12 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { Table *mt; lua_lock(L); api_checknelems(L, 1); - obj = index2adr(L, objindex); + obj = index2addr(L, objindex); api_checkvalidindex(L, obj); if (ttisnil(L->top - 1)) mt = NULL; else { - api_check(L, ttistable(L->top - 1)); + api_check(L, ttistable(L->top - 1), "table expected"); mt = hvalue(L->top - 1); } switch (ttype(obj)) { @@ -716,8 +729,10 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; - if (mt) + if (mt) { luaC_objbarrier(L, rawuvalue(obj), mt); + luaC_checkfinalizer(L, rawuvalue(obj)); + } break; } default: { @@ -736,9 +751,9 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { int res = 1; lua_lock(L); api_checknelems(L, 1); - o = index2adr(L, idx); + o = index2addr(L, idx); api_checkvalidindex(L, o); - api_check(L, ttistable(L->top - 1)); + api_check(L, ttistable(L->top - 1), "table expected"); switch (ttype(o)) { case LUA_TFUNCTION: clvalue(o)->c.env = hvalue(L->top - 1); @@ -746,9 +761,6 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { case LUA_TUSERDATA: uvalue(o)->env = hvalue(L->top - 1); break; - case LUA_TTHREAD: - sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); - break; default: res = 0; break; @@ -765,21 +777,36 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { */ -#define adjustresults(L,nres) \ - { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } +#define checkresults(L,na,nr) \ + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ + "results from function overflow current stack size") + +LUA_API int lua_getctx (lua_State *L, int *ctx) { + if (L->ci->callstatus & CIST_YIELDED) { + if (ctx) *ctx = L->ci->u.c.ctx; + return L->ci->u.c.status; + } + else return LUA_OK; +} -#define checkresults(L,na,nr) \ - api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) - -LUA_API void lua_call (lua_State *L, int nargs, int nresults) { +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, + lua_CFunction k) { StkId func; lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); func = L->top - (nargs+1); - luaD_call(L, func, nresults); + if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ + luaD_call(L, func, nresults, 1); /* do the call */ + } + else /* no continuation or no yieldable */ + luaD_call(L, func, nresults, 0); /* just do the call */ adjustresults(L, nresults); lua_unlock(L); } @@ -797,68 +824,55 @@ struct CallS { /* data to `f_call' */ static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); - luaD_call(L, c->func, c->nresults); + luaD_call(L, c->func, c->nresults, 0); } -LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { +LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, + int ctx, lua_CFunction k) { struct CallS c; int status; ptrdiff_t func; lua_lock(L); + api_check(L, k == NULL || !isLua(L->ci), + "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); if (errfunc == 0) func = 0; else { - StkId o = index2adr(L, errfunc); + StkId o = index2addr(L, errfunc); api_checkvalidindex(L, o); func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ - c.nresults = nresults; - status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ + c.nresults = nresults; /* do a 'conventional' protected call */ + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); + } + else { /* prepare continuation (call is already protected by 'resume') */ + CallInfo *ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ + /* save information for error recovery */ + ci->u.c.oldtop = savestack(L, c.func); + ci->u.c.old_allowhook = L->allowhook; + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + /* mark that function may do error recovery */ + ci->callstatus |= CIST_YPCALL; + luaD_call(L, c.func, nresults, 1); /* do the call */ + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + status = LUA_OK; /* if it is here, there were no errors */ + } adjustresults(L, nresults); lua_unlock(L); return status; } -/* -** Execute a protected C call. -*/ -struct CCallS { /* data to `f_Ccall' */ - lua_CFunction func; - void *ud; -}; - - -static void f_Ccall (lua_State *L, void *ud) { - struct CCallS *c = cast(struct CCallS *, ud); - Closure *cl; - cl = luaF_newCclosure(L, 0, getcurrenv(L)); - cl->c.f = c->func; - setclvalue(L, L->top, cl); /* push function */ - api_incr_top(L); - setpvalue(L->top, c->ud); /* push only argument */ - api_incr_top(L); - luaD_call(L, L->top - 2, 0); -} - - -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { - struct CCallS c; - int status; - lua_lock(L); - c.func = func; - c.ud = ud; - status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); - lua_unlock(L); - return status; -} - - LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname) { ZIO z; @@ -879,7 +893,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) - status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); + status = luaU_dump(L, getproto(o), writer, data, 0); else status = 1; lua_unlock(L); @@ -911,7 +925,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCCOLLECT: { - luaC_fullgc(L); + luaC_fullgc(L, 0); break; } case LUA_GCCOUNT: { @@ -924,11 +938,9 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCSTEP: { + lu_mem oldts = g->GCthreshold; lu_mem a = (cast(lu_mem, data) << 10); - if (a <= g->totalbytes) - g->GCthreshold = g->totalbytes - a; - else - g->GCthreshold = 0; + g->GCthreshold = (a <= g->totalbytes) ? g->totalbytes - a : 0; while (g->GCthreshold <= g->totalbytes) { luaC_step(L); if (g->gcstate == GCSpause) { /* end of cycle? */ @@ -936,6 +948,8 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } } + if (oldts == MAX_LUMEM) /* collector was stopped? */ + g->GCthreshold = oldts; /* keep it that way */ break; } case LUA_GCSETPAUSE: { @@ -948,6 +962,10 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->gcstepmul = data; break; } + case LUA_GCISRUNNING: { + res = (g->GCthreshold != MAX_LUMEM); + break; + } default: res = -1; /* invalid option */ } lua_unlock(L); @@ -974,8 +992,8 @@ LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); - t = index2adr(L, idx); - api_check(L, ttistable(t)); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { api_incr_top(L); @@ -992,8 +1010,7 @@ LUA_API void lua_concat (lua_State *L, int n) { api_checknelems(L, n); if (n >= 2) { luaC_checkGC(L); - luaV_concat(L, n, cast_int(L->top - L->base) - 1); - L->top -= (n-1); + luaV_concat(L, n); } else if (n == 0) { /* push empty string */ setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); @@ -1004,6 +1021,16 @@ LUA_API void lua_concat (lua_State *L, int n) { } +LUA_API void lua_len (lua_State *L, int idx) { + StkId t; + lua_lock(L); + t = index2addr(L, idx); + luaV_objlen(L, L->top, t); + api_incr_top(L); + lua_unlock(L); +} + + LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { lua_Alloc f; lua_lock(L); @@ -1049,7 +1076,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val) { Proto *p = f->l.p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; - return getstr(p->upvalues[n-1]); + return getstr(p->upvalues[n-1].name); } } @@ -1058,7 +1085,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); - name = aux_upvalue(index2adr(L, funcindex), n, &val); + name = aux_upvalue(index2addr(L, funcindex), n, &val); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1073,7 +1100,7 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { TValue *val; StkId fi; lua_lock(L); - fi = index2adr(L, funcindex); + fi = index2addr(L, funcindex); api_checknelems(L, 1); name = aux_upvalue(fi, n, &val); if (name) { @@ -1085,3 +1112,49 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { return name; } + +static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { + Closure *f; + Proto *p; + StkId fi = index2addr(L, fidx); + api_check(L, ttisfunction(fi), "function expected"); + f = clvalue(fi); + api_check(L, !f->c.isC, "Lua function expected"); + p = f->l.p; + api_check(L, (1 <= n && n <= p->sizeupvalues), "invalid upvalue index"); + if (pf) *pf = f; + return &f->l.upvals[n - 1]; /* get its upvalue pointer */ +} + + +LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { + Closure *f; + StkId fi = index2addr(L, fidx); + api_check(L, ttisfunction(fi), "function expected"); + f = clvalue(fi); + if (f->c.isC) { + api_check(L, 1 <= n && n <= f->c.nupvalues, "invalid upvalue index"); + return &f->c.upvalue[n - 1]; + } + else return *getupvalref(L, fidx, n, NULL); +} + + +LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + Closure *f1; + UpVal **up1 = getupvalref(L, fidx1, n1, &f1); + UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + *up1 = *up2; + luaC_objbarrier(L, f1, *up2); +} + + +#if defined(LUA_COMPAT_CPCALL) +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); + lua_pushlightuserdata(L, &func); + lua_pushlightuserdata(L, ud); + return lua_pcall(L, 2, 0, 0); +} +#endif diff --git a/src/lapi.h b/src/lapi.h index 2c3fab244e..0909a3911d 100644 --- a/src/lapi.h +++ b/src/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lapi.h,v 2.7 2009/11/27 15:37:59 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -8,9 +8,17 @@ #define lapi_h -#include "lobject.h" +#include "llimits.h" +#include "lstate.h" +#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ + "stack overflow");} + +#define adjustresults(L,nres) \ + { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } + +#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ + "not enough elements in the stack") -LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); #endif diff --git a/src/lauxlib.c b/src/lauxlib.c index 10f14e2c08..9972555e34 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,11 +1,10 @@ /* -** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $ +** $Id: lauxlib.c,v 1.196 2009/12/22 15:32:50 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ -#include #include #include #include @@ -25,9 +24,6 @@ #include "lauxlib.h" -#define FREELIST_REF 0 /* free list of references */ - - /* convert a stack index to positive */ #define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ lua_gettop(L) + (i) + 1) @@ -35,11 +31,131 @@ /* ** {====================================================== -** Error-report functions +** Traceback ** ======================================================= */ +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ + + + +/* +** search for 'objidx' in table at index -1. +** return 1 + string at top if find a good name. +*/ +static int findfield (lua_State *L, int objidx, int level) { + int found = 0; + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (!found && lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (findfield(L, objidx, level - 1)) { /* try recursively */ + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + + +static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_pushglobaltable(L); + if (findfield(L, top + 1, 2)) { + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + + +static void pushfuncname (lua_State *L, lua_Debug *ar) { + if (*ar->namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, "function " LUA_QS, ar->name); + else if (*ar->what == 'm') /* main? */ + lua_pushfstring(L, "main chunk"); + else if (*ar->what == 'C' || *ar->what == 't') { + if (pushglobalfuncname(L, ar)) { + lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else + lua_pushliteral(L, "?"); + } + else + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); +} + + +static int countlevels (lua_State *L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } + /* do a binary search */ + while (li < le) { + int m = (li + le)/2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; +} + + +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level) { + lua_Debug ar; + int top = lua_gettop(L); + int numlevels = countlevels(L1); + int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; + if (msg) lua_pushfstring(L, "%s\n", msg); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (level == mark) { /* too many levels? */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ + level = numlevels - LEVELS2; /* and skip to last ones */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + lua_pushfstring(L, "\n\t%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + lua_pushliteral(L, " in "); + pushfuncname(L, &ar); + if (ar.istailcall) + lua_pushliteral(L, "\n\t(...tail calls...)"); + lua_concat(L, lua_gettop(L) - top); + } + } + lua_concat(L, lua_gettop(L) - top); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Error-report functions +** ======================================================= +*/ + LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ @@ -48,17 +164,16 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling " LUA_QS " on bad self (%s)", - ar.name, extramsg); + return luaL_error(L, "calling " LUA_QS " on bad self", ar.name); } if (ar.name == NULL) - ar.name = "?"; + ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", narg, ar.name, extramsg); } -LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { +LUALIB_API int luaL_typeerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); @@ -66,7 +181,7 @@ LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { static void tag_error (lua_State *L, int narg, int tag) { - luaL_typerror(L, narg, lua_typename(L, tag)); + luaL_typeerror(L, narg, lua_typename(L, tag)); } @@ -96,18 +211,11 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { /* }====================================================== */ -LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, - const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, narg, def) : - luaL_checkstring(L, narg); - int i; - for (i=0; lst[i]; i++) - if (strcmp(lst[i], name) == 0) - return i; - return luaL_argerror(L, narg, - lua_pushfstring(L, "invalid option " LUA_QS, name)); -} - +/* +** {====================================================== +** Userdata's metatable manipulation +** ======================================================= +*/ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ @@ -121,25 +229,56 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { } -LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { +LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); if (p != NULL) { /* value is a userdata? */ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ - if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ - lua_pop(L, 2); /* remove both metatables */ - return p; - } + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; } } - luaL_typerror(L, ud, tname); /* else error */ - return NULL; /* to avoid warnings */ + return NULL; /* value is not a userdata with a metatable */ +} + + +LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { + void *p = luaL_testudata(L, ud, tname); + if (p == NULL) luaL_typeerror(L, ud, tname); + return p; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Argument check functions +** ======================================================= +*/ + +LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, + const char *const lst[]) { + const char *name = (def) ? luaL_optstring(L, narg, def) : + luaL_checkstring(L, narg); + int i; + for (i=0; lst[i]; i++) + if (strcmp(lst[i], name) == 0) + return i; + return luaL_argerror(L, narg, + lua_pushfstring(L, "invalid option " LUA_QS, name)); } -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { - if (!lua_checkstack(L, space)) - luaL_error(L, "stack overflow (%s)", mes); +LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { + if (!lua_checkstack(L, space)) { + if (msg) + luaL_error(L, "stack overflow (%s)", msg); + else + luaL_error(L, "stack overflow"); + } } @@ -199,189 +338,9 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, return luaL_opt(L, luaL_checkinteger, narg, def); } - -LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { - if (!lua_getmetatable(L, obj)) /* no metatable? */ - return 0; - lua_pushstring(L, event); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - lua_pop(L, 2); /* remove metatable and metafield */ - return 0; - } - else { - lua_remove(L, -2); /* remove only metatable */ - return 1; - } -} - - -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = abs_index(L, obj); - if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ - return 0; - lua_pushvalue(L, obj); - lua_call(L, 1, 1); - return 1; -} - - -LUALIB_API void (luaL_register) (lua_State *L, const char *libname, - const luaL_Reg *l) { - luaI_openlib(L, libname, l, 0); -} - - -static int libsize (const luaL_Reg *l) { - int size = 0; - for (; l->name; l++) size++; - return size; -} - - -LUALIB_API void luaI_openlib (lua_State *L, const char *libname, - const luaL_Reg *l, int nup) { - if (libname) { - int size = libsize(l); - /* check whether lib already exists */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); - lua_getfield(L, -1, libname); /* get _LOADED[libname] */ - if (!lua_istable(L, -1)) { /* not found? */ - lua_pop(L, 1); /* remove previous result */ - /* try global variable (and create one if it does not exist) */ - if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) - luaL_error(L, "name conflict for module " LUA_QS, libname); - lua_pushvalue(L, -1); - lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ - } - lua_remove(L, -2); /* remove _LOADED table */ - lua_insert(L, -(nup+1)); /* move library table to below upvalues */ - } - for (; l->name; l++) { - int i; - for (i=0; ifunc, nup); - lua_setfield(L, -(nup+2), l->name); - } - lua_pop(L, nup); /* remove upvalues */ -} - - - -/* -** {====================================================== -** getn-setn: size for arrays -** ======================================================= -*/ - -#if defined(LUA_COMPAT_GETN) - -static int checkint (lua_State *L, int topop) { - int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; - lua_pop(L, topop); - return n; -} - - -static void getsizes (lua_State *L) { - lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); - if (lua_isnil(L, -1)) { /* no `size' table? */ - lua_pop(L, 1); /* remove nil */ - lua_newtable(L); /* create it */ - lua_pushvalue(L, -1); /* `size' will be its own metatable */ - lua_setmetatable(L, -2); - lua_pushliteral(L, "kv"); - lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ - } -} - - -LUALIB_API void luaL_setn (lua_State *L, int t, int n) { - t = abs_index(L, t); - lua_pushliteral(L, "n"); - lua_rawget(L, t); - if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ - lua_pushliteral(L, "n"); /* use it */ - lua_pushinteger(L, n); - lua_rawset(L, t); - } - else { /* use `sizes' */ - getsizes(L); - lua_pushvalue(L, t); - lua_pushinteger(L, n); - lua_rawset(L, -3); /* sizes[t] = n */ - lua_pop(L, 1); /* remove `sizes' */ - } -} - - -LUALIB_API int luaL_getn (lua_State *L, int t) { - int n; - t = abs_index(L, t); - lua_pushliteral(L, "n"); /* try t.n */ - lua_rawget(L, t); - if ((n = checkint(L, 1)) >= 0) return n; - getsizes(L); /* else try sizes[t] */ - lua_pushvalue(L, t); - lua_rawget(L, -2); - if ((n = checkint(L, 2)) >= 0) return n; - return (int)lua_objlen(L, t); -} - -#endif - /* }====================================================== */ - -LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, - const char *r) { - const char *wild; - size_t l = strlen(p); - luaL_Buffer b; - luaL_buffinit(L, &b); - while ((wild = strstr(s, p)) != NULL) { - luaL_addlstring(&b, s, wild - s); /* push prefix */ - luaL_addstring(&b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after `p' */ - } - luaL_addstring(&b, s); /* push last suffix */ - luaL_pushresult(&b); - return lua_tostring(L, -1); -} - - -LUALIB_API const char *luaL_findtable (lua_State *L, int idx, - const char *fname, int szhint) { - const char *e; - lua_pushvalue(L, idx); - do { - e = strchr(fname, '.'); - if (e == NULL) e = fname + strlen(fname); - lua_pushlstring(L, fname, e - fname); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { /* no such field? */ - lua_pop(L, 1); /* remove this nil */ - lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ - lua_pushlstring(L, fname, e - fname); - lua_pushvalue(L, -2); - lua_settable(L, -4); /* set new table into field */ - } - else if (!lua_istable(L, -1)) { /* field has a non-table value? */ - lua_pop(L, 2); /* remove table and value */ - return fname; /* return problematic part of the name */ - } - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - } while (*e == '.'); - return NULL; -} - - - /* ** {====================================================== ** Generic Buffer manipulation @@ -411,9 +370,9 @@ static void adjuststack (luaL_Buffer *B) { if (B->lvl > 1) { lua_State *L = B->L; int toget = 1; /* number of levels to concat */ - size_t toplen = lua_strlen(L, -1); + size_t toplen = lua_rawlen(L, -1); do { - size_t l = lua_strlen(L, -(toget+1)); + size_t l = lua_rawlen(L, -(toget+1)); if (B->lvl - toget + 1 >= LIMIT || toplen > l) { toplen += l; toget++; @@ -470,6 +429,7 @@ LUALIB_API void luaL_addvalue (luaL_Buffer *B) { LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { + luaL_checkstack(L, LIMIT + LUA_MINSTACK, "no space for new buffer"); B->L = L; B->p = B->buffer; B->lvl = 0; @@ -478,6 +438,16 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { /* }====================================================== */ +/* +** {====================================================== +** Reference system +** ======================================================= +*/ + +/* number of prereserved references (for internal use) */ +#define FREELIST_REF (LUA_RIDX_LAST + 1) /* free list of references */ + + LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; t = abs_index(L, t); @@ -493,8 +463,12 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ - ref = (int)lua_objlen(L, t); - ref++; /* create new reference */ + ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ + if (ref == FREELIST_REF) { /* FREELIST_REF not initialized? */ + lua_pushinteger(L, 0); + lua_rawseti(L, t, FREELIST_REF); + ref = FREELIST_REF + 1; + } } lua_rawseti(L, t, ref); return ref; @@ -511,6 +485,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { } } +/* }====================================================== */ /* @@ -534,6 +509,9 @@ static const char *getF (lua_State *L, void *ud, size_t *size) { *size = 1; return "\n"; } + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' calls 'fread', terminal may still wait for user input. + The next check avoids this problem. */ if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); return (*size > 0) ? lf->buff : NULL; @@ -574,7 +552,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); /* skip eventual `#!...' */ - while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; lf.extraline = 0; } ungetc(c, lf.f); @@ -615,13 +593,149 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, } -LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { +LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { return luaL_loadbuffer(L, s, strlen(s), s); } +/* }====================================================== */ -/* }====================================================== */ + +LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { + if (!lua_getmetatable(L, obj)) /* no metatable? */ + return 0; + lua_pushstring(L, event); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); /* remove metatable and metafield */ + return 0; + } + else { + lua_remove(L, -2); /* remove only metatable */ + return 1; + } +} + + +LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { + obj = abs_index(L, obj); + if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ + return 0; + lua_pushvalue(L, obj); + lua_call(L, 1, 1); + return 1; +} + + +LUALIB_API int luaL_len (lua_State *L, int idx) { + int l; + lua_len(L, idx); + l = lua_tointeger(L, -1); + if (l == 0 && !lua_isnumber(L, -1)) + luaL_error(L, "object length is not a number"); + lua_pop(L, 1); /* remove object */ + return l; +} + + +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ + switch (lua_type(L, idx)) { + case LUA_TNUMBER: + case LUA_TSTRING: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), + lua_topointer(L, idx)); + break; + } + } + return lua_tolstring(L, -1, len); +} + + +static int libsize (const luaL_Reg *l) { + int size = 0; + for (; l->name; l++) size++; + return size; +} + + +LUALIB_API void luaL_register (lua_State *L, const char *libname, + const luaL_Reg *l) { + luaL_checkversion(L); + if (libname) { + /* check whether lib already exists */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); + lua_getfield(L, -1, libname); /* get _LOADED[libname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + lua_pushglobaltable(L); + if (luaL_findtable(L, 0, libname, libsize(l)) != NULL) + luaL_error(L, "name conflict for module " LUA_QS, libname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ + } + lua_remove(L, -2); /* remove _LOADED table */ + } + if (l == NULL) return; /* nothing to register? */ + for (; l->name; l++) { /* else fill the table with given functions */ + lua_pushcfunction(L, l->func); + lua_setfield(L, -2, l->name); + } +} + + +LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, + const char *r) { + const char *wild; + size_t l = strlen(p); + luaL_Buffer b; + luaL_buffinit(L, &b); + while ((wild = strstr(s, p)) != NULL) { + luaL_addlstring(&b, s, wild - s); /* push prefix */ + luaL_addstring(&b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after `p' */ + } + luaL_addstring(&b, s); /* push last suffix */ + luaL_pushresult(&b); + return lua_tostring(L, -1); +} + + +LUALIB_API const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + if (idx) lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { @@ -637,10 +751,9 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { static int panic (lua_State *L) { - (void)L; /* to avoid warnings */ fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); - return 0; + return 0; /* return to Lua to abort */ } @@ -650,3 +763,13 @@ LUALIB_API lua_State *luaL_newstate (void) { return L; } + +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) { + const lua_Number *v = lua_version(L); + if (v != lua_version(NULL)) + luaL_error(L, "multiple Lua VMs detected"); + else if (*v != ver) + luaL_error(L, "version mismatch: app. needs %d, Lua core provides %f", + ver, *v); +} + diff --git a/src/lauxlib.h b/src/lauxlib.h index 34258235db..d014348179 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lauxlib.h,v 1.98 2010/01/06 15:14:15 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -15,18 +15,6 @@ #include "lua.h" -#if defined(LUA_COMPAT_GETN) -LUALIB_API int (luaL_getn) (lua_State *L, int t); -LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); -#else -#define luaL_getn(L,i) ((int)lua_objlen(L, i)) -#define luaL_setn(L,i,j) ((void)0) /* no op! */ -#endif - -#if defined(LUA_COMPAT_OPENLIB) -#define luaI_openlib luaL_openlib -#endif - /* extra error code for `luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) @@ -38,6 +26,8 @@ typedef struct luaL_Reg { } luaL_Reg; +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); +#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup); @@ -45,7 +35,8 @@ LUALIB_API void (luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); +LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); +LUALIB_API int (luaL_typeerror) (lua_State *L, int narg, const char *tname); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); @@ -63,6 +54,7 @@ LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int narg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); @@ -81,6 +73,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); +LUALIB_API int luaL_len (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -88,6 +81,8 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, const char *fname, int szhint); +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level); @@ -137,9 +132,6 @@ typedef struct luaL_Buffer { ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ (*(B)->p++ = (char)(c))) -/* compatibility only */ -#define luaL_putchar(B,c) luaL_addchar(B,c) - #define luaL_addsize(B,n) ((B)->p += (n)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); @@ -169,6 +161,7 @@ LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); #define luaL_reg luaL_Reg + #endif diff --git a/src/lbaselib.c b/src/lbaselib.c index 2a4c079d3b..162c06f202 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ +** $Id: lbaselib.c,v 1.235 2009/12/28 16:30:31 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -20,32 +20,25 @@ #include "lualib.h" - - -/* -** If your system does not support `stdout', you can just remove this function. -** If you need, you can define your own `print' function, following this -** model but changing `fputs' to put the strings at a proper place -** (a console window or a log file, for instance). -*/ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; - lua_getglobal(L, "tostring"); + lua_getfield(L, LUA_ENVIRONINDEX, "tostring"); for (i=1; i<=n; i++) { const char *s; + size_t l; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ lua_call(L, 1, 1); - s = lua_tostring(L, -1); /* get result */ + s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); - if (i>1) fputs("\t", stdout); - fputs(s, stdout); + if (i>1) luai_writestring("\t", 1); + luai_writestring(s, l); lua_pop(L, 1); /* pop result */ } - fputs("\n", stdout); + luai_writestring("\n", 1); return 0; } @@ -107,13 +100,16 @@ static int luaB_setmetatable (lua_State *L) { luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); if (luaL_getmetafield(L, 1, "__metatable")) - luaL_error(L, "cannot change a protected metatable"); + return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; } + +#if defined(LUA_COMPAT_FENV) + static void getfunc (lua_State *L, int opt) { if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); else { @@ -123,40 +119,38 @@ static void getfunc (lua_State *L, int opt) { if (lua_getstack(L, level, &ar) == 0) luaL_argerror(L, 1, "invalid level"); lua_getinfo(L, "f", &ar); - if (lua_isnil(L, -1)) - luaL_error(L, "no function environment for tail call at level %d", - level); } } - static int luaB_getfenv (lua_State *L) { getfunc(L, 1); if (lua_iscfunction(L, -1)) /* is a C function? */ - lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ + lua_pushglobaltable(L); /* return the global env. */ else lua_getfenv(L, -1); return 1; } - static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); getfunc(L, 0); lua_pushvalue(L, 2); - if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { - /* change environment of current thread */ - lua_pushthread(L); - lua_insert(L, -2); - lua_setfenv(L, -2); - return 0; - } - else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) - luaL_error(L, - LUA_QL("setfenv") " cannot change environment of given object"); + if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) + return luaL_error(L, + LUA_QL("setfenv") " cannot change environment of given object"); return 1; } +#else + +static int luaB_getfenv (lua_State *L) { + return luaL_error(L, "getfenv/setfenv deprecated"); +} + +#define luaB_setfenv luaB_getfenv + +#endif + static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); @@ -185,31 +179,33 @@ static int luaB_rawset (lua_State *L) { static int luaB_gcinfo (lua_State *L) { - lua_pushinteger(L, lua_getgccount(L)); + lua_pushinteger(L, lua_gc(L, LUA_GCCOUNT, 0)); return 1; } static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", NULL}; + "count", "step", "setpause", "setstepmul", "isrunning", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; - int o = luaL_checkoption(L, 1, "collect", opts); + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, + LUA_GCISRUNNING}; + int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; int ex = luaL_optint(L, 2, 0); - int res = lua_gc(L, optsnum[o], ex); - switch (optsnum[o]) { + int res = lua_gc(L, o, ex); + switch (o) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); lua_pushnumber(L, res + ((lua_Number)b/1024)); - return 1; + lua_pushinteger(L, b); + return 2; } - case LUA_GCSTEP: { + case LUA_GCSTEP: case LUA_GCISRUNNING: { lua_pushboolean(L, res); return 1; } default: { - lua_pushnumber(L, res); + lua_pushinteger(L, res); return 1; } } @@ -223,6 +219,22 @@ static int luaB_type (lua_State *L) { } +static int pairsmeta (lua_State *L, const char *method, int iszero) { + if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ + luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ + lua_pushvalue(L, lua_upvalueindex(1)); /* will return generator, */ + lua_pushvalue(L, 1); /* state, */ + if (iszero) lua_pushinteger(L, 0); /* and initial value */ + else lua_pushnil(L); + } + else { + lua_pushvalue(L, 1); /* argument 'self' to metamethod */ + lua_call(L, 1, 3); /* get 3 values from metamethod */ + } + return 3; +} + + static int luaB_next (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 2); /* create a 2nd argument if there isn't one */ @@ -236,11 +248,7 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushnil(L); /* and initial value */ - return 3; + return pairsmeta(L, "__pairs", 0); } @@ -250,21 +258,17 @@ static int ipairsaux (lua_State *L) { i++; /* next value */ lua_pushinteger(L, i); lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 0 : 2; + return (lua_isnil(L, -1) && i > luaL_len(L, 1)) ? 0 : 2; } static int luaB_ipairs (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushinteger(L, 0); /* and initial value */ - return 3; + return pairsmeta(L, "__ipairs", 1); } static int load_aux (lua_State *L, int status) { - if (status == 0) /* OK? */ + if (status == LUA_OK) return 1; else { lua_pushnil(L); @@ -274,87 +278,140 @@ static int load_aux (lua_State *L, int status) { } -static int luaB_loadstring (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - const char *chunkname = luaL_optstring(L, 2, s); - return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); -} - - static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); return load_aux(L, luaL_loadfile(L, fname)); } +/* +** {====================================================== +** Generic Read function +** ======================================================= +*/ + +static const char *checkrights (lua_State *L, const char *mode, const char *s) { + if (strchr(mode, 'b') == NULL && *s == LUA_SIGNATURE[0]) + return lua_pushstring(L, "attempt to load a binary chunk"); + if (strchr(mode, 't') == NULL && *s != LUA_SIGNATURE[0]) + return lua_pushstring(L, "attempt to load a text chunk"); + return NULL; /* chunk in allowed format */ +} + + +/* +** reserves a slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed +*/ +#define RESERVEDSLOT 4 + + /* ** Reader for generic `load' function: `lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ +typedef struct { /* reader state */ + int f; /* position of reader function on stack */ + const char *mode; /* allowed modes (binary/text) */ +} Readstat; + static const char *generic_reader (lua_State *L, void *ud, size_t *size) { - (void)ud; /* to avoid warnings */ + const char *s; + Readstat *stat = (Readstat *)ud; luaL_checkstack(L, 2, "too many nested functions"); - lua_pushvalue(L, 1); /* get function */ + lua_pushvalue(L, stat->f); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { *size = 0; return NULL; } - else if (lua_isstring(L, -1)) { - lua_replace(L, 3); /* save string in a reserved stack slot */ - return lua_tolstring(L, 3, size); + else if ((s = lua_tostring(L, -1)) != NULL) { + if (stat->mode != NULL) { /* first time? */ + s = checkrights(L, stat->mode, s); /* check mode */ + stat->mode = NULL; /* to avoid further checks */ + if (s) luaL_error(L, s); + } + lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ + return lua_tolstring(L, RESERVEDSLOT, size); + } + else { + luaL_error(L, "reader function must return a string"); + return NULL; /* to avoid warnings */ } - else luaL_error(L, "reader function must return a string"); - return NULL; /* to avoid warnings */ } -static int luaB_load (lua_State *L) { +static int luaB_load_aux (lua_State *L, int farg) { int status; - const char *cname = luaL_optstring(L, 2, "=(load)"); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ - status = lua_load(L, generic_reader, NULL, cname); + Readstat stat; + size_t l; + const char *s = lua_tolstring(L, farg, &l); + stat.mode = luaL_optstring(L, farg + 2, "bt"); + if (s != NULL) { /* loading a string? */ + const char *chunkname = luaL_optstring(L, farg + 1, s); + status = (checkrights(L, stat.mode, s) != NULL) + || luaL_loadbuffer(L, s, l, chunkname); + } + else { /* loading from a reader function */ + const char *chunkname = luaL_optstring(L, farg + 1, "=(load)"); + luaL_checktype(L, farg, LUA_TFUNCTION); + stat.f = farg; + lua_settop(L, RESERVEDSLOT); /* create reserved slot */ + status = lua_load(L, generic_reader, &stat, chunkname); + } return load_aux(L, status); } +static int luaB_load (lua_State *L) { + return luaB_load_aux(L, 1); +} + + +static int luaB_loadin (lua_State *L) { + int n; + luaL_checktype(L, 1, LUA_TTABLE); + n = luaB_load_aux(L, 2); + if (n == 1) { /* success? */ + lua_pushvalue(L, 1); /* environment for loaded function */ + lua_setfenv(L, -2); + } + return n; +} + + +static int luaB_loadstring (lua_State *L) { + lua_settop(L, 2); + lua_pushliteral(L, "tb"); + return luaB_load(L); /* dostring(s, n) == load(s, n, "tb") */ + +} +/* }====================================================== */ + + +static int dofilecont (lua_State *L) { + return lua_gettop(L) - 1; +} + + static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); - int n = lua_gettop(L); - if (luaL_loadfile(L, fname) != 0) lua_error(L); - lua_call(L, 0, LUA_MULTRET); - return lua_gettop(L) - n; + lua_settop(L, 1); + if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); + lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); + return dofilecont(L); } static int luaB_assert (lua_State *L) { - luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); return lua_gettop(L); } -static int luaB_unpack (lua_State *L) { - int i, e, n; - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 2, 1); - e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); - if (i > e) return 0; /* empty range */ - n = e - i + 1; /* number of elements */ - if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ - return luaL_error(L, "too many results to unpack"); - lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ - while (i++ < e) /* push arg[i + 1...e] */ - lua_rawgeti(L, 1, i); - return n; -} - - static int luaB_select (lua_State *L) { int n = lua_gettop(L); if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { @@ -371,11 +428,25 @@ static int luaB_select (lua_State *L) { } +static int pcallcont (lua_State *L) { + int errfunc; /* call has an error function in bottom of the stack */ + int status = lua_getctx(L, &errfunc); + lua_assert(status != LUA_OK); + lua_pushboolean(L, (status == LUA_YIELD)); /* first result (status) */ + if (errfunc) /* came from xpcall? */ + lua_replace(L, 1); /* put first result in place of error function */ + else /* came from pcall */ + lua_insert(L, 1); /* open space for first result */ + return lua_gettop(L); +} + + static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); - status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); - lua_pushboolean(L, (status == 0)); + status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, pcallcont); + luaL_checkstack(L, 1, NULL); + lua_pushboolean(L, (status == LUA_OK)); lua_insert(L, 1); return lua_gettop(L); /* return status + all results */ } @@ -383,11 +454,14 @@ static int luaB_pcall (lua_State *L) { static int luaB_xpcall (lua_State *L) { int status; - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_insert(L, 1); /* put error function under function to be called */ - status = lua_pcall(L, 0, LUA_MULTRET, 1); - lua_pushboolean(L, (status == 0)); + int n = lua_gettop(L); + luaL_argcheck(L, n >= 2, 2, "value expected"); + lua_pushvalue(L, 1); /* exchange function... */ + lua_copy(L, 2, 1); /* ...and error handler */ + lua_replace(L, 2); + status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 1, pcallcont); + luaL_checkstack(L, 1, NULL); + lua_pushboolean(L, (status == LUA_OK)); lua_replace(L, 1); return lua_gettop(L); /* return status + all results */ } @@ -395,25 +469,7 @@ static int luaB_xpcall (lua_State *L) { static int luaB_tostring (lua_State *L) { luaL_checkany(L, 1); - if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ - return 1; /* use its value */ - switch (lua_type(L, 1)) { - case LUA_TNUMBER: - lua_pushstring(L, lua_tostring(L, 1)); - break; - case LUA_TSTRING: - lua_pushvalue(L, 1); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: - lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); - break; - } + luaL_tolstring(L, 1, NULL); return 1; } @@ -424,7 +480,9 @@ static int luaB_newproxy (lua_State *L) { if (lua_toboolean(L, 1) == 0) return 1; /* no metatable */ else if (lua_isboolean(L, 1)) { - lua_newtable(L); /* create a new metatable `m' ... */ + lua_createtable(L, 0, 1); /* create a new metatable `m' ... */ + lua_pushboolean(L, 1); + lua_setfield(L, -2, "__gc"); /* ... m.__gc = false (HACK!!)... */ lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ lua_pushboolean(L, 1); lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ @@ -454,6 +512,7 @@ static const luaL_Reg base_funcs[] = { {"getmetatable", luaB_getmetatable}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, + {"loadin", luaB_loadin}, {"loadstring", luaB_loadstring}, {"next", luaB_next}, {"pcall", luaB_pcall}, @@ -467,7 +526,6 @@ static const luaL_Reg base_funcs[] = { {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, - {"unpack", luaB_unpack}, {"xpcall", luaB_xpcall}, {NULL, NULL} }; @@ -479,57 +537,25 @@ static const luaL_Reg base_funcs[] = { ** ======================================================= */ -#define CO_RUN 0 /* running */ -#define CO_SUS 1 /* suspended */ -#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */ -#define CO_DEAD 3 - -static const char *const statnames[] = - {"running", "suspended", "normal", "dead"}; - -static int costatus (lua_State *L, lua_State *co) { - if (L == co) return CO_RUN; - switch (lua_status(co)) { - case LUA_YIELD: - return CO_SUS; - case 0: { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ - return CO_NOR; /* it is running */ - else if (lua_gettop(co) == 0) - return CO_DEAD; - else - return CO_SUS; /* initial state */ - } - default: /* some error occured */ - return CO_DEAD; - } -} - - -static int luaB_costatus (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - lua_pushstring(L, statnames[costatus(L, co)]); - return 1; -} - - static int auxresume (lua_State *L, lua_State *co, int narg) { - int status = costatus(L, co); - if (!lua_checkstack(co, narg)) - luaL_error(L, "too many arguments to resume"); - if (status != CO_SUS) { - lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); + int status; + if (!lua_checkstack(co, narg)) { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } lua_xmove(L, co, narg); - lua_setlevel(L, co); status = lua_resume(co, narg); - if (status == 0 || status == LUA_YIELD) { + if (status == LUA_OK || status == LUA_YIELD) { int nres = lua_gettop(co); - if (!lua_checkstack(L, nres + 1)) - luaL_error(L, "too many results to resume"); + if (!lua_checkstack(L, nres + 1)) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } lua_xmove(co, L, nres); /* move yielded values */ return nres; } @@ -575,8 +601,7 @@ static int luaB_auxwrap (lua_State *L) { static int luaB_cocreate (lua_State *L) { lua_State *NL = lua_newthread(L); - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); + luaL_checktype(L, 1, LUA_TFUNCTION); lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; @@ -595,13 +620,41 @@ static int luaB_yield (lua_State *L) { } -static int luaB_corunning (lua_State *L) { - if (lua_pushthread(L)) - lua_pushnil(L); /* main thread is not a coroutine */ +static int luaB_costatus (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "coroutine expected"); + if (L == co) lua_pushliteral(L, "running"); + else { + switch (lua_status(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case LUA_OK: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occurred */ + lua_pushliteral(L, "dead"); + break; + } + } return 1; } +static int luaB_corunning (lua_State *L) { + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; +} + + static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, {"resume", luaB_coresume}, @@ -625,13 +678,13 @@ static void auxopen (lua_State *L, const char *name, static void base_open (lua_State *L) { /* set global _G */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setglobal(L, "_G"); + lua_pushglobaltable(L); + lua_setfield(L, LUA_ENVIRONINDEX, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); - lua_setglobal(L, "_VERSION"); /* set global _VERSION */ - /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + lua_setfield(L, LUA_ENVIRONINDEX, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxiliary functions as upvalues */ auxopen(L, "ipairs", luaB_ipairs, ipairsaux); auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ @@ -641,11 +694,11 @@ static void base_open (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_setglobal(L, "newproxy"); /* set global `newproxy' */ + lua_setfield(L, LUA_ENVIRONINDEX, "newproxy"); /* set global `newproxy' */ } -LUALIB_API int luaopen_base (lua_State *L) { +LUAMOD_API int luaopen_base (lua_State *L) { base_open(L); luaL_register(L, LUA_COLIBNAME, co_funcs); return 2; diff --git a/src/lbitlib.c b/src/lbitlib.c new file mode 100644 index 0000000000..5b6a6aae06 --- /dev/null +++ b/src/lbitlib.c @@ -0,0 +1,123 @@ +/* +** $Id: lbitlib.c,v 1.2 2009/11/24 12:05:44 roberto Exp $ +** Standard library for bitwise operations +** See Copyright Notice in lua.h +*/ + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* number of bits considered when shifting/rotating (must be a power of 2) */ +#define NBITS 32 + + +typedef LUA_INT32 b_int; +typedef unsigned LUA_INT32 b_uint; + + +static b_uint getuintarg (lua_State *L, int arg) { + b_uint r; + lua_Number x = lua_tonumber(L, arg); + if (x == 0) luaL_checktype(L, arg, LUA_TNUMBER); + lua_number2uint(r, x); + return r; +} + + +static b_uint andaux (lua_State *L) { + int i, n = lua_gettop(L); + b_uint r = ~(b_uint)0; + for (i = 1; i <= n; i++) + r &= getuintarg(L, i); + return r; +} + + +static int b_and (lua_State *L) { + b_uint r = andaux(L); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_test (lua_State *L) { + b_uint r = andaux(L); + lua_pushboolean(L, r != 0); + return 1; +} + + +static int b_or (lua_State *L) { + int i, n = lua_gettop(L); + b_uint r = 0; + for (i = 1; i <= n; i++) + r |= getuintarg(L, i); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_xor (lua_State *L) { + int i, n = lua_gettop(L); + b_uint r = 0; + for (i = 1; i <= n; i++) + r ^= getuintarg(L, i); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_not (lua_State *L) { + b_uint r = ~getuintarg(L, 1); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_shift (lua_State *L) { + b_uint r = getuintarg(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + if (i < 0) { /* shift right? */ + i = -i; + if (i >= NBITS) r = 0; + else r >>= i; + } + else { /* shift left */ + if (i >= NBITS) r = 0; + else r <<= i; + } + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static int b_rotate (lua_State *L) { + b_uint r = getuintarg(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + i &= (NBITS - 1); /* i = i % NBITS */ + r = (r << i) | (r >> (NBITS - i)); + lua_pushnumber(L, lua_uint2number(r)); + return 1; +} + + +static const luaL_Reg bitlib[] = { + {"band", b_and}, + {"btest", b_test}, + {"bor", b_or}, + {"bxor", b_xor}, + {"bnot", b_not}, + {"bshift", b_shift}, + {"brotate", b_rotate}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_bit (lua_State *L) { + luaL_register(L, LUA_BITLIBNAME, bitlib); + return 1; +} diff --git a/src/lcode.c b/src/lcode.c index cff626b7fa..4f10e09544 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: lcode.c,v 2.42 2009/09/23 20:33:05 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -21,6 +21,7 @@ #include "lobject.h" #include "lopcodes.h" #include "lparser.h" +#include "lstring.h" #include "ltable.h" @@ -35,20 +36,14 @@ static int isnumeral(expdesc *e) { void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ - if (fs->pc == 0) { /* function start? */ - if (from >= fs->nactvar) - return; /* positions are already clean */ - } - else { - previous = &fs->f->code[fs->pc-1]; - if (GET_OPCODE(*previous) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pto = GETARG_B(*previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(*previous, from+n-1); - return; - } + previous = &fs->f->code[fs->pc-1]; + if (GET_OPCODE(*previous) == OP_LOADNIL) { + int pfrom = GETARG_A(*previous); + int pto = GETARG_B(*previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(*previous, from+n-1); + return; } } } @@ -196,6 +191,55 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { } +static int luaK_code (FuncState *fs, Instruction i) { + Proto *f = fs->f; + dischargejpc(fs); /* `pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, + MAX_INT, "opcodes"); + f->code[fs->pc] = i; + /* save corresponding line information */ + luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + MAX_INT, "opcodes"); + f->lineinfo[fs->pc] = fs->ls->lastline; + return fs->pc++; +} + + +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == iABC); + lua_assert(getBMode(o) != OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgN || c == 0); + lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); + return luaK_code(fs, CREATE_ABC(o, a, b, c)); +} + + +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { + lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); + lua_assert(getCMode(o) == OpArgN); + lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); + return luaK_code(fs, CREATE_ABx(o, a, bc)); +} + + +static int codeextraarg (FuncState *fs, int a) { + lua_assert(a <= MAXARG_Ax); + return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); +} + + +int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k) { + if (k < MAXARG_Bx) + return luaK_codeABx(fs, o, reg, k + 1); + else { + int p = luaK_codeABx(fs, o, reg, 0); + codeextraarg(fs, k); + return p; + } +} + + void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { @@ -226,24 +270,29 @@ static void freeexp (FuncState *fs, expdesc *e) { } -static int addk (FuncState *fs, TValue *k, TValue *v) { +static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->L; - TValue *idx = luaH_set(L, fs->h, k); + TValue *idx = luaH_set(L, fs->h, key); Proto *f = fs->f; - int oldsize = f->sizek; + int k, oldsize; if (ttisnumber(idx)) { - lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); - return cast_int(nvalue(idx)); - } - else { /* constant not found; create a new entry */ - setnvalue(idx, cast_num(fs->nk)); - luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, - MAXARG_Bx, "constant table overflow"); - while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); - setobj(L, &f->k[fs->nk], v); - luaC_barrier(L, f, v); - return fs->nk++; + lua_Number n = nvalue(idx); + lua_number2int(k, n); + if (luaO_rawequalObj(&f->k[k], v)) + return k; + /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); + go through and create a new entry for this value */ } + /* constant not found; create a new entry */ + oldsize = f->sizek; + k = fs->nk; + setnvalue(idx, cast_num(k)); + luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); + while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); + setobj(L, &f->k[k], v); + fs->nk++; + luaC_barrier(L, f, v); + return k; } @@ -255,9 +304,20 @@ int luaK_stringK (FuncState *fs, TString *s) { int luaK_numberK (FuncState *fs, lua_Number r) { + int n; + lua_State *L = fs->L; TValue o; setnvalue(&o, r); - return addk(fs, &o, &o); + if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ + /* use raw representation as key to avoid numeric problems */ + setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r))); + incr_top(L); + n = addk(fs, L->top - 1, &o); + L->top--; + } + else + n = addk(fs, &o, &o); /* regular case */ + return n; } @@ -313,7 +373,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VGLOBAL: { - e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); + e->u.s.info = luaK_codeABxX(fs, OP_GETGLOBAL, 0, e->u.s.info); e->k = VRELOCABLE; break; } @@ -352,11 +412,11 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VK: { - luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); + luaK_codek(fs, reg, e->u.s.info); break; } case VKNUM: { - luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); + luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { @@ -444,19 +504,21 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { - case VKNUM: case VTRUE: case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ - e->u.s.info = (e->k == VNIL) ? nilK(fs) : - (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : - boolK(fs, (e->k == VTRUE)); + e->u.s.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); e->k = VK; return RKASK(e->u.s.info); } else break; } + case VKNUM: { + e->u.s.info = luaK_numberK(fs, e->u.nval); + e->k = VK; + /* go through */ + } case VK: { if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ return RKASK(e->u.s.info); @@ -483,7 +545,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { } case VGLOBAL: { int e = luaK_exp2anyreg(fs, ex); - luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); + luaK_codeABxX(fs, OP_SETGLOBAL, e, var->u.s.info); break; } case VINDEXED: { @@ -544,15 +606,18 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { pc = NO_JUMP; /* always true; do nothing */ break; } - case VFALSE: { - pc = luaK_jump(fs); /* always jump */ - break; - } case VJMP: { invertjump(fs, e); pc = e->u.s.info; break; } + case VFALSE: { + if (!hasjumps(e)) { + pc = luaK_jump(fs); /* always jump */ + break; + } + /* else go through */ + } default: { pc = jumponcond(fs, e, 0); break; @@ -572,14 +637,17 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) { pc = NO_JUMP; /* always false; do nothing */ break; } - case VTRUE: { - pc = luaK_jump(fs); /* always jump */ - break; - } case VJMP: { pc = e->u.s.info; break; } + case VTRUE: { + if (!hasjumps(e)) { + pc = luaK_jump(fs); /* always jump */ + break; + } + /* else go through */ + } default: { pc = jumponcond(fs, e, 1); break; @@ -633,26 +701,11 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { - lua_Number v1, v2, r; + lua_Number r; if (!isnumeral(e1) || !isnumeral(e2)) return 0; - v1 = e1->u.nval; - v2 = e2->u.nval; - switch (op) { - case OP_ADD: r = luai_numadd(v1, v2); break; - case OP_SUB: r = luai_numsub(v1, v2); break; - case OP_MUL: r = luai_nummul(v1, v2); break; - case OP_DIV: - if (v2 == 0) return 0; /* do not attempt to divide by 0 */ - r = luai_numdiv(v1, v2); break; - case OP_MOD: - if (v2 == 0) return 0; /* do not attempt to divide by 0 */ - r = luai_nummod(v1, v2); break; - case OP_POW: r = luai_numpow(v1, v2); break; - case OP_UNM: r = luai_numunm(v1); break; - case OP_LEN: return 0; /* no constant folding for 'len' */ - default: lua_assert(0); r = 0; break; - } - if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ + if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) + return 0; /* do not attempt to divide by 0 */ + r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval); e1->u.nval = r; return 1; } @@ -699,9 +752,12 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { case OPR_MINUS: { - if (!isnumeral(e)) - luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ - codearith(fs, OP_UNM, e, &e2); + if (isnumeral(e)) /* minus constant? */ + e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ + else { + luaK_exp2anyreg(fs, e); + codearith(fs, OP_UNM, e, &e2); + } break; } case OPR_NOT: codenot(fs, e); break; @@ -772,18 +828,19 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { } break; } - case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; - case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; - case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; - case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; - case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; - case OPR_POW: codearith(fs, OP_POW, e1, e2); break; - case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; - case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; - case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; - case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; - case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; - case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + codearith(fs, op - OPR_ADD + OP_ADD, e1, e2); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: { + codecomp(fs, op - OPR_EQ + OP_EQ, 1, e1, e2); + break; + } + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, op - OPR_NE + OP_EQ, 0, e1, e2); + break; + } default: lua_assert(0); } } @@ -794,46 +851,18 @@ void luaK_fixline (FuncState *fs, int line) { } -static int luaK_code (FuncState *fs, Instruction i, int line) { - Proto *f = fs->f; - dischargejpc(fs); /* `pc' will change */ - /* put new instruction in code array */ - luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, - MAX_INT, "code size overflow"); - f->code[fs->pc] = i; - /* save corresponding line information */ - luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, - MAX_INT, "code size overflow"); - f->lineinfo[fs->pc] = line; - return fs->pc++; -} - - -int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { - lua_assert(getOpMode(o) == iABC); - lua_assert(getBMode(o) != OpArgN || b == 0); - lua_assert(getCMode(o) != OpArgN || c == 0); - return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); -} - - -int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { - lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); - lua_assert(getCMode(o) == OpArgN); - return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); -} - - void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); - else { + else if (c <= MAXARG_Ax) { luaK_codeABC(fs, OP_SETLIST, base, b, 0); - luaK_code(fs, cast(Instruction, c), fs->ls->lastline); + codeextraarg(fs, c); } + else + luaX_syntaxerror(fs->ls, "constructor too long"); fs->freereg = base + 1; /* free registers with list values */ } diff --git a/src/lcode.h b/src/lcode.h index b941c60721..8ef67e55fa 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lcode.h,v 1.52 2009/09/23 20:33:05 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -21,13 +21,13 @@ /* -** grep "ORDER OPR" if you change these enums +** grep "ORDER OPR" if you change these enums (ORDER OP) */ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, - OPR_NE, OPR_EQ, - OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_NOBINOPR } BinOpr; @@ -42,8 +42,13 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) +#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) + +#define luaK_codek(fs,reg,k) luaK_codeABxX(fs, OP_LOADK, reg, k) + LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); +LUAI_FUNC int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); diff --git a/src/lctype.c b/src/lctype.c new file mode 100644 index 0000000000..b3627f9978 --- /dev/null +++ b/src/lctype.c @@ -0,0 +1,45 @@ +/* +** $Id: lctype.c,v 1.8 2009/11/19 19:06:52 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#include + +#include "lctype.h" + +LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { + 0x00, /* EOZ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x04, 0x04, 0x04, 0x04, 0x05, + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/lctype.h b/src/lctype.h new file mode 100644 index 0000000000..b43baa790b --- /dev/null +++ b/src/lctype.h @@ -0,0 +1,50 @@ +/* +** $Id: lctype.h,v 1.8 2009/11/19 19:06:52 roberto Exp $ +** 'ctype' functions for Lua +** See Copyright Notice in lua.h +*/ + +#ifndef lctype_h +#define lctype_h + + +#include + +#include "lua.h" + +#include "llimits.h" + + +#define ALPHABIT 0 +#define DIGITBIT 1 +#define PRINTBIT 2 +#define SPACEBIT 3 +#define XDIGITBIT 4 +#define UPPERBIT 5 + + +#define MASK(B) (1 << (B)) + + +/* +** add 1 to char to allow index -1 (EOZ) +*/ +#define testprop(c,p) (luai_ctype_[(c)+1] & (p)) + +/* +** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' +*/ +#define lislalpha(c) testprop(c, MASK(ALPHABIT)) +#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) +#define lisupper(c) testprop(c, MASK(UPPERBIT)) +#define lisdigit(c) testprop(c, MASK(DIGITBIT)) +#define lisspace(c) testprop(c, MASK(SPACEBIT)) +#define lisprint(c) testprop(c, MASK(PRINTBIT)) +#define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) + + +/* one more entry for 0 and one more for -1 (EOZ) */ +LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; + +#endif + diff --git a/src/ldblib.c b/src/ldblib.c index 67de1222a9..eeaedc1f1a 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $ +** $Id: ldblib.c,v 1.119 2010/01/06 14:42:35 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -45,6 +45,7 @@ static int db_setmetatable (lua_State *L) { static int db_getfenv (lua_State *L) { + luaL_checkany(L, 1); lua_getfenv(L, 1); return 1; } @@ -72,6 +73,12 @@ static void settabsi (lua_State *L, const char *i, int v) { } +static void settabsb (lua_State *L, const char *i, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, i); +} + + static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; @@ -99,7 +106,7 @@ static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); - const char *options = luaL_optstring(L, arg+2, "flnSu"); + const char *options = luaL_optstring(L, arg+2, "flnStu"); if (lua_isnumber(L, arg+1)) { if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ @@ -126,19 +133,24 @@ static int db_getinfo (lua_State *L) { } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); - if (strchr(options, 'u')) + if (strchr(options, 'u')) { settabsi(L, "nups", ar.nups); + settabsi(L, "nparams", ar.nparams); + settabsb(L, "isvararg", ar.isvararg); + } if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } + if (strchr(options, 't')) + settabsb(L, "istailcall", ar.istailcall); if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ } - + static int db_getlocal (lua_State *L) { int arg; @@ -179,7 +191,6 @@ static int auxupvalue (lua_State *L, int get) { const char *name; int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); - if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); @@ -199,13 +210,40 @@ static int db_setupvalue (lua_State *L) { } +static int checkupval (lua_State *L, int argf, int argnup) { + lua_Debug ar; + int nup = luaL_checkint(L, argnup); + luaL_checktype(L, argf, LUA_TFUNCTION); + lua_pushvalue(L, argf); + lua_getinfo(L, ">u", &ar); + luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); + return nup; +} + + +static int db_upvalueid (lua_State *L) { + int n = checkupval(L, 1, 2); + lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); + return 1; +} + + +static int db_upvaluejoin (lua_State *L) { + int n1 = checkupval(L, 1, 2); + int n2 = checkupval(L, 3, 4); + luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); + luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); + lua_upvaluejoin(L, 1, n1, 3, n2); + return 0; +} + static const char KEY_HOOK = 'h'; static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = - {"call", "return", "line", "count", "tail return"}; + {"call", "return", "line", "count", "tail call"}; lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushlightuserdata(L, L); @@ -315,58 +353,16 @@ static int db_debug (lua_State *L) { } -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ - -static int db_errorfb (lua_State *L) { - int level; - int firstpart = 1; /* still before eventual `...' */ +static int db_traceback (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - if (lua_isnumber(L, arg+2)) { - level = (int)lua_tointeger(L, arg+2); - lua_pop(L, 1); - } - else - level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ - if (lua_gettop(L) == arg) - lua_pushliteral(L, ""); - else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ - else lua_pushliteral(L, "\n"); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - if (level > LEVELS1 && firstpart) { - /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L1, level+LEVELS2, &ar)) - level--; /* keep going */ - else { - lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ - level++; - } - firstpart = 0; - continue; - } - lua_pushliteral(L, "\n\t"); - lua_getinfo(L1, "Snl", &ar); - lua_pushfstring(L, "%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - if (*ar.namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, " in function " LUA_QS, ar.name); - else { - if (*ar.what == 'm') /* main? */ - lua_pushfstring(L, " in main chunk"); - else if (*ar.what == 'C' || *ar.what == 't') - lua_pushliteral(L, " ?"); /* C function or tail call */ - else - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } - lua_concat(L, lua_gettop(L) - arg); + const char *msg = lua_tostring(L, arg + 1); + if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ + lua_pushvalue(L, arg + 1); /* return it untouched */ + else { + int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); + luaL_traceback(L, L1, msg, level); } - lua_concat(L, lua_gettop(L) - arg); return 1; } @@ -380,17 +376,19 @@ static const luaL_Reg dblib[] = { {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, + {"upvaluejoin", db_upvaluejoin}, + {"upvalueid", db_upvalueid}, {"setfenv", db_setfenv}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, {"setupvalue", db_setupvalue}, - {"traceback", db_errorfb}, + {"traceback", db_traceback}, {NULL, NULL} }; -LUALIB_API int luaopen_debug (lua_State *L) { +LUAMOD_API int luaopen_debug (lua_State *L) { luaL_register(L, LUA_DBLIBNAME, dblib); return 1; } diff --git a/src/ldebug.c b/src/ldebug.c index 50ad3d3803..1c18d70122 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ +** $Id: ldebug.c,v 2.61 2010/01/06 14:42:35 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -33,20 +33,14 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); -static int currentpc (lua_State *L, CallInfo *ci) { - if (!isLua(ci)) return -1; /* function is not a Lua function? */ - if (ci == L->ci) - ci->savedpc = L->savedpc; - return pcRel(ci->savedpc, ci_func(ci)->l.p); +static int currentpc (CallInfo *ci) { + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); } -static int currentline (lua_State *L, CallInfo *ci) { - int pc = currentpc(L, ci); - if (pc < 0) - return -1; /* only active lua functions have current-line information */ - else - return getline(ci_func(ci)->l.p, pc); +static int currentline (CallInfo *ci) { + return getfuncline(ci_func(ci)->l.p, currentpc(ci)); } @@ -58,6 +52,8 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { mask = 0; func = NULL; } + if (isLua(L->ci)) + L->oldpc = L->ci->u.l.savedpc; L->hook = func; L->basehookcount = count; resethookcount(L); @@ -84,19 +80,13 @@ LUA_API int lua_gethookcount (lua_State *L) { LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { int status; CallInfo *ci; + if (level < 0) return 0; /* invalid (negative) level */ lua_lock(L); - for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) level--; - if (f_isLua(ci)) /* Lua function? */ - level -= ci->tailcalls; /* skip lost tail calls */ - } - if (level == 0 && ci > L->base_ci) { /* level found? */ - status = 1; - ar->i_ci = cast_int(ci - L->base_ci); - } - else if (level < 0) { /* level is of a lost tail call? */ + if (level == 0 && ci != &L->base_ci) { /* level found? */ status = 1; - ar->i_ci = 0; + ar->i_ci = ci; } else status = 0; /* no such level */ lua_unlock(L); @@ -104,43 +94,49 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { } -static Proto *getluaproto (CallInfo *ci) { - return (isLua(ci) ? ci_func(ci)->l.p : NULL); -} - - -static const char *findlocal (lua_State *L, CallInfo *ci, int n) { - const char *name; - Proto *fp = getluaproto(ci); - if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) - return name; /* is a local variable in a Lua function */ - else { - StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; - if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ - return "(*temporary)"; - else - return NULL; +static const char *findlocal (lua_State *L, CallInfo *ci, int n, + StkId *pos) { + const char *name = NULL; + StkId base; + if (isLua(ci)) { + base = ci->u.l.base; + name = luaF_getlocalname(ci_func(ci)->l.p, n, currentpc(ci)); + } + else + base = ci->func + 1; + if (name == NULL) { /* no 'standard' name? */ + StkId limit = (ci == L->ci) ? L->top : ci->next->func; + if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ + name = "(*temporary)"; /* generic name for any valid slot */ + else { + *pos = base; /* to avoid warnings */ + return NULL; /* no name */ + } } + *pos = base + (n - 1); + return name; } LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { - CallInfo *ci = L->base_ci + ar->i_ci; - const char *name = findlocal(L, ci, n); + StkId pos; + const char *name = findlocal(L, ar->i_ci, n, &pos); lua_lock(L); - if (name) - luaA_pushobject(L, ci->base + (n - 1)); + if (name) { + setobj2s(L, L->top, pos); + api_incr_top(L); + } lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - CallInfo *ci = L->base_ci + ar->i_ci; - const char *name = findlocal(L, ci, n); + StkId pos; + const char *name = findlocal(L, ar->i_ci, n, &pos); lua_lock(L); if (name) - setobjs2s(L, ci->base + (n - 1), L->top - 1); + setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ lua_unlock(L); return name; @@ -164,39 +160,26 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { } -static void info_tailcall (lua_Debug *ar) { - ar->name = ar->namewhat = ""; - ar->what = "tail"; - ar->lastlinedefined = ar->linedefined = ar->currentline = -1; - ar->source = "=(tail call)"; - luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); - ar->nups = 0; -} - - static void collectvalidlines (lua_State *L, Closure *f) { if (f == NULL || f->c.isC) { setnilvalue(L->top); + incr_top(L); } else { - Table *t = luaH_new(L, 0, 0); - int *lineinfo = f->l.p->lineinfo; int i; + int *lineinfo = f->l.p->lineinfo; + Table *t = luaH_new(L); + sethvalue(L, L->top, t); + incr_top(L); for (i=0; il.p->sizelineinfo; i++) - setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); - sethvalue(L, L->top, t); + setbvalue(luaH_setint(L, t, lineinfo[i]), 1); } - incr_top(L); } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, Closure *f, CallInfo *ci) { int status = 1; - if (f == NULL) { - info_tailcall(ar); - return status; - } for (; *what; what++) { switch (*what) { case 'S': { @@ -204,11 +187,23 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'l': { - ar->currentline = (ci) ? currentline(L, ci) : -1; + ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; break; } case 'u': { ar->nups = f->c.nupvalues; + if (f->c.isC) { + ar->isvararg = 1; + ar->nparams = 0; + } + else { + ar->isvararg = f->l.p->is_vararg; + ar->nparams = f->l.p->numparams; + } + break; + } + case 't': { + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; break; } case 'n': { @@ -241,15 +236,14 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { f = clvalue(func); L->top--; /* pop function */ } - else if (ar->i_ci != 0) { /* no tail call? */ - ci = L->base_ci + ar->i_ci; + else { + ci = ar->i_ci; lua_assert(ttisfunction(ci->func)); f = clvalue(ci->func); } status = auxgetinfo(L, what, ar, f, ci); if (strchr(what, 'f')) { - if (f == NULL) setnilvalue(L->top); - else setclvalue(L, L->top, f); + setclvalue(L, L->top, f); incr_top(L); } if (strchr(what, 'L')) @@ -261,314 +255,170 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { /* ** {====================================================== -** Symbolic Execution and code checker +** Symbolic Execution ** ======================================================= */ -#define check(x) if (!(x)) return 0; - -#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) - -#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) - - -static int precheck (const Proto *pt) { - check(pt->maxstacksize <= MAXSTACK); - check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); - check(!(pt->is_vararg & VARARG_NEEDSARG) || - (pt->is_vararg & VARARG_HASARG)); - check(pt->sizeupvalues <= pt->nups); - check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); - check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); - return 1; -} - - -#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) - -int luaG_checkopenop (Instruction i) { - switch (GET_OPCODE(i)) { - case OP_CALL: - case OP_TAILCALL: - case OP_RETURN: - case OP_SETLIST: { - check(GETARG_B(i) == 0); - return 1; - } - default: return 0; /* invalid instruction after an open call */ - } -} - - -static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { - switch (mode) { - case OpArgN: check(r == 0); break; - case OpArgU: break; - case OpArgR: checkreg(pt, r); break; - case OpArgK: - check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); - break; - } - return 1; +static const char *kname (Proto *p, int c) { + if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + return svalue(&p->k[INDEXK(c)]); + else + return "?"; } -static Instruction symbexec (const Proto *pt, int lastpc, int reg) { - int pc; - int last; /* stores position of last instruction that changed `reg' */ - last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ - check(precheck(pt)); +static const char *getobjname (lua_State *L, CallInfo *ci, int reg, + const char **name) { + Proto *p; + int lastpc, pc; + const char *what = NULL; + lua_assert(isLua(ci)); + p = ci_func(ci)->l.p; + lastpc = currentpc(ci); + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ for (pc = 0; pc < lastpc; pc++) { - Instruction i = pt->code[pc]; + Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); - int b = 0; - int c = 0; - check(op < NUM_OPCODES); - checkreg(pt, a); - switch (getOpMode(op)) { - case iABC: { - b = GETARG_B(i); - c = GETARG_C(i); - check(checkArgMode(pt, b, getBMode(op))); - check(checkArgMode(pt, c, getCMode(op))); + switch (op) { + case OP_GETGLOBAL: { + if (reg == a) { + int g = GETARG_Bx(i); + if (g != 0) g--; + else g = GETARG_Ax(p->code[++pc]); + lua_assert(ttisstring(&p->k[g])); + *name = svalue(&p->k[g]); + what = "global"; + } break; } - case iABx: { - b = GETARG_Bx(i); - if (getBMode(op) == OpArgK) check(b < pt->sizek); + case OP_MOVE: { + if (reg == a) { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < a) + what = getobjname(L, ci, b, name); /* get name for 'b' */ + else what = NULL; + } break; } - case iAsBx: { - b = GETARG_sBx(i); - if (getBMode(op) == OpArgR) { - int dest = pc+1+b; - check(0 <= dest && dest < pt->sizecode); - if (dest > 0) { - int j; - /* check that it does not jump to a setlist count; this - is tricky, because the count from a previous setlist may - have the same value of an invalid setlist; so, we must - go all the way back to the first of them (if any) */ - for (j = 0; j < dest; j++) { - Instruction d = pt->code[dest-1-j]; - if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; - } - /* if 'j' is even, previous value is not a setlist (even if - it looks like one) */ - check((j&1) == 0); - } + case OP_GETTABLE: { + if (reg == a) { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + what = "field"; } break; } - } - if (testAMode(op)) { - if (a == reg) last = pc; /* change register `a' */ - } - if (testTMode(op)) { - check(pc+2 < pt->sizecode); /* check skip */ - check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); - } - switch (op) { - case OP_LOADBOOL: { - if (c == 1) { /* does it jump? */ - check(pc+2 < pt->sizecode); /* check its jump */ - check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST || - GETARG_C(pt->code[pc+1]) != 0); + case OP_GETUPVAL: { + if (reg == a) { + int u = GETARG_B(i); /* upvalue index */ + TString *tn = p->upvalues[u].name; + *name = tn ? getstr(tn) : "?"; + what = "upvalue"; } break; } case OP_LOADNIL: { - if (a <= reg && reg <= b) - last = pc; /* set registers from `a' to `b' */ - break; - } - case OP_GETUPVAL: - case OP_SETUPVAL: { - check(b < pt->nups); - break; - } - case OP_GETGLOBAL: - case OP_SETGLOBAL: { - check(ttisstring(&pt->k[b])); + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (a <= reg && reg <= b) /* set registers from 'a' to 'b' */ + what = NULL; break; } case OP_SELF: { - checkreg(pt, a+1); - if (reg == a+1) last = pc; - break; - } - case OP_CONCAT: { - check(b < c); /* at least two operands */ - break; - } - case OP_TFORLOOP: { - check(c >= 1); /* at least one result (control variable) */ - checkreg(pt, a+2+c); /* space for results */ - if (reg >= a+2) last = pc; /* affect all regs above its base */ + if (reg == a) { + int k = GETARG_C(i); /* key index */ + *name = kname(p, k); + what = "method"; + } break; } - case OP_FORLOOP: - case OP_FORPREP: - checkreg(pt, a+3); - /* go through */ - case OP_JMP: { - int dest = pc+1+b; - /* not full check and jump is forward and do not skip `lastpc'? */ - if (reg != NO_REG && pc < dest && dest <= lastpc) - pc += b; /* do the jump */ + case OP_TFORCALL: { + if (reg >= a + 2) what = NULL; /* affect all regs above its base */ break; } case OP_CALL: case OP_TAILCALL: { - if (b != 0) { - checkreg(pt, a+b-1); - } - c--; /* c = num. returns */ - if (c == LUA_MULTRET) { - check(checkopenop(pt, pc)); - } - else if (c != 0) - checkreg(pt, a+c-1); - if (reg >= a) last = pc; /* affect all registers above base */ - break; - } - case OP_RETURN: { - b--; /* b = num. returns */ - if (b > 0) checkreg(pt, a+b-1); + if (reg >= a) what = NULL; /* affect all registers above base */ break; } - case OP_SETLIST: { - if (b > 0) checkreg(pt, a + b); - if (c == 0) { - pc++; - check(pc < pt->sizecode - 1); - } - break; - } - case OP_CLOSURE: { - int nup, j; - check(b < pt->sizep); - nup = pt->p[b]->nups; - check(pc + nup < pt->sizecode); - for (j = 1; j <= nup; j++) { - OpCode op1 = GET_OPCODE(pt->code[pc + j]); - check(op1 == OP_GETUPVAL || op1 == OP_MOVE); - } - if (reg != NO_REG) /* tracing? */ - pc += nup; /* do not 'execute' these pseudo-instructions */ + case OP_JMP: { + int b = GETARG_sBx(i); + int dest = pc + 1 + b; + /* jump is forward and do not skip `lastpc'? */ + if (pc < dest && dest <= lastpc) + pc += b; /* do the jump */ break; } - case OP_VARARG: { - check((pt->is_vararg & VARARG_ISVARARG) && - !(pt->is_vararg & VARARG_NEEDSARG)); - b--; - if (b == LUA_MULTRET) check(checkopenop(pt, pc)); - checkreg(pt, a+b-1); + default: + if (testAMode(op) && reg == a) what = NULL; break; - } - default: break; } } - return pt->code[last]; -} - -#undef check -#undef checkjump -#undef checkreg - -/* }====================================================== */ - - -int luaG_checkcode (const Proto *pt) { - return (symbexec(pt, pt->sizecode, NO_REG) != 0); -} - - -static const char *kname (Proto *p, int c) { - if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) - return svalue(&p->k[INDEXK(c)]); - else - return "?"; -} - - -static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, - const char **name) { - if (isLua(ci)) { /* a Lua function? */ - Proto *p = ci_func(ci)->l.p; - int pc = currentpc(L, ci); - Instruction i; - *name = luaF_getlocalname(p, stackpos+1, pc); - if (*name) /* is a local? */ - return "local"; - i = symbexec(p, pc, stackpos); /* try symbolic execution */ - lua_assert(pc != -1); - switch (GET_OPCODE(i)) { - case OP_GETGLOBAL: { - int g = GETARG_Bx(i); /* global index */ - lua_assert(ttisstring(&p->k[g])); - *name = svalue(&p->k[g]); - return "global"; - } - case OP_MOVE: { - int a = GETARG_A(i); - int b = GETARG_B(i); /* move from `b' to `a' */ - if (b < a) - return getobjname(L, ci, b, name); /* get name for `b' */ - break; - } - case OP_GETTABLE: { - int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - return "field"; - } - case OP_GETUPVAL: { - int u = GETARG_B(i); /* upvalue index */ - *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; - return "upvalue"; - } - case OP_SELF: { - int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - return "method"; - } - default: break; - } - } - return NULL; /* no useful name found */ + return what; } static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + TMS tm = 0; Instruction i; - if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) + if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous)) return NULL; /* calling function is not Lua (or is unknown) */ - ci--; /* calling function */ - i = ci_func(ci)->l.p->code[currentpc(L, ci)]; - if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || - GET_OPCODE(i) == OP_TFORLOOP) - return getobjname(L, ci, GETARG_A(i), name); - else - return NULL; /* no useful name can be found */ + ci = ci->previous; /* calling function */ + i = ci_func(ci)->l.p->code[currentpc(ci)]; + if (GET_OPCODE(i) == OP_EXTRAARG) /* extra argument? */ + i = ci_func(ci)->l.p->code[currentpc(ci) - 1]; /* get 'real' instruction */ + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + case OP_TFORLOOP: + return getobjname(L, ci, GETARG_A(i), name); + case OP_GETGLOBAL: + case OP_SELF: + case OP_GETTABLE: tm = TM_INDEX; break; + case OP_SETGLOBAL: + case OP_SETTABLE: tm = TM_NEWINDEX; break; + case OP_EQ: tm = TM_EQ; break; + case OP_ADD: tm = TM_ADD; break; + case OP_SUB: tm = TM_SUB; break; + case OP_MUL: tm = TM_MUL; break; + case OP_DIV: tm = TM_DIV; break; + case OP_MOD: tm = TM_MOD; break; + case OP_POW: tm = TM_POW; break; + case OP_UNM: tm = TM_UNM; break; + case OP_LEN: tm = TM_LEN; break; + case OP_LT: tm = TM_LT; break; + case OP_LE: tm = TM_LE; break; + case OP_CONCAT: tm = TM_CONCAT; break; + default: + return NULL; /* else no useful name can be found */ + } + *name = getstr(G(L)->tmname[tm]); + return "metamethod"; } +/* }====================================================== */ + + /* only ANSI way to check whether a pointer points to an array */ static int isinstack (CallInfo *ci, const TValue *o) { StkId p; - for (p = ci->base; p < ci->top; p++) + for (p = ci->u.l.base; p < ci->top; p++) if (o == p) return 1; return 0; } void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + CallInfo *ci = L->ci; const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; - const char *kind = (isinstack(L->ci, o)) ? - getobjname(L, L->ci, cast_int(o - L->base), &name) : + const char *kind = (isLua(ci) && isinstack(ci, o)) ? + getobjname(L, ci, cast_int(o - ci->u.l.base), &name) : NULL; if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", @@ -580,7 +430,7 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; - lua_assert(!ttisstring(p1) && !ttisnumber(p1)); + lua_assert(!ttisstring(p1) && !ttisnumber(p2)); luaG_typeerror(L, p1, "concatenate"); } @@ -608,8 +458,8 @@ static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(L, ci); - luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); + int line = currentline(ci); + luaO_chunkid(buff, getstr(ci_func(ci)->l.p->source), LUA_IDSIZE); luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } } @@ -622,7 +472,7 @@ void luaG_errormsg (lua_State *L) { setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); - luaD_call(L, L->top - 2, 1); /* call it */ + luaD_call(L, L->top - 2, 1, 0); /* call it */ } luaD_throw(L, LUA_ERRRUN); } diff --git a/src/ldebug.h b/src/ldebug.h index ba28a97248..545fa345ed 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ldebug.h,v 2.5 2009/06/10 16:57:53 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -13,7 +13,7 @@ #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) -#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) +#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) #define resethookcount(L) (L->hookcount = L->basehookcount) @@ -27,7 +27,5 @@ LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); LUAI_FUNC void luaG_errormsg (lua_State *L); -LUAI_FUNC int luaG_checkcode (const Proto *pt); -LUAI_FUNC int luaG_checkopenop (Instruction i); #endif diff --git a/src/ldo.c b/src/ldo.c index 8de05f728e..555113d3c8 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $ +** $Id: ldo.c,v 2.79 2009/12/22 15:32:50 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "lua.h" +#include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -39,6 +40,38 @@ ** ======================================================= */ +/* +** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By +** default, Lua handles errors with exceptions when compiling as +** C++ code, with _longjmp/_setjmp when asked to use them, and with +** longjmp/setjmp otherwise. +*/ +#if !defined(LUAI_THROW) + +#if defined(__cplusplus) +/* C++ exceptions */ +#define LUAI_THROW(L,c) throw(c) +#define LUAI_TRY(L,c,a) \ + try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } +#define luai_jmpbuf int /* dummy variable */ + +#elif defined(LUA_USE_ULONGJMP) +/* in Unix, try _longjmp/_setjmp (more efficient) */ +#define LUAI_THROW(L,c) _longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#else +/* default handling with long jumps */ +#define LUAI_THROW(L,c) longjmp((c)->b, 1) +#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } +#define luai_jmpbuf jmp_buf + +#endif + +#endif + + /* chain list of long jump buffers */ struct lua_longjmp { @@ -48,7 +81,7 @@ struct lua_longjmp { }; -void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { +static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); @@ -58,8 +91,7 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } - case LUA_ERRSYNTAX: - case LUA_ERRRUN: { + default: { setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } @@ -68,55 +100,39 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { } -static void restore_stack_limit (lua_State *L) { - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); - if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ - int inuse = cast_int(L->ci - L->base_ci); - if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUAI_MAXCALLS); - } -} - - -static void resetstack (lua_State *L, int status) { - L->ci = L->base_ci; - L->base = L->ci->base; - luaF_close(L, L->base); /* close eventual pending closures */ - luaD_seterrorobj(L, status, L->base); - L->nCcalls = L->baseCcalls; - L->allowhook = 1; - restore_stack_limit(L); - L->errfunc = 0; - L->errorJmp = NULL; -} - - void luaD_throw (lua_State *L, int errcode) { - if (L->errorJmp) { - L->errorJmp->status = errcode; - LUAI_THROW(L, L->errorJmp); + if (L->errorJmp) { /* thread has an error handler? */ + L->errorJmp->status = errcode; /* set status */ + LUAI_THROW(L, L->errorJmp); /* jump to it */ } - else { - L->status = cast_byte(errcode); - if (G(L)->panic) { - resetstack(L, errcode); - lua_unlock(L); - G(L)->panic(L); + else { /* thread has no error handler */ + L->status = cast_byte(errcode); /* mark it as dead */ + if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */ + luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */ + } + else { /* no handler at all; abort */ + if (G(L)->panic) { /* panic function? */ + lua_unlock(L); + G(L)->panic(L); /* call it (last chance to jump out) */ + } + abort(); } - exit(EXIT_FAILURE); } } int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + unsigned short oldnCcalls = G(L)->nCcalls; struct lua_longjmp lj; - lj.status = 0; + lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; LUAI_TRY(L, &lj, (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ + G(L)->nCcalls = oldnCcalls; return lj.status; } @@ -129,112 +145,126 @@ static void correctstack (lua_State *L, TValue *oldstack) { L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; - for (ci = L->base_ci; ci <= L->ci; ci++) { + for (ci = L->ci; ci != NULL; ci = ci->previous) { ci->top = (ci->top - oldstack) + L->stack; - ci->base = (ci->base - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; + if (isLua(ci)) + ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; } - L->base = (L->base - oldstack) + L->stack; } +/* some space for error handling */ +#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + + void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; - int realsize = newsize + 1 + EXTRA_STACK; - lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); - luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); - L->stacksize = realsize; - L->stack_last = L->stack+newsize; + int lim = L->stacksize; + lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); + luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); + for (; lim < newsize; lim++) + setnilvalue(L->stack + lim); /* erase new segment */ + L->stacksize = newsize; + L->stack_last = L->stack + newsize - EXTRA_STACK; correctstack(L, oldstack); } -void luaD_reallocCI (lua_State *L, int newsize) { - CallInfo *oldci = L->base_ci; - luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); - L->size_ci = newsize; - L->ci = (L->ci - oldci) + L->base_ci; - L->end_ci = L->base_ci + L->size_ci - 1; +void luaD_growstack (lua_State *L, int n) { + int size = L->stacksize; + if (size > LUAI_MAXSTACK) /* error after extra size? */ + luaD_throw(L, LUA_ERRERR); + else { + int needed = L->top - L->stack + n + EXTRA_STACK; + int newsize = 2 * size; + if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; + if (newsize < needed) newsize = needed; + if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ + luaD_reallocstack(L, ERRORSTACKSIZE); + luaG_runerror(L, "stack overflow"); + } + else + luaD_reallocstack(L, newsize); + } } -void luaD_growstack (lua_State *L, int n) { - if (n <= L->stacksize) /* double size is enough? */ - luaD_reallocstack(L, 2*L->stacksize); - else - luaD_reallocstack(L, L->stacksize + n); +static int stackinuse (lua_State *L) { + CallInfo *ci; + StkId lim = L->top; + for (ci = L->ci; ci != NULL; ci = ci->previous) { + lua_assert(ci->top <= L->stack_last); + if (lim < ci->top) lim = ci->top; + } + return cast_int(lim - L->stack) + 1; /* part of stack in use */ } -static CallInfo *growCI (lua_State *L) { - if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ - luaD_throw(L, LUA_ERRERR); - else { - luaD_reallocCI(L, 2*L->size_ci); - if (L->size_ci > LUAI_MAXCALLS) - luaG_runerror(L, "stack overflow"); - } - return ++L->ci; +void luaD_shrinkstack (lua_State *L) { + int inuse = stackinuse(L); + int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; + if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; + if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */ + goodsize >= L->stacksize) /* would grow instead of shrink? */ + condmovestack(L); /* don't change stack (change only for debugging) */ + else + luaD_reallocstack(L, goodsize); /* shrink it */ } -void luaD_callhook (lua_State *L, int event, int line) { +void luaD_hook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && L->allowhook) { + CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, L->ci->top); + ptrdiff_t ci_top = savestack(L, ci->top); lua_Debug ar; ar.event = event; ar.currentline = line; - if (event == LUA_HOOKTAILRET) - ar.i_ci = 0; /* tail call; no debug information about it */ - else - ar.i_ci = cast_int(L->ci - L->base_ci); + ar.i_ci = ci; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - L->ci->top = L->top + LUA_MINSTACK; - lua_assert(L->ci->top <= L->stack_last); + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ + ci->callstatus |= CIST_HOOKED; lua_unlock(L); (*hook)(L, &ar); lua_lock(L); lua_assert(!L->allowhook); L->allowhook = 1; - L->ci->top = restorestack(L, ci_top); + ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); + ci->callstatus &= ~CIST_HOOKED; } } +static void callhook (lua_State *L, CallInfo *ci) { + int hook = LUA_HOOKCALL; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + if (isLua(ci->previous) && + GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { + ci->callstatus |= CIST_TAIL; + hook = LUA_HOOKTAILCALL; + } + luaD_hook(L, hook, -1); + ci->u.l.savedpc--; /* correct 'pc' */ +} + + static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; - Table *htab = NULL; StkId base, fixed; - for (; actual < nfixargs; ++actual) - setnilvalue(L->top++); -#if defined(LUA_COMPAT_VARARG) - if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ - int nvar = actual - nfixargs; /* number of extra arguments */ - lua_assert(p->is_vararg & VARARG_HASARG); - luaC_checkGC(L); - htab = luaH_new(L, nvar, 1); /* create `arg' table */ - for (i=0; itop - nvar + i); - /* store counter in field `n' */ - setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); - } -#endif + lua_assert(actual >= nfixargs); /* move fixed parameters to final position */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ for (i=0; itop++, fixed+i); - setnilvalue(fixed+i); - } - /* add `arg' parameter */ - if (htab) { - sethvalue(L, L->top++, htab); - lua_assert(iswhite(obj2gco(htab))); + setobjs2s(L, L->top++, fixed + i); + setnilvalue(fixed + i); } return base; } @@ -256,11 +286,12 @@ static StkId tryfuncTM (lua_State *L, StkId func) { -#define inc_ci(L) \ - ((L->ci == L->end_ci) ? growCI(L) : \ - (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) +#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) +/* +** returns true if function has been executed (C function) +*/ int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr; @@ -268,88 +299,70 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); cl = &clvalue(func)->l; - L->ci->savedpc = L->savedpc; + L->ci->nresults = nresults; if (!cl->isC) { /* Lua function? prepare its call */ CallInfo *ci; - StkId st, base; + int nparams, nargs; + StkId base; Proto *p = cl->p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); - if (!p->is_vararg) { /* no varargs? */ + nargs = cast_int(L->top - func) - 1; /* number of real arguments */ + nparams = p->numparams; /* number of expected parameters */ + for (; nargs < nparams; nargs++) + setnilvalue(L->top++); /* complete missing arguments */ + if (!p->is_vararg) /* no varargs? */ base = func + 1; - if (L->top > base + p->numparams) - L->top = base + p->numparams; - } - else { /* vararg function */ - int nargs = cast_int(L->top - func) - 1; + else /* vararg function */ base = adjust_varargs(L, p, nargs); - func = restorestack(L, funcr); /* previous call may change the stack */ - } - ci = inc_ci(L); /* now `enter' new function */ + ci = next_ci(L); /* now 'enter' new function */ ci->func = func; - L->base = ci->base = base; - ci->top = L->base + p->maxstacksize; + ci->u.l.base = base; + ci->top = base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); - L->savedpc = p->code; /* starting point */ - ci->tailcalls = 0; - ci->nresults = nresults; - for (st = L->top; st < ci->top; st++) - setnilvalue(st); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_LUA; L->top = ci->top; - if (L->hookmask & LUA_MASKCALL) { - L->savedpc++; /* hooks assume 'pc' is already incremented */ - luaD_callhook(L, LUA_HOOKCALL, -1); - L->savedpc--; /* correct 'pc' */ - } - return PCRLUA; + if (L->hookmask & LUA_MASKCALL) + callhook(L, ci); + return 0; } else { /* if is a C function, call it */ CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = inc_ci(L); /* now `enter' new function */ + ci = next_ci(L); /* now 'enter' new function */ ci->func = restorestack(L, funcr); - L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); - ci->nresults = nresults; + ci->callstatus = 0; if (L->hookmask & LUA_MASKCALL) - luaD_callhook(L, LUA_HOOKCALL, -1); + luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); - if (n < 0) /* yielding? */ - return PCRYIELD; - else { - luaD_poscall(L, L->top - n); - return PCRC; - } + api_checknelems(L, n); + luaD_poscall(L, L->top - n); + return 1; } } -static StkId callrethooks (lua_State *L, StkId firstResult) { - ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ - luaD_callhook(L, LUA_HOOKRET, -1); - if (f_isLua(L->ci)) { /* Lua function? */ - while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */ - luaD_callhook(L, LUA_HOOKTAILRET, -1); - } - return restorestack(L, fr); -} - - int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; - CallInfo *ci; - if (L->hookmask & LUA_MASKRET) - firstResult = callrethooks(L, firstResult); - ci = L->ci--; + CallInfo *ci = L->ci; + if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { + if (L->hookmask & LUA_MASKRET) { + ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ + luaD_hook(L, LUA_HOOKRET, -1); + firstResult = restorestack(L, fr); + } + L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ + } res = ci->func; /* res == final position of 1st result */ + L->ci = ci = ci->previous; /* back to caller */ wanted = ci->nresults; - L->base = (ci - 1)->base; /* restore base */ - L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); @@ -365,112 +378,219 @@ int luaD_poscall (lua_State *L, StkId firstResult) { ** The arguments are on the stack, right after the function. ** When returns, all the results are on the stack, starting at the original ** function position. -*/ -void luaD_call (lua_State *L, StkId func, int nResults) { - if (++L->nCcalls >= LUAI_MAXCCALLS) { - if (L->nCcalls == LUAI_MAXCCALLS) +*/ +void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { + global_State *g = G(L); + if (++g->nCcalls >= LUAI_MAXCCALLS) { + if (g->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ - luaV_execute(L, 1); /* call it */ - L->nCcalls--; + if (!allowyield) L->nny++; + if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ + luaV_execute(L); /* call it */ + if (!allowyield) L->nny--; + g->nCcalls--; luaC_checkGC(L); } -static void resume (lua_State *L, void *ud) { - StkId firstArg = cast(StkId, ud); +static void finishCcall (lua_State *L) { CallInfo *ci = L->ci; - if (L->status == 0) { /* start coroutine? */ - lua_assert(ci == L->base_ci && firstArg > L->base); - if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) - return; - } - else { /* resuming from previous yield */ - lua_assert(L->status == LUA_YIELD); - L->status = 0; - if (!f_isLua(ci)) { /* `common' yield? */ - /* finish interrupted execution of `OP_CALL' */ - lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); - if (luaD_poscall(L, firstArg)) /* complete it... */ - L->top = L->ci->top; /* and correct top if not multiple results */ + int n; + lua_assert(ci->u.c.k != NULL); /* must have a continuation */ + lua_assert(L->nny == 0); + /* finish 'luaD_call' */ + G(L)->nCcalls--; + /* finish 'lua_callk' */ + adjustresults(L, ci->nresults); + /* call continuation function */ + if (!(ci->callstatus & CIST_STAT)) /* no call status? */ + ci->u.c.status = LUA_YIELD; /* 'default' status */ + lua_assert(ci->u.c.status != LUA_OK); + ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED; + lua_unlock(L); + n = (*ci->u.c.k)(L); + lua_lock(L); + api_checknelems(L, n); + /* finish 'luaD_precall' */ + luaD_poscall(L, L->top - n); +} + + +static void unroll (lua_State *L, void *ud) { + UNUSED(ud); + for (;;) { + if (L->ci == &L->base_ci) /* stack is empty? */ + return; /* coroutine finished normally */ + if (!isLua(L->ci)) /* C function? */ + finishCcall(L); + else { /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L); /* execute down to higher C 'boundary' */ } - else /* yielded inside a hook: just continue its execution */ - L->base = L->ci->base; } - luaV_execute(L, cast_int(L->ci - L->base_ci)); } -static int resume_error (lua_State *L, const char *msg) { - L->top = L->ci->base; - setsvalue2s(L, L->top, luaS_new(L, msg)); +/* +** check whether thread has a suspended protected call +*/ +static CallInfo *findpcall (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; + } + return NULL; /* no pending pcall */ +} + + +static int recover (lua_State *L, int status) { + StkId oldtop; + CallInfo *ci = findpcall(L); + if (ci == NULL) return 0; /* no recovery point */ + /* "finish" luaD_pcall */ + oldtop = restorestack(L, ci->u.c.oldtop); + luaF_close(L, oldtop); + seterrorobj(L, status, oldtop); + L->ci = ci; + L->allowhook = ci->u.c.old_allowhook; + L->nny = 0; /* should be zero to be yieldable */ + luaD_shrinkstack(L); + L->errfunc = ci->u.c.old_errfunc; + ci->callstatus |= CIST_STAT; /* call has error status */ + ci->u.c.status = status; /* (here it is) */ + return 1; /* continue running the coroutine */ +} + + +/* +** signal an error in the call to 'resume', not in the execution of the +** coroutine itself. (Such errors should not be handled by any coroutine +** error hanlder and should not kill the coroutine.) +*/ +static void resume_error (lua_State *L, const char *msg, StkId firstArg) { + L->top = firstArg; /* remove args from the stack */ + setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ incr_top(L); - lua_unlock(L); - return LUA_ERRRUN; + luaD_throw(L, -1); /* jump back to 'lua_resume' */ +} + + +/* +** do the work for 'lua_resume' in protected mode +*/ +static void resume (lua_State *L, void *ud) { + StkId firstArg = cast(StkId, ud); + CallInfo *ci = L->ci; + if (G(L)->nCcalls >= LUAI_MAXCCALLS) + resume_error(L, "C stack overflow", firstArg); + if (L->status == LUA_OK) { /* may be starting a coroutine */ + if (ci != &L->base_ci) /* not in base level? */ + resume_error(L, "cannot resume non-suspended coroutine", firstArg); + /* coroutine is in base level; start running it */ + if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ + luaV_execute(L); /* call it */ + } + else if (L->status != LUA_YIELD) + resume_error(L, "cannot resume dead coroutine", firstArg); + else { /* resuming from previous yield */ + L->status = LUA_OK; + if (isLua(ci)) /* yielded inside a hook? */ + luaV_execute(L); /* just continue running Lua code */ + else { /* 'common' yield */ + if (ci->u.c.k != NULL) { /* does it have a continuation? */ + int n; + ci->u.c.status = LUA_YIELD; /* 'default' status */ + ci->callstatus |= CIST_YIELDED; + ci->func = restorestack(L, ci->u.c.oldtop); + lua_unlock(L); + n = (*ci->u.c.k)(L); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); + firstArg = L->top - n; /* yield results come from continuation */ + } + G(L)->nCcalls--; /* finish 'luaD_call' */ + luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ + } + unroll(L, NULL); + } } LUA_API int lua_resume (lua_State *L, int nargs) { int status; lua_lock(L); - if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci)) - return resume_error(L, "cannot resume non-suspended coroutine"); - if (L->nCcalls >= LUAI_MAXCCALLS) - return resume_error(L, "C stack overflow"); luai_userstateresume(L, nargs); - lua_assert(L->errfunc == 0); - L->baseCcalls = ++L->nCcalls; + ++G(L)->nCcalls; /* count resume */ + L->nny = 0; /* allow yields */ status = luaD_rawrunprotected(L, resume, L->top - nargs); - if (status != 0) { /* error? */ - L->status = cast_byte(status); /* mark thread as `dead' */ - luaD_seterrorobj(L, status, L->top); - L->ci->top = L->top; - } - else { - lua_assert(L->nCcalls == L->baseCcalls); - status = L->status; + if (status == -1) /* error calling 'lua_resume'? */ + status = LUA_ERRRUN; + else { /* yield or regular error */ + while (status != LUA_OK && status != LUA_YIELD) { /* error? */ + if (recover(L, status)) /* recover point? */ + status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */ + else { /* unrecoverable error */ + L->status = cast_byte(status); /* mark thread as `dead' */ + seterrorobj(L, status, L->top); + L->ci->top = L->top; + break; + } + } + lua_assert(status == L->status); } - --L->nCcalls; + L->nny = 1; /* do not allow yields */ + --G(L)->nCcalls; lua_unlock(L); return status; } -LUA_API int lua_yield (lua_State *L, int nresults) { +LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { + CallInfo *ci = L->ci; luai_userstateyield(L, nresults); lua_lock(L); - if (L->nCcalls > L->baseCcalls) + api_checknelems(L, nresults); + if (L->nny > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - L->base = L->top - nresults; /* protect stack slots below */ L->status = LUA_YIELD; + if (isLua(ci)) { /* inside a hook? */ + api_check(L, k == NULL, "hooks cannot continue after yielding"); + } + else { + if ((ci->u.c.k = k) != NULL) { /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + ci->u.c.oldtop = savestack(L, ci->func); /* save current 'func' */ + } + ci->func = L->top - nresults - 1; /* protect stack slots below */ + luaD_throw(L, LUA_YIELD); + } + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ lua_unlock(L); - return -1; + return 0; /* return to 'luaD_hook' */ } int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; - unsigned short oldnCcalls = L->nCcalls; - ptrdiff_t old_ci = saveci(L, L->ci); + CallInfo *old_ci = L->ci; lu_byte old_allowhooks = L->allowhook; + unsigned short old_nny = L->nny; ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); - if (status != 0) { /* an error occurred? */ + if (status != LUA_OK) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close eventual pending closures */ - luaD_seterrorobj(L, status, oldtop); - L->nCcalls = oldnCcalls; - L->ci = restoreci(L, old_ci); - L->base = L->ci->base; - L->savedpc = L->ci->savedpc; + luaF_close(L, oldtop); /* close possible pending closures */ + seterrorobj(L, status, oldtop); + L->ci = old_ci; L->allowhook = old_allowhooks; - restore_stack_limit(L); + L->nny = old_nny; + luaD_shrinkstack(L); } L->errfunc = old_errfunc; return status; @@ -484,6 +604,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* buffer to be used by the scanner */ + Varlist varl; /* list of local variables (to be used by the parser) */ const char *name; }; @@ -493,25 +614,30 @@ static void f_parser (lua_State *L, void *ud) { Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = luaZ_lookahead(p->z); - luaC_checkGC(L); - tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, - &p->buff, p->name); - cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); + tf = (c == LUA_SIGNATURE[0]) + ? luaU_undump(L, p->z, &p->buff, p->name) + : luaY_parser(L, p->z, &p->buff, &p->varl, p->name); + setptvalue2s(L, L->top, tf); + incr_top(L); + cl = luaF_newLclosure(L, tf->sizeupvalues, G(L)->l_gt); cl->l.p = tf; - for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ + setclvalue(L, L->top - 1, cl); + for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ cl->l.upvals[i] = luaF_newupval(L); - setclvalue(L, L->top, cl); - incr_top(L); } int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; + L->nny++; /* cannot yield during parsing */ p.z = z; p.name = name; + p.varl.actvar = NULL; p.varl.nactvar = p.varl.actvarsize = 0; luaZ_initbuffer(L, &p.buff); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); + luaM_freearray(L, p.varl.actvar, p.varl.actvarsize); + L->nny--; return status; } diff --git a/src/ldo.h b/src/ldo.h index 98fddac59f..88962d9c5d 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ldo.h,v 2.18 2009/12/17 12:28:57 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,45 +13,33 @@ #include "lzio.h" -#define luaD_checkstack(L,n) \ - if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ - luaD_growstack(L, n); \ - else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); +#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \ + luaD_growstack(L, n); else condmovestack(L); -#define incr_top(L) {luaD_checkstack(L,1); L->top++;} +#define incr_top(L) {L->top++; luaD_checkstack(L,0);} #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) -#define saveci(L,p) ((char *)(p) - (char *)L->base_ci) -#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) - - -/* results from luaD_precall */ -#define PCRLUA 0 /* initiated a call to a Lua function */ -#define PCRC 1 /* did a call to a C function */ -#define PCRYIELD 2 /* C funtion yielded */ - /* type of protected functions, to be ran by `runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); -LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); +LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); -LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults, + int allowyield); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); -LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); +LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); -LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); - #endif diff --git a/src/ldump.c b/src/ldump.c index c9d3d4870f..f95381abae 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ldump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ typedef struct { } DumpState; #define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) -#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) +#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) static void DumpBlock(const void* b, size_t size, DumpState* D) { @@ -60,7 +60,7 @@ static void DumpVector(const void* b, int n, size_t size, DumpState* D) static void DumpString(const TString* s, DumpState* D) { - if (s==NULL || getstr(s)==NULL) + if (s==NULL) { size_t size=0; DumpVar(size,D); @@ -108,6 +108,17 @@ static void DumpConstants(const Proto* f, DumpState* D) for (i=0; ip[i],f->source,D); } +static void DumpUpvalues(const Proto* f, DumpState* D) +{ + int i,n=f->sizeupvalues; + DumpInt(n,D); + for (i=0; iupvalues[i].instack, D); + DumpChar(f->upvalues[i].idx, D); + } +} + static void DumpDebug(const Proto* f, DumpState* D) { int i,n; @@ -123,7 +134,7 @@ static void DumpDebug(const Proto* f, DumpState* D) } n= (D->strip) ? 0 : f->sizeupvalues; DumpInt(n,D); - for (i=0; iupvalues[i],D); + for (i=0; iupvalues[i].name,D); } static void DumpFunction(const Proto* f, const TString* p, DumpState* D) @@ -131,12 +142,13 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpString((f->source==p || D->strip) ? NULL : f->source,D); DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); - DumpChar(f->nups,D); DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); + DumpChar(f->envreg,D); DumpCode(f,D); DumpConstants(f,D); + DumpUpvalues(f,D); DumpDebug(f,D); } diff --git a/src/lfunc.c b/src/lfunc.c index 813e88f583..afc097c608 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $ +** $Id: lfunc.c,v 2.19 2009/12/16 16:42:58 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -16,34 +16,32 @@ #include "lgc.h" #include "lmem.h" #include "lobject.h" +#include "lopcodes.h" #include "lstate.h" -Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { - Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); - luaC_link(L, obj2gco(c), LUA_TFUNCTION); +Closure *luaF_newCclosure (lua_State *L, int n, Table *e) { + Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl; c->c.isC = 1; c->c.env = e; - c->c.nupvalues = cast_byte(nelems); + c->c.nupvalues = cast_byte(n); return c; } -Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { - Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); - luaC_link(L, obj2gco(c), LUA_TFUNCTION); +Closure *luaF_newLclosure (lua_State *L, int n, Table *e) { + Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; c->l.isC = 0; c->l.env = e; - c->l.nupvalues = cast_byte(nelems); - while (nelems--) c->l.upvals[nelems] = NULL; + c->l.nupvalues = cast_byte(n); + while (n--) c->l.upvals[n] = NULL; return c; } UpVal *luaF_newupval (lua_State *L) { - UpVal *uv = luaM_new(L, UpVal); - luaC_link(L, obj2gco(uv), LUA_TUPVAL); + UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; uv->v = &uv->u.value; setnilvalue(uv->v); return uv; @@ -55,21 +53,18 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { GCObject **pp = &L->openupval; UpVal *p; UpVal *uv; - while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { + while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { lua_assert(p->v != &p->u.value); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, obj2gco(p))) /* is it dead? */ - changewhite(obj2gco(p)); /* ressurect it */ + changewhite(obj2gco(p)); /* ressurrect it */ return p; } pp = &p->next; } - uv = luaM_new(L, UpVal); /* not found: create a new one */ - uv->tt = LUA_TUPVAL; - uv->marked = luaC_white(g); + /* not found: create a new one */ + uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; uv->v = level; /* current value lives in the stack */ - uv->next = *pp; /* chain it in the proper position */ - *pp = obj2gco(uv); uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ uv->u.l.next = g->uvhead.u.l.next; uv->u.l.next->u.l.prev = uv; @@ -96,7 +91,7 @@ void luaF_freeupval (lua_State *L, UpVal *uv) { void luaF_close (lua_State *L, StkId level) { UpVal *uv; global_State *g = G(L); - while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { + while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { GCObject *o = obj2gco(uv); lua_assert(!isblack(o) && uv->v != &uv->u.value); L->openupval = uv->next; /* remove from `open' list */ @@ -113,38 +108,37 @@ void luaF_close (lua_State *L, StkId level) { Proto *luaF_newproto (lua_State *L) { - Proto *f = luaM_new(L, Proto); - luaC_link(L, obj2gco(f), LUA_TPROTO); + Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p; f->k = NULL; f->sizek = 0; f->p = NULL; f->sizep = 0; f->code = NULL; f->sizecode = 0; + f->lineinfo = NULL; f->sizelineinfo = 0; - f->sizeupvalues = 0; - f->nups = 0; f->upvalues = NULL; + f->sizeupvalues = 0; f->numparams = 0; f->is_vararg = 0; f->maxstacksize = 0; - f->lineinfo = NULL; - f->sizelocvars = 0; f->locvars = NULL; + f->sizelocvars = 0; f->linedefined = 0; f->lastlinedefined = 0; f->source = NULL; + f->envreg = NO_REG; return f; } void luaF_freeproto (lua_State *L, Proto *f) { - luaM_freearray(L, f->code, f->sizecode, Instruction); - luaM_freearray(L, f->p, f->sizep, Proto *); - luaM_freearray(L, f->k, f->sizek, TValue); - luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); - luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); - luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); + luaM_freearray(L, f->code, f->sizecode); + luaM_freearray(L, f->p, f->sizep); + luaM_freearray(L, f->k, f->sizek); + luaM_freearray(L, f->lineinfo, f->sizelineinfo); + luaM_freearray(L, f->locvars, f->sizelocvars); + luaM_freearray(L, f->upvalues, f->sizeupvalues); luaM_free(L, f); } diff --git a/src/lfunc.h b/src/lfunc.h index a68cf5151c..2e02419bd6 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ diff --git a/src/lgc.c b/src/lgc.c index d9e0b78294..2094d386ae 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lgc.c,v 2.67 2009/12/22 15:32:50 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -29,54 +29,148 @@ #define GCFINALIZECOST 100 -#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) +#define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) #define makewhite(g,x) \ - ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) + (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) -#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) -#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) +#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) +#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) -#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) +#define stringmark(s) resetbits((s)->tsv.marked, WHITEBITS) #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) -#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) - - -#define KEYWEAK bitmask(KEYWEAKBIT) -#define VALUEWEAK bitmask(VALUEWEAKBIT) +#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) #define markvalue(g,o) { checkconsistency(o); \ - if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } + if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } -#define markobject(g,t) { if (iswhite(obj2gco(t))) \ +#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } -#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) +static void reallymarkobject (global_State *g, GCObject *o); + + +/* +** {====================================================== +** Generic functions +** ======================================================= +*/ + +static void linktable (Table *h, GCObject **p) { + h->gclist = *p; + *p = obj2gco(h); +} static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ + setdeadvalue(gkey(n)); /* dead key; remove it */ +} + + +/* +** The next function tells whether a key or value can be cleared from +** a weak table. Non-collectable objects are never removed from weak +** tables. Strings behave as `values', so are never removed too. for +** other objects: if really collected, cannot keep them; for objects +** being finalized, keep them in keys, but not in values +*/ +static int iscleared (const TValue *o, int iskey) { + if (!iscollectable(o)) return 0; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return 0; + } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); +} + + +void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { + global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + lua_assert(gch(o)->tt != LUA_TTABLE); + /* must keep invariant? */ + if (g->gcstate == GCSpropagate) + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ + makewhite(g, o); /* mark as white just to avoid other barriers */ +} + + +void luaC_barrierback (lua_State *L, Table *t) { + global_State *g = G(L); + GCObject *o = obj2gco(t); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + black2gray(o); /* make table gray (again) */ + t->gclist = g->grayagain; + g->grayagain = o; +} + + +/* +** create a new collectable object and link it to '*list' +*/ +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, + int offset) { + global_State *g = G(L); + GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); + if (list == NULL) + list = &g->rootgc; /* standard list for collectable objects */ + gch(o)->marked = luaC_white(g); + gch(o)->tt = tt; + gch(o)->next = *list; + *list = o; + return o; +} + + +void luaC_linkupval (lua_State *L, UpVal *uv) { + global_State *g = G(L); + GCObject *o = obj2gco(uv); + gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ + g->rootgc = o; + if (isgray(o)) { + if (g->gcstate == GCSpropagate) { + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv->v); + } + else { /* sweep phase: sweep it (turning it into white) */ + makewhite(g, o); + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + } + } } +/* }====================================================== */ + + + +/* +** {====================================================== +** Mark functions +** ======================================================= +*/ static void reallymarkobject (global_State *g, GCObject *o) { lua_assert(iswhite(o) && !isdead(g, o)); white2gray(o); - switch (o->gch.tt) { + switch (gch(o)->tt) { case LUA_TSTRING: { return; } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; gray2black(o); /* udata are never gray */ - if (mt) markobject(g, mt); + markobject(g, mt); markobject(g, gco2u(o)->env); return; } @@ -93,8 +187,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { break; } case LUA_TTABLE: { - gco2h(o)->gclist = g->gray; - g->gray = o; + linktable(gco2t(o), &g->gray); break; } case LUA_TTHREAD: { @@ -112,87 +205,145 @@ static void reallymarkobject (global_State *g, GCObject *o) { } -static void marktmu (global_State *g) { - GCObject *u = g->tmudata; - if (u) { - do { - u = u->gch.next; - makewhite(g, u); /* may be marked, if left from previous GC */ - reallymarkobject(g, u); - } while (u != g->tmudata); +static void markmt (global_State *g) { + int i; + for (i=0; imt[i]); +} + + +static void markbeingfnz (global_State *g) { + GCObject *o; + for (o = g->tobefnz; o != NULL; o = gch(o)->next) { + lua_assert(testbit(gch(o)->marked, SEPARATED)); + makewhite(g, o); + reallymarkobject(g, o); } } -/* move `dead' udata that need finalization to list `tmudata' */ -size_t luaC_separateudata (lua_State *L, int all) { +/* mark root set */ +static void markroot (lua_State *L) { global_State *g = G(L); - size_t deadmem = 0; - GCObject **p = &g->mainthread->next; - GCObject *curr; - while ((curr = *p) != NULL) { - if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) - p = &curr->gch.next; /* don't bother with them */ - else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { - markfinalized(gco2u(curr)); /* don't need finalization */ - p = &curr->gch.next; - } - else { /* must call its gc method */ - deadmem += sizeudata(gco2u(curr)); - markfinalized(gco2u(curr)); - *p = curr->gch.next; - /* link `curr' at the end of `tmudata' list */ - if (g->tmudata == NULL) /* list is empty? */ - g->tmudata = curr->gch.next = curr; /* creates a circular list */ - else { - curr->gch.next = g->tmudata->gch.next; - g->tmudata->gch.next = curr; - g->tmudata = curr; - } + g->gray = NULL; + g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; + markobject(g, g->mainthread); + /* make global table and registry to be traversed before main stack */ + markobject(g, g->l_gt); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ + g->gcstate = GCSpropagate; +} + + +static void remarkupvals (global_State *g) { + UpVal *uv; + for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (isgray(obj2gco(uv))) + markvalue(g, uv->v); + } +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Traverse functions +** ======================================================= +*/ + +static void traverseweakvalue (global_State *g, Table *h) { + int i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + checkdeadkey(n); + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { + lua_assert(!ttisnil(gkey(n))); + markvalue(g, gkey(n)); } } - return deadmem; + linktable(h, &g->weak); } -static int traversetable (global_State *g, Table *h) { - int i; - int weakkey = 0; - int weakvalue = 0; - const TValue *mode; - if (h->metatable) - markobject(g, h->metatable); - mode = gfasttm(g, h->metatable, TM_MODE); - if (mode && ttisstring(mode)) { /* is there a weak mode? */ - weakkey = (strchr(svalue(mode), 'k') != NULL); - weakvalue = (strchr(svalue(mode), 'v') != NULL); - if (weakkey || weakvalue) { /* is really weak? */ - h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ - h->marked |= cast_byte((weakkey << KEYWEAKBIT) | - (weakvalue << VALUEWEAKBIT)); - h->gclist = g->weak; /* must be cleared after GC, ... */ - g->weak = obj2gco(h); /* ... so put in the appropriate list */ +static int traverseephemeron (global_State *g, Table *h) { + int marked = 0; + int hasclears = 0; + int i = h->sizearray; + while (i--) { /* mark array part (numeric keys are 'strong') */ + if (valiswhite(&h->array[i])) { + marked = 1; + reallymarkobject(g, gcvalue(&h->array[i])); } } - if (weakkey && weakvalue) return 1; - if (!weakvalue) { - i = h->sizearray; - while (i--) - markvalue(g, &h->array[i]); + i = sizenode(h); + while (i--) { + Node *n = gnode(h, i); + checkdeadkey(n); + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ + else if (valiswhite(gval(n))) { + /* value is not marked yet */ + if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ + hasclears = 1; /* may have to propagate mark from key to value */ + else { /* mark value only if key is marked */ + marked = 1; /* some mark changed status */ + reallymarkobject(g, gcvalue(gval(n))); + } + } } + if (hasclears) + linktable(h, &g->ephemeron); + else /* nothing to propagate */ + linktable(h, &g->weak); /* avoid convergence phase */ + return marked; +} + + +static void traversestrongtable (global_State *g, Table *h) { + int i; + i = h->sizearray; + while (i--) + markvalue(g, &h->array[i]); i = sizenode(h); while (i--) { Node *n = gnode(h, i); - lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); + checkdeadkey(n); if (ttisnil(gval(n))) removeentry(n); /* remove empty entries */ else { lua_assert(!ttisnil(gkey(n))); - if (!weakkey) markvalue(g, gkey(n)); - if (!weakvalue) markvalue(g, gval(n)); + markvalue(g, gkey(n)); + markvalue(g, gval(n)); } } - return weakkey || weakvalue; +} + + +static void traversetable (global_State *g, Table *h) { + const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + markobject(g, h->metatable); + if (mode && ttisstring(mode)) { /* is there a weak mode? */ + int weakkey = (strchr(svalue(mode), 'k') != NULL); + int weakvalue = (strchr(svalue(mode), 'v') != NULL); + if (weakkey || weakvalue) { /* is really weak? */ + black2gray(obj2gco(h)); /* keep table gray */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h); + else + linktable(h, &g->allweak); /* nothing to traverse now */ + return; + } /* else go through */ + } + traversestrongtable(g, h); } @@ -206,13 +357,11 @@ static void traverseproto (global_State *g, Proto *f) { for (i=0; isizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i=0; isizeupvalues; i++) { /* mark upvalue names */ - if (f->upvalues[i]) - stringmark(f->upvalues[i]); - } - for (i=0; isizep; i++) { /* mark nested protos */ - if (f->p[i]) - markobject(g, f->p[i]); + if (f->upvalues[i].name) + stringmark(f->upvalues[i].name); } + for (i=0; isizep; i++) /* mark nested protos */ + markobject(g, f->p[i]); for (i=0; isizelocvars; i++) { /* mark local-variable names */ if (f->locvars[i].varname) stringmark(f->locvars[i].varname); @@ -220,7 +369,6 @@ static void traverseproto (global_State *g, Proto *f) { } - static void traverseclosure (global_State *g, Closure *cl) { markobject(g, cl->c.env); if (cl->c.isC) { @@ -230,7 +378,7 @@ static void traverseclosure (global_State *g, Closure *cl) { } else { int i; - lua_assert(cl->l.nupvalues == cl->l.p->nups); + lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); markobject(g, cl->l.p); for (i=0; il.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); @@ -238,35 +386,17 @@ static void traverseclosure (global_State *g, Closure *cl) { } -static void checkstacksizes (lua_State *L, StkId max) { - int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ - int s_used = cast_int(max - L->stack); /* part of stack in use */ - if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ - return; /* do not touch the stacks */ - if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) - luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ - condhardstacktests(luaD_reallocCI(L, ci_used + 1)); - if (4*s_used < L->stacksize && - 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) - luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ - condhardstacktests(luaD_reallocstack(L, s_used)); -} - - -static void traversestack (global_State *g, lua_State *l) { - StkId o, lim; - CallInfo *ci; - markvalue(g, gt(l)); - lim = l->top; - for (ci = l->base_ci; ci <= l->ci; ci++) { - lua_assert(ci->top <= l->stack_last); - if (lim < ci->top) lim = ci->top; - } - for (o = l->stack; o < l->top; o++) +static void traversestack (global_State *g, lua_State *L) { + StkId o; + if (L->stack == NULL) + return; /* stack not completely built yet */ + for (o = L->stack; o < L->top; o++) markvalue(g, o); - for (; o <= lim; o++) - setnilvalue(o); - checkstacksizes(l, lim); + if (g->gcstate == GCSatomic) { /* final traversal? */ + StkId lim = L->stack + L->stacksize; /* real end of stack */ + for (; o < lim; o++) /* clear not-marked stack slice */ + setnilvalue(o); + } } @@ -278,12 +408,11 @@ static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); - switch (o->gch.tt) { + switch (gch(o)->tt) { case LUA_TTABLE: { - Table *h = gco2h(o); + Table *h = gco2t(o); g->gray = h->gclist; - if (traversetable(g, h)) /* table is weak? */ - black2gray(o); /* keep it gray */ + traversetable(g, h); return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h); } @@ -301,8 +430,7 @@ static l_mem propagatemark (global_State *g) { g->grayagain = o; black2gray(o); traversestack(g, th); - return sizeof(lua_State) + sizeof(TValue) * th->stacksize + - sizeof(CallInfo) * th->size_ci; + return sizeof(lua_State) + sizeof(TValue) * th->stacksize; } case LUA_TPROTO: { Proto *p = gco2p(o); @@ -310,7 +438,7 @@ static l_mem propagatemark (global_State *g) { traverseproto(g, p); return sizeof(Proto) + sizeof(Instruction) * p->sizecode + sizeof(Proto *) * p->sizep + - sizeof(TValue) * p->sizek + + sizeof(TValue) * p->sizek + sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues; @@ -320,46 +448,54 @@ static l_mem propagatemark (global_State *g) { } -static size_t propagateall (global_State *g) { - size_t m = 0; - while (g->gray) m += propagatemark(g); - return m; +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); } -/* -** The next function tells whether a key or value can be cleared from -** a weak table. Non-collectable objects are never removed from weak -** tables. Strings behave as `values', so are never removed too. for -** other objects: if really collected, cannot keep them; for userdata -** being finalized, keep them in keys, but not in values -*/ -static int iscleared (const TValue *o, int iskey) { - if (!iscollectable(o)) return 0; - if (ttisstring(o)) { - stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ - return 0; - } - return iswhite(gcvalue(o)) || - (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); +static void traverselistofgrays (global_State *g, GCObject **l) { + lua_assert(g->gray == NULL); /* no grays left */ + g->gray = *l; /* now 'l' is new gray list */ + *l = NULL; + propagateall(g); } +static void convergeephemerons (global_State *g) { + int changed; + do { + GCObject *w; + GCObject *next = g->ephemeron; + g->ephemeron = NULL; + changed = 0; + while ((w = next) != NULL) { + next = gco2t(w)->gclist; + if (traverseephemeron(g, gco2t(w))) { + changed = 1; + propagateall(g); + } + } + } while (changed); +} + +/* }====================================================== */ + + /* -** clear collected entries from weaktables +** {====================================================== +** Sweep Functions +** ======================================================= */ + +/* clear collected entries from weaktables */ static void cleartable (GCObject *l) { while (l) { - Table *h = gco2h(l); + Table *h = gco2t(l); int i = h->sizearray; - lua_assert(testbit(h->marked, VALUEWEAKBIT) || - testbit(h->marked, KEYWEAKBIT)); - if (testbit(h->marked, VALUEWEAKBIT)) { - while (i--) { - TValue *o = &h->array[i]; - if (iscleared(o, 0)) /* value was collected? */ - setnilvalue(o); /* remove value */ - } + while (i--) { + TValue *o = &h->array[i]; + if (iscleared(o, 0)) /* value was collected? */ + setnilvalue(o); /* remove value */ } i = sizenode(h); while (i--) { @@ -376,32 +512,35 @@ static void cleartable (GCObject *l) { static void freeobj (lua_State *L, GCObject *o) { - switch (o->gch.tt) { + switch (gch(o)->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; - case LUA_TTABLE: luaH_free(L, gco2h(o)); break; - case LUA_TTHREAD: { - lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); - luaE_freethread(L, gco2th(o)); - break; - } + case LUA_TTABLE: luaH_free(L, gco2t(o)); break; + case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; + case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TSTRING: { G(L)->strt.nuse--; luaM_freemem(L, o, sizestring(gco2ts(o))); break; } - case LUA_TUSERDATA: { - luaM_freemem(L, o, sizeudata(gco2u(o))); - break; - } default: lua_assert(0); } } - #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) +static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); + + +static void sweepthread (lua_State *L, lua_State *L1, int alive) { + if (L1->stack == NULL) return; /* stack not completely built yet */ + sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ + luaE_freeCI(L1); /* free extra CallInfo slots */ + /* should not change the stack during an emergency gc cycle */ + if (alive && G(L)->gckind != KGC_EMERGENCY) + luaD_shrinkstack(L1); +} static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { @@ -409,54 +548,68 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { global_State *g = G(L); int deadmask = otherwhite(g); while ((curr = *p) != NULL && count-- > 0) { - if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ - sweepwholelist(L, &gco2th(curr)->openupval); - if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ - lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); + int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; + if (gch(curr)->tt == LUA_TTHREAD) + sweepthread(L, gco2th(curr), alive); + if (alive) { + lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ - p = &curr->gch.next; + p = &gch(curr)->next; } else { /* must erase `curr' */ lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); - *p = curr->gch.next; - if (curr == g->rootgc) /* is the first element of the list? */ - g->rootgc = curr->gch.next; /* adjust first */ + *p = gch(curr)->next; /* remove 'curr' from list */ freeobj(L, curr); } } return p; } +/* }====================================================== */ + + +/* +** {====================================================== +** Finalization +** ======================================================= +*/ static void checkSizes (lua_State *L) { global_State *g = G(L); - /* check size of string hash */ - if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && - g->strt.size > MINSTRTABSIZE*2) - luaS_resize(L, g->strt.size/2); /* table is too big */ - /* check size of buffer */ - if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - size_t newsize = luaZ_sizebuffer(&g->buff) / 2; - luaZ_resizebuffer(L, &g->buff, newsize); + if (g->strt.nuse < cast(lu_int32, g->strt.size)) { + /* string-table size could be the smaller power of 2 larger than 'nuse' */ + int size = 1 << luaO_ceillog2(g->strt.nuse); + if (size < g->strt.size) /* current table too large? */ + luaS_resize(L, size); /* shrink it */ } + luaZ_freebuffer(L, &g->buff); } -static void GCTM (lua_State *L) { - global_State *g = G(L); - GCObject *o = g->tmudata->gch.next; /* get first element */ - Udata *udata = rawgco2u(o); - const TValue *tm; - /* remove udata from `tmudata' */ - if (o == g->tmudata) /* last element? */ - g->tmudata = NULL; - else - g->tmudata->gch.next = udata->uv.next; - udata->uv.next = g->mainthread->next; /* return it to `root' list */ - g->mainthread->next = o; +static Udata *udata2finalize (global_State *g) { + GCObject *o = g->tobefnz; /* get first element */ + g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ + gch(o)->next = g->rootgc; /* return it to `root' list */ + g->rootgc = o; + lua_assert(isfinalized(gch(o))); + resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ makewhite(g, o); - tm = fasttm(L, udata->uv.metatable, TM_GC); - if (tm != NULL) { + return rawgco2u(o); +} + + +static void dothecall (lua_State *L, void *ud) { + UNUSED(ud); + luaD_call(L, L->top - 2, 0, 0); +} + + +static void GCTM (lua_State *L, int propagateerrors) { + global_State *g = G(L); + Udata *udata = udata2finalize(g); + const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC); + if (tm != NULL && ttisfunction(tm)) { + int status; lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ @@ -464,92 +617,116 @@ static void GCTM (lua_State *L) { setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; - luaD_call(L, L->top - 2, 0); + status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ g->GCthreshold = oldt; /* restore threshold */ + if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ + if (status == LUA_ERRRUN) { /* is there an error msg.? */ + luaO_pushfstring(L, "error in __gc tag method (%s)", + lua_tostring(L, -1)); + status = LUA_ERRGCMM; /* error in __gc metamethod */ + } + luaD_throw(L, status); /* re-send error */ + } } } -/* -** Call all GC tag methods -*/ -void luaC_callGCTM (lua_State *L) { - while (G(L)->tmudata) - GCTM(L); +/* move 'dead' udata that need finalization to list 'tobefnz' */ +void luaC_separateudata (lua_State *L, int all) { + global_State *g = G(L); + GCObject **p = &g->mainthread->next; + GCObject *curr; + GCObject **lastnext = &g->tobefnz; + /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ + while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; + while ((curr = *p) != NULL) { /* traverse all finalizable objects */ + lua_assert(gch(curr)->tt == LUA_TUSERDATA && !isfinalized(gco2u(curr))); + lua_assert(testbit(gch(curr)->marked, SEPARATED)); + if (!(all || iswhite(curr))) /* not being collected? */ + p = &gch(curr)->next; /* don't bother with it */ + else { + l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ + *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */ + /* link 'curr' at the end of 'tobefnz' list */ + gch(curr)->next = *lastnext; + *lastnext = curr; + lastnext = &gch(curr)->next; + } + } } -void luaC_freeall (lua_State *L) { +void luaC_checkfinalizer (lua_State *L, Udata *u) { global_State *g = G(L); - int i; - g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ - sweepwholelist(L, &g->rootgc); - for (i = 0; i < g->strt.size; i++) /* free all string lists */ - sweepwholelist(L, &g->strt.hash[i]); + if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */ + isfinalized(&u->uv) || /* ... or is finalized... */ + gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ + return; /* nothing to be done */ + else { /* move 'u' to 2nd part of root list */ + GCObject **p; + for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) + lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */ + *p = u->uv.next; /* remove 'u' from root list */ + u->uv.next = g->mainthread->next; /* re-link it in list */ + g->mainthread->next = obj2gco(u); + l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ + } } +/* }====================================================== */ -static void markmt (global_State *g) { - int i; - for (i=0; imt[i]) markobject(g, g->mt[i]); -} +/* +** {====================================================== +** GC control +** ======================================================= +*/ -/* mark root set */ -static void markroot (lua_State *L) { +void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); - g->gray = NULL; - g->grayagain = NULL; - g->weak = NULL; - markobject(g, g->mainthread); - /* make global table be traversed before main stack */ - markvalue(g, gt(g->mainthread)); - markvalue(g, registry(L)); - markmt(g); - g->gcstate = GCSpropagate; -} - - -static void remarkupvals (global_State *g) { - UpVal *uv; - for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - if (isgray(obj2gco(uv))) - markvalue(g, uv->v); - } + int i; + while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */ + /* following "white" makes all objects look dead */ + g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); + sweepwholelist(L, &g->rootgc); + lua_assert(g->rootgc == obj2gco(g->mainthread) && + g->mainthread->next == NULL); + for (i = 0; i < g->strt.size; i++) /* free all string lists */ + sweepwholelist(L, &g->strt.hash[i]); + lua_assert(g->strt.nuse == 0); } static void atomic (lua_State *L) { global_State *g = G(L); - size_t udsize; /* total size of userdata to be finalized */ - /* remark occasional upvalues of (maybe) dead threads */ - remarkupvals(g); - /* traverse objects cautch by write barrier and by 'remarkupvals' */ - propagateall(g); - /* remark weak tables */ - g->gray = g->weak; - g->weak = NULL; + g->gcstate = GCSatomic; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ - markmt(g); /* mark basic metatables (again) */ - propagateall(g); - /* remark gray again */ - g->gray = g->grayagain; - g->grayagain = NULL; + /* registry and global metatables may be changed by API */ + markvalue(g, &g->l_registry); + markmt(g); /* mark basic metatables */ + /* remark occasional upvalues of (maybe) dead threads */ + remarkupvals(g); + /* traverse objects caught by write barrier and by 'remarkupvals' */ propagateall(g); - udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ - marktmu(g); /* mark `preserved' userdata */ - udsize += propagateall(g); /* remark, to propagate `preserveness' */ - cleartable(g->weak); /* remove collected objects from weak tables */ - /* flip current white */ - g->currentwhite = cast_byte(otherwhite(g)); - g->sweepstrgc = 0; - g->sweepgc = &g->rootgc; + /* at this point, all strongly accessible objects are marked. + Start marking weakly accessible objects. */ + traverselistofgrays(g, &g->weak); /* remark weak tables */ + traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ + traverselistofgrays(g, &g->grayagain); /* remark gray again */ + convergeephemerons(g); + luaC_separateudata(L, 0); /* separate userdata to be finalized */ + markbeingfnz(g); /* mark userdata that will be finalized */ + propagateall(g); /* remark, to propagate `preserveness' */ + convergeephemerons(g); + /* remove collected objects from weak tables */ + cleartable(g->weak); + cleartable(g->ephemeron); + cleartable(g->allweak); + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + g->sweepstrgc = 0; /* go to sweep phase */ g->gcstate = GCSsweepstring; - g->estimate = g->totalbytes - udsize; /* first estimate */ } @@ -570,35 +747,27 @@ static l_mem singlestep (lua_State *L) { } } case GCSsweepstring: { - lu_mem old = g->totalbytes; sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); - if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ - g->gcstate = GCSsweep; /* end sweep-string phase */ - lua_assert(old >= g->totalbytes); - g->estimate -= old - g->totalbytes; + if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ + g->sweepgc = &g->rootgc; + g->gcstate = GCSsweep; /* sweep all other objects */ + } return GCSWEEPCOST; } case GCSsweep: { - lu_mem old = g->totalbytes; g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - if (*g->sweepgc == NULL) { /* nothing more to sweep? */ - checkSizes(L); + if (*g->sweepgc == NULL) /* nothing more to sweep? */ g->gcstate = GCSfinalize; /* end sweep phase */ - } - lua_assert(old >= g->totalbytes); - g->estimate -= old - g->totalbytes; return GCSWEEPMAX*GCSWEEPCOST; } case GCSfinalize: { - if (g->tmudata) { - GCTM(L); - if (g->estimate > GCFINALIZECOST) - g->estimate -= GCFINALIZECOST; + if (g->tobefnz) { + GCTM(L, 1); return GCFINALIZECOST; } else { + checkSizes(L); g->gcstate = GCSpause; /* end collection */ - g->gcdept = 0; return 0; } } @@ -609,103 +778,56 @@ static l_mem singlestep (lua_State *L) { void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; - if (lim == 0) - lim = (MAX_LUMEM-1)/2; /* no limit */ - g->gcdept += g->totalbytes - g->GCthreshold; - do { + l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */ + lu_mem debt = g->totalbytes - g->GCthreshold; + lua_assert(g->gckind == KGC_NORMAL); + do { /* always perform at least one single step */ lim -= singlestep(L); - if (g->gcstate == GCSpause) - break; - } while (lim > 0); - if (g->gcstate != GCSpause) { - if (g->gcdept < GCSTEPSIZE) - g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ - else { - g->gcdept -= GCSTEPSIZE; - g->GCthreshold = g->totalbytes; - } - } - else { - lua_assert(g->totalbytes >= g->estimate); - setthreshold(g); - } + } while (lim > 0 && g->gcstate != GCSpause); + g->GCthreshold = (g->gcstate != GCSpause) + ? g->totalbytes + GCSTEPSIZE + : (g->totalbytes/100) * g->gcpause; + /* compensate if GC is "behind schedule" (has some debt to pay) */ + if (g->GCthreshold > debt) g->GCthreshold -= debt; } -void luaC_fullgc (lua_State *L) { +/* +** advances the garbage collector until it reaches a state allowed +** by 'statemask' +*/ +void luaC_runtilstate (lua_State *L, int statesmask) { global_State *g = G(L); - if (g->gcstate <= GCSpropagate) { - /* reset sweep marks to sweep all elements (returning them to white) */ - g->sweepstrgc = 0; - g->sweepgc = &g->rootgc; - /* reset other collector lists */ - g->gray = NULL; - g->grayagain = NULL; - g->weak = NULL; - g->gcstate = GCSsweepstring; - } - lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); - /* finish any pending sweep phase */ - while (g->gcstate != GCSfinalize) { - lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); + while (!testbit(statesmask, g->gcstate)) singlestep(L); - } - markroot(L); - while (g->gcstate != GCSpause) { - singlestep(L); - } - setthreshold(g); -} - - -void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { - global_State *g = G(L); - lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - lua_assert(ttype(&o->gch) != LUA_TTABLE); - /* must keep invariant? */ - if (g->gcstate == GCSpropagate) - reallymarkobject(g, v); /* restore invariant */ - else /* don't mind */ - makewhite(g, o); /* mark as white just to avoid other barriers */ } -void luaC_barrierback (lua_State *L, Table *t) { - global_State *g = G(L); - GCObject *o = obj2gco(t); - lua_assert(isblack(o) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - black2gray(o); /* make table gray (again) */ - t->gclist = g->grayagain; - g->grayagain = o; -} - - -void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { +/* +** performs a full GC cycle; if "isememrgency", does not call +** finalizers (which could change stack positions) +*/ +void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); - o->gch.next = g->rootgc; - g->rootgc = o; - o->gch.marked = luaC_white(g); - o->gch.tt = tt; + lua_assert(g->gckind == KGC_NORMAL); + g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; + if (g->gcstate == GCSpropagate) { /* marking phase? */ + /* must sweep all objects to turn them back to white + (as white does not change, nothing will be collected) */ + g->sweepstrgc = 0; + g->gcstate = GCSsweepstring; + } + /* finish any pending sweep phase */ + luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep)); + markroot(L); /* start a new collection */ + /* run collector up to finalizers */ + luaC_runtilstate(L, bitmask(GCSfinalize)); + g->gckind = KGC_NORMAL; + if (!isemergency) /* do not run finalizers during emergency GC */ + luaC_runtilstate(L, ~bitmask(GCSfinalize)); + g->GCthreshold = (g->totalbytes/100) * g->gcpause; } +/* }====================================================== */ -void luaC_linkupval (lua_State *L, UpVal *uv) { - global_State *g = G(L); - GCObject *o = obj2gco(uv); - o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ - g->rootgc = o; - if (isgray(o)) { - if (g->gcstate == GCSpropagate) { - gray2black(o); /* closed upvalues need barrier */ - luaC_barrier(L, uv, uv->v); - } - else { /* sweep phase: sweep it (turning it into white) */ - makewhite(g, o); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - } - } -} diff --git a/src/lgc.h b/src/lgc.h index 5a8dc605b3..bab2e85022 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -16,25 +16,26 @@ */ #define GCSpause 0 #define GCSpropagate 1 -#define GCSsweepstring 2 -#define GCSsweep 3 -#define GCSfinalize 4 +#define GCSatomic 2 +#define GCSsweepstring 3 +#define GCSsweep 4 +#define GCSfinalize 5 + /* -** some userful bit tricks +** some useful bit tricks */ -#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) -#define setbits(x,m) ((x) |= (m)) -#define testbits(x,m) ((x) & (m)) -#define bitmask(b) (1<<(b)) -#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) -#define l_setbit(x,b) setbits(x, bitmask(b)) -#define resetbit(x,b) resetbits(x, bitmask(b)) -#define testbit(x,b) testbits(x, bitmask(b)) +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) #define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) #define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) -#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) @@ -44,8 +45,7 @@ ** bit 1 - object is white (type 1) ** bit 2 - object is black ** bit 3 - for userdata: has been finalized -** bit 3 - for tables: has weak keys -** bit 4 - for tables: has weak values +** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz ** bit 5 - object is fixed (should not be collected) ** bit 6 - object is "super" fixed (only the main thread) */ @@ -55,14 +55,13 @@ #define WHITE1BIT 1 #define BLACKBIT 2 #define FINALIZEDBIT 3 -#define KEYWEAKBIT 3 -#define VALUEWEAKBIT 4 +#define SEPARATED 4 #define FIXEDBIT 5 #define SFIXEDBIT 6 #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) -#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define iswhite(x) testbits((x)->gch.marked, WHITEBITS) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) #define isgray(x) (!isblack(x) && !iswhite(x)) @@ -77,10 +76,8 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_checkGC(L) { \ - condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ - if (G(L)->totalbytes >= G(L)->GCthreshold) \ - luaC_step(L); } +#define luaC_checkGC(L) \ + {condchangemem(L); if (G(L)->totalbytes >= G(L)->GCthreshold) luaC_step(L);} #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ @@ -96,15 +93,17 @@ #define luaC_objbarriert(L,t,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } -LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); -LUAI_FUNC void luaC_callGCTM (lua_State *L); -LUAI_FUNC void luaC_freeall (lua_State *L); +LUAI_FUNC void luaC_separateudata (lua_State *L, int all); +LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); -LUAI_FUNC void luaC_fullgc (lua_State *L); -LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); +LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, + GCObject **list, int offset); LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); +LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); #endif diff --git a/src/linit.c b/src/linit.c index c1f90dfab7..a9430605f5 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,10 +1,18 @@ /* -** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $ -** Initialization of libraries for lua.c +** $Id: linit.c,v 1.23 2009/12/22 15:32:50 roberto Exp $ +** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ +/* +** If you embed Lua in your program and need to open the standard +** libraries, call luaL_openlibs in your program. If you need a +** different set of libraries, copy this file to your project and edit +** it to suit your needs. +*/ + + #define linit_c #define LUA_LIB @@ -14,25 +22,54 @@ #include "lauxlib.h" -static const luaL_Reg lualibs[] = { - {"", luaopen_base}, +/* +** these libs are loaded by lua.c and are readily available to any Lua +** program +*/ +static const luaL_Reg loadedlibs[] = { + {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, + {LUA_BITLIBNAME, luaopen_bit}, {LUA_MATHLIBNAME, luaopen_math}, + {NULL, NULL} +}; + + +/* +** these libs are preloaded and must be required before used +*/ +static const luaL_Reg preloadedlibs[] = { {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { - const luaL_Reg *lib = lualibs; - for (; lib->func; lib++) { + const luaL_Reg *lib; + /* call open functions from 'loadedlibs' */ + for (lib = loadedlibs; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_pushstring(L, lib->name); lua_call(L, 1, 0); } + /* add open functions from 'preloadedlibs' into 'package.preload' table */ + lua_pushglobaltable(L); + luaL_findtable(L, 0, "package.preload", 0); + for (lib = preloadedlibs; lib->func; lib++) { + lua_pushcfunction(L, lib->func); + lua_setfield(L, -2, lib->name); + } + lua_pop(L, 1); /* remove package.preload table */ +#if defined(LUA_COMPAT_DEBUGLIB) + lua_pushglobaltable(L); + lua_getfield(L, -1, "require"); + lua_pushliteral(L, LUA_DBLIBNAME); + lua_call(L, 1, 0); /* call 'require"debug"' */ + lua_pop(L, 1); /* remove global table */ +#endif } diff --git a/src/liolib.c b/src/liolib.c index e79ed1cb2e..64fa43b4d1 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ +** $Id: liolib.c,v 2.85 2009/12/17 16:20:01 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -19,6 +19,33 @@ #include "lualib.h" +/* +** lua_popen spawns a new process connected to the current one through +** the file streams. +*/ +#if !defined(lua_popen) + +#if defined(LUA_USE_POPEN) + +#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) +#define lua_pclose(L,file) ((void)L, pclose(file)) + +#elif defined(LUA_WIN) + +#define lua_popen(L,c,m) ((void)L, _popen(c,m)) +#define lua_pclose(L,file) ((void)L, _pclose(file)) + +#else + +#define lua_popen(L,c,m) ((void)((void)c, m), \ + luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) +#define lua_pclose(L,file) ((void)((void)L, file), -1) + +#endif + +#endif + + #define IO_INPUT 1 #define IO_OUTPUT 2 @@ -57,9 +84,8 @@ static void fileerror (lua_State *L, int arg, const char *filename) { static int io_type (lua_State *L) { void *ud; luaL_checkany(L, 1); - ud = lua_touserdata(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); - if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + ud = luaL_testudata(L, 1, LUA_FILEHANDLE); + if (ud == NULL) lua_pushnil(L); /* not a file */ else if (*((FILE **)ud) == NULL) lua_pushliteral(L, "closed file"); @@ -107,9 +133,14 @@ static int io_noclose (lua_State *L) { */ static int io_pclose (lua_State *L) { FILE **p = tofilep(L); - int ok = lua_pclose(L, *p); + int stat = lua_pclose(L, *p); *p = NULL; - return pushresult(L, ok, NULL); + if (stat == -1) /* error? */ + return pushresult(L, 0, NULL); + else { + lua_pushinteger(L, stat); + return 1; /* return status */ + } } @@ -161,7 +192,16 @@ static int io_tostring (lua_State *L) { static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); - FILE **pf = newfile(L); + FILE **pf; + int i = 0; + /* check whether 'mode' matches '[rwa]%+?b?' */ + if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL && + (mode[i] != '+' || ++i) && /* skip if char is '+' */ + (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ + (mode[i] == '\0'))) + luaL_error(L, "invalid mode " LUA_QL("%s") + " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); + pf = newfile(L); *pf = fopen(filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } @@ -296,7 +336,7 @@ static int read_line (lua_State *L, FILE *f) { char *p = luaL_prepbuffer(&b); if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ luaL_pushresult(&b); /* close buffer */ - return (lua_objlen(L, -1) > 0); /* check whether read something */ + return (lua_rawlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); if (l == 0 || p[l-1] != '\n') @@ -311,20 +351,21 @@ static int read_line (lua_State *L, FILE *f) { static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t rlen; /* how much to read */ - size_t nr; /* number of chars actually read */ + size_t tbr = n; /* number of chars to be read */ + size_t rlen; /* how much to read in each cycle */ + size_t nr; /* number of chars actually read in each cycle */ luaL_Buffer b; luaL_buffinit(L, &b); rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ do { char *p = luaL_prepbuffer(&b); - if (rlen > n) rlen = n; /* cannot read more than asked */ + if (rlen > tbr) rlen = tbr; /* cannot read more than asked */ nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); - n -= nr; /* still have to read `n' chars */ - } while (n > 0 && nr == rlen); /* until end of count or eof */ + tbr -= nr; /* still have to read 'tbr' chars */ + } while (tbr > 0 && nr == rlen); /* until end of count or eof */ luaL_pushresult(&b); /* close buffer */ - return (n == 0 || lua_objlen(L, -1) > 0); + return (tbr < n); /* true iff read something */ } @@ -387,13 +428,13 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); - int sucess; + int success; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); - sucess = read_line(L, f); + success = read_line(L, f); if (ferror(f)) return luaL_error(L, "%s", strerror(errno)); - if (sucess) return 1; + if (success) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ lua_settop(L, 0); @@ -408,7 +449,7 @@ static int io_readline (lua_State *L) { static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - 1; + int nargs = lua_gettop(L) - arg; int status = 1; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { @@ -422,7 +463,8 @@ static int g_write (lua_State *L, FILE *f, int arg) { status = status && (fwrite(s, sizeof(char), l, f) == l); } } - return pushresult(L, status, NULL); + if (status) return 1; /* file handle already on stack top */ + else return pushresult(L, status, NULL); } @@ -432,7 +474,9 @@ static int io_write (lua_State *L) { static int f_write (lua_State *L) { - return g_write(L, tofile(L), 2); + FILE * f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); } @@ -531,7 +575,7 @@ static void newfenv (lua_State *L, lua_CFunction cls) { } -LUALIB_API int luaopen_io (lua_State *L) { +LUAMOD_API int luaopen_io (lua_State *L) { createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ newfenv(L, io_fclose); diff --git a/src/llex.c b/src/llex.c index 6dc319358c..3cfdbca176 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,11 +1,10 @@ /* -** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: llex.c,v 2.34 2009/11/17 16:33:38 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ -#include #include #include @@ -14,6 +13,7 @@ #include "lua.h" +#include "lctype.h" #include "ldo.h" #include "llex.h" #include "lobject.h" @@ -29,35 +29,36 @@ - #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ -const char *const luaX_tokens [] = { +static const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", - "..", "...", "==", ">=", "<=", "~=", - "", "", "", "", - NULL + "..", "...", "==", ">=", "<=", "~=", "", + "", "", "" }; #define save_and_next(ls) (save(ls, ls->current), next(ls)) +static void lexerror (LexState *ls, const char *msg, int token); + + static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; - if (b->n + 1 > b->buffsize) { + if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { size_t newsize; - if (b->buffsize >= MAX_SIZET/2) - luaX_lexerror(ls, "lexical element too long", 0); - newsize = b->buffsize * 2; + if (luaZ_sizebuffer(b) >= MAX_SIZET/2) + lexerror(ls, "lexical element too long", 0); + newsize = luaZ_sizebuffer(b) * 2; luaZ_resizebuffer(ls->L, b, newsize); } - b->buffer[b->n++] = cast(char, c); + b->buffer[luaZ_bufflen(b)++] = cast(char, c); } @@ -72,17 +73,19 @@ void luaX_init (lua_State *L) { } -#define MAXSRC 80 - - const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { lua_assert(token == cast(unsigned char, token)); - return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : - luaO_pushfstring(ls->L, "%c", token); + return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : + luaO_pushfstring(ls->L, "char(%d)", token); + } + else { + const char *s = luaX_tokens[token - FIRST_RESERVED]; + if (token < TK_EOS) + return luaO_pushfstring(ls->L, LUA_QS, s); + else + return s; } - else - return luaX_tokens[token-FIRST_RESERVED]; } @@ -92,34 +95,39 @@ static const char *txtToken (LexState *ls, int token) { case TK_STRING: case TK_NUMBER: save(ls, '\0'); - return luaZ_buffer(ls->buff); + return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff)); default: return luaX_token2str(ls, token); } } -void luaX_lexerror (LexState *ls, const char *msg, int token) { - char buff[MAXSRC]; - luaO_chunkid(buff, getstr(ls->source), MAXSRC); +static void lexerror (LexState *ls, const char *msg, int token) { + char buff[LUA_IDSIZE]; + luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE); msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); if (token) - luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); + luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); } void luaX_syntaxerror (LexState *ls, const char *msg) { - luaX_lexerror(ls, msg, ls->t.token); + lexerror(ls, msg, ls->t.token); } TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; + TValue *o; /* entry for `str' */ TString *ts = luaS_newlstr(L, str, l); - TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ - if (ttisnil(o)) + setsvalue2s(L, L->top++, ts); /* anchor string */ + o = luaH_setstr(L, ls->fs->h, ts); + if (ttisnil(o)) { setbvalue(o, 1); /* make sure `str' will not be collected */ + luaC_checkGC(L); + } + L->top--; return ts; } @@ -159,7 +167,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { static int check_next (LexState *ls, const char *set) { - if (!strchr(set, ls->current)) + if (ls->current == '\0' || !strchr(set, ls->current)) return 0; save_and_next(ls); return 1; @@ -174,29 +182,32 @@ static void buffreplace (LexState *ls, char from, char to) { } +#if !defined(getlocaledecpoint) +#define getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + static void trydecpoint (LexState *ls, SemInfo *seminfo) { /* format error: try to update decimal point separator */ - struct lconv *cv = localeconv(); char old = ls->decpoint; - ls->decpoint = (cv ? cv->decimal_point[0] : '.'); + ls->decpoint = getlocaledecpoint(); buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ - luaX_lexerror(ls, "malformed number", TK_NUMBER); + lexerror(ls, "malformed number", TK_NUMBER); } } /* LUA_NUMBER */ static void read_numeral (LexState *ls, SemInfo *seminfo) { - lua_assert(isdigit(ls->current)); + lua_assert(lisdigit(ls->current)); do { save_and_next(ls); - } while (isdigit(ls->current) || ls->current == '.'); + } while (lisdigit(ls->current) || ls->current == '.'); if (check_next(ls, "Ee")) /* `E'? */ check_next(ls, "+-"); /* optional exponent sign */ - while (isalnum(ls->current) || ls->current == '_') + while (lislalnum(ls->current)) save_and_next(ls); save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ @@ -219,37 +230,18 @@ static int skip_sep (LexState *ls) { static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { - int cont = 0; - (void)(cont); /* avoid warnings when `cont' is not used */ save_and_next(ls); /* skip 2nd `[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { case EOZ: - luaX_lexerror(ls, (seminfo) ? "unfinished long string" : - "unfinished long comment", TK_EOS); + lexerror(ls, (seminfo) ? "unfinished long string" : + "unfinished long comment", TK_EOS); break; /* to avoid warnings */ -#if defined(LUA_COMPAT_LSTR) - case '[': { - if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd `[' */ - cont++; -#if LUA_COMPAT_LSTR == 1 - if (sep == 0) - luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); -#endif - } - break; - } -#endif case ']': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `]' */ -#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 - cont--; - if (sep == 0 && cont >= 0) break; -#endif goto endloop; } break; @@ -273,19 +265,61 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } +static int hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else if (lisupper(c)) return c - 'A' + 10; + else return c - 'a' + 10; +} + + +static int readhexaesc (LexState *ls) { + int c1, c2 = EOZ; + if (!lisxdigit(c1 = next(ls)) || !lisxdigit(c2 = next(ls))) { + luaZ_resetbuffer(ls->buff); /* prepare error message */ + save(ls, '\\'); save(ls, 'x'); + if (c1 != EOZ) save(ls, c1); + if (c2 != EOZ) save(ls, c2); + lexerror(ls, "hexadecimal digit expected", TK_STRING); + } + return (hexavalue(c1) << 4) + hexavalue(c2); +} + + +static int readdecesc (LexState *ls) { + int c1 = ls->current, c2, c3; + int c = c1 - '0'; + if (lisdigit(c2 = next(ls))) { + c = 10*c + c2 - '0'; + if (lisdigit(c3 = next(ls))) { + c = 10*c + c3 - '0'; + if (c > UCHAR_MAX) { + luaZ_resetbuffer(ls->buff); /* prepare error message */ + save(ls, '\\'); + save(ls, c1); save(ls, c2); save(ls, c3); + lexerror(ls, "decimal escape too large", TK_STRING); + } + return c; + } + } + /* else, has read one character that was not a digit */ + zungetc(ls->z); /* return it to input stream */ + return c; +} + + static void read_string (LexState *ls, int del, SemInfo *seminfo) { save_and_next(ls); while (ls->current != del) { switch (ls->current) { case EOZ: - luaX_lexerror(ls, "unfinished string", TK_EOS); + lexerror(ls, "unfinished string", TK_EOS); continue; /* to avoid warnings */ case '\n': case '\r': - luaX_lexerror(ls, "unfinished string", TK_STRING); + lexerror(ls, "unfinished string", TK_STRING); continue; /* to avoid warnings */ - case '\\': { - int c; + case '\\': { /* escape sequences */ + int c; /* final character to be saved */ next(ls); /* do not save the `\' */ switch (ls->current) { case 'a': c = '\a'; break; @@ -295,28 +329,20 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; - case '\n': /* go through */ + case 'x': c = readhexaesc(ls); break; + case '\n': case '\r': save(ls, '\n'); inclinenumber(ls); continue; case EOZ: continue; /* will raise an error next loop */ default: { - if (!isdigit(ls->current)) - save_and_next(ls); /* handles \\, \", \', and \? */ - else { /* \xxx */ - int i = 0; - c = 0; - do { - c = 10*c + (ls->current-'0'); - next(ls); - } while (++i<3 && isdigit(ls->current)); - if (c > UCHAR_MAX) - luaX_lexerror(ls, "escape sequence too large", TK_STRING); - save(ls, c); - } - continue; + if (!lisdigit(ls->current)) + c = ls->current; /* handles \\, \", \', and \? */ + else /* digital escape \ddd */ + c = readdecesc(ls); + break; } } - save(ls, c); next(ls); + save(ls, c); continue; } default: @@ -364,7 +390,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_STRING; } else if (sep == -1) return '['; - else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); + else lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { next(ls); @@ -398,7 +424,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_DOTS; /* ... */ else return TK_CONCAT; /* .. */ } - else if (!isdigit(ls->current)) return '.'; + else if (!lisdigit(ls->current)) return '.'; else { read_numeral(ls, seminfo); return TK_NUMBER; @@ -408,21 +434,21 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_EOS; } default: { - if (isspace(ls->current)) { + if (lisspace(ls->current)) { lua_assert(!currIsNewline(ls)); next(ls); continue; } - else if (isdigit(ls->current)) { + else if (lisdigit(ls->current)) { read_numeral(ls, seminfo); return TK_NUMBER; } - else if (isalpha(ls->current) || ls->current == '_') { + else if (lislalpha(ls->current)) { /* identifier or reserved word */ TString *ts; do { save_and_next(ls); - } while (isalnum(ls->current) || ls->current == '_'); + } while (lislalnum(ls->current)); ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); if (ts->tsv.reserved > 0) /* reserved word? */ @@ -454,8 +480,9 @@ void luaX_next (LexState *ls) { } -void luaX_lookahead (LexState *ls) { +int luaX_lookahead (LexState *ls) { lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); + return ls->lookahead.token; } diff --git a/src/llex.h b/src/llex.h index a9201cee48..d687fb8d4d 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: llex.h,v 1.62 2009/10/11 20:02:19 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -28,18 +28,14 @@ enum RESERVED { TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ - TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, - TK_NAME, TK_STRING, TK_EOS + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_EOS, + TK_NUMBER, TK_NAME, TK_STRING }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) -/* array with token `names' */ -LUAI_DATA const char *const luaX_tokens []; - - typedef union { lua_Number r; TString *ts; @@ -62,6 +58,7 @@ typedef struct LexState { struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ + struct Varlist *varl; /* list of all active local variables */ TString *source; /* current source name */ char decpoint; /* locale decimal point */ } LexState; @@ -72,8 +69,7 @@ LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source); LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); -LUAI_FUNC void luaX_lookahead (LexState *ls); -LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); +LUAI_FUNC int luaX_lookahead (LexState *ls); LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); diff --git a/src/llimits.h b/src/llimits.h index ca8dcb7224..6bf49840a3 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: llimits.h,v 1.77 2009/12/17 12:50:20 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -15,7 +15,7 @@ #include "lua.h" -typedef LUAI_UINT32 lu_int32; +typedef unsigned LUA_INT32 lu_int32; typedef LUAI_UMEM lu_mem; @@ -44,6 +44,10 @@ typedef unsigned char lu_byte; /* type to ensure maximum alignment */ +#if !defined(LUAI_USER_ALIGNMENT_T) +#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } +#endif + typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; @@ -52,34 +56,47 @@ typedef LUAI_UACNUMBER l_uacNumber; /* internal assertions for in-house debugging */ -#ifdef lua_assert - +#if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) -#define api_check(l,e) lua_assert(e) - #else - #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) -#define api_check luai_apicheck +#endif +/* +** assertion for checking API calls +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(L,e) { (void)L; assert(e); } +#elif !defined(luai_apicheck) +#define luai_apicheck(L,e) lua_assert(e) #endif +#define api_check(l,e,msg) luai_apicheck(l,(e) && msg) + -#ifndef UNUSED +#if !defined(UNUSED) #define UNUSED(x) ((void)(x)) /* to avoid warnings */ #endif -#ifndef cast #define cast(t, exp) ((t)(exp)) -#endif #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) +/* +** maximum depth for nested C calls and syntactical nested non-terminals +** in a program. (Value must fit in an unsigned short int.) +*/ +#if !defined(LUAI_MAXCCALLS) +#define LUAI_MAXCCALLS 200 +#endif + + /* ** type for virtual-machine instructions @@ -95,34 +112,73 @@ typedef lu_int32 Instruction; /* minimum size for the string table (must be power of 2) */ -#ifndef MINSTRTABSIZE +#if !defined(MINSTRTABSIZE) #define MINSTRTABSIZE 32 #endif /* minimum size for string buffer */ -#ifndef LUA_MINBUFFER +#if !defined(LUA_MINBUFFER) #define LUA_MINBUFFER 32 #endif -#ifndef lua_lock -#define lua_lock(L) ((void) 0) +#if !defined(lua_lock) +#define lua_lock(L) ((void) 0) #define lua_unlock(L) ((void) 0) #endif -#ifndef luai_threadyield +#if !defined(luai_threadyield) #define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif +/* +** these macros allow user-specific actions on threads when you defined +** LUAI_EXTRASPACE and need to do something extra when a thread is +** created/deleted/resumed/yielded. +*/ +#if !defined(luai_userstateopen) +#define luai_userstateopen(L) ((void)L) +#endif + +#if !defined(luai_userstateclose) +#define luai_userstateclose(L) ((void)L) +#endif + +#if !defined(luai_userstatethread) +#define luai_userstatethread(L,L1) ((void)L) +#endif + +#if !defined(luai_userstatefree) +#define luai_userstatefree(L) ((void)L) +#endif + +#if !defined(luai_userstateresume) +#define luai_userstateresume(L,n) ((void)L) +#endif + +#if !defined(luai_userstateyield) +#define luai_userstateyield(L,n) ((void)L) +#endif + + + + /* ** macro to control inclusion of some hard tests on stack reallocation -*/ -#ifndef HARDSTACKTESTS -#define condhardstacktests(x) ((void)0) +*/ +#if !defined(HARDSTACKTESTS) +#define condmovestack(L) ((void)0) +#else +/* realloc stack keeping its size */ +#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize) +#endif + +#if !defined(HARDMEMTESTS) +#define condchangemem(L) condmovestack(L) #else -#define condhardstacktests(x) x +#define condchangemem(L) luaC_fullgc(L, 0) #endif #endif diff --git a/src/lmathlib.c b/src/lmathlib.c index 441fbf736c..27e6847ed8 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lmathlib.c,v 1.74 2009/11/24 12:05:44 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -112,11 +112,24 @@ static int math_pow (lua_State *L) { } static int math_log (lua_State *L) { - lua_pushnumber(L, log(luaL_checknumber(L, 1))); + lua_Number x = luaL_checknumber(L, 1); + lua_Number res; + if (lua_isnoneornil(L, 2)) + res = log(x); + else { + lua_Number base = luaL_checknumber(L, 2); + if (base == 10.0) res = log10(x); + else res = log(x)/log(base); + } + lua_pushnumber(L, res); return 1; } static int math_log10 (lua_State *L) { +#if !defined(LUA_COMPAT_LOG10) + luaL_error(L, "function " LUA_QL("log10") + " is deprecated; use log(x, 10) instead"); +#endif lua_pushnumber(L, log10(luaL_checknumber(L, 1))); return 1; } @@ -188,16 +201,16 @@ static int math_random (lua_State *L) { break; } case 1: { /* only upper limit */ - int u = luaL_checkint(L, 1); - luaL_argcheck(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ + lua_Number u = luaL_checknumber(L, 1); + luaL_argcheck(L, 1.0 <= u, 1, "interval is empty"); + lua_pushnumber(L, floor(r*u) + 1.0); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ - int l = luaL_checkint(L, 1); - int u = luaL_checkint(L, 2); - luaL_argcheck(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ + lua_Number l = luaL_checknumber(L, 1); + lua_Number u = luaL_checknumber(L, 2); + luaL_argcheck(L, l <= u, 2, "interval is empty"); + lua_pushnumber(L, floor(r*(u-l+1)) + l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); @@ -208,6 +221,7 @@ static int math_random (lua_State *L) { static int math_randomseed (lua_State *L) { srand(luaL_checkint(L, 1)); + (void)rand(); /* discard first value to avoid undesirable correlations */ return 0; } @@ -248,16 +262,12 @@ static const luaL_Reg mathlib[] = { /* ** Open math library */ -LUALIB_API int luaopen_math (lua_State *L) { +LUAMOD_API int luaopen_math (lua_State *L) { luaL_register(L, LUA_MATHLIBNAME, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, HUGE_VAL); lua_setfield(L, -2, "huge"); -#if defined(LUA_COMPAT_MOD) - lua_getfield(L, -1, "fmod"); - lua_setfield(L, -2, "mod"); -#endif return 1; } diff --git a/src/lmem.c b/src/lmem.c index ae7d8c965f..022ccfd3cf 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lmem.c,v 1.74 2009/12/16 16:42:58 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" @@ -25,12 +26,11 @@ ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); ** (`osize' is the old size, `nsize' is the new size) ** -** Lua ensures that (ptr == NULL) iff (osize == 0). -** -** * frealloc(ud, NULL, 0, x) creates a new block of size `x' +** * frealloc(ud, NULL, x, s) creates a new block of size `s' (no +** matter 'x'). ** ** * frealloc(ud, p, x, 0) frees the block `p' -** (in this specific case, frealloc must return NULL). +** (in this specific case, frealloc must return NULL); ** particularly, frealloc(ud, NULL, 0, 0) does nothing ** (which is equivalent to free(NULL) in ANSI C) ** @@ -44,12 +44,12 @@ void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, - int limit, const char *errormsg) { + int limit, const char *what) { void *newblock; int newsize; if (*size >= limit/2) { /* cannot double it? */ if (*size >= limit) /* cannot grow even a little? */ - luaG_runerror(L, errormsg); + luaG_runerror(L, "too many %s (limit is %d)", what, limit); newsize = limit; /* still have at least one free place */ } else { @@ -74,13 +74,26 @@ void *luaM_toobig (lua_State *L) { ** generic allocation routine. */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + void *newblock; global_State *g = G(L); - lua_assert((osize == 0) == (block == NULL)); - block = (*g->frealloc)(g->ud, block, osize, nsize); - if (block == NULL && nsize > 0) - luaD_throw(L, LUA_ERRMEM); - lua_assert((nsize == 0) == (block == NULL)); - g->totalbytes = (g->totalbytes - osize) + nsize; - return block; + size_t realosize = (block) ? osize : 0; + lua_assert((realosize == 0) == (block == NULL)); +#if defined(HARDMEMTESTS) + if (nsize > realosize && g->GCthreshold != MAX_LUMEM) + luaC_fullgc(L, 1); /* force a GC whenever possible */ +#endif + newblock = (*g->frealloc)(g->ud, block, osize, nsize); + if (newblock == NULL && nsize > 0) { + lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ + if (g->GCthreshold != MAX_LUMEM) { + luaC_fullgc(L, 1); /* try to free some memory... */ + newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ + } + if (newblock == NULL) + luaD_throw(L, LUA_ERRMEM); + } + lua_assert((nsize == 0) == (newblock == NULL)); + g->totalbytes = (g->totalbytes - realosize) + nsize; + return newblock; } diff --git a/src/lmem.h b/src/lmem.h index 7c2dcb3220..b8b3bae94a 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lmem.h,v 1.35 2009/12/16 16:42:58 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -23,13 +23,15 @@ #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) -#define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t)) +#define luaM_freearray(L, b, n) luaM_reallocv(L, (b), n, 0, sizeof((b)[0])) -#define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t)) +#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) #define luaM_newvector(L,n,t) \ cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) +#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) + #define luaM_growvector(L,v,nelems,size,t,limit,e) \ if ((nelems)+1 > (size)) \ ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) @@ -37,13 +39,14 @@ #define luaM_reallocvector(L, v,oldn,n,t) \ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) +LUAI_FUNC void *luaM_toobig (lua_State *L); +/* not to be called directly */ LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); -LUAI_FUNC void *luaM_toobig (lua_State *L); LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, int limit, - const char *errormsg); + const char *what); #endif diff --git a/src/loadlib.c b/src/loadlib.c index 0d401eba1c..8b2d691194 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ +** $Id: loadlib.c,v 1.73 2010/01/06 14:35:17 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -22,6 +22,43 @@ #include "lualib.h" +/* +** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment +** variables that Lua check to set its paths. +*/ +#if !defined(LUA_PATH_VAR) +#define LUA_PATH_VAR "LUA_PATH" +#endif + +#if !defined(LUA_CPATH_VAR) +#define LUA_CPATH_VAR "LUA_CPATH" +#endif + + +/* +** LUA_PATH_SEP is the character that separates templates in a path. +** LUA_PATH_MARK is the string that marks the substitution points in a +** template. +** LUA_EXEC_DIR in a Windows path is replaced by the executable's +** directory. +** LUA_IGMARK is a mark to ignore all before it when building the +** luaopen_ function name. +*/ +#if !defined (LUA_PATH_SEP) +#define LUA_PATH_SEP ";" +#endif +#if !defined (LUA_PATH_MARK) +#define LUA_PATH_MARK "?" +#endif +#if !defined (LUA_EXEC_DIR) +#define LUA_EXEC_DIR "!" +#endif +#if !defined (LUA_IGMARK) +#define LUA_IGMARK "-" +#endif + + + /* prefix for open functions in C libraries */ #define LUA_POF "luaopen_" @@ -42,13 +79,16 @@ #define setprogdir(L) ((void)0) +/* +** system-dependent functions +*/ static void ll_unloadlib (void *lib); -static void *ll_load (lua_State *L, const char *path); +static void *ll_load (lua_State *L, const char *path, int seeglb); static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); -#if defined(LUA_DL_DLOPEN) +#if defined(LUA_USE_DLOPEN) /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. @@ -65,8 +105,8 @@ static void ll_unloadlib (void *lib) { } -static void *ll_load (lua_State *L, const char *path) { - void *lib = dlopen(path, RTLD_NOW); +static void *ll_load (lua_State *L, const char *path, int seeglb) { + void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : 0)); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } @@ -89,8 +129,6 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { ** ======================================================================= */ -#include - #undef setprogdir @@ -98,12 +136,12 @@ static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; DWORD nsize = sizeof(buff)/sizeof(char); - DWORD n = GetModuleFileNameA(NULL, buff, nsize); + DWORD n = GetModuleFileName(NULL, buff, nsize); if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) luaL_error(L, "unable to get ModuleFileName"); else { *lb = '\0'; - luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); lua_remove(L, -2); /* remove original string */ } } @@ -112,7 +150,7 @@ static void setprogdir (lua_State *L) { static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; - if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buffer, sizeof(buffer), NULL)) lua_pushstring(L, buffer); else @@ -124,8 +162,9 @@ static void ll_unloadlib (void *lib) { } -static void *ll_load (lua_State *L, const char *path) { - HINSTANCE lib = LoadLibraryA(path); +static void *ll_load (lua_State *L, const char *path, int seeglb) { + HINSTANCE lib = LoadLibrary(path); + (void)(seeglb); /* symbols are 'global' by default? */ if (lib == NULL) pusherror(L); return lib; } @@ -144,7 +183,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #elif defined(LUA_DL_DYLD) /* ** {====================================================================== -** Native Mac OS X / Darwin Implementation +** Old native Mac OS X - only for old versions of Mac OS (< 10.3) ** ======================================================================= */ @@ -188,7 +227,7 @@ static void ll_unloadlib (void *lib) { } -static void *ll_load (lua_State *L, const char *path) { +static void *ll_load (lua_State *L, const char *path, int seeglb) { NSObjectFileImage img; NSObjectFileImageReturnCode ret; /* this would be a rare case, but prevents crashing if it happens */ @@ -198,8 +237,10 @@ static void *ll_load (lua_State *L, const char *path) { } ret = NSCreateObjectFileImageFromFile(path, &img); if (ret == NSObjectFileImageSuccess) { - NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | - NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSModule mod = NSLinkModule(img, + path, + NSLINKMODULE_OPTION_RETURN_ON_ERROR | + (seeglb ? 0 : NSLINKMODULE_OPTION_PRIVATE)); NSDestroyObjectFileImage(img); if (mod == NULL) pusherror(L); return mod; @@ -237,19 +278,19 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { static void ll_unloadlib (void *lib) { - (void)lib; /* to avoid warnings */ + (void)(lib); /* to avoid warnings */ } -static void *ll_load (lua_State *L, const char *path) { - (void)path; /* to avoid warnings */ +static void *ll_load (lua_State *L, const char *path, int seeglb) { + (void)(path); /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { - (void)lib; (void)sym; /* to avoid warnings */ + (void)(lib); (void)(sym); /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } @@ -266,7 +307,7 @@ static void **ll_register (lua_State *L, const char *path) { if (!lua_isnil(L, -1)) /* is there an entry? */ plib = (void **)lua_touserdata(L, -1); else { /* no entry yet; create one */ - lua_pop(L, 1); + lua_pop(L, 1); /* remove result from gettable */ plib = (void **)lua_newuserdata(L, sizeof(const void *)); *plib = NULL; luaL_getmetatable(L, "_LOADLIB"); @@ -293,15 +334,18 @@ static int gctm (lua_State *L) { static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { void **reg = ll_register(L, path); - if (*reg == NULL) *reg = ll_load(L, path); - if (*reg == NULL) - return ERRLIB; /* unable to load library */ + if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); + if (*reg == NULL) return ERRLIB; /* unable to load library */ + if (*sym == '*') { /* loading only library (no function)? */ + lua_pushboolean(L, 1); /* return 'true' */ + return 0; /* no errors */ + } else { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); - return 0; /* return function */ + lua_pushcfunction(L, f); /* else return function */ + return 0; /* no errors */ } } @@ -339,27 +383,21 @@ static int readable (const char *filename) { static const char *pushnexttemplate (lua_State *L, const char *path) { const char *l; - while (*path == *LUA_PATHSEP) path++; /* skip separators */ + while (*path == *LUA_PATH_SEP) path++; /* skip separators */ if (*path == '\0') return NULL; /* no more templates */ - l = strchr(path, *LUA_PATHSEP); /* find next separator */ + l = strchr(path, *LUA_PATH_SEP); /* find next separator */ if (l == NULL) l = path + strlen(path); lua_pushlstring(L, path, l - path); /* template */ return l; } -static const char *findfile (lua_State *L, const char *name, - const char *pname) { - const char *path; - name = luaL_gsub(L, name, ".", LUA_DIRSEP); - lua_getfield(L, LUA_ENVIRONINDEX, pname); - path = lua_tostring(L, -1); - if (path == NULL) - luaL_error(L, LUA_QL("package.%s") " must be a string", pname); +static const char *searchpath (lua_State *L, const char *name, + const char *path) { lua_pushliteral(L, ""); /* error accumulator */ while ((path = pushnexttemplate(L, path)) != NULL) { - const char *filename; - filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + const char *filename = luaL_gsub(L, lua_tostring(L, -1), + LUA_PATH_MARK, name); lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ @@ -371,6 +409,29 @@ static const char *findfile (lua_State *L, const char *name, } +static int ll_searchpath (lua_State *L) { + const char *f = searchpath(L, luaL_checkstring(L, 1), luaL_checkstring(L, 2)); + if (f != NULL) return 1; + else { /* error message is on top of the stack */ + lua_pushnil(L); + lua_insert(L, -2); + return 2; /* return nil + error message */ + } +} + + +static const char *findfile (lua_State *L, const char *name, + const char *pname) { + const char *path; + name = luaL_gsub(L, name, ".", LUA_DIRSEP); + lua_getfield(L, LUA_ENVIRONINDEX, pname); + path = lua_tostring(L, -1); + if (path == NULL) + luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + return searchpath(L, name, path); +} + + static void loaderror (lua_State *L, const char *filename) { luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); @@ -382,37 +443,34 @@ static int loader_Lua (lua_State *L) { const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path"); if (filename == NULL) return 1; /* library not found in this path */ - if (luaL_loadfile(L, filename) != 0) + if (luaL_loadfile(L, filename) != LUA_OK) loaderror(L, filename); return 1; /* library loaded successfully */ } -static const char *mkfuncname (lua_State *L, const char *modname) { +static int loadfunc(lua_State *L, const char *filename, const char *modname) { const char *funcname; const char *mark = strchr(modname, *LUA_IGMARK); if (mark) modname = mark + 1; funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); funcname = lua_pushfstring(L, POF"%s", funcname); lua_remove(L, -2); /* remove 'gsub' result */ - return funcname; + return ll_loadfunc(L, filename, funcname); } static int loader_C (lua_State *L) { - const char *funcname; const char *name = luaL_checkstring(L, 1); const char *filename = findfile(L, name, "cpath"); if (filename == NULL) return 1; /* library not found in this path */ - funcname = mkfuncname(L, name); - if (ll_loadfunc(L, filename, funcname) != 0) + if (loadfunc(L, filename, name) != 0) loaderror(L, filename); return 1; /* library loaded successfully */ } static int loader_Croot (lua_State *L) { - const char *funcname; const char *filename; const char *name = luaL_checkstring(L, 1); const char *p = strchr(name, '.'); @@ -421,8 +479,7 @@ static int loader_Croot (lua_State *L) { lua_pushlstring(L, name, p - name); filename = findfile(L, lua_tostring(L, -1), "cpath"); if (filename == NULL) return 1; /* root not found */ - funcname = mkfuncname(L, name); - if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if ((stat = loadfunc(L, filename, name)) != 0) { if (stat != ERRFUNC) loaderror(L, filename); /* real error */ lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, name, filename); @@ -502,7 +559,7 @@ static int ll_require (lua_State *L) { ** 'module' function ** ======================================================= */ - + static void setfenv (lua_State *L) { lua_Debug ar; @@ -510,9 +567,9 @@ static void setfenv (lua_State *L) { lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_iscfunction(L, -1)) luaL_error(L, LUA_QL("module") " not called from a Lua function"); - lua_pushvalue(L, -2); + lua_pushvalue(L, -2); /* copy new environment table to top */ lua_setfenv(L, -2); - lua_pop(L, 1); + lua_pop(L, 1); /* remove function */ } @@ -549,7 +606,8 @@ static int ll_module (lua_State *L) { if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ - if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) + lua_pushglobaltable(L); + if (luaL_findtable(L, 0, modname, 1) != NULL) return luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ @@ -565,7 +623,7 @@ static int ll_module (lua_State *L) { lua_pushvalue(L, -1); setfenv(L); dooptions(L, loaded - 1); - return 0; + return 1; } @@ -576,7 +634,7 @@ static int ll_seeall (lua_State *L) { lua_pushvalue(L, -1); lua_setmetatable(L, 1); } - lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_pushglobaltable(L); lua_setfield(L, -2, "__index"); /* mt.__index = _G */ return 0; } @@ -596,8 +654,8 @@ static void setpath (lua_State *L, const char *fieldname, const char *envname, lua_pushstring(L, def); /* use default */ else { /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ - path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, - LUA_PATHSEP AUXMARK LUA_PATHSEP); + path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, + LUA_PATH_SEP AUXMARK LUA_PATH_SEP); luaL_gsub(L, path, AUXMARK, def); lua_remove(L, -2); } @@ -608,6 +666,7 @@ static void setpath (lua_State *L, const char *fieldname, const char *envname, static const luaL_Reg pk_funcs[] = { {"loadlib", ll_loadlib}, + {"searchpath", ll_searchpath}, {"seeall", ll_seeall}, {NULL, NULL} }; @@ -624,7 +683,7 @@ static const lua_CFunction loaders[] = {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; -LUALIB_API int luaopen_package (lua_State *L) { +LUAMOD_API int luaopen_package (lua_State *L) { int i; /* create new type _LOADLIB */ luaL_newmetatable(L, "_LOADLIB"); @@ -632,25 +691,20 @@ LUALIB_API int luaopen_package (lua_State *L) { lua_setfield(L, -2, "__gc"); /* create `package' table */ luaL_register(L, LUA_LOADLIBNAME, pk_funcs); -#if defined(LUA_COMPAT_LOADLIB) - lua_getfield(L, -1, "loadlib"); - lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); -#endif - lua_pushvalue(L, -1); - lua_replace(L, LUA_ENVIRONINDEX); + lua_copy(L, -1, LUA_ENVIRONINDEX); /* create `loaders' table */ - lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); + lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { lua_pushcfunction(L, loaders[i]); lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ - setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ - setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ + setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); /* set field `path' */ + setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* set field `cpath' */ /* store config information */ - lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" - LUA_EXECDIR "\n" LUA_IGMARK); + lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" + LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); lua_setfield(L, -2, "config"); /* set field `loaded' */ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); @@ -658,7 +712,7 @@ LUALIB_API int luaopen_package (lua_State *L) { /* set field `preload' */ lua_newtable(L); lua_setfield(L, -2, "preload"); - lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_pushglobaltable(L); luaL_register(L, NULL, ll_funcs); /* open lib into global table */ lua_pop(L, 1); return 1; /* return 'package' table */ diff --git a/src/lobject.c b/src/lobject.c index 4ff50732a4..8f5c5691da 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,10 +1,9 @@ /* -** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lobject.c,v 2.34 2009/11/26 11:39:20 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ -#include #include #include #include @@ -15,6 +14,8 @@ #include "lua.h" +#include "lctype.h" +#include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" @@ -24,7 +25,7 @@ -const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; +LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; /* @@ -32,26 +33,26 @@ const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ -int luaO_int2fb (unsigned int x) { - int e = 0; /* expoent */ - while (x >= 16) { +int luaO_int2fb (lu_int32 x) { + int e = 0; /* exponent */ + if (x < 8) return x; + while (x >= 0x10) { x = (x+1) >> 1; e++; } - if (x < 8) return x; - else return ((e+1) << 3) | (cast_int(x) - 8); + return ((e+1) << 3) | (cast_int(x) - 8); } /* converts back */ int luaO_fb2int (int x) { - int e = (x >> 3) & 31; + int e = (x >> 3) & 0x1f; if (e == 0) return x; - else return ((x & 7)+8) << (e - 1); + else return ((x & 7) + 8) << (e - 1); } -int luaO_log2 (unsigned int x) { +int luaO_ceillog2 (unsigned int x) { static const lu_byte log_2[256] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, @@ -62,10 +63,10 @@ int luaO_log2 (unsigned int x) { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; - int l = -1; + int l = 0; + x--; while (x >= 256) { l += 8; x >>= 8; } return l + log_2[x]; - } @@ -87,6 +88,20 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { } +lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(NULL, v1, v2); + case LUA_OPSUB: return luai_numsub(NULL, v1, v2); + case LUA_OPMUL: return luai_nummul(NULL, v1, v2); + case LUA_OPDIV: return luai_numdiv(NULL, v1, v2); + case LUA_OPMOD: return luai_nummod(NULL, v1, v2); + case LUA_OPPOW: return luai_numpow(NULL, v1, v2); + case LUA_OPUNM: return luai_numunm(N, v1); + default: lua_assert(0); return 0; + } +} + + int luaO_str2d (const char *s, lua_Number *result) { char *endptr; *result = lua_str2number(s, &endptr); @@ -94,7 +109,7 @@ int luaO_str2d (const char *s, lua_Number *result) { if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ *result = cast_num(strtoul(s, &endptr, 16)); if (*endptr == '\0') return 1; /* most common case */ - while (isspace(cast(unsigned char, *endptr))) endptr++; + while (lisspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ return 1; } @@ -151,11 +166,9 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { break; } default: { - char buff[3]; - buff[0] = '%'; - buff[1] = *(e+1); - buff[2] = '\0'; - pushstr(L, buff); + luaG_runerror(L, + "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"), + *(e + 1)); break; } } @@ -163,8 +176,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { fmt = e+2; } pushstr(L, fmt); - luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); - L->top -= n; + luaV_concat(L, n+1); return svalue(L->top - 1); } @@ -179,36 +191,46 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { } + +#define LL(x) (sizeof(x) - 1) +#define RETS "..." +#define PRE "[string \"" +#define POS "\"]" + +#define addstr(a,b,l) ( memcpy(a,b,l), a += (l) ) + void luaO_chunkid (char *out, const char *source, size_t bufflen) { - if (*source == '=') { - strncpy(out, source+1, bufflen); /* remove first char */ - out[bufflen-1] = '\0'; /* ensures null termination */ + size_t l = strlen(source); + if (*source == '=') { /* 'literal' source */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l); + else { /* truncate it */ + addstr(out, source + 1, bufflen - 1); + *out = '\0'; + } } - else { /* out = "source", or "...source" */ - if (*source == '@') { - size_t l; - source++; /* skip the `@' */ - bufflen -= sizeof(" '...' "); - l = strlen(source); - strcpy(out, ""); - if (l > bufflen) { - source += (l-bufflen); /* get last part of file name */ - strcat(out, "..."); - } - strcat(out, source); + else if (*source == '@') { /* file name */ + if (l <= bufflen) /* small enough? */ + memcpy(out, source + 1, l); + else { /* add '...' before rest of name */ + addstr(out, RETS, LL(RETS)); + bufflen -= LL(RETS); + memcpy(out, source + 1 + l - bufflen, bufflen); } - else { /* out = [string "string"] */ - size_t len = strcspn(source, "\n\r"); /* stop at first newline */ - bufflen -= sizeof(" [string \"...\"] "); - if (len > bufflen) len = bufflen; - strcpy(out, "[string \""); - if (source[len] != '\0') { /* must truncate? */ - strncat(out, source, len); - strcat(out, "..."); - } - else - strcat(out, source); - strcat(out, "\"]"); + } + else { /* string; format as [string "source"] */ + const char *nl = strchr(source, '\n'); /* find first new line (if any) */ + addstr(out, PRE, LL(PRE)); /* add prefix */ + bufflen -= LL(PRE RETS POS); /* save space for prefix+suffix */ + if (l < bufflen && nl == NULL) { /* small one-line source? */ + addstr(out, source, l); /* keep it */ + } + else { + if (nl != NULL) l = nl - source; /* stop at first newline */ + if (l > bufflen) l = bufflen; + addstr(out, source, l); + addstr(out, RETS, LL(RETS)); } + memcpy(out, POS, LL(POS) + 1); } } diff --git a/src/lobject.h b/src/lobject.h index f1e447ef3b..2969fe7d62 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $ +** $Id: lobject.h,v 2.34 2010/01/08 20:00:20 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -52,7 +52,6 @@ typedef struct GCheader { - /* ** Union of all Lua values */ @@ -64,17 +63,22 @@ typedef union { } Value; + /* ** Tagged Values */ -#define TValuefields Value value; int tt +#define TValuefields Value value_; int tt_ typedef struct lua_TValue { TValuefields; } TValue; +/* macro defining a nil value to be used in definitions */ +#define NILCONSTANT {NULL}, LUA_TNIL + + /* Macros to test type */ #define ttisnil(o) (ttype(o) == LUA_TNIL) #define ttisnumber(o) (ttype(o) == LUA_TNUMBER) @@ -85,83 +89,90 @@ typedef struct lua_TValue { #define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) #define ttisthread(o) (ttype(o) == LUA_TTHREAD) #define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) +#define ttisdeadkey(o) (ttype(o) == LUA_TDEADKEY) /* Macros to access values */ -#define ttype(o) ((o)->tt) -#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) -#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) -#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) -#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#define ttype(o) ((o)->tt_) +#define gcvalue(o) check_exp(iscollectable(o), (o)->value_.gc) +#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value_.p) +#define nvalue(o) check_exp(ttisnumber(o), (o)->value_.n) +#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value_.gc->ts) #define tsvalue(o) (&rawtsvalue(o)->tsv) -#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value_.gc->u) #define uvalue(o) (&rawuvalue(o)->uv) -#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) -#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) -#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) -#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) +#define clvalue(o) check_exp(ttisfunction(o), &(o)->value_.gc->cl) +#define hvalue(o) check_exp(ttistable(o), &(o)->value_.gc->h) +#define bvalue(o) check_exp(ttisboolean(o), (o)->value_.b) +#define thvalue(o) check_exp(ttisthread(o), &(o)->value_.gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) /* ** for internal debug only */ -#define checkconsistency(obj) \ - lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) +#define iscollectable(o) (ttype(o) >= LUA_TSTRING) + +#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) + +#define checkconsistency(obj) lua_assert(!iscollectable(obj) || righttt(obj)) #define checkliveness(g,obj) \ - lua_assert(!iscollectable(obj) || \ - ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + lua_assert(!iscollectable(obj) || (righttt(obj) && !isdead(g,gcvalue(obj)))) /* Macros to set values */ -#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) +#define setnilvalue(obj) ((obj)->tt_=LUA_TNIL) #define setnvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } + { TValue *i_o=(obj); i_o->value_.n=(x); i_o->tt_=LUA_TNUMBER; } + +#define changenvalue(obj,x) \ + ( lua_assert((obj)->tt_==LUA_TNUMBER), (obj)->value_.n=(x) ) #define setpvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } + { TValue *i_o=(obj); i_o->value_.p=(x); i_o->tt_=LUA_TLIGHTUSERDATA; } #define setbvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } + { TValue *i_o=(obj); i_o->value_.b=(x); i_o->tt_=LUA_TBOOLEAN; } #define setsvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TSTRING; \ checkliveness(G(L),i_o); } #define setuvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TUSERDATA; \ checkliveness(G(L),i_o); } #define setthvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTHREAD; \ checkliveness(G(L),i_o); } #define setclvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TFUNCTION; \ checkliveness(G(L),i_o); } #define sethvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTABLE; \ checkliveness(G(L),i_o); } #define setptvalue(L,obj,x) \ { TValue *i_o=(obj); \ - i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TPROTO; \ checkliveness(G(L),i_o); } +#define setdeadvalue(obj) ((obj)->tt_=LUA_TDEADKEY) #define setobj(L,obj1,obj2) \ - { const TValue *o2=(obj2); TValue *o1=(obj1); \ - o1->value = o2->value; o1->tt=o2->tt; \ - checkliveness(G(L),o1); } + { const TValue *o2=(obj2); TValue *o1=(obj1); \ + o1->value_ = o2->value_; o1->tt_=o2->tt_; \ + checkliveness(G(L),o1); } /* @@ -183,11 +194,6 @@ typedef struct lua_TValue { #define setobj2n setobj #define setsvalue2n setsvalue -#define setttype(obj, tt) (ttype(obj) = (tt)) - - -#define iscollectable(o) (ttype(o) >= LUA_TSTRING) - typedef TValue *StkId; /* index to stack elements */ @@ -224,6 +230,15 @@ typedef union Udata { +/* +** Upvalues from a function prototype +*/ +typedef struct Upvaldesc { + TString *name; /* upvalue name (for debug information) */ + lu_byte instack; + lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ +} Upvaldesc; + /* ** Function Prototypes @@ -235,9 +250,9 @@ typedef struct Proto { struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ struct LocVar *locvars; /* information about local variables */ - TString **upvalues; /* upvalue names */ + Upvaldesc *upvalues; /* upvalue information */ TString *source; - int sizeupvalues; + int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of `k' */ int sizecode; int sizelineinfo; @@ -246,19 +261,13 @@ typedef struct Proto { int linedefined; int lastlinedefined; GCObject *gclist; - lu_byte nups; /* number of upvalues */ lu_byte numparams; lu_byte is_vararg; lu_byte maxstacksize; + lu_byte envreg; /* register in outer function with initial environment */ } Proto; -/* masks for new-style vararg */ -#define VARARG_HASARG 1 -#define VARARG_ISVARARG 2 -#define VARARG_NEEDSARG 4 - - typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ @@ -312,9 +321,10 @@ typedef union Closure { } Closure; -#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) -#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) +#define iscfunction(o) (ttisfunction(o) && clvalue(o)->c.isC) +#define isLfunction(o) (ttisfunction(o) && !clvalue(o)->c.isC) +#define getproto(o) (clvalue(o)->l.p) /* ** Tables @@ -337,7 +347,7 @@ typedef struct Node { typedef struct Table { CommonHeader; - lu_byte flags; /* 1<

      >POS_A) & MASK1(SIZE_A,0))) -#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ - ((cast(Instruction, u)<>pos) & MASK1(size,0))) +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ + ((cast(Instruction, v)<>POS_B) & MASK1(SIZE_B,0))) -#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ - ((cast(Instruction, b)<>POS_C) & MASK1(SIZE_C,0))) -#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ - ((cast(Instruction, b)<>POS_Bx) & MASK1(SIZE_Bx,0))) -#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ - ((cast(Instruction, b)< C) then pc++ */ -OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ @@ -197,39 +211,46 @@ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) =) R(A)*/ -OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ +OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ -OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ +OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ + +OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/ + +OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ } OpCode; -#define NUM_OPCODES (cast(int, OP_VARARG) + 1) +#define NUM_OPCODES (cast(int, OP_EXTRAARG) + 1) /*=========================================================================== Notes: - (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, - and can be 0: OP_CALL then sets `top' to last_result+1, so - next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. + (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is + set to last_result+1, so next open instruction (OP_CALL, OP_RETURN, + OP_SETLIST) may use `top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and - set top (like in OP_CALL with C == 0). + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to `top'. - (*) In OP_RETURN, if (B == 0) then return up to `top' + (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next + 'instruction' is EXTRAARG(real C). - (*) In OP_SETLIST, if (B == 0) then B = `top'; - if (C == 0) then next `instruction' is real C + (*) In OP_LOADK, OP_GETGLOBAL, and OP_SETGLOBAL, if (Bx == 0) then next + 'instruction' is EXTRAARG(real Bx). (*) For comparisons, A specifies what condition the test should accept - (true or false). + (true or false). + + (*) All `skips' (pc++) assume that next instruction is a jump. - (*) All `skips' (pc++) assume that next instruction is a jump ===========================================================================*/ @@ -239,8 +260,8 @@ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ ** bits 2-3: C arg mode ** bits 4-5: B arg mode ** bit 6: instruction set register A -** bit 7: operator is a test -*/ +** bit 7: operator is a test (next instruction must be a jump) +*/ enum OpArgMask { OpArgN, /* argument is not used */ @@ -249,7 +270,7 @@ enum OpArgMask { OpArgK /* argument is a constant or register/constant */ }; -LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; +LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES]; #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) #define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) @@ -258,7 +279,7 @@ LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) -LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ +LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ diff --git a/src/loslib.c b/src/loslib.c index da06a572ac..41592088b0 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** $Id: loslib.c,v 1.29 2009/12/17 13:08:51 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -20,6 +20,45 @@ #include "lualib.h" +/* +** list of valid conversion specifiers @* for the 'strftime' function +*/ +#if !defined(LUA_STRFTIMEOPTIONS) + +#if !defined(LUA_USE_POSIX) +#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } +#else +#define LUA_STRFTIMEOPTIONS { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ + "E", "cCxXyY", \ + "O", "deHImMSuUVwWy" } +#endif + +#endif + + + +/* +** By default, Lua uses tmpnam except when POSIX is available, where it +** uses mkstemp. +*/ +#if defined(LUA_USE_MKSTEMP) +#include +#define LUA_TMPNAMBUFSIZE 32 +#define lua_tmpnam(b,e) { \ + strcpy(b, "/tmp/lua_XXXXXX"); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#elif !defined(lua_tmpnam) + +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif + + + static int os_pushresult (lua_State *L, int i, const char *filename) { int en = errno; /* calls to Lua API may change this value */ if (i) { @@ -121,6 +160,30 @@ static int getfield (lua_State *L, const char *key, int d) { } +static const char *checkoption (lua_State *L, const char *conv, char *buff) { + static const char *const options[] = LUA_STRFTIMEOPTIONS; + unsigned int i; + for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { + if (*conv != '\0' && strchr(options[i], *conv) != NULL) { + buff[1] = *conv; + if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ + buff[2] = '\0'; /* end buffer */ + return conv + 1; + } + else if (*(conv + 1) != '\0' && + strchr(options[i + 1], *(conv + 1)) != NULL) { + buff[2] = *(conv + 1); /* valid two-char conversion specifier */ + buff[3] = '\0'; /* end buffer */ + return conv + 2; + } + } + } + luaL_argerror(L, 1, + lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); + return conv; /* to avoid warnings */ +} + + static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); @@ -146,17 +209,17 @@ static int os_date (lua_State *L) { setboolfield(L, "isdst", stm->tm_isdst); } else { - char cc[3]; + char cc[4]; luaL_Buffer b; - cc[0] = '%'; cc[2] = '\0'; + cc[0] = '%'; luaL_buffinit(L, &b); - for (; *s; s++) { - if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ - luaL_addchar(&b, *s); + while (*s) { + if (*s != '%') /* no conversion specifier? */ + luaL_addchar(&b, *s++); else { size_t reslen; char buff[200]; /* should be big enough for any conversion result */ - cc[1] = *(++s); + s = checkoption(L, s + 1, cc); reslen = strftime(buff, sizeof(buff), cc, stm); luaL_addlstring(&b, buff, reslen); } @@ -214,9 +277,13 @@ static int os_setlocale (lua_State *L) { static int os_exit (lua_State *L) { - exit(luaL_optint(L, 1, EXIT_SUCCESS)); + int status = luaL_optint(L, 1, EXIT_SUCCESS); + if (lua_toboolean(L, 2)) + lua_close(L); + exit(status); } + static const luaL_Reg syslib[] = { {"clock", os_clock}, {"date", os_date}, @@ -236,7 +303,7 @@ static const luaL_Reg syslib[] = { -LUALIB_API int luaopen_os (lua_State *L) { +LUAMOD_API int luaopen_os (lua_State *L) { luaL_register(L, LUA_OSLIBNAME, syslib); return 1; } diff --git a/src/lparser.c b/src/lparser.c index 1e2a9a88b7..cc21f67fcd 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -27,11 +27,13 @@ -#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) +/* maximum number of local variables per function (must be smaller + than 250, due to the bytecode format) */ +#define MAXVARS 200 + -#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) +#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) -#define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) /* @@ -55,6 +57,8 @@ static void expr (LexState *ls, expdesc *v); static void anchor_token (LexState *ls) { + /* last token from outer function must be EOS */ + lua_assert(ls->fs != NULL || ls->t.token == TK_EOS); if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { TString *ts = ls->t.seminfo.ts; luaX_newstring(ls, getstr(ts), ts->tsv.len); @@ -64,16 +68,23 @@ static void anchor_token (LexState *ls) { static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); + luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); } static void errorlimit (FuncState *fs, int limit, const char *what) { - const char *msg = (fs->f->linedefined == 0) ? - luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : - luaO_pushfstring(fs->L, "function at line %d has more than %d %s", - fs->f->linedefined, limit, what); - luaX_lexerror(fs->ls, msg, 0); + const char *msg; + const char *where = (fs->f->linedefined == 0) ? + "main function" : + luaO_pushfstring(fs->L, "function at line %d", fs->f->linedefined); + msg = luaO_pushfstring(fs->L, "too many %s (limit is %d) in %s", + what, limit, where); + luaX_syntaxerror(fs->ls, msg); +} + + +static void checklimit (FuncState *fs, int v, int l, const char *what) { + if (v > l) errorlimit(fs, l, what); } @@ -107,7 +118,7 @@ static void check_match (LexState *ls, int what, int who, int where) { error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - LUA_QS " expected (to close " LUA_QS " at line %d)", + "%s expected (to close %s at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } @@ -135,7 +146,7 @@ static void codestring (LexState *ls, expdesc *e, TString *s) { } -static void checkname(LexState *ls, expdesc *e) { +static void checkname (LexState *ls, expdesc *e) { codestring(ls, e, str_checkname(ls)); } @@ -145,7 +156,7 @@ static int registerlocalvar (LexState *ls, TString *varname) { Proto *f = fs->f; int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, SHRT_MAX, "too many local variables"); + LocVar, SHRT_MAX, "local variables"); while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); @@ -153,14 +164,30 @@ static int registerlocalvar (LexState *ls, TString *varname) { } -#define new_localvarliteral(ls,v,n) \ - new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) +static void new_localvar (LexState *ls, TString *name) { + FuncState *fs = ls->fs; + Varlist *vl = ls->varl; + int reg = registerlocalvar(ls, name); + checklimit(fs, vl->nactvar + 1 - fs->firstlocal, + MAXVARS, "local variables"); + luaM_growvector(ls->L, vl->actvar, vl->nactvar + 1, + vl->actvarsize, vardesc, MAX_INT, "local variables"); + vl->actvar[vl->nactvar++].idx = cast(unsigned short, reg); +} + + +static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { + new_localvar(ls, luaX_newstring(ls, name, sz)); +} +#define new_localvarliteral(ls,v) \ + new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) -static void new_localvar (LexState *ls, TString *name, int n) { - FuncState *fs = ls->fs; - luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); - fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); + +static LocVar *getlocvar (FuncState *fs, int i) { + int idx = fs->ls->varl->actvar[fs->firstlocal + i].idx; + lua_assert(idx < fs->nlocvars); + return &fs->f->locvars[idx]; } @@ -168,15 +195,15 @@ static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { - getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; + getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; } } -static void removevars (LexState *ls, int tolevel) { - FuncState *fs = ls->fs; +static void removevars (FuncState *fs, int tolevel) { + fs->ls->varl->nactvar -= (fs->nactvar - tolevel); while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar).endpc = fs->pc; + getlocvar(fs, --fs->nactvar)->endpc = fs->pc; } @@ -184,30 +211,31 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { int i; Proto *f = fs->f; int oldsize = f->sizeupvalues; - for (i=0; inups; i++) { - if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { - lua_assert(f->upvalues[i] == name); + int instk = (v->k == VLOCAL); + lua_assert(instk || v->k == VUPVAL); + for (i=0; inups; i++) { + if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) { + lua_assert(f->upvalues[i].name == name); return i; } } /* new one */ - luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); - luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, - TString *, MAX_INT, ""); - while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; - f->upvalues[f->nups] = name; + checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues"); + luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, + Upvaldesc, UCHAR_MAX, "upvalues"); + while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; + f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->L, f, name); - lua_assert(v->k == VLOCAL || v->k == VUPVAL); - fs->upvalues[f->nups].k = cast_byte(v->k); - fs->upvalues[f->nups].info = cast_byte(v->u.s.info); - return f->nups++; + f->upvalues[fs->nups].instack = cast_byte(instk); + f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); + return fs->nups++; } static int searchvar (FuncState *fs, TString *n) { int i; for (i=fs->nactvar-1; i >= 0; i--) { - if (n == getlocvar(fs, i).varname) + if (n == getlocvar(fs, i)->varname) return i; } return -1; /* not found */ @@ -222,10 +250,8 @@ static void markupval (FuncState *fs, int level) { static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { - if (fs == NULL) { /* no more levels? */ - init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ - return VGLOBAL; - } + if (fs == NULL) /* no more levels? */ + return VGLOBAL; /* default is global variable */ else { int v = searchvar(fs, n); /* look up at current level */ if (v >= 0) { @@ -248,8 +274,16 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; - if (singlevaraux(fs, varname, var, 1) == VGLOBAL) - var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ + if (singlevaraux(fs, varname, var, 1) == VGLOBAL) { + if (fs->envreg == NO_REG) /* regular global? */ + init_exp(var, VGLOBAL, luaK_stringK(fs, varname)); + else { /* "globals" are in current lexical environment */ + expdesc key; + init_exp(var, VLOCAL, fs->envreg); /* current environment */ + codestring(ls, &key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ + } + } } @@ -274,12 +308,13 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { static void enterlevel (LexState *ls) { - if (++ls->L->nCcalls > LUAI_MAXCCALLS) - luaX_lexerror(ls, "chunk has too many syntax levels", 0); + global_State *g = G(ls->L); + ++g->nCcalls; + checklimit(ls->fs, g->nCcalls, LUAI_MAXCCALLS, "syntax levels"); } -#define leavelevel(ls) ((ls)->L->nCcalls--) +#define leavelevel(ls) (G((ls)->L)->nCcalls--) static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { @@ -296,7 +331,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; fs->bl = bl->previous; - removevars(fs->ls, bl->nactvar); + removevars(fs, bl->nactvar); if (bl->upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); /* a block either controls scope or breaks (never both) */ @@ -307,49 +342,51 @@ static void leaveblock (FuncState *fs) { } -static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { - FuncState *fs = ls->fs; - Proto *f = fs->f; +static void pushclosure (LexState *ls, Proto *clp, expdesc *v) { + FuncState *fs = ls->fs->prev; + Proto *f = fs->f; /* prototype of function creating new closure */ int oldsize = f->sizep; - int i; luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, - MAXARG_Bx, "constant table overflow"); + MAXARG_Bx, "functions"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; - f->p[fs->np++] = func->f; - luaC_objbarrier(ls->L, f, func->f); + f->p[fs->np++] = clp; + /* initial environment for new function is current lexical environment */ + clp->envreg = fs->envreg; + luaC_objbarrier(ls->L, f, clp); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); - for (i=0; if->nups; i++) { - OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; - luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); - } } static void open_func (LexState *ls, FuncState *fs) { lua_State *L = ls->L; - Proto *f = luaF_newproto(L); - fs->f = f; + Proto *f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; fs->L = L; ls->fs = fs; fs->pc = 0; - fs->lasttarget = -1; + fs->lasttarget = 0; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; fs->np = 0; + fs->nups = 0; fs->nlocvars = 0; fs->nactvar = 0; + fs->firstlocal = ls->varl->nactvar; + fs->envreg = NO_REG; fs->bl = NULL; + f = luaF_newproto(L); + fs->f = f; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ - fs->h = luaH_new(L, 0, 0); - /* anchor table of constants and prototype (to avoid being collected) */ - sethvalue2s(L, L->top, fs->h); - incr_top(L); + /* anchor prototype (to avoid being collected) */ setptvalue2s(L, L->top, f); incr_top(L); + fs->h = luaH_new(L); + /* anchor table of constants (to avoid being collected) */ + sethvalue2s(L, L->top, fs->h); + incr_top(L); } @@ -357,7 +394,7 @@ static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; - removevars(ls, 0); + removevars(fs, 0); luaK_ret(fs, 0, 0); /* final return */ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; @@ -369,30 +406,37 @@ static void close_func (LexState *ls) { f->sizep = fs->np; luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); f->sizelocvars = fs->nlocvars; - luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); - f->sizeupvalues = f->nups; - lua_assert(luaG_checkcode(f)); + luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); + f->sizeupvalues = fs->nups; lua_assert(fs->bl == NULL); ls->fs = fs->prev; - L->top -= 2; /* remove table and prototype from the stack */ - /* last token read was anchored in defunct function; must reanchor it */ - if (fs) anchor_token(ls); + /* last token read was anchored in defunct function; must re-anchor it */ + anchor_token(ls); + L->top--; /* pop table of constants */ + luaC_checkGC(L); + L->top--; /* pop prototype (after possible collection) */ } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, + const char *name) { struct LexState lexstate; struct FuncState funcstate; + TString *tname = luaS_new(L, name); + setsvalue2s(L, L->top, tname); /* push name to protect it */ + incr_top(L); lexstate.buff = buff; - luaX_setinput(L, &lexstate, z, luaS_new(L, name)); + lexstate.varl = varl; + luaX_setinput(L, &lexstate, z, tname); open_func(&lexstate, &funcstate); - funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ + funcstate.f->is_vararg = 1; /* main function is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); + L->top--; /* pop name */ lua_assert(funcstate.prev == NULL); - lua_assert(funcstate.f->nups == 0); + lua_assert(funcstate.nups == 0); lua_assert(lexstate.fs == NULL); return funcstate.f; } @@ -404,8 +448,8 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { /*============================================================*/ -static void field (LexState *ls, expdesc *v) { - /* field -> ['.' | ':'] NAME */ +static void fieldsel (LexState *ls, expdesc *v) { + /* fieldsel -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyreg(fs, v); @@ -447,7 +491,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { expdesc key, val; int rkkey; if (ls->t.token == TK_NAME) { - luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ @@ -488,15 +532,39 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { static void listfield (LexState *ls, struct ConsControl *cc) { + /* listfield -> exp */ expr(ls, &cc->v); - luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); + checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } +static void field (LexState *ls, struct ConsControl *cc) { + /* field -> listfield | recfield */ + switch(ls->t.token) { + case TK_NAME: { /* may be 'listfield' or 'recfield' */ + if (luaX_lookahead(ls) != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { + recfield(ls, cc); + break; + } + default: { + listfield(ls, cc); + break; + } + } +} + + static void constructor (LexState *ls, expdesc *t) { - /* constructor -> ?? */ + /* constructor -> '{' [ field { sep field } [sep] ] '}' + sep -> ',' | ';' */ FuncState *fs = ls->fs; int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); @@ -511,24 +579,7 @@ static void constructor (LexState *ls, expdesc *t) { lua_assert(cc.v.k == VVOID || cc.tostore > 0); if (ls->t.token == '}') break; closelistfield(fs, &cc); - switch(ls->t.token) { - case TK_NAME: { /* may be listfields or recfields */ - luaX_lookahead(ls); - if (ls->lookahead.token != '=') /* expression? */ - listfield(ls, &cc); - else - recfield(ls, &cc); - break; - } - case '[': { /* constructor_item -> recfield */ - recfield(ls, &cc); - break; - } - default: { /* constructor_part -> listfield */ - listfield(ls, &cc); - break; - } - } + field(ls, &cc); } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); @@ -550,17 +601,13 @@ static void parlist (LexState *ls) { do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ - new_localvar(ls, str_checkname(ls), nparams++); + new_localvar(ls, str_checkname(ls)); + nparams++; break; } case TK_DOTS: { /* param -> `...' */ luaX_next(ls); -#if defined(LUA_COMPAT_VARARG) - /* use `arg' as default name */ - new_localvarliteral(ls, "arg", nparams++); - f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; -#endif - f->is_vararg |= VARARG_ISVARARG; + f->is_vararg = 1; break; } default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); @@ -568,7 +615,7 @@ static void parlist (LexState *ls) { } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); - f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); + f->numparams = cast_byte(fs->nactvar); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -580,7 +627,7 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { new_fs.f->linedefined = line; checknext(ls, '('); if (needself) { - new_localvarliteral(ls, "self", 0); + new_localvarliteral(ls, "self"); adjustlocalvars(ls, 1); } parlist(ls); @@ -588,8 +635,8 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { chunk(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); + pushclosure(ls, new_fs.f, e); close_func(ls); - pushclosure(ls, &new_fs, e); } @@ -694,8 +741,8 @@ static void primaryexp (LexState *ls, expdesc *v) { prefixexp(ls, v); for (;;) { switch (ls->t.token) { - case '.': { /* field */ - field(ls, v); + case '.': { /* fieldsel */ + fieldsel(ls, v); break; } case '[': { /* `[' exp1 `]' */ @@ -725,7 +772,7 @@ static void primaryexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | + /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { @@ -753,7 +800,6 @@ static void simpleexp (LexState *ls, expdesc *v) { FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); - fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } @@ -811,11 +857,11 @@ static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ - {10, 9}, {5, 4}, /* power and concat (right associative) */ - {3, 3}, {3, 3}, /* equality and inequality */ - {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ - {2, 2}, {1, 1} /* logical (and/or) */ + {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */ + {10, 9}, {5, 4}, /* ^, .. (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ }; #define UNARY_PRIORITY 8 /* priority for unary operators */ @@ -938,8 +984,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) check_conflict(ls, lh, &nv.v); - luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, - "variables in assignment"); + checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls, + "variable names"); assignment(ls, &nv, nvars+1); } else { /* assignment -> `=' explist1 */ @@ -1000,7 +1046,7 @@ static void whilestat (LexState *ls, int line) { enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); - luaK_patchlist(fs, luaK_jump(fs), whileinit); + luaK_jumpto(fs, whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ @@ -1021,13 +1067,13 @@ static void repeatstat (LexState *ls, int line) { condexit = cond(ls); /* read condition (inside scope block) */ if (!bl2.upval) { /* no upvalues? */ leaveblock(fs); /* finish scope */ - luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ } else { /* complete semantics when there are upvalues */ breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ - luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ + luaK_jumpto(fs, repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ } @@ -1035,11 +1081,12 @@ static void repeatstat (LexState *ls, int line) { static int exp1 (LexState *ls) { expdesc e; - int k; + int reg; expr(ls, &e); - k = e.k; luaK_exp2nextreg(ls->fs, &e); - return k; + lua_assert(e.k == VNONRELOC); + reg = e.u.s.info; + return reg; } @@ -1057,10 +1104,15 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { block(ls); leaveblock(fs); /* end of scope for declared variables */ luaK_patchtohere(fs, prep); - endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : - luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); - luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); + if (isnum) /* numeric for? */ + endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); + else { /* generic for */ + luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); + luaK_fixline(fs, line); + endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); + } + luaK_patchlist(fs, endfor, prep + 1); + luaK_fixline(fs, line); } @@ -1068,10 +1120,10 @@ static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; - new_localvarliteral(ls, "(for index)", 0); - new_localvarliteral(ls, "(for limit)", 1); - new_localvarliteral(ls, "(for step)", 2); - new_localvar(ls, varname, 3); + new_localvarliteral(ls, "(for index)"); + new_localvarliteral(ls, "(for limit)"); + new_localvarliteral(ls, "(for step)"); + new_localvar(ls, varname); checknext(ls, '='); exp1(ls); /* initial value */ checknext(ls, ','); @@ -1079,7 +1131,7 @@ static void fornum (LexState *ls, TString *varname, int line) { if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ - luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); + luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); @@ -1090,17 +1142,19 @@ static void forlist (LexState *ls, TString *indexname) { /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState *fs = ls->fs; expdesc e; - int nvars = 0; + int nvars = 4; /* gen, state, control, plus at least one declared var */ int line; int base = fs->freereg; /* create control variables */ - new_localvarliteral(ls, "(for generator)", nvars++); - new_localvarliteral(ls, "(for state)", nvars++); - new_localvarliteral(ls, "(for control)", nvars++); + new_localvarliteral(ls, "(for generator)"); + new_localvarliteral(ls, "(for state)"); + new_localvarliteral(ls, "(for control)"); /* create declared variables */ - new_localvar(ls, indexname, nvars++); - while (testnext(ls, ',')) - new_localvar(ls, str_checkname(ls), nvars++); + new_localvar(ls, indexname); + while (testnext(ls, ',')) { + new_localvar(ls, str_checkname(ls)); + nvars++; + } checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 3, explist1(ls, &e), &e); @@ -1165,14 +1219,12 @@ static void ifstat (LexState *ls, int line) { static void localfunc (LexState *ls) { expdesc v, b; FuncState *fs = ls->fs; - new_localvar(ls, str_checkname(ls), 0); + new_localvar(ls, str_checkname(ls)); init_exp(&v, VLOCAL, fs->freereg); luaK_reserveregs(fs, 1); adjustlocalvars(ls, 1); body(ls, &b, 0, ls->linenumber); luaK_storevar(fs, &v, &b); - /* debug information will only see the variable after this point! */ - getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; } @@ -1182,7 +1234,8 @@ static void localstat (LexState *ls) { int nexps; expdesc e; do { - new_localvar(ls, str_checkname(ls), nvars++); + new_localvar(ls, str_checkname(ls)); + nvars++; } while (testnext(ls, ',')); if (testnext(ls, '=')) nexps = explist1(ls, &e); @@ -1196,14 +1249,14 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {field} [`:' NAME] */ + /* funcname -> NAME {fieldsel} [`:' NAME] */ int needself = 0; singlevar(ls, v); while (ls->t.token == '.') - field(ls, v); + fieldsel(ls, v); if (ls->t.token == ':') { needself = 1; - field(ls, v); + fieldsel(ls, v); } return needself; } @@ -1221,6 +1274,24 @@ static void funcstat (LexState *ls, int line) { } +static void instat (LexState *ls, int line) { + /* instat -> IN exp DO block END */ + FuncState *fs = ls->fs; + int oldenv = fs->envreg; /* save current environment */ + BlockCnt bl; + luaX_next(ls); /* skip IN */ + enterblock(fs, &bl, 0); /* scope for environment variable */ + new_localvarliteral(ls, "(environment)"); + fs->envreg = exp1(ls); /* new environment */ + adjustlocalvars(ls, 1); + checknext(ls, TK_DO); + block(ls); + leaveblock(fs); + check_match(ls, TK_END, TK_IN, line); + fs->envreg = oldenv; /* restore outer environment */ +} + + static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; @@ -1285,6 +1356,10 @@ static int statement (LexState *ls) { check_match(ls, TK_END, TK_DO, line); return 0; } + case TK_IN: { + instat(ls, line); + return 0; + } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); return 0; diff --git a/src/lparser.h b/src/lparser.h index 18836afd1c..2ad0a5099f 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lparser.h,v 1.61 2009/10/11 20:02:19 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,8 +23,8 @@ typedef enum { VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ - VLOCAL, /* info = local register */ - VUPVAL, /* info = index of upvalue in `upvalues' */ + VLOCAL, /* info = local register; aux = read only */ + VUPVAL, /* info = index of upvalue in 'upvalues'; aux = read only */ VGLOBAL, /* info = index of table; aux = index of global name in `k' */ VINDEXED, /* info = table register; aux = index register (or `k') */ VJMP, /* info = instruction pc */ @@ -34,6 +34,7 @@ typedef enum { VVARARG /* info = instruction pc */ } expkind; + typedef struct expdesc { expkind k; union { @@ -45,10 +46,17 @@ typedef struct expdesc { } expdesc; -typedef struct upvaldesc { - lu_byte k; - lu_byte info; -} upvaldesc; +typedef struct vardesc { + unsigned short idx; +} vardesc; + + +/* list of all active local variables */ +typedef struct Varlist { + vardesc *actvar; + int nactvar; + int actvarsize; +} Varlist; struct BlockCnt; /* defined in lparser.c */ @@ -68,15 +76,16 @@ typedef struct FuncState { int freereg; /* first free register */ int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ + int firstlocal; /* index of first local var of this function */ short nlocvars; /* number of elements in `locvars' */ lu_byte nactvar; /* number of active local variables */ - upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ - unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ + lu_byte nups; /* number of upvalues */ + lu_byte envreg; /* register holding current lexical environment */ } FuncState; LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - const char *name); + Varlist *varl, const char *name); #endif diff --git a/src/lstate.c b/src/lstate.c index 4313b83a0c..426fdec629 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $ +** $Id: lstate.c,v 2.68 2009/12/22 15:32:50 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include "lua.h" +#include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -24,55 +25,139 @@ #include "ltm.h" -#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) -#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) -#define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) +#if !defined(LUAI_GCPAUSE) +#define LUAI_GCPAUSE 162 /* 162% (wait memory to double before next GC) */ +#endif + +#if !defined(LUAI_GCMUL) +#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ +#endif + + +/* +** thread state + extra space +*/ +typedef struct LX { +#if defined(LUAI_EXTRASPACE) + char buff[LUAI_EXTRASPACE]; +#endif + lua_State l; +} LX; /* ** Main thread combines a thread state and the global state */ typedef struct LG { - lua_State l; + LX l; global_State g; } LG; - + + + +#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) + + + +/* +** maximum number of nested calls made by error-handling function +*/ +#define LUAI_EXTRACALLS 10 + + +CallInfo *luaE_extendCI (lua_State *L) { + CallInfo *ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + return ci; +} + + +void luaE_freeCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + luaM_free(L, ci); + } +} static void stack_init (lua_State *L1, lua_State *L) { - /* initialize CallInfo array */ - L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); - L1->ci = L1->base_ci; - L1->size_ci = BASIC_CI_SIZE; - L1->end_ci = L1->base_ci + L1->size_ci - 1; + int i; /* initialize stack array */ - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); - L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); + L1->stacksize = BASIC_STACK_SIZE; + for (i = 0; i < BASIC_STACK_SIZE; i++) + setnilvalue(L1->stack + i); /* erase new stack */ L1->top = L1->stack; - L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; + L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; /* initialize first ci */ L1->ci->func = L1->top; - setnilvalue(L1->top++); /* `function' entry for this `ci' */ - L1->base = L1->ci->base = L1->top; + setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ L1->ci->top = L1->top + LUA_MINSTACK; + L1->ci->callstatus = 0; +} + + +static void freestack (lua_State *L) { + L->ci = &L->base_ci; /* reset 'ci' list */ + luaE_freeCI(L); + luaM_freearray(L, L->stack, L->stacksize); +} + + +/* +** Calls the function in variable pointed to by userdata in first argument +** (Userdata cannot point directly to the function because pointer to +** function is not compatible with void*.) +*/ +static int cpcall (lua_State *L) { + lua_CFunction f = *(lua_CFunction *)lua_touserdata(L, 1); + lua_remove(L, 1); /* remove f from stack */ + /* restore original environment for 'cpcall' */ + lua_pushglobaltable(L); + lua_replace(L, LUA_ENVIRONINDEX); + return f(L); } -static void freestack (lua_State *L, lua_State *L1) { - luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); - luaM_freearray(L, L1->stack, L1->stacksize, TValue); +/* +** Create registry table and its predefined values +*/ +static void init_registry (lua_State *L, global_State *g) { + Closure *cp; + TValue mt; + /* create registry */ + Table *registry = luaH_new(L); + sethvalue(L, &g->l_registry, registry); + luaH_resize(L, registry, LUA_RIDX_LAST, 0); + /* registry[LUA_RIDX_MAINTHREAD] = L */ + setthvalue(L, &mt, L); + setobj2t(L, luaH_setint(L, registry, LUA_RIDX_MAINTHREAD), &mt); + /* registry[LUA_RIDX_CPCALL] = cpcall */ + cp = luaF_newCclosure(L, 0, g->l_gt); + cp->c.f = cpcall; + setclvalue(L, &mt, cp); + setobj2t(L, luaH_setint(L, registry, LUA_RIDX_CPCALL), &mt); + /* registry[LUA_RIDX_GLOBALS] = l_gt */ + sethvalue(L, &mt, g->l_gt); + setobj2t(L, luaH_setint(L, registry, LUA_RIDX_GLOBALS), &mt); } /* -** open parts that may cause memory-allocation errors +** open parts of the state that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ - sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ - sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ + g->l_gt = luaH_new(L); /* table of globals */ + init_registry(L, g); luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); @@ -81,6 +166,10 @@ static void f_luaopen (lua_State *L, void *ud) { } +/* +** preinitialize a state with consistent values without allocating +** any memory (to avoid errors) +*/ static void preinit_state (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; @@ -92,51 +181,53 @@ static void preinit_state (lua_State *L, global_State *g) { L->allowhook = 1; resethookcount(L); L->openupval = NULL; - L->size_ci = 0; - L->nCcalls = L->baseCcalls = 0; - L->status = 0; - L->base_ci = L->ci = NULL; - L->savedpc = NULL; + L->nny = 1; + L->status = LUA_OK; + L->base_ci.next = L->base_ci.previous = NULL; + L->ci = &L->base_ci; L->errfunc = 0; - setnilvalue(gt(L)); } static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_freeall(L); /* collect all objects */ - lua_assert(g->rootgc == obj2gco(L)); - lua_assert(g->strt.nuse == 0); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); + luaC_freeallobjects(L); /* collect all objects */ + luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); luaZ_freebuffer(L, &g->buff); - freestack(L, L); + freestack(L); lua_assert(g->totalbytes == sizeof(LG)); - (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); } -lua_State *luaE_newthread (lua_State *L) { - lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); - luaC_link(L, obj2gco(L1), LUA_TTHREAD); +LUA_API lua_State *lua_newthread (lua_State *L) { + lua_State *L1; + lua_lock(L); + luaC_checkGC(L); + L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th; + setthvalue(L, L->top, L1); + api_incr_top(L); preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ - setobj2n(L, gt(L1), gt(L)); /* share table of globals */ L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); lua_assert(iswhite(obj2gco(L1))); + lua_unlock(L); + luai_userstatethread(L, L1); return L1; } void luaE_freethread (lua_State *L, lua_State *L1) { + LX *l = fromstate(L1); luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); luai_userstatefree(L1); - freestack(L, L1); - luaM_freemem(L, fromstate(L1), state_size(lua_State)); + freestack(L1); + luaM_free(L, l); } @@ -144,14 +235,16 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; - void *l = (*f)(ud, NULL, 0, state_size(LG)); + LG *l = cast(LG *, (*f)(ud, NULL, 0, sizeof(LG))); if (l == NULL) return NULL; - L = tostate(l); - g = &((LG *)L)->g; + L = &l->l.l; + g = &l->g; L->next = NULL; L->tt = LUA_TTHREAD; g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); L->marked = luaC_white(g); + g->gckind = KGC_NORMAL; + g->nCcalls = 0; set2bits(L->marked, FIXEDBIT, SFIXEDBIT); preinit_state(L, g); g->frealloc = f; @@ -159,27 +252,23 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->mainthread = L; g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; - g->GCthreshold = 0; /* mark it as unfinished state */ + g->GCthreshold = MAX_LUMEM; /* no GC while building state */ g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; - setnilvalue(registry(L)); + setnilvalue(&g->l_registry); + g->l_gt = NULL; luaZ_initbuffer(L, &g->buff); g->panic = NULL; + g->version = lua_version(NULL); g->gcstate = GCSpause; g->rootgc = obj2gco(L); - g->sweepstrgc = 0; - g->sweepgc = &g->rootgc; - g->gray = NULL; - g->grayagain = NULL; - g->weak = NULL; - g->tmudata = NULL; + g->tobefnz = NULL; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; - g->gcdept = 0; for (i=0; imt[i] = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { + if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { /* memory allocation error: free partial state */ close_state(L); L = NULL; @@ -190,25 +279,14 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { } -static void callallgcTM (lua_State *L, void *ud) { - UNUSED(ud); - luaC_callGCTM(L); /* call GC metamethods for all udata */ -} - - LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ - L->errfunc = 0; /* no error function during GC metamethods */ - do { /* repeat until no more errors */ - L->ci = L->base_ci; - L->base = L->top = L->ci->base; - L->nCcalls = L->baseCcalls = 0; - } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); - lua_assert(G(L)->tmudata == NULL); + luaC_separateudata(L, 1); /* separate all udata with GC metamethods */ + lua_assert(L->next == NULL); luai_userstateclose(L); close_state(L); } + diff --git a/src/lstate.h b/src/lstate.h index 3bc575b6bc..4ca3e02f42 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $ +** $Id: lstate.h,v 2.52 2009/12/22 15:32:50 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -14,15 +14,35 @@ #include "lzio.h" +/* -struct lua_longjmp; /* defined in ldo.c */ +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed. +** +** Lua keeps most objects linked in list g->rootgc. The link uses field +** 'next' of the CommonHeader. +** +** Strings are kept in several lists headed by the array g->strt.hash. +** +** Open upvalues are not subject to independent garbage collection. They +** are collected together with their respective threads. Lua keeps a +** double-linked list with all open upvalues (g->uvhead) so that it can +** mark objects referred by them. (They are always gray, so they must +** be remarked in the atomic step. Usually their contents would be marked +** when traversing the respective threads, but the thread may already be +** dead, while the upvalue is still accessible through closures.) +** +** Userdata with finalizers are kept in the list g->rootgc, but after +** the mainthread, which should be otherwise the last element in the +** list, as it was the first one inserted there. +** +** The list g->tobefnz links all userdata being finalized. +*/ -/* table of globals */ -#define gt(L) (&L->l_gt) -/* registry */ -#define registry(L) (&G(L)->l_registry) +struct lua_longjmp; /* defined in ldo.c */ + /* extra stack space to handle TM calls and some other extras */ @@ -34,6 +54,11 @@ struct lua_longjmp; /* defined in ldo.c */ #define BASIC_STACK_SIZE (2*LUA_MINSTACK) +/* kinds of Garbage Collection */ +#define KGC_NORMAL 0 +#define KGC_FORCED 1 /* gc was forced by the program */ +#define KGC_EMERGENCY 2 /* gc was forced by an allocation failure */ + typedef struct stringtable { GCObject **hash; @@ -46,20 +71,44 @@ typedef struct stringtable { ** informations about a call */ typedef struct CallInfo { - StkId base; /* base for this function */ StkId func; /* function index in the stack */ StkId top; /* top for this function */ - const Instruction *savedpc; - int nresults; /* expected number of results from this function */ - int tailcalls; /* number of tail calls lost under this entry */ + struct CallInfo *previous, *next; /* dynamic call link */ + short nresults; /* expected number of results from a call */ + lu_byte callstatus; + union { + struct { /* only for Lua functions */ + StkId base; /* base for this function */ + const Instruction *savedpc; + } l; + struct { /* only for C functions */ + int ctx; /* context info. in case of yields */ + lua_CFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + ptrdiff_t oldtop; + lu_byte old_allowhook; + lu_byte status; + } c; + } u; } CallInfo; +/* +** Bits in CallInfo status +*/ +#define CIST_LUA (1<<0) /* call is running a Lua function */ +#define CIST_HOOKED (1<<1) /* call is running a debug hook */ +#define CIST_REENTRY (1<<2) /* call is running on same invocation of + luaV_execute of previous call */ +#define CIST_YIELDED (1<<3) /* call reentered after suspension */ +#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ +#define CIST_STAT (1<<5) /* call has an error status (pcall) */ +#define CIST_TAIL (1<<6) /* call was tail called */ + #define curr_func(L) (clvalue(L->ci->func)) #define ci_func(ci) (clvalue((ci)->func)) -#define f_isLua(ci) (!ci_func(ci)->c.isC) -#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) +#define isLua(ci) ((ci)->callstatus & CIST_LUA) /* @@ -69,26 +118,30 @@ typedef struct global_State { stringtable strt; /* hash table for strings */ lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ + unsigned short nCcalls; /* number of nested C calls */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ + lu_byte gckind; /* kind of GC running */ int sweepstrgc; /* position of sweep in `strt' */ GCObject *rootgc; /* list of all collectable objects */ - GCObject **sweepgc; /* position of sweep in `rootgc' */ + GCObject **sweepgc; /* current position of sweep */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ - GCObject *weak; /* list of weak tables (to be cleared) */ - GCObject *tmudata; /* last element of list of userdata to be GC */ - Mbuffer buff; /* temporary buffer for string concatentation */ - lu_mem GCthreshold; + GCObject *weak; /* list of tables with weak values */ + GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ + GCObject *allweak; /* list of all-weak tables */ + GCObject *tobefnz; /* list of userdata to be GC */ + Mbuffer buff; /* temporary buffer for string concatenation */ + lu_mem GCthreshold; /* when totalbytes > GCthreshold, run GC step */ lu_mem totalbytes; /* number of bytes currently allocated */ - lu_mem estimate; /* an estimate of number of bytes actually in use */ - lu_mem gcdept; /* how much GC is `behind schedule' */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ TValue l_registry; + struct Table *l_gt; /* table of globals */ struct lua_State *mainthread; UpVal uvhead; /* head of double-linked list of all open upvalues */ + const lua_Number *version; /* pointer to version number */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */ TString *tmname[TM_N]; /* array with tag-method names */ } global_State; @@ -101,29 +154,24 @@ struct lua_State { CommonHeader; lu_byte status; StkId top; /* first free slot in the stack */ - StkId base; /* base of current function */ global_State *l_G; CallInfo *ci; /* call info for current function */ - const Instruction *savedpc; /* `savedpc' of current function */ + const Instruction *oldpc; /* last pc traced */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ - CallInfo *end_ci; /* points after end of ci array*/ - CallInfo *base_ci; /* array of CallInfo's */ int stacksize; - int size_ci; /* size of array `base_ci' */ - unsigned short nCcalls; /* number of nested C calls */ - unsigned short baseCcalls; /* nested C calls when resuming coroutine */ + unsigned short nny; /* number of non-yieldable calls in stack */ lu_byte hookmask; lu_byte allowhook; int basehookcount; int hookcount; lua_Hook hook; - TValue l_gt; /* table of globals */ TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ ptrdiff_t errfunc; /* current error handling function (stack index) */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ }; @@ -134,7 +182,7 @@ struct lua_State { ** Union of all collectable objects */ union GCObject { - GCheader gch; + GCheader gch; /* common header */ union TString ts; union Udata u; union Closure cl; @@ -145,25 +193,27 @@ union GCObject { }; +#define gch(o) (&(o)->gch) + /* macros to convert a GCObject into a specific value */ #define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) #define gco2ts(o) (&rawgco2ts(o)->tsv) #define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) #define gco2u(o) (&rawgco2u(o)->uv) #define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) -#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) #define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) -#define ngcotouv(o) \ - check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) /* macro to convert any Lua object into a GCObject */ #define obj2gco(v) (cast(GCObject *, (v))) -LUAI_FUNC lua_State *luaE_newthread (lua_State *L); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); +LUAI_FUNC void luaE_freeCI (lua_State *L); + #endif diff --git a/src/lstring.c b/src/lstring.c index 49113151cc..69b96d027a 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lstring.c,v 2.16 2009/12/16 16:42:58 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -20,54 +20,54 @@ void luaS_resize (lua_State *L, int newsize) { - GCObject **newhash; - stringtable *tb; int i; - if (G(L)->gcstate == GCSsweepstring) - return; /* cannot resize during GC traverse */ - newhash = luaM_newvector(L, newsize, GCObject *); - tb = &G(L)->strt; - for (i=0; istrt; + /* cannot resize while GC is traversing strings */ + luaC_runtilstate(L, ~bitmask(GCSsweepstring)); + if (newsize > tb->size) { + luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); + for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL; + } /* rehash */ for (i=0; isize; i++) { GCObject *p = tb->hash[i]; + tb->hash[i] = NULL; while (p) { /* for each node in the list */ - GCObject *next = p->gch.next; /* save next */ - unsigned int h = gco2ts(p)->hash; - int h1 = lmod(h, newsize); /* new position */ - lua_assert(cast_int(h%newsize) == lmod(h, newsize)); - p->gch.next = newhash[h1]; /* chain it */ - newhash[h1] = p; + GCObject *next = gch(p)->next; /* save next */ + unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ + gch(p)->next = tb->hash[h]; /* chain it */ + tb->hash[h] = p; p = next; } } - luaM_freearray(L, tb->hash, tb->size, TString *); + if (newsize < tb->size) { + /* shrinking slice must be empty */ + lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); + luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); + } tb->size = newsize; - tb->hash = newhash; } static TString *newlstr (lua_State *L, const char *str, size_t l, unsigned int h) { + size_t totalsize; /* total size of TString object */ + GCObject **list; /* (pointer to) list where it will be inserted */ TString *ts; - stringtable *tb; + stringtable *tb = &G(L)->strt; if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) luaM_toobig(L); - ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); + if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ + totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); + list = &tb->hash[lmod(h, tb->size)]; + ts = &luaC_newobj(L, LUA_TSTRING, totalsize, list, 0)->ts; ts->tsv.len = l; ts->tsv.hash = h; - ts->tsv.marked = luaC_white(G(L)); - ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; memcpy(ts+1, str, l*sizeof(char)); ((char *)(ts+1))[l] = '\0'; /* ending 0 */ - tb = &G(L)->strt; - h = lmod(h, tb->size); - ts->tsv.next = tb->hash[h]; /* chain new entry */ - tb->hash[h] = obj2gco(ts); tb->nuse++; - if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) - luaS_resize(L, tb->size*2); /* too crowded */ return ts; } @@ -81,15 +81,16 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; - o = o->gch.next) { + o = gch(o)->next) { TString *ts = rawgco2ts(o); - if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { - /* string may be dead */ - if (isdead(G(L), o)) changewhite(o); + if (h == ts->tsv.hash && ts->tsv.len == l && + (memcmp(str, getstr(ts), l) == 0)) { + if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ + changewhite(o); /* resurrect it */ return ts; } } - return newlstr(L, str, l, h); /* not found */ + return newlstr(L, str, l, h); /* not found; create a new string */ } @@ -97,15 +98,10 @@ Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) luaM_toobig(L); - u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); - u->uv.marked = luaC_white(G(L)); /* is not finalized */ - u->uv.tt = LUA_TUSERDATA; + u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u; u->uv.len = s; u->uv.metatable = NULL; u->uv.env = e; - /* chain it on udata list (after main thread) */ - u->uv.next = G(L)->mainthread->next; - G(L)->mainthread->next = obj2gco(u); return u; } diff --git a/src/lstring.h b/src/lstring.h index 73a2ff8b38..1d2e91ea13 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ diff --git a/src/lstrlib.c b/src/lstrlib.c index 1b4763d4ee..0c03b493a6 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ +** $Id: lstrlib.c,v 1.148 2010/01/04 16:37:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -20,6 +20,15 @@ #include "lualib.h" +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + /* macro to `unsign' a character */ #define uchar(c) ((unsigned char)(c)) @@ -28,27 +37,28 @@ static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); - lua_pushinteger(L, l); + lua_pushinteger(L, (lua_Integer)l); return 1; } -static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { - /* relative string position: negative means back from end */ - if (pos < 0) pos += (ptrdiff_t)len + 1; - return (pos >= 0) ? pos : 0; +/* translate a relative string position: negative means back from end */ +static size_t posrelat (ptrdiff_t pos, size_t len) { + if (pos >= 0) return (size_t)pos; + else if (pos == -pos || (size_t)-pos > len) return 0; + else return len - ((size_t)-pos) + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); - ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); + size_t start = posrelat(luaL_checkinteger(L, 2), l); + size_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; - if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; + if (end > l) end = l; if (start <= end) - lua_pushlstring(L, s+start-1, end-start+1); + lua_pushlstring(L, s + start - 1, end - start + 1); else lua_pushliteral(L, ""); return 1; } @@ -106,11 +116,11 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); - ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + size_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + size_t pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; - if (posi <= 0) posi = 1; - if ((size_t)pose > l) pose = l; + if (posi < 1) posi = 1; + if (pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); if (posi + n <= pose) /* overflow? */ @@ -186,7 +196,7 @@ typedef struct MatchState { static int check_capture (MatchState *ms, int l) { l -= '1'; if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index"); + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return l; } @@ -374,7 +384,15 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case ')': { /* end capture */ return end_capture(ms, s, p+1); } - case L_ESC: { + case '\0': { /* end of pattern */ + return s; /* match succeeded */ + } + case '$': { + if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + return (s == ms->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); @@ -393,25 +411,17 @@ static const char *match (MatchState *ms, const char *s, const char *p) { !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; /* else return match(ms, s, ep); */ } - default: { - if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p+1))); - if (s == NULL) return NULL; - p+=2; goto init; /* else return match(ms, s, p+2) */ - } - goto dflt; /* case default */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p+1))); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(ms, s, p+2) */ } + default: break; /* go through to 'dflt' */ } } - case '\0': { /* end of pattern */ - return s; /* match succeeded */ - } - case '$': { - if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ - return (s == ms->src_end) ? s : NULL; /* check end of string */ - else goto dflt; - } - default: dflt: { /* it is a pattern item */ + default: dflt: { /* pattern class plus optional sufix */ const char *ep = classend(ms, p); /* points to what is next */ int m = ssrc_end && singlematch(uchar(*s), p, ep); switch (*ep) { @@ -496,33 +506,36 @@ static int str_find_aux (lua_State *L, int find) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); - ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; - if (init < 0) init = 0; - else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; + size_t init = posrelat(luaL_optinteger(L, 3, 1), l1); + if (init < 1) init = 1; + else if (init > l1 + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } if (find && (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ - const char *s2 = lmemfind(s+init, l1-init, p, l2); + const char *s2 = lmemfind(s + init - 1, l1 - init + 1, p, l2); if (s2) { - lua_pushinteger(L, s2-s+1); - lua_pushinteger(L, s2-s+l2); + lua_pushinteger(L, s2 - s + 1); + lua_pushinteger(L, s2 - s + l2); return 2; } } else { MatchState ms; int anchor = (*p == '^') ? (p++, 1) : 0; - const char *s1=s+init; + const char *s1 = s + init - 1; ms.L = L; ms.src_init = s; - ms.src_end = s+l1; + ms.src_end = s + l1; do { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { if (find) { - lua_pushinteger(L, s1-s+1); /* start */ - lua_pushinteger(L, res-s); /* end */ + lua_pushinteger(L, s1 - s + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else @@ -596,8 +609,12 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, luaL_addchar(b, news[i]); else { i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) + if (!isdigit(uchar(news[i]))) { + if (news[i] != L_ESC) + luaL_error(ms->L, "invalid use of " LUA_QL("%c") + " in replacement string", L_ESC); luaL_addchar(b, news[i]); + } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { @@ -610,14 +627,9 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e) { + const char *e, int tr) { lua_State *L = ms->L; - switch (lua_type(L, 3)) { - case LUA_TNUMBER: - case LUA_TSTRING: { - add_s(ms, b, s, e); - return; - } + switch (tr) { case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); @@ -630,13 +642,17 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, lua_gettable(L, 3); break; } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); + return; + } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) - luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } @@ -645,10 +661,10 @@ static int str_gsub (lua_State *L) { size_t srcl; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checkstring(L, 2); - int tr = lua_type(L, 3); - int max_s = luaL_optint(L, 4, srcl+1); + int tr = lua_type(L, 3); + size_t max_s = luaL_optinteger(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; - int n = 0; + size_t n = 0; MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || @@ -664,7 +680,7 @@ static int str_gsub (lua_State *L) { e = match(&ms, src, p); if (e) { n++; - add_value(&ms, &b, src, e); + add_value(&ms, &b, src, e, tr); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ @@ -682,6 +698,24 @@ static int str_gsub (lua_State *L) { /* }====================================================== */ +/* +** length modifier for integer conversions ** in 'string.format' and +** integer type corresponding to the previous length +*/ + +#if defined(LUA_USELONGLONG) + +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long + +#else + +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long + +#endif + + /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 /* valid flags in a format specification */ @@ -698,25 +732,20 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { const char *s = luaL_checklstring(L, arg, &l); luaL_addchar(b, '"'); while (l--) { - switch (*s) { - case '"': case '\\': case '\n': { - luaL_addchar(b, '\\'); - luaL_addchar(b, *s); - break; - } - case '\r': { - luaL_addlstring(b, "\\r", 2); - break; - } - case '\0': { - luaL_addlstring(b, "\\000", 4); - break; - } - default: { - luaL_addchar(b, *s); - break; - } + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); } + else if (*s == '\0' || iscntrl(uchar(*s))) { + char buff[10]; + if (*s != '\0' && !isdigit(uchar(*(s+1)))) + sprintf(buff, "\\%d", uchar(*s)); + else + sprintf(buff, "\\%03d", uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); s++; } luaL_addchar(b, '"'); @@ -737,7 +766,7 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; - strncpy(form, strfrmt, p - strfrmt + 1); + memcpy(form, strfrmt, p - strfrmt + 1); form += p - strfrmt + 1; *form = '\0'; return p; @@ -772,17 +801,16 @@ static int str_format (lua_State *L) { strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - sprintf(buff, form, (int)luaL_checknumber(L, arg)); - break; - } - case 'd': case 'i': { - addintlen(form); - sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); + sprintf(buff, form, luaL_checkint(L, arg)); break; } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + lua_Number n = luaL_checknumber(L, arg); + LUA_INTFRM_T r = (n < 0) ? (LUA_INTFRM_T)n : + (LUA_INTFRM_T)(unsigned LUA_INTFRM_T)n; addintlen(form); - sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); + sprintf(buff, form, r); break; } case 'e': case 'E': case 'f': @@ -857,12 +885,8 @@ static void createmetatable (lua_State *L) { /* ** Open string library */ -LUALIB_API int luaopen_string (lua_State *L) { +LUAMOD_API int luaopen_string (lua_State *L) { luaL_register(L, LUA_STRLIBNAME, strlib); -#if defined(LUA_COMPAT_GFIND) - lua_getfield(L, -1, "gmatch"); - lua_setfield(L, -2, "gfind"); -#endif createmetatable(L); return 1; } diff --git a/src/ltable.c b/src/ltable.c index ec84f4fabc..78ff1d7402 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $ +** $Id: ltable.c,v 2.47 2009/12/17 15:46:44 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -18,7 +18,6 @@ ** Hence even when the load factor reaches 100%, performance remains good. */ -#include #include #define ltable_c @@ -48,7 +47,7 @@ #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) - + #define hashstr(t,str) hashpow2(t, (str)->tsv.hash) #define hashboolean(t,p) hashpow2(t, p) @@ -72,9 +71,11 @@ #define dummynode (&dummynode_) +#define isdummy(n) ((n) == dummynode) + static const Node dummynode_ = { - {{NULL}, LUA_TNIL}, /* value */ - {{{NULL}, LUA_TNIL, NULL}} /* key */ + {NILCONSTANT}, /* value */ + {{NILCONSTANT, NULL}} /* key */ }; @@ -82,13 +83,13 @@ static const Node dummynode_ = { ** hash for lua_Numbers */ static Node *hashnum (const Table *t, lua_Number n) { - unsigned int a[numints]; int i; - if (luai_numeq(n, 0)) /* avoid problems with -0 */ - return gnode(t, 0); - memcpy(a, &n, sizeof(a)); - for (i = 1; i < numints; i++) a[0] += a[i]; - return hashmod(t, a[0]); + luai_hashnum(i, n); + if (i < 0) { + i = -i; /* must be a positive value */ + if (i < 0) i = 0; /* handle INT_MIN */ + } + return hashmod(t, i); } @@ -132,7 +133,7 @@ static int arrayindex (const TValue *key) { /* ** returns the index of a `key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The -** beginning of a traversal is signalled by -1. +** beginning of a traversal is signaled by -1. */ static int findindex (lua_State *L, Table *t, StkId key) { int i; @@ -211,7 +212,7 @@ static int computesizes (int nums[], int *narray) { static int countint (const TValue *key, int *nums) { int k = arrayindex(key); if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ - nums[ceillog2(k)]++; /* count as such */ + nums[luaO_ceillog2(k)]++; /* count as such */ return 1; } else @@ -277,7 +278,7 @@ static void setnodevector (lua_State *L, Table *t, int size) { } else { int i; - lsize = ceillog2(size); + lsize = luaO_ceillog2(size); if (lsize > MAXBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); @@ -294,7 +295,7 @@ static void setnodevector (lua_State *L, Table *t, int size) { } -static void resize (lua_State *L, Table *t, int nasize, int nhsize) { +void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; @@ -302,13 +303,13 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ - setnodevector(L, t, nhsize); + setnodevector(L, t, nhsize); if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; iarray[i])) - setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); + setobjt2t(L, luaH_setint(L, t, i+1), &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); @@ -319,14 +320,14 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) { if (!ttisnil(gval(old))) setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } - if (nold != dummynode) - luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ + if (!isdummy(nold)) + luaM_freearray(L, nold, twoto(oldhsize)); /* free old array */ } void luaH_resizearray (lua_State *L, Table *t, int nasize) { - int nsize = (t->node == dummynode) ? 0 : sizenode(t); - resize(L, t, nasize, nsize); + int nsize = isdummy(t->node) ? 0 : sizenode(t); + luaH_resize(L, t, nasize, nsize); } @@ -345,7 +346,7 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { /* compute new size for array part */ na = computesizes(nums, &nasize); /* resize the table to new computed sizes */ - resize(L, t, nasize, totaluse - na); + luaH_resize(L, t, nasize, totaluse - na); } @@ -355,32 +356,28 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { */ -Table *luaH_new (lua_State *L, int narray, int nhash) { - Table *t = luaM_new(L, Table); - luaC_link(L, obj2gco(t), LUA_TTABLE); +Table *luaH_new (lua_State *L) { + Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table), NULL, 0)->h; t->metatable = NULL; t->flags = cast_byte(~0); - /* temporary values (kept only if some malloc fails) */ t->array = NULL; t->sizearray = 0; - t->lsizenode = 0; - t->node = cast(Node *, dummynode); - setarrayvector(L, t, narray); - setnodevector(L, t, nhash); + setnodevector(L, t, 0); return t; } void luaH_free (lua_State *L, Table *t) { - if (t->node != dummynode) - luaM_freearray(L, t->node, sizenode(t), Node); - luaM_freearray(L, t->array, t->sizearray, TValue); + if (!isdummy(t->node)) + luaM_freearray(L, t->node, sizenode(t)); + luaM_freearray(L, t->array, t->sizearray); luaM_free(L, t); } static Node *getfreepos (Table *t) { - while (t->lastfree-- > t->node) { + while (t->lastfree > t->node) { + t->lastfree--; if (ttisnil(gkey(t->lastfree))) return t->lastfree; } @@ -390,22 +387,22 @@ static Node *getfreepos (Table *t) { /* -** inserts a new key into a hash table; first, check whether key's main -** position is free. If not, check whether colliding node is in its main -** position or not: if it is not, move colliding node to an empty place and -** put new key in its main position; otherwise (colliding node is in its main -** position), new key goes to an empty position. +** inserts a new key into a hash table; first, check whether key's main +** position is free. If not, check whether colliding node is in its main +** position or not: if it is not, move colliding node to an empty place and +** put new key in its main position; otherwise (colliding node is in its main +** position), new key goes to an empty position. */ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { Node *mp = mainposition(t, key); - if (!ttisnil(gval(mp)) || mp == dummynode) { + if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ Node *othern; Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ return luaH_set(L, t, key); /* re-insert key into grown table */ } - lua_assert(n != dummynode); + lua_assert(!isdummy(n)); othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ @@ -422,7 +419,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { mp = n; } } - gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; + setobj2t(L, gkey(mp), key); luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); @@ -432,7 +429,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { /* ** search function for integers */ -const TValue *luaH_getnum (Table *t, int key) { +const TValue *luaH_getint (Table *t, int key) { /* (1 <= key && key <= t->sizearray) */ if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; @@ -475,7 +472,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { lua_Number n = nvalue(key); lua_number2int(k, n); if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ - return luaH_getnum(t, k); /* use specialized version */ + return luaH_getint(t, k); /* use specialized version */ /* else go through */ } default: { @@ -498,15 +495,15 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && luai_numisnan(nvalue(key))) + else if (ttisnumber(key) && luai_numisnan(L, nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } } -TValue *luaH_setnum (lua_State *L, Table *t, int key) { - const TValue *p = luaH_getnum(t, key); +TValue *luaH_setint (lua_State *L, Table *t, int key) { + const TValue *p = luaH_getint(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else { @@ -533,20 +530,20 @@ static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; /* find `i' and `j' such that i is present and j is not */ - while (!ttisnil(luaH_getnum(t, j))) { + while (!ttisnil(luaH_getint(t, j))) { i = j; j *= 2; if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; - while (!ttisnil(luaH_getnum(t, i))) i++; + while (!ttisnil(luaH_getint(t, i))) i++; return i - 1; } } /* now do a binary search between them */ while (j - i > 1) { unsigned int m = (i+j)/2; - if (ttisnil(luaH_getnum(t, m))) j = m; + if (ttisnil(luaH_getint(t, m))) j = m; else i = m; } return i; @@ -570,7 +567,7 @@ int luaH_getn (Table *t) { return i; } /* else must find a boundary in hash part */ - else if (t->node == dummynode) /* hash part is empty? */ + else if (isdummy(t->node)) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t, j); } @@ -583,6 +580,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) { return mainposition(t, key); } -int luaH_isdummy (Node *n) { return n == dummynode; } +int luaH_isdummy (Node *n) { return isdummy(n); } #endif diff --git a/src/ltable.h b/src/ltable.h index f5b9d5ead0..784377ac9a 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: ltable.h,v 2.13 2009/11/06 17:07:48 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -11,20 +11,21 @@ #define gnode(t,i) (&(t)->node[i]) -#define gkey(n) (&(n)->i_key.nk) +#define gkey(n) (&(n)->i_key.tvk) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) #define key2tval(n) (&(n)->i_key.tvk) -LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); -LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); +LUAI_FUNC const TValue *luaH_getint (Table *t, int key); +LUAI_FUNC TValue *luaH_setint (lua_State *L, Table *t, int key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); -LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); +LUAI_FUNC Table *luaH_new (lua_State *L); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); diff --git a/src/ltablib.c b/src/ltablib.c index b6d9cb4ac7..b2360807c8 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $ +** $Id: ltablib.c,v 1.53 2009/12/28 16:30:31 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -16,18 +16,20 @@ #include "lualib.h" -#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) +#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), lua_rawlen(L, n)) static int foreachi (lua_State *L) { - int i; int n = aux_getn(L, 1); + int i; + if (lua_getctx(L, &i) == LUA_YIELD) goto poscall; luaL_checktype(L, 2, LUA_TFUNCTION); - for (i=1; i <= n; i++) { + for (i = 1; i <= n; i++) { lua_pushvalue(L, 2); /* function */ lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ - lua_call(L, 2, 1); + lua_callk(L, 2, 1, i, foreachi); + poscall: if (!lua_isnil(L, -1)) return 1; lua_pop(L, 1); /* remove nil result */ @@ -36,23 +38,32 @@ static int foreachi (lua_State *L) { } -static int foreach (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_pushnil(L); /* first key */ - while (lua_next(L, 1)) { - lua_pushvalue(L, 2); /* function */ - lua_pushvalue(L, -3); /* key */ - lua_pushvalue(L, -3); /* value */ - lua_call(L, 2, 1); +static int foreachcont (lua_State *L) { + for (;;) { if (!lua_isnil(L, -1)) return 1; lua_pop(L, 2); /* remove value and result */ + if (lua_next(L, 1) == 0) /* no more elements? */ + return 0; + lua_pushvalue(L, 2); /* function */ + lua_pushvalue(L, -3); /* key */ + lua_pushvalue(L, -3); /* value */ + lua_callk(L, 2, 1, 0, foreachcont); } - return 0; } +static int foreach (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_pushnil(L); /* first key */ + lua_pushnil(L); /* first value */ + lua_pushnil(L); /* first "return" */ + return foreachcont(L); +} + + +#if defined(LUA_COMPAT_MAXN) static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); @@ -67,7 +78,11 @@ static int maxn (lua_State *L) { lua_pushnumber(L, max); return 1; } - +#else +static int maxn (lua_State *L) { + return luaL_error(L, "function 'maxn' is deprecated"); +} +#endif static int getn (lua_State *L) { lua_pushinteger(L, aux_getn(L, 1)); @@ -75,18 +90,6 @@ static int getn (lua_State *L) { } -static int setn (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); -#ifndef luaL_setn - luaL_setn(L, 1, luaL_checkint(L, 2)); -#else - luaL_error(L, LUA_QL("setn") " is obsolete"); -#endif - lua_pushvalue(L, 1); - return 1; -} - - static int tinsert (lua_State *L) { int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ @@ -109,7 +112,6 @@ static int tinsert (lua_State *L) { return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); } } - luaL_setn(L, 1, e); /* new size */ lua_rawseti(L, 1, pos); /* t[pos] = v */ return 0; } @@ -119,8 +121,7 @@ static int tremove (lua_State *L) { int e = aux_getn(L, 1); int pos = luaL_optint(L, 2, e); if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ - return 0; /* nothing to remove */ - luaL_setn(L, 1, e - 1); /* t.n = n-1 */ + return 0; /* nothing to remove */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ;pos= 1; top--) /* assign elements */ + lua_rawseti(L, LUA_ENVIRONINDEX, top); + lua_pushvalue(L, LUA_ENVIRONINDEX); /* return new table */ + return 1; +} + + +static int unpack (lua_State *L) { + int i, e, n; + luaL_checktype(L, 1, LUA_TTABLE); + i = luaL_optint(L, 2, 1); + e = luaL_opt(L, luaL_checkint, 3, (int)lua_rawlen(L, 1)); + if (i > e) return 0; /* empty range */ + n = e - i + 1; /* number of elements */ + if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ + return luaL_error(L, "too many results to unpack"); + lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ + while (i++ < e) /* push arg[i + 1...e] */ + lua_rawgeti(L, 1, i); + return n; +} + +/* }====================================================== */ + + /* ** {====================================================== ** Quicksort ** (based on `Algorithms in MODULA-3', Robert Sedgewick; ** Addison-Wesley, 1993.) +** ======================================================= */ @@ -187,7 +227,7 @@ static int sort_comp (lua_State *L, int a, int b) { return res; } else /* a < b? */ - return lua_lessthan(L, a, b); + return lua_compare(L, a, b, LUA_OPLT); } static void auxsort (lua_State *L, int l, int u) { @@ -224,12 +264,12 @@ static void auxsort (lua_State *L, int l, int u) { for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ /* repeat ++i until a[i] >= P */ while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>u) luaL_error(L, "invalid order function for sorting"); + if (i>=u) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* repeat --j until a[j] <= P */ while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j " +#define LUA_PROMPT2 ">> " +#endif + +#if !defined(LUA_PROGNAME) +#define LUA_PROGNAME "lua" +#endif + +#if !defined(LUA_MAXINPUT) +#define LUA_MAXINPUT 512 +#endif + +#if !defined(LUA_INIT_VAR) +#define LUA_INIT_VAR "LUA_INIT" +#endif + + +/* +** lua_stdin_is_tty detects whether the standard input is a 'tty' (that +** is, whether we're running lua interactively). +*/ +#if defined(LUA_USE_ISATTY) +#include +#define lua_stdin_is_tty() isatty(0) +#elif defined(LUA_WIN) +#include +#include +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) +#else +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + + +/* +** lua_readline defines how to show a prompt and then read a line from +** the standard input. +** lua_saveline defines how to "save" a read line in a "history". +** lua_freeline defines how to free a line read by lua_readline. +*/ +#if defined(LUA_USE_READLINE) + +#include +#include +#include +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) ((void)L, free(b)) + +#elif !defined(lua_readline) + +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } + +#endif + + + static lua_State *globalL = NULL; @@ -41,7 +104,7 @@ static void laction (int i) { static void print_usage (void) { fprintf(stderr, - "usage: %s [options] [script [args]].\n" + "usage: %s [options] [script [args]]\n" "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" " -l name require library " LUA_QL("name") "\n" @@ -63,32 +126,38 @@ static void l_message (const char *pname, const char *msg) { static int report (lua_State *L, int status) { - if (status && !lua_isnil(L, -1)) { + if (status != LUA_OK && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); + /* force a complete garbage collection in case of errors */ + lua_gc(L, LUA_GCCOLLECT, 0); } return status; } -static int traceback (lua_State *L) { - if (!lua_isstring(L, 1)) /* 'message' not a string? */ - return 1; /* keep it intact */ - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); - if (!lua_istable(L, -1)) { +/* the next function is called unprotected, so it must avoid errors */ +static void finalreport (lua_State *L, int status) { + if (status != LUA_OK) { + const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1) + : NULL; + if (msg == NULL) msg = "(error object is not a string)"; + l_message(progname, msg); lua_pop(L, 1); - return 1; } - lua_getfield(L, -1, "traceback"); - if (!lua_isfunction(L, -1)) { - lua_pop(L, 2); - return 1; +} + + +static int traceback (lua_State *L) { + const char *msg = lua_tostring(L, 1); + if (msg) + luaL_traceback(L, L, msg, 1); + else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */ + if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */ + lua_pushliteral(L, "(no error message)"); } - lua_pushvalue(L, 1); /* pass error message */ - lua_pushinteger(L, 2); /* skip this function and traceback */ - lua_call(L, 2, 1); /* call debug.traceback */ return 1; } @@ -98,18 +167,17 @@ static int docall (lua_State *L, int narg, int clear) { int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ + globalL = L; /* to be available to 'laction' */ signal(SIGINT, laction); status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); signal(SIGINT, SIG_DFL); lua_remove(L, base); /* remove traceback function */ - /* force a complete garbage collection in case of errors */ - if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); return status; } static void print_version (void) { - l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); + printf("%s\n", LUA_COPYRIGHT); } @@ -132,19 +200,21 @@ static int getargs (lua_State *L, char **argv, int n) { static int dofile (lua_State *L, const char *name) { - int status = luaL_loadfile(L, name) || docall(L, 0, 1); + int status = luaL_loadfile(L, name); + if (status == LUA_OK) status = docall(L, 0, 1); return report(L, status); } static int dostring (lua_State *L, const char *s, const char *name) { - int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); + int status = luaL_loadbuffer(L, s, strlen(s), name); + if (status == LUA_OK) status = docall(L, 0, 1); return report(L, status); } static int dolibrary (lua_State *L, const char *name) { - lua_getglobal(L, "require"); + lua_getfield(L, LUA_ENVIRONINDEX, "require"); lua_pushstring(L, name); return report(L, docall(L, 1, 1)); } @@ -152,20 +222,22 @@ static int dolibrary (lua_State *L, const char *name) { static const char *get_prompt (lua_State *L, int firstline) { const char *p; - lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + lua_getfield(L, LUA_ENVIRONINDEX, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ return p; } +/* mark in error messages for incomplete statements */ +#define mark "" +#define marklen (sizeof(mark) - 1) static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); - const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); - if (strstr(msg, LUA_QL("")) == tp) { + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, mark) == 0) { lua_pop(L, 1); return 1; } @@ -199,7 +271,9 @@ static int loadline (lua_State *L) { if (!pushline(L, 1)) return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + size_t l; + const char *line = lua_tolstring(L, 1, &l); + status = luaL_loadbuffer(L, line, l, "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ if (!pushline(L, 0)) /* no more input? */ return -1; @@ -218,19 +292,20 @@ static void dotty (lua_State *L) { const char *oldprogname = progname; progname = NULL; while ((status = loadline(L)) != -1) { - if (status == 0) status = docall(L, 0, 0); + if (status == LUA_OK) status = docall(L, 0, 0); report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); + if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); + lua_getfield(L, LUA_ENVIRONINDEX, "print"); lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK) l_message(progname, lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); } } lua_settop(L, 0); /* clear stack */ - fputs("\n", stdout); + luai_writestring("\n", 1); fflush(stdout); progname = oldprogname; } @@ -240,22 +315,22 @@ static int handle_script (lua_State *L, char **argv, int n) { int status; const char *fname; int narg = getargs(L, argv, n); /* collect arguments */ - lua_setglobal(L, "arg"); + lua_setfield(L, LUA_ENVIRONINDEX, "arg"); fname = argv[n]; - if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); lua_insert(L, -(narg+1)); - if (status == 0) + if (status == LUA_OK) status = docall(L, narg, 0); else - lua_pop(L, narg); + lua_pop(L, narg); return report(L, status); } /* check that argument has no extra characters at the end */ -#define notail(x) {if ((x)[2] != '\0') return -1;} +#define noextrachars(x) {if ((x)[2] != '\0') return -1;} static int collectargs (char **argv, int *pi, int *pv, int *pe) { @@ -265,15 +340,15 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { return i; switch (argv[i][1]) { /* option */ case '-': - notail(argv[i]); + noextrachars(argv[i]); return (argv[i+1] != NULL ? i+1 : 0); case '\0': return i; case 'i': - notail(argv[i]); + noextrachars(argv[i]); *pi = 1; /* go through */ case 'v': - notail(argv[i]); + noextrachars(argv[i]); *pv = 1; break; case 'e': @@ -301,92 +376,89 @@ static int runargs (lua_State *L, char **argv, int n) { const char *chunk = argv[i] + 2; if (*chunk == '\0') chunk = argv[++i]; lua_assert(chunk != NULL); - if (dostring(L, chunk, "=(command line)") != 0) - return 1; + if (dostring(L, chunk, "=(command line)") != LUA_OK) + return 0; break; } case 'l': { const char *filename = argv[i] + 2; if (*filename == '\0') filename = argv[++i]; lua_assert(filename != NULL); - if (dolibrary(L, filename)) - return 1; /* stop if file fails */ + if (dolibrary(L, filename) != LUA_OK) + return 0; /* stop if file fails */ break; } default: break; } } - return 0; + return 1; } static int handle_luainit (lua_State *L) { - const char *init = getenv(LUA_INIT); - if (init == NULL) return 0; /* status OK */ + const char *init = getenv(LUA_INIT_VAR); + if (init == NULL) return LUA_OK; else if (init[0] == '@') return dofile(L, init+1); else - return dostring(L, init, "=" LUA_INIT); + return dostring(L, init, "=" LUA_INIT_VAR); } -struct Smain { - int argc; - char **argv; - int status; -}; - - static int pmain (lua_State *L) { - struct Smain *s = (struct Smain *)lua_touserdata(L, 1); - char **argv = s->argv; + int argc = lua_tointeger(L, 1); + char **argv = (char **)lua_touserdata(L, 2); int script; int has_i = 0, has_v = 0, has_e = 0; - globalL = L; if (argv[0] && argv[0][0]) progname = argv[0]; - lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ - luaL_openlibs(L); /* open libraries */ - lua_gc(L, LUA_GCRESTART, 0); - s->status = handle_luainit(L); - if (s->status != 0) return 0; script = collectargs(argv, &has_i, &has_v, &has_e); if (script < 0) { /* invalid args? */ print_usage(); - s->status = 1; return 0; } if (has_v) print_version(); - s->status = runargs(L, argv, (script > 0) ? script : s->argc); - if (s->status != 0) return 0; - if (script) - s->status = handle_script(L, argv, script); - if (s->status != 0) return 0; - if (has_i) + /* open standard libraries */ + luaL_checkversion(L); + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ + luaL_openlibs(L); /* open libraries */ + lua_gc(L, LUA_GCRESTART, 0); + /* run LUA_INIT */ + if (handle_luainit(L) != LUA_OK) return 0; + /* execute arguments -e and -l */ + if (!runargs(L, argv, (script > 0) ? script : argc)) return 0; + /* execute main script (if there is one) */ + if (script && handle_script(L, argv, script) != LUA_OK) return 0; + if (has_i) /* -i option? */ dotty(L); - else if (script == 0 && !has_e && !has_v) { + else if (script == 0 && !has_e && !has_v) { /* no arguments? */ if (lua_stdin_is_tty()) { print_version(); dotty(L); } else dofile(L, NULL); /* executes stdin as a file */ } - return 0; + lua_pushboolean(L, 1); /* signal no errors */ + return 1; } int main (int argc, char **argv) { - int status; - struct Smain s; - lua_State *L = lua_open(); /* create state */ + static lua_CFunction ppmain = &pmain; + int status, result; + lua_State *L = luaL_newstate(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } - s.argc = argc; - s.argv = argv; - status = lua_cpcall(L, &pmain, &s); - report(L, status); + /* call 'pmain' in protected mode */ + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); /* calling function */ + lua_pushlightuserdata(L, &ppmain); + lua_pushinteger(L, argc); + lua_pushlightuserdata(L, argv); + status = lua_pcall(L, 3, 1, 0); + result = lua_toboolean(L, -1); /* get result */ + finalreport(L, status); lua_close(L); - return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; + return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/lua.h b/src/lua.h index e4bdfd3b94..b86ac6cf63 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,6 +1,6 @@ /* -** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ -** Lua - An Extensible Extension Language +** $Id: lua.h,v 1.260 2010/01/06 15:08:00 roberto Exp $ +** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ @@ -16,35 +16,36 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1" -#define LUA_RELEASE "Lua 5.1.4" -#define LUA_VERSION_NUM 501 -#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" +#define LUA_VERSION "Lua 5.2" +#define LUA_RELEASE "Lua 5.2.0 (work1)" +#define LUA_VERSION_NUM 502 +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" -/* mark for precompiled code (`Lua') */ -#define LUA_SIGNATURE "\033Lua" +/* mark for precompiled code ('Lua') */ +#define LUA_SIGNATURE "\033Lua" -/* option for multiple returns in `lua_pcall' and `lua_call' */ +/* option for multiple returns in 'lua_pcall' and 'lua_call' */ #define LUA_MULTRET (-1) /* ** pseudo-indices */ -#define LUA_REGISTRYINDEX (-10000) -#define LUA_ENVIRONINDEX (-10001) -#define LUA_GLOBALSINDEX (-10002) -#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) +#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX +#define LUA_ENVIRONINDEX (LUA_REGISTRYINDEX - 1) +#define lua_upvalueindex(i) (LUA_ENVIRONINDEX - (i)) -/* thread status; 0 is OK */ +/* thread status */ +#define LUA_OK 0 #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 -#define LUA_ERRERR 5 +#define LUA_ERRGCMM 5 +#define LUA_ERRERR 6 typedef struct lua_State lua_State; @@ -87,12 +88,11 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); #define LUA_MINSTACK 20 -/* -** generic extra include file -*/ -#if defined(LUA_USER_H) -#include LUA_USER_H -#endif +/* predefined values in the registry */ +#define LUA_RIDX_MAINTHREAD 1 +#define LUA_RIDX_CPCALL 2 +#define LUA_RIDX_GLOBALS 3 +#define LUA_RIDX_LAST LUA_RIDX_GLOBALS /* type of numbers in Lua */ @@ -104,6 +104,15 @@ typedef LUA_INTEGER lua_Integer; +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + + /* ** state manipulation */ @@ -114,6 +123,9 @@ LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); +LUA_API const lua_Number *(lua_version) (lua_State *L); + + /* ** basic stack manipulation */ @@ -123,6 +135,7 @@ LUA_API void (lua_pushvalue) (lua_State *L, int idx); LUA_API void (lua_remove) (lua_State *L, int idx); LUA_API void (lua_insert) (lua_State *L, int idx); LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); LUA_API int (lua_checkstack) (lua_State *L, int sz); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); @@ -139,29 +152,47 @@ LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); -LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); - LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API size_t (lua_rawlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); LUA_API const void *(lua_topointer) (lua_State *L, int idx); +/* +** Comparison and arithmetic functions +*/ + +#define LUA_OPADD 0 /* ORDER TM */ +#define LUA_OPSUB 1 +#define LUA_OPMUL 2 +#define LUA_OPDIV 3 +#define LUA_OPMOD 4 +#define LUA_OPPOW 5 +#define LUA_OPUNM 6 + +LUA_API void (lua_arith) (lua_State *L, int op); + +#define LUA_OPEQ 0 +#define LUA_OPLT 1 +#define LUA_OPLE 2 + +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); + + /* ** push functions (C -> stack) */ -LUA_API void (lua_pushnil) (lua_State *L); -LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); -LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); -LUA_API void (lua_pushstring) (lua_State *L, const char *s); +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); @@ -196,11 +227,18 @@ LUA_API int (lua_setfenv) (lua_State *L, int idx); /* -** `load' and `call' functions (load and run Lua code) +** 'load' and 'call' functions (load and run Lua code) */ -LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); -LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); -LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx, + lua_CFunction k); +#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) + +LUA_API int (lua_getctx) (lua_State *L, int *ctx); + +LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + int ctx, lua_CFunction k); +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) + LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname); @@ -210,7 +248,9 @@ LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); /* ** coroutine functions */ -LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, + lua_CFunction k); +#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) LUA_API int (lua_resume) (lua_State *L, int narg); LUA_API int (lua_status) (lua_State *L); @@ -226,6 +266,7 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 +#define LUA_GCISRUNNING 8 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -239,13 +280,14 @@ LUA_API int (lua_error) (lua_State *L); LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); +LUA_API void (lua_len) (lua_State *L, int idx); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); -LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); +LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); -/* +/* ** =============================================================== ** some useful macros ** =============================================================== @@ -255,11 +297,13 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); #define lua_newtable(L) lua_createtable(L, 0, 0) -#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) +#define lua_setglobal(L,s) lua_setfield(L, LUA_ENVIRONINDEX, (s)) +#define lua_getglobal(L,s) lua_getfield(L, LUA_ENVIRONINDEX, (s)) -#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) +#define lua_register(L,n,f) \ + (lua_pushcfunction(L, (f)), lua_setfield(L, LUA_ENVIRONINDEX, (n))) -#define lua_strlen(L,i) lua_objlen(L, (i)) +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) @@ -273,31 +317,13 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); #define lua_pushliteral(L, s) \ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) -#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) -#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_pushglobaltable(L) \ + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) -/* -** compatibility macros and functions -*/ - -#define lua_open() luaL_newstate() - -#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) - -#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) - -#define lua_Chunkreader lua_Reader -#define lua_Chunkwriter lua_Writer - - -/* hack */ -LUA_API void lua_setlevel (lua_State *from, lua_State *to); - - /* ** {====================================================================== ** Debug API @@ -312,7 +338,7 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to); #define LUA_HOOKRET 1 #define LUA_HOOKLINE 2 #define LUA_HOOKCOUNT 3 -#define LUA_HOOKTAILRET 4 +#define LUA_HOOKTAILCALL 4 /* @@ -326,36 +352,43 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to); typedef struct lua_Debug lua_Debug; /* activation record */ -/* Functions to be called by the debuger in specific events */ +/* Functions to be called by the debugger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); -LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); +LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); +LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); +LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); + +LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); +LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); -LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); -LUA_API lua_Hook lua_gethook (lua_State *L); -LUA_API int lua_gethookmask (lua_State *L); -LUA_API int lua_gethookcount (lua_State *L); +LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook (lua_gethook) (lua_State *L); +LUA_API int (lua_gethookmask) (lua_State *L); +LUA_API int (lua_gethookcount) (lua_State *L); struct lua_Debug { int event; const char *name; /* (n) */ - const char *namewhat; /* (n) `global', `local', `field', `method' */ - const char *what; /* (S) `Lua', `C', `main', `tail' */ + const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ + const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ const char *source; /* (S) */ int currentline; /* (l) */ - int nups; /* (u) number of upvalues */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ + unsigned char nups; /* (u) number of upvalues */ + unsigned char nparams;/* (u) number of parameters */ + char isvararg; /* (u) */ + char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ - int i_ci; /* active function */ + struct CallInfo *i_ci; /* active function */ }; /* }====================================================================== */ diff --git a/etc/lua.hpp b/src/lua.hpp similarity index 100% rename from etc/lua.hpp rename to src/lua.hpp diff --git a/src/luac.c b/src/luac.c index d07017391b..451bfffce1 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ +** $Id: luac.c,v 1.57 2008/03/26 13:40:18 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ #include "lundump.h" #define PROGNAME "luac" /* default program name */ -#define OUTPUT PROGNAME ".out" /* default output file */ +#define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ @@ -52,20 +52,20 @@ static void usage(const char* message) else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, - "usage: %s [options] [filenames].\n" + "usage: %s [options] [filenames]\n" "Available options are:\n" - " - process stdin\n" " -l list\n" " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" - " -- stop handling options\n", - progname,Output); + " -- stop handling options\n" + " - process stdin and stop handling options\n" + ,progname,Output); exit(EXIT_FAILURE); } -#define IS(s) (strcmp(argv[i],s)==0) +#define IS(s) (strcmp(argv[i],s)==0) static int doargs(int argc, char* argv[]) { @@ -108,7 +108,7 @@ static int doargs(int argc, char* argv[]) } if (version) { - printf("%s %s\n",LUA_RELEASE,LUA_COPYRIGHT); + printf("%s\n",LUA_COPYRIGHT); if (version==argc-1) exit(EXIT_SUCCESS); } return i; @@ -183,6 +183,13 @@ static int pmain(lua_State* L) return 0; } +LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); + lua_pushlightuserdata(L, &func); + lua_pushlightuserdata(L, ud); + return lua_pcall(L, 2, 0, 0); +} + int main(int argc, char* argv[]) { lua_State* L; @@ -190,7 +197,7 @@ int main(int argc, char* argv[]) int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); - L=lua_open(); + L=luaL_newstate(); if (L==NULL) fatal("not enough memory for state"); s.argc=argc; s.argv=argv; diff --git a/src/luaconf.h b/src/luaconf.h index e2cb26163a..9cd0beb2fb 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $ +** $Id: luaconf.h,v 1.127 2010/01/06 15:15:04 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,7 @@ ** CHANGE it (define it) if you want Lua to avoid the use of any ** non-ansi feature or library. */ -#if defined(__STRICT_ANSI__) +#if !defined(LUA_ANSI) && defined(__STRICT_ANSI__) #define LUA_ANSI #endif @@ -33,6 +33,13 @@ #define LUA_WIN #endif +#if defined(LUA_WIN) +#include +#define LUA_DL_DLL +#endif + + + #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ @@ -41,13 +48,14 @@ #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX -#define LUA_DL_DYLD /* does not need extra library */ +#define LUA_USE_DLOPEN +#define LUA_USE_READLINE /* needs some extra libraries */ #endif /* -@@ LUA_USE_POSIX includes all functionallity listed as X/Open System +@@ LUA_USE_POSIX includes all functionality listed as X/Open System @* Interfaces Extension (XSI). ** CHANGE it (define it) if your system is XSI compatible. */ @@ -59,17 +67,6 @@ #endif -/* -@@ LUA_PATH and LUA_CPATH are the names of the environment variables that -@* Lua check to set its paths. -@@ LUA_INIT is the name of the environment variable that Lua -@* checks for initialization code. -** CHANGE them if you want different names. -*/ -#define LUA_PATH "LUA_PATH" -#define LUA_CPATH "LUA_CPATH" -#define LUA_INIT "LUA_INIT" - /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for @@ -88,20 +85,20 @@ #define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" #define LUA_PATH_DEFAULT \ - ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua" #define LUA_CPATH_DEFAULT \ - ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" + LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" #else #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/5.1/" #define LUA_CDIR LUA_ROOT "lib/lua/5.1/" #define LUA_PATH_DEFAULT \ - "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" #define LUA_CPATH_DEFAULT \ - "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" #endif @@ -117,35 +114,10 @@ #endif -/* -@@ LUA_PATHSEP is the character that separates templates in a path. -@@ LUA_PATH_MARK is the string that marks the substitution points in a -@* template. -@@ LUA_EXECDIR in a Windows path is replaced by the executable's -@* directory. -@@ LUA_IGMARK is a mark to ignore all before it when bulding the -@* luaopen_ function name. -** CHANGE them if for some reason your system cannot use those -** characters. (E.g., if one of those characters is a common character -** in file/directory names.) Probably you do not need to change them. -*/ -#define LUA_PATHSEP ";" -#define LUA_PATH_MARK "?" -#define LUA_EXECDIR "!" -#define LUA_IGMARK "-" - - -/* -@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. -** CHANGE that if ptrdiff_t is not adequate on your machine. (On most -** machines, ptrdiff_t gives a good choice between int or long.) -*/ -#define LUA_INTEGER ptrdiff_t - - /* @@ LUA_API is a mark for all core API functions. -@@ LUALIB_API is a mark for all standard library functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. ** CHANGE them if you need to define those functions in some special way. ** For instance, if you want to create one Windows DLL with the core and ** the libraries, you may want to use the following definition (define @@ -167,29 +139,38 @@ /* more often than not the libs go together with the core */ #define LUALIB_API LUA_API +#define LUAMOD_API LUALIB_API /* @@ LUAI_FUNC is a mark for all extern functions that are not to be @* exported to outside modules. -@@ LUAI_DATA is a mark for all extern (const) variables that are not to -@* be exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables +@* that are not to be exported to outside modules (LUAI_DDEF for +@* definitions and LUAI_DDEC for declarations). ** CHANGE them if you need to mark them in some special way. Elf/gcc ** (versions 3.2 and later) mark them as "hidden" to optimize access -** when Lua is compiled as a shared library. +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. */ #if defined(luaall_c) #define LUAI_FUNC static -#define LUAI_DATA /* empty */ +#define LUAI_DDEC static +#define LUAI_DDEF static #elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) #define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#define LUAI_DATA LUAI_FUNC +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ #else #define LUAI_FUNC extern -#define LUAI_DATA extern +#define LUAI_DDEC extern +#define LUAI_DDEF /* empty */ #endif @@ -211,175 +192,86 @@ /* -** {================================================================== -** Stand-alone configuration -** =================================================================== +@@ luai_writestring defines how 'print' prints its results. +** CHANGE it if your system does not have a useful stdout. */ +#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#if defined(lua_c) || defined(luaall_c) -/* -@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that -@* is, whether we're running lua interactively). -** CHANGE it if you have a better definition for non-POSIX/non-Windows -** systems. -*/ -#if defined(LUA_USE_ISATTY) -#include -#define lua_stdin_is_tty() isatty(0) -#elif defined(LUA_WIN) -#include -#include -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) -#else -#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ -#endif -/* -@@ LUA_PROMPT is the default prompt used by stand-alone Lua. -@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. -** CHANGE them if you want different prompts. (You can also change the -** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) -*/ -#define LUA_PROMPT "> " -#define LUA_PROMPT2 ">> " - /* -@@ LUA_PROGNAME is the default name for the stand-alone Lua program. -** CHANGE it if your stand-alone interpreter has a different name and -** your system is not able to detect that name automatically. +** {================================================================== +** Compatibility with previous versions +** =================================================================== */ -#define LUA_PROGNAME "lua" - /* -@@ LUA_MAXINPUT is the maximum length for an input line in the -@* stand-alone interpreter. -** CHANGE it if you need longer lines. +@@ LUA_COMPAT_ALL controls all compatibility options. +** You can define it to get all options, or change specific options +** to fit your specific needs. */ -#define LUA_MAXINPUT 512 - +#if defined(LUA_COMPAT_ALL) /* -@@ lua_readline defines how to show a prompt and then read a line from -@* the standard input. -@@ lua_saveline defines how to "save" a read line in a "history". -@@ lua_freeline defines how to free a line read by lua_readline. -** CHANGE them if you want to improve this functionality (e.g., by using -** GNU readline and history facilities). +@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. +** You can replace it with 'table.unpack'. */ -#if defined(LUA_USE_READLINE) -#include -#include -#include -#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) -#define lua_saveline(L,idx) \ - if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ - add_history(lua_tostring(L, idx)); /* add it to history */ -#define lua_freeline(L,b) ((void)L, free(b)) -#else -#define lua_readline(L,b,p) \ - ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ - fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } -#define lua_freeline(L,b) { (void)L; (void)b; } -#endif - -#endif - -/* }================================================================== */ - +#define LUA_COMPAT_UNPACK /* -@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles -@* as a percentage. -** CHANGE it if you want the GC to run faster or slower (higher values -** mean larger pauses which mean slower collection.) You can also change -** this value dynamically. +@@ LUA_COMPAT_CPCALL controls the presence of function 'lua_cpcall'. +** You can replace it with the preregistered function 'cpcall'. */ -#define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ - +#define LUA_COMPAT_CPCALL +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* -@@ LUAI_GCMUL defines the default speed of garbage collection relative to -@* memory allocation as a percentage. -** CHANGE it if you want to change the granularity of the garbage -** collection. (Higher values mean coarser collections. 0 represents -** infinity, where each step performs a full collection.) You can also -** change this value dynamically. +@@ LUA_COMPAT_FENV controls the presence of functions 'setfenv/getfenv'. +** You can replace them with lexical environments, 'loadin', or the +** debug library. */ -#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ - - +#define LUA_COMPAT_FENV /* -@@ LUA_COMPAT_GETN controls compatibility with old getn behavior. -** CHANGE it (define it) if you want exact compatibility with the -** behavior of setn/getn in Lua 5.0. +@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. +** You can rewrite 'log10(x)' as 'log(x, 10)'. */ -#undef LUA_COMPAT_GETN +#define LUA_COMPAT_LOG10 /* -@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. -** CHANGE it to undefined as soon as you do not need a global 'loadlib' -** function (the function is still available as 'package.loadlib'). +@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. */ -#undef LUA_COMPAT_LOADLIB +#define LUA_COMPAT_MAXN /* -@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. -** CHANGE it to undefined as soon as your programs use only '...' to -** access vararg parameters (instead of the old 'arg' table). +@@ LUA_COMPAT_DEBUGLIB controls compatibility with preloading +** the debug library. +** You should add 'require"debug"' everywhere you need the debug +** library. */ -#define LUA_COMPAT_VARARG +#define LUA_COMPAT_DEBUGLIB /* -@@ LUA_COMPAT_MOD controls compatibility with old math.mod function. -** CHANGE it to undefined as soon as your programs use 'math.fmod' or -** the new '%' operator instead of 'math.mod'. +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. */ -#define LUA_COMPAT_MOD +#define lua_strlen(L,i) lua_rawlen(L, (i)) -/* -@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting -@* facility. -** CHANGE it to 2 if you want the old behaviour, or undefine it to turn -** off the advisory error when nesting [[...]]. -*/ -#define LUA_COMPAT_LSTR 1 +#define lua_objlen(L,i) lua_rawlen(L, (i)) -/* -@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. -** CHANGE it to undefined as soon as you rename 'string.gfind' to -** 'string.gmatch'. -*/ -#define LUA_COMPAT_GFIND +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) -/* -@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' -@* behavior. -** CHANGE it to undefined as soon as you replace to 'luaL_register' -** your uses of 'luaL_openlib' -*/ -#define LUA_COMPAT_OPENLIB +/* compatibility with previous wrong spelling */ +#define luaL_typerror luaL_typeerror +#endif +/* }================================================================== */ -/* -@@ luai_apicheck is the assert macro used by the Lua-C API. -** CHANGE luai_apicheck if you want Lua to perform some checks in the -** parameters it gets from API calls. This may slow down the interpreter -** a bit, but may be quite useful when debugging C code that interfaces -** with Lua. A useful redefinition is to use assert.h. -*/ -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(L,o) { (void)L; assert(o); } -#else -#define luai_apicheck(L,o) { (void)L; } -#endif /* @@ -399,51 +291,41 @@ /* -@@ LUAI_UINT32 is an unsigned integer with at least 32 bits. -@@ LUAI_INT32 is an signed integer with at least 32 bits. +@@ LUA_INT32 is an signed integer with exactly 32 bits. @@ LUAI_UMEM is an unsigned integer big enough to count the total @* memory used by Lua. @@ LUAI_MEM is a signed integer big enough to count the total memory @* used by Lua. ** CHANGE here if for some weird reason the default definitions are not -** good enough for your machine. (The definitions in the 'else' -** part always works, but may waste space on machines with 64-bit -** longs.) Probably you do not need to change this. +** good enough for your machine. Probably you do not need to change +** this. */ #if LUAI_BITSINT >= 32 -#define LUAI_UINT32 unsigned int -#define LUAI_INT32 int -#define LUAI_MAXINT32 INT_MAX +#define LUA_INT32 int #define LUAI_UMEM size_t #define LUAI_MEM ptrdiff_t #else /* 16-bit ints */ -#define LUAI_UINT32 unsigned long -#define LUAI_INT32 long -#define LUAI_MAXINT32 LONG_MAX +#define LUA_INT32 long #define LUAI_UMEM unsigned long #define LUAI_MEM long #endif /* -@@ LUAI_MAXCALLS limits the number of nested calls. -** CHANGE it if you need really deep recursive calls. This limit is -** arbitrary; its only purpose is to stop infinite recursion before -** exhausting memory. +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua to consume unlimited stack +** space (and to reserve some numbers for pseudo-indices). */ -#define LUAI_MAXCALLS 20000 +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif - -/* -@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function -@* can use. -** CHANGE it if you need lots of (Lua) stack space for your C -** functions. This limit is arbitrary; its only purpose is to stop C -** functions to consume unlimited stack space. (must be smaller than -** -LUA_REGISTRYINDEX) -*/ -#define LUAI_MAXCSTACK 8000 +/* reserve some space for error handling */ +#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) @@ -461,27 +343,6 @@ */ -/* -@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and -@* syntactical nested non-terminals in a program. -*/ -#define LUAI_MAXCCALLS 200 - - -/* -@@ LUAI_MAXVARS is the maximum number of local variables per function -@* (must be smaller than 250). -*/ -#define LUAI_MAXVARS 200 - - -/* -@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function -@* (must be smaller than 250). -*/ -#define LUAI_MAXUPVALUES 60 - - /* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. */ @@ -528,25 +389,44 @@ /* @@ The luai_num* macros define the primitive operations over numbers. */ -#if defined(LUA_CORE) + +/* the following operations need the math library */ +#if defined(lobject_c) || defined(lvm_c) || defined(luaall_c) #include -#define luai_numadd(a,b) ((a)+(b)) -#define luai_numsub(a,b) ((a)-(b)) -#define luai_nummul(a,b) ((a)*(b)) -#define luai_numdiv(a,b) ((a)/(b)) -#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) -#define luai_numpow(a,b) (pow(a,b)) -#define luai_numunm(a) (-(a)) +#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) +#define luai_numpow(L,a,b) (pow(a,b)) +#endif + +/* these are quite standard operations */ +#if defined(LUA_CORE) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numdiv(L,a,b) ((a)/(b)) +#define luai_numunm(L,a) (-(a)) #define luai_numeq(a,b) ((a)==(b)) -#define luai_numlt(a,b) ((a)<(b)) -#define luai_numle(a,b) ((a)<=(b)) -#define luai_numisnan(a) (!luai_numeq((a), (a))) +#define luai_numlt(L,a,b) ((a)<(b)) +#define luai_numle(L,a,b) ((a)<=(b)) +#define luai_numisnan(L,a) (!luai_numeq((a), (a))) #endif + +/* +@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. +** CHANGE that if ptrdiff_t is not adequate on your machine. (On most +** machines, ptrdiff_t gives a good choice between int or long.) +*/ +#define LUA_INTEGER ptrdiff_t + + /* @@ lua_number2int is a macro to convert lua_Number to int. -@@ lua_number2integer is a macro to convert lua_Number to lua_Integer. +@@ lua_number2integer is a macro to convert lua_Number to lUA_INTEGER. +@@ lua_number2uint is a macro to convert a lua_Number to an unsigned +@* LUA_INT32. +@@ lua_uint2number is a macro to convert an unsigned LUA_INT32 +@* to a lua_Number. ** CHANGE them if you know a faster way to convert a lua_Number to ** int (with any rounding method and without throwing errors) in your ** system. In Pentium machines, a naive typecast from double to int @@ -555,7 +435,7 @@ /* On a Pentium, resort to a trick */ #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ - (defined(__i386) || defined (_M_IX86) || defined(__i386__)) + (defined(__i386) || defined (_M_IX86) || defined(__i386__)) /* On a Microsoft compiler, use assembler */ #if defined(_MSC_VER) @@ -563,190 +443,54 @@ #define lua_number2int(i,d) __asm fld d __asm fistp i #define lua_number2integer(i,n) lua_number2int(i, n) +#else /* the next trick should work on any Pentium, but sometimes clashes with a DirectX idiosyncrasy */ -#else union luai_Cast { double l_d; long l_l; }; #define lua_number2int(i,d) \ { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } #define lua_number2integer(i,n) lua_number2int(i, n) +#define lua_number2uint(i,n) lua_number2int(i, n) #endif -/* this option always works, but may be slow */ #else +/* this option always works, but may be slow */ #define lua_number2int(i,d) ((i)=(int)(d)) -#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) +#define lua_number2integer(i,d) ((i)=(LUA_INTEGER)(d)) +#define lua_number2uint(i,d) ((i)=(unsigned LUA_INT32)(d)) #endif -/* }================================================================== */ - - -/* -@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. -** CHANGE it if your system requires alignments larger than double. (For -** instance, if your system supports long doubles and they must be -** aligned in 16-byte boundaries, then you should add long double in the -** union.) Probably you do not need to change this. -*/ -#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } - - -/* -@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. -** CHANGE them if you prefer to use longjmp/setjmp even with C++ -** or if want/don't to use _longjmp/_setjmp instead of regular -** longjmp/setjmp. By default, Lua handles errors with exceptions when -** compiling as C++ code, with _longjmp/_setjmp when asked to use them, -** and with longjmp/setjmp otherwise. -*/ -#if defined(__cplusplus) -/* C++ exceptions */ -#define LUAI_THROW(L,c) throw(c) -#define LUAI_TRY(L,c,a) try { a } catch(...) \ - { if ((c)->status == 0) (c)->status = -1; } -#define luai_jmpbuf int /* dummy variable */ - -#elif defined(LUA_USE_ULONGJMP) -/* in Unix, try _longjmp/_setjmp (more efficient) */ -#define LUAI_THROW(L,c) _longjmp((c)->b, 1) -#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } -#define luai_jmpbuf jmp_buf - -#else -/* default handling with long jumps */ -#define LUAI_THROW(L,c) longjmp((c)->b, 1) -#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } -#define luai_jmpbuf jmp_buf - -#endif - - -/* -@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern -@* can do during pattern-matching. -** CHANGE it if you need more captures. This limit is arbitrary. -*/ -#define LUA_MAXCAPTURES 32 - -/* -@@ lua_tmpnam is the function that the OS library uses to create a -@* temporary name. -@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. -** CHANGE them if you have an alternative to tmpnam (which is considered -** insecure) or if you want the original tmpnam anyway. By default, Lua -** uses tmpnam except when POSIX is available, where it uses mkstemp. -*/ -#if defined(loslib_c) || defined(luaall_c) - -#if defined(LUA_USE_MKSTEMP) -#include -#define LUA_TMPNAMBUFSIZE 32 -#define lua_tmpnam(b,e) { \ - strcpy(b, "/tmp/lua_XXXXXX"); \ - e = mkstemp(b); \ - if (e != -1) close(e); \ - e = (e == -1); } - -#else -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } -#endif - -#endif +/* on several machines, coercion from unsigned to double is too slow, + so avoid that if possible */ +#define lua_uint2number(u) \ + ((LUA_INT32)(u) < 0 ? (lua_Number)(u) : (lua_Number)(LUA_INT32)(u)) /* -@@ lua_popen spawns a new process connected to the current one through -@* the file streams. -** CHANGE it if you have a way to implement it in your system. +@@ luai_hashnum is a macro do hash a lua_Number value into an integer. +@* The hash must be deterministic and give reasonable values for +@* both small and large values (outside the range of integers). +@* It is used only in ltable.c. */ -#if defined(LUA_USE_POPEN) - -#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) -#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) - -#elif defined(LUA_WIN) -#define lua_popen(L,c,m) ((void)L, _popen(c,m)) -#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) +#if defined(ltable_c) || defined(luaall_c) -#else +#include +#include -#define lua_popen(L,c,m) ((void)((void)c, m), \ - luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) -#define lua_pclose(L,file) ((void)((void)L, file), 0) +#define luai_hashnum(i,d) { int e; \ + d = frexp(d, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ + lua_number2int(i, d); i += e; } #endif -/* -@@ LUA_DL_* define which dynamic-library system Lua should use. -** CHANGE here if Lua has problems choosing the appropriate -** dynamic-library system for your platform (either Windows' DLL, Mac's -** dyld, or Unix's dlopen). If your system is some kind of Unix, there -** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for -** it. To use dlopen you also need to adapt the src/Makefile (probably -** adding -ldl to the linker options), so Lua does not select it -** automatically. (When you change the makefile to add -ldl, you must -** also add -DLUA_USE_DLOPEN.) -** If you do not want any kind of dynamic library, undefine all these -** options. -** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. -*/ -#if defined(LUA_USE_DLOPEN) -#define LUA_DL_DLOPEN -#endif - -#if defined(LUA_WIN) -#define LUA_DL_DLL -#endif - - -/* -@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State -@* (the data goes just *before* the lua_State pointer). -** CHANGE (define) this if you really need that. This value must be -** a multiple of the maximum alignment required for your machine. -*/ -#define LUAI_EXTRASPACE 0 - - -/* -@@ luai_userstate* allow user-specific actions on threads. -** CHANGE them if you defined LUAI_EXTRASPACE and need to do something -** extra when a thread is created/deleted/resumed/yielded. -*/ -#define luai_userstateopen(L) ((void)L) -#define luai_userstateclose(L) ((void)L) -#define luai_userstatethread(L,L1) ((void)L) -#define luai_userstatefree(L) ((void)L) -#define luai_userstateresume(L,n) ((void)L) -#define luai_userstateyield(L,n) ((void)L) - - -/* -@@ LUA_INTFRMLEN is the length modifier for integer conversions -@* in 'string.format'. -@@ LUA_INTFRM_T is the integer type correspoding to the previous length -@* modifier. -** CHANGE them if your system supports long long or does not support long. -*/ - -#if defined(LUA_USELONGLONG) - -#define LUA_INTFRMLEN "ll" -#define LUA_INTFRM_T long long - -#else - -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long +/* }================================================================== */ -#endif diff --git a/src/lualib.h b/src/lualib.h index 469417f670..d5e4ba9d02 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lualib.h,v 1.39 2009/11/24 12:05:44 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -16,32 +16,35 @@ #define LUA_COLIBNAME "coroutine" -LUALIB_API int (luaopen_base) (lua_State *L); +LUAMOD_API int (luaopen_base) (lua_State *L); #define LUA_TABLIBNAME "table" -LUALIB_API int (luaopen_table) (lua_State *L); +LUAMOD_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" -LUALIB_API int (luaopen_io) (lua_State *L); +LUAMOD_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" -LUALIB_API int (luaopen_os) (lua_State *L); +LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" -LUALIB_API int (luaopen_string) (lua_State *L); +LUAMOD_API int (luaopen_string) (lua_State *L); + +#define LUA_BITLIBNAME "bit" +LUAMOD_API int (luaopen_bit) (lua_State *L); #define LUA_MATHLIBNAME "math" -LUALIB_API int (luaopen_math) (lua_State *L); +LUAMOD_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" -LUALIB_API int (luaopen_debug) (lua_State *L); +LUAMOD_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" -LUALIB_API int (luaopen_package) (lua_State *L); +LUAMOD_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ -LUALIB_API void (luaL_openlibs) (lua_State *L); +LUALIB_API void (luaL_openlibs) (lua_State *L); diff --git a/src/lundump.c b/src/lundump.c index 8010a45795..244d6e52b6 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $ +** $Id: lundump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -29,7 +29,6 @@ typedef struct { #ifdef LUAC_TRUST_BINARIES #define IF(c,s) -#define error(S,s) #else #define IF(c,s) if (c) error(S,s) @@ -111,10 +110,10 @@ static void LoadConstants(LoadState* S, Proto* f) switch (t) { case LUA_TNIL: - setnilvalue(o); + setnilvalue(o); break; case LUA_TBOOLEAN: - setbvalue(o,LoadChar(S)!=0); + setbvalue(o,LoadChar(S)!=0); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); @@ -123,7 +122,7 @@ static void LoadConstants(LoadState* S, Proto* f) setsvalue2n(S->L,o,LoadString(S)); break; default: - error(S,"bad constant"); + IF (1, "bad constant"); break; } } @@ -134,6 +133,20 @@ static void LoadConstants(LoadState* S, Proto* f) for (i=0; ip[i]=LoadFunction(S,f->source); } +static void LoadUpvalues(LoadState* S, Proto* f) +{ + int i,n; + n=LoadInt(S); + f->upvalues=luaM_newvector(S->L,n,Upvaldesc); + f->sizeupvalues=n; + for (i=0; iupvalues[i].name=NULL; + for (i=0; iupvalues[i].instack=LoadChar(S); + f->upvalues[i].idx=LoadChar(S); + } +} + static void LoadDebug(LoadState* S, Proto* f) { int i,n; @@ -152,31 +165,28 @@ static void LoadDebug(LoadState* S, Proto* f) f->locvars[i].endpc=LoadInt(S); } n=LoadInt(S); - f->upvalues=luaM_newvector(S->L,n,TString*); - f->sizeupvalues=n; - for (i=0; iupvalues[i]=NULL; - for (i=0; iupvalues[i]=LoadString(S); + for (i=0; iupvalues[i].name=LoadString(S); } static Proto* LoadFunction(LoadState* S, TString* p) { Proto* f; - if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep"); + if (++G(S->L)->nCcalls > LUAI_MAXCCALLS) error(S, "function nest too deep"); f=luaF_newproto(S->L); setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); - f->nups=LoadByte(S); f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); + f->envreg=LoadByte(S); LoadCode(S,f); LoadConstants(S,f); + LoadUpvalues(S,f); LoadDebug(S,f); - IF (!luaG_checkcode(f), "bad code"); S->L->top--; - S->L->nCcalls--; + G(S->L)->nCcalls--; return f; } diff --git a/src/lundump.h b/src/lundump.h index c80189dbff..5b19104fd0 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lundump.h,v 1.37 2005/11/16 11:55:07 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ diff --git a/src/lvm.c b/src/lvm.c index ee3256ab94..a315088848 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ +** $Id: lvm.c,v 2.102 2009/12/17 16:20:01 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -57,51 +57,41 @@ int luaV_tostring (lua_State *L, StkId obj) { } -static void traceexec (lua_State *L, const Instruction *pc) { +static void traceexec (lua_State *L) { + CallInfo *ci = L->ci; lu_byte mask = L->hookmask; - const Instruction *oldpc = L->savedpc; - L->savedpc = pc; if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { resethookcount(L); - luaD_callhook(L, LUA_HOOKCOUNT, -1); + luaD_hook(L, LUA_HOOKCOUNT, -1); } if (mask & LUA_MASKLINE) { - Proto *p = ci_func(L->ci)->l.p; - int npc = pcRel(pc, p); - int newline = getline(p, npc); - /* call linehook when enter a new function, when jump back (loop), - or when enter a new line */ - if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) - luaD_callhook(L, LUA_HOOKLINE, newline); + Proto *p = ci_func(ci)->l.p; + int npc = pcRel(ci->u.l.savedpc, p); + int newline = getfuncline(p, npc); + if (npc == 0 || /* call linehook when enter a new function, */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ + luaD_hook(L, LUA_HOOKLINE, newline); } + L->oldpc = ci->u.l.savedpc; } -static void callTMres (lua_State *L, StkId res, const TValue *f, - const TValue *p1, const TValue *p2) { - ptrdiff_t result = savestack(L, res); - setobj2s(L, L->top, f); /* push function */ - setobj2s(L, L->top+1, p1); /* 1st argument */ - setobj2s(L, L->top+2, p2); /* 2nd argument */ - luaD_checkstack(L, 3); - L->top += 3; - luaD_call(L, L->top - 3, 1); - res = restorestack(L, result); - L->top--; - setobjs2s(L, res, L->top); -} - - - static void callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, const TValue *p3) { - setobj2s(L, L->top, f); /* push function */ - setobj2s(L, L->top+1, p1); /* 1st argument */ - setobj2s(L, L->top+2, p2); /* 2nd argument */ - setobj2s(L, L->top+3, p3); /* 3th argument */ - luaD_checkstack(L, 4); - L->top += 4; - luaD_call(L, L->top - 4, 0); + const TValue *p2, TValue *p3, int hasres) { + ptrdiff_t result = savestack(L, p3); + setobj2s(L, L->top++, f); /* push function */ + setobj2s(L, L->top++, p1); /* 1st argument */ + setobj2s(L, L->top++, p2); /* 2nd argument */ + if (!hasres) /* no result? 'p3' is third argument */ + setobj2s(L, L->top++, p3); /* 3th argument */ + luaD_checkstack(L, 0); + /* metamethod may yield only when called from Lua code */ + luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); + if (hasres) { /* if has result, move it to its place */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } } @@ -122,10 +112,10 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { - callTMres(L, val, tm, t, key); + callTM(L, tm, t, key, val, 1); return; } - t = tm; /* else repeat with `tm' */ + t = tm; /* else repeat with 'tm' */ } luaG_runerror(L, "loop in gettable"); } @@ -133,6 +123,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; + TValue temp; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ @@ -149,10 +140,12 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { - callTM(L, tm, t, key, val); + callTM(L, tm, t, key, val, 0); return; } - t = tm; /* else repeat with `tm' */ + /* else repeat with 'tm' */ + setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ + t = &temp; } luaG_runerror(L, "loop in settable"); } @@ -164,7 +157,7 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; - callTMres(L, res, tm, p1, p2); + callTM(L, tm, p1, p2, res, 1); return 1; } @@ -191,7 +184,7 @@ static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; - callTMres(L, L->top, tm1, p1, p2); + callTM(L, tm1, p1, p2, L->top, 1); return !l_isfalse(L->top); } @@ -223,7 +216,7 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numlt(nvalue(l), nvalue(r)); + return luai_numlt(L, nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) @@ -232,12 +225,12 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { } -static int lessequal (lua_State *L, const TValue *l, const TValue *r) { +int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) - return luai_numle(nvalue(l), nvalue(r)); + return luai_numle(L, nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ @@ -248,7 +241,7 @@ static int lessequal (lua_State *L, const TValue *l, const TValue *r) { } -int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { +int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { @@ -258,8 +251,7 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, - TM_EQ); + tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { @@ -270,22 +262,27 @@ int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ - callTMres(L, L->top, tm, t1, t2); /* call TM */ + callTM(L, tm, t1, t2, L->top, 1); /* call TM */ return !l_isfalse(L->top); } -void luaV_concat (lua_State *L, int total, int last) { +void luaV_concat (lua_State *L, int total) { + lua_assert(total >= 2); do { - StkId top = L->base + last + 1; + StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ - (void)tostring(L, top - 2); /* result is first op (as string) */ + } + else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ + (void)tostring(L, top - 2); /* result is first operand */ + else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { + setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */ + } else { - /* at least two string values; get as many as possible */ + /* at least two non-empty string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; @@ -304,42 +301,119 @@ void luaV_concat (lua_State *L, int total, int last) { } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } - total -= n-1; /* got `n' strings to create 1 new */ - last -= n-1; + total -= n-1; /* got 'n' strings to create 1 new */ + L->top -= n-1; /* poped 'n' strings and pushed one */ } while (total > 1); /* repeat until only 1 result left */ } -static void Arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op) { +void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { + const TValue *tm; + switch (ttype(rb)) { + case LUA_TTABLE: { + Table *h = hvalue(rb); + tm = fasttm(L, h->metatable, TM_LEN); + if (tm) break; /* metamethod? break switch to call it */ + setnvalue(ra, cast_num(luaH_getn(h))); /* else primitive len */ + return; + } + case LUA_TSTRING: { + setnvalue(ra, cast_num(tsvalue(rb)->len)); + return; + } + default: { /* try metamethod */ + tm = luaT_gettmbyobj(L, rb, TM_LEN); + if (ttisnil(tm)) /* no metamethod? */ + luaG_typeerror(L, rb, "get length of"); + break; + } + } + callTM(L, tm, rb, luaO_nilobject, ra, 1); +} + + +void luaV_arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { - lua_Number nb = nvalue(b), nc = nvalue(c); - switch (op) { - case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; - case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; - case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; - case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; - case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; - case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; - case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; - default: lua_assert(0); break; - } + lua_Number res = luaO_arith(op - TM_ADD + LUA_OPADD, nvalue(b), nvalue(c)); + setnvalue(ra, res); } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); } +/* +** finish execution of an opcode interrupted by an yield +*/ +void luaV_finishOp (lua_State *L) { + CallInfo *ci = L->ci; + StkId base = ci->u.l.base; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ + OpCode op = GET_OPCODE(inst); + if (op == OP_EXTRAARG) { /* extra argument? */ + inst = *(ci->u.l.savedpc - 2); /* get its 'main' instruction */ + op = GET_OPCODE(inst); + } + switch (op) { /* finish its execution */ + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: + case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: + case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { + setobjs2s(L, base + GETARG_A(inst), --L->top); + break; + } + case OP_LE: case OP_LT: case OP_EQ: { + int res = !l_isfalse(L->top - 1); + L->top--; + /* metamethod should not be called when operand is K */ + lua_assert(!ISK(GETARG_B(inst))); + if (op == OP_LE && /* "<=" using "<" instead? */ + ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) + res = !res; /* invert result */ + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); + if (res != GETARG_A(inst)) /* condition failed? */ + ci->u.l.savedpc++; /* skip jump instruction */ + break; + } + case OP_CONCAT: { + StkId top = L->top - 1; /* top when 'call_binTM' was called */ + int b = GETARG_B(inst); /* first element to concatenate */ + int total = top - 1 - (base + b); /* elements yet to concatenate */ + setobj2s(L, top - 2, top); /* put TM result in proper position */ + if (total > 1) { /* are there elements to concat? */ + L->top = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ + } + /* move final result to final position */ + setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); + L->top = ci->top; /* restore top */ + break; + } + case OP_TFORCALL: { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); + L->top = ci->top; /* correct top */ + break; + } + case OP_CALL: { + if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ + L->top = ci->top; /* adjust results */ + break; + } + case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE: + break; + default: lua_assert(0); + } +} + + /* ** some macros for common tasks in `luaV_execute' */ -#define runtime_check(L, c) { if (!(c)) break; } - #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) @@ -348,13 +422,14 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) -#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) +#define KBx(i) \ + (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) -#define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} +#define dojump(i) { ci->u.l.savedpc += (i); luai_threadyield(L);} -#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } +#define Protect(x) { {x;}; base = ci->u.l.base; } #define arith_op(op,tm) { \ @@ -362,55 +437,50 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, TValue *rc = RKC(i); \ if (ttisnumber(rb) && ttisnumber(rc)) { \ lua_Number nb = nvalue(rb), nc = nvalue(rc); \ - setnvalue(ra, op(nb, nc)); \ + setnvalue(ra, op(L, nb, nc)); \ } \ else \ - Protect(Arith(L, ra, rb, rc, tm)); \ + Protect(luaV_arith(L, ra, rb, rc, tm)); \ } -void luaV_execute (lua_State *L, int nexeccalls) { - LClosure *cl; - StkId base; - TValue *k; - const Instruction *pc; - reentry: /* entry point */ - lua_assert(isLua(L->ci)); - pc = L->savedpc; - cl = &clvalue(L->ci->func)->l; - base = L->base; - k = cl->p->k; +void luaV_execute (lua_State *L) { + CallInfo *ci = L->ci; + LClosure *cl = &clvalue(ci->func)->l; + TValue *k = cl->p->k; + StkId base = ci->u.l.base; + lua_assert(isLua(ci)); /* main loop of interpreter */ for (;;) { - const Instruction i = *pc++; + Instruction i = *(ci->u.l.savedpc++); StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L, pc); + traceexec(L); if (L->status == LUA_YIELD) { /* did hook yield? */ - L->savedpc = pc - 1; - return; + ci->u.l.savedpc--; /* undo increment */ + luaD_throw(L, LUA_YIELD); } - base = L->base; + base = ci->u.l.base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); - lua_assert(base == L->base && L->base == L->ci->base); - lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); - lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); + lua_assert(base == ci->u.l.base); + lua_assert(base <= L->top && L->top < L->stack + L->stacksize); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { - setobj2s(L, ra, KBx(i)); + TValue *rb = KBx(i); + setobj2s(L, ra, rb); continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ + if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { @@ -439,9 +509,10 @@ void luaV_execute (lua_State *L, int nexeccalls) { } case OP_SETGLOBAL: { TValue g; + TValue *rb = KBx(i); sethvalue(L, &g, cl->env); - lua_assert(ttisstring(KBx(i))); - Protect(luaV_settable(L, &g, KBx(i), ra)); + lua_assert(ttisstring(rb)); + Protect(luaV_settable(L, &g, rb, ra)); continue; } case OP_SETUPVAL: { @@ -457,7 +528,10 @@ void luaV_execute (lua_State *L, int nexeccalls) { case OP_NEWTABLE: { int b = GETARG_B(i); int c = GETARG_C(i); - sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); + Table *t = luaH_new(L); + sethvalue(L, ra, t); + if (b != 0 || c != 0) + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); Protect(luaC_checkGC(L)); continue; } @@ -495,10 +569,10 @@ void luaV_execute (lua_State *L, int nexeccalls) { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); - setnvalue(ra, luai_numunm(nb)); + setnvalue(ra, luai_numunm(L, nb)); } else { - Protect(Arith(L, ra, rb, rb, TM_UNM)); + Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); } continue; } @@ -508,34 +582,20 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_LEN: { - const TValue *rb = RB(i); - switch (ttype(rb)) { - case LUA_TTABLE: { - setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); - break; - } - case LUA_TSTRING: { - setnvalue(ra, cast_num(tsvalue(rb)->len)); - break; - } - default: { /* try metamethod */ - Protect( - if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) - luaG_typeerror(L, rb, "get length of"); - ) - } - } + Protect(luaV_objlen(L, ra, RB(i))); continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); - Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); + L->top = base + c + 1; /* mark the end of concat operands */ + Protect(luaV_concat(L, c-b+1); luaC_checkGC(L)); + L->top = ci->top; /* restore top */ setobjs2s(L, RA(i), base+b); continue; } case OP_JMP: { - dojump(L, pc, GETARG_sBx(i)); + dojump(GETARG_sBx(i)); continue; } case OP_EQ: { @@ -543,117 +603,110 @@ void luaV_execute (lua_State *L, int nexeccalls) { TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(*pc)); + dojump(GETARG_sBx(*ci->u.l.savedpc)); ) - pc++; + ci->u.l.savedpc++; continue; } case OP_LT: { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(*pc)); + dojump(GETARG_sBx(*ci->u.l.savedpc)); ) - pc++; + ci->u.l.savedpc++; continue; } case OP_LE: { Protect( - if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(*pc)); + if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) + dojump(GETARG_sBx(*ci->u.l.savedpc)); ) - pc++; + ci->u.l.savedpc++; continue; } case OP_TEST: { - if (l_isfalse(ra) != GETARG_C(i)) - dojump(L, pc, GETARG_sBx(*pc)); - pc++; + if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra)) + dojump(GETARG_sBx(*ci->u.l.savedpc)); + ci->u.l.savedpc++; continue; } case OP_TESTSET: { TValue *rb = RB(i); - if (l_isfalse(rb) != GETARG_C(i)) { + if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) { setobjs2s(L, ra, rb); - dojump(L, pc, GETARG_sBx(*pc)); + dojump(GETARG_sBx(*ci->u.l.savedpc)); } - pc++; + ci->u.l.savedpc++; continue; } case OP_CALL: { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->savedpc = pc; - switch (luaD_precall(L, ra, nresults)) { - case PCRLUA: { - nexeccalls++; - goto reentry; /* restart luaV_execute over new Lua function */ - } - case PCRC: { - /* it was a C function (`precall' called it); adjust results */ - if (nresults >= 0) L->top = L->ci->top; - base = L->base; - continue; - } - default: { - return; /* yield */ - } + if (luaD_precall(L, ra, nresults)) { /* C function? */ + if (nresults >= 0) L->top = ci->top; /* adjust results */ + base = ci->u.l.base; + continue; + } + else { /* Lua function */ + ci = L->ci; + ci->callstatus |= CIST_REENTRY; + break; /* restart luaV_execute over new Lua function */ } } case OP_TAILCALL: { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->savedpc = pc; lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - switch (luaD_precall(L, ra, LUA_MULTRET)) { - case PCRLUA: { - /* tail call: put new frame in place of previous one */ - CallInfo *ci = L->ci - 1; /* previous frame */ - int aux; - StkId func = ci->func; - StkId pfunc = (ci+1)->func; /* previous function index */ - if (L->openupval) luaF_close(L, ci->base); - L->base = ci->base = ci->func + ((ci+1)->base - pfunc); - for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ - setobjs2s(L, func+aux, pfunc+aux); - ci->top = L->top = func+aux; /* correct top */ - lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); - ci->savedpc = L->savedpc; - ci->tailcalls++; /* one more call lost */ - L->ci--; /* remove new frame */ - goto reentry; - } - case PCRC: { /* it was a C function (`precall' called it) */ - base = L->base; - continue; - } - default: { - return; /* yield */ - } + if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + base = ci->u.l.base; + continue; + } + else { + /* tail call: put called frame (n) in place of caller one (o) */ + CallInfo *nci = L->ci; /* called frame */ + CallInfo *oci = nci->previous; /* caller frame */ + StkId nfunc = nci->func; /* called function */ + StkId ofunc = oci->func; /* caller function */ + /* last stack slot filled by 'precall' */ + StkId lim = nci->u.l.base + getproto(nfunc)->numparams; + int aux; + /* close all upvalues from previous call */ + if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); + /* move new frame into old one */ + for (aux = 0; nfunc + aux < lim; aux++) + setobjs2s(L, ofunc + aux, nfunc + aux); + oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ + oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ + oci->u.l.savedpc = nci->u.l.savedpc; + oci->callstatus |= CIST_TAIL; /* function was tail called */ + ci = L->ci = oci; /* remove new frame */ + lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); + break; /* restart luaV_execute over new Lua function */ } } case OP_RETURN: { int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; - if (L->openupval) luaF_close(L, base); - L->savedpc = pc; + if (cl->p->sizep > 0) luaF_close(L, base); b = luaD_poscall(L, ra); - if (--nexeccalls == 0) /* was previous function running `here'? */ - return; /* no: return */ - else { /* yes: continue its execution */ - if (b) L->top = L->ci->top; - lua_assert(isLua(L->ci)); - lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); - goto reentry; + if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */ + return; /* external invocation: return */ + else { /* invocation via reentry: continue execution */ + ci = L->ci; + if (b) L->top = ci->top; + lua_assert(isLua(ci)); + lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); + break; /* restart luaV_execute over new Lua function */ } } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); - lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ + lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); - if (luai_numlt(0, step) ? luai_numle(idx, limit) - : luai_numle(limit, idx)) { - dojump(L, pc, GETARG_sBx(i)); /* jump back */ + if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit) + : luai_numle(L, limit, idx)) { + dojump(GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } @@ -663,31 +716,34 @@ void luaV_execute (lua_State *L, int nexeccalls) { const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; - L->savedpc = pc; /* next steps may throw errors */ if (!tonumber(init, ra)) luaG_runerror(L, LUA_QL("for") " initial value must be a number"); else if (!tonumber(plimit, ra+1)) luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); - setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); - dojump(L, pc, GETARG_sBx(i)); + setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); + dojump(GETARG_sBx(i)); continue; } - case OP_TFORLOOP: { + case OP_TFORCALL: { StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); - L->top = cb+3; /* func. + 2 args (state and index) */ - Protect(luaD_call(L, cb, GETARG_C(i))); - L->top = L->ci->top; - cb = RA(i) + 3; /* previous call may change the stack */ - if (!ttisnil(cb)) { /* continue loop? */ - setobjs2s(L, cb-1, cb); /* save control variable */ - dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ + L->top = cb + 3; /* func. + 2 args (state and index) */ + Protect(luaD_call(L, cb, GETARG_C(i), 1)); + L->top = ci->top; + i = *(ci->u.l.savedpc++); /* go to next instruction */ + ra = RA(i); + lua_assert(GET_OPCODE(i) == OP_TFORLOOP); + /* go through */ + } + case OP_TFORLOOP: { + if (!ttisnil(ra + 1)) { /* continue loop? */ + setobjs2s(L, ra, ra + 1); /* save control variable */ + dojump(GETARG_sBx(i)); /* jump back */ } - pc++; continue; } case OP_SETLIST: { @@ -695,21 +751,21 @@ void luaV_execute (lua_State *L, int nexeccalls) { int c = GETARG_C(i); int last; Table *h; - if (n == 0) { - n = cast_int(L->top - ra) - 1; - L->top = L->ci->top; + if (n == 0) n = cast_int(L->top - ra) - 1; + if (c == 0) { + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + c = GETARG_Ax(*ci->u.l.savedpc++); } - if (c == 0) c = cast_int(*pc++); - runtime_check(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* pre-alloc it at once */ for (; n > 0; n--) { TValue *val = ra+n; - setobj2t(L, luaH_setnum(L, h, last--), val); + setobj2t(L, luaH_setint(L, h, last--), val); luaC_barriert(L, h, val); } + L->top = ci->top; /* correct top (in case of previous open call) */ continue; } case OP_CLOSE: { @@ -717,39 +773,43 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_CLOSURE: { - Proto *p; - Closure *ncl; - int nup, j; - p = cl->p->p[GETARG_Bx(i)]; - nup = p->nups; - ncl = luaF_newLclosure(L, nup, cl->env); + Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */ + int nup = p->sizeupvalues; + Closure *ncl = luaF_newLclosure(L, nup, cl->env); + Upvaldesc *uv = p->upvalues; + int j; ncl->l.p = p; - for (j=0; jl.upvals[j] = cl->upvals[GETARG_B(*pc)]; - else { - lua_assert(GET_OPCODE(*pc) == OP_MOVE); - ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); - } + setclvalue(L, ra, ncl); /* anchor new closure in stack */ + if (p->envreg != NO_REG) { /* lexical environment? */ + StkId env = base + p->envreg; + if (!ttistable(env)) + luaG_runerror(L, "environment is not a table: " + "cannot create closure"); + else + ncl->l.env = hvalue(env); + } + for (j = 0; j < nup; j++) { /* fill in upvalues */ + if (uv[j].instack) /* upvalue refers to local variable? */ + ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx); + else /* get upvalue from enclosing function */ + ncl->l.upvals[j] = cl->upvals[uv[j].idx]; } - setclvalue(L, ra, ncl); Protect(luaC_checkGC(L)); continue; } case OP_VARARG: { int b = GETARG_B(i) - 1; int j; - CallInfo *ci = L->ci; - int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; - if (b == LUA_MULTRET) { + int n = cast_int(base - ci->func) - cl->p->numparams - 1; + if (b < 0) { /* B == 0? */ + b = n; /* get all var. arguments */ Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ - b = n; L->top = ra + n; } for (j = 0; j < b; j++) { if (j < n) { - setobjs2s(L, ra + j, ci->base - n + j); + setobjs2s(L, ra + j, base - n + j); } else { setnilvalue(ra + j); @@ -757,7 +817,16 @@ void luaV_execute (lua_State *L, int nexeccalls) { } continue; } + case OP_EXTRAARG: { + luaG_runerror(L, "bad opcode"); + return; + } } + /* function changed (call/return): update pointers */ + lua_assert(ci == L->ci); + cl = &clvalue(ci->func)->l; + k = cl->p->k; + base = ci->u.l.base; } } diff --git a/src/lvm.h b/src/lvm.h index bfe4f5678d..8e91da5925 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lvm.h,v 2.14 2009/12/17 16:20:01 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -13,24 +13,30 @@ #include "ltm.h" -#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) +#define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o))) -#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \ - (((o) = luaV_tonumber(o,n)) != NULL)) +#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL)) #define equalobj(L,o1,o2) \ - (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) + (ttype(o1) == ttype(o2) && luaV_equalval_(L, o1, o2)) +/* not to called directly */ +LUAI_FUNC int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2); + LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); -LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); -LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); +LUAI_FUNC void luaV_finishOp (lua_State *L); +LUAI_FUNC void luaV_execute (lua_State *L); +LUAI_FUNC void luaV_concat (lua_State *L, int total); +LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb, + const TValue *rc, TMS op); +LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); #endif diff --git a/src/lzio.c b/src/lzio.c index 293edd59b0..5121ada846 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ diff --git a/src/lzio.h b/src/lzio.h index 51d695d8c1..53eb91efe3 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $ +** $Id: lzio.h,v 1.22 2009/05/18 17:26:25 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -21,6 +21,9 @@ typedef struct Zio ZIO; #define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) +#define zungetc(z) ((z)->n++, (z)->p--) + + typedef struct Mbuffer { char *buffer; size_t n; diff --git a/src/print.c b/src/print.c index e240cfc3c6..fb491e7e88 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ +** $Id: print.c,v 1.58 2008/09/11 12:05:06 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -30,7 +30,7 @@ static void PrintString(const TString* ts) int c=s[i]; switch (c) { - case '"': printf("\\\""); break; + case '"': printf("\\\""); break; case '\\': printf("\\\\"); break; case '\a': printf("\\a"); break; case '\b': printf("\\b"); break; @@ -84,7 +84,10 @@ static void PrintCode(const Proto* f) int c=GETARG_C(i); int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); - int line=getline(f,pc); + int line=getfuncline(f,pc); +#ifdef LUAC_DUMP_INSTRUCTIONS + printf("%0*X",2*sizeof(i),i); +#endif printf("\t%d\t",pc+1); if (line>0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); @@ -109,7 +112,7 @@ static void PrintCode(const Proto* f) break; case OP_GETUPVAL: case OP_SETUPVAL: - printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); break; case OP_GETGLOBAL: case OP_SETGLOBAL: @@ -155,7 +158,7 @@ static void PrintCode(const Proto* f) } } -#define SS(x) (x==1)?"":"s" +#define SS(x) ((x==1)?"":"s") #define S(x) x,SS(x) static void PrintHeader(const Proto* f) @@ -173,14 +176,15 @@ static void PrintHeader(const Proto* f) S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); printf("%d%s param%s, %d slot%s, %d upvalue%s, ", f->numparams,f->is_vararg?"+":"",SS(f->numparams), - S(f->maxstacksize),S(f->nups)); + S(f->maxstacksize),S(f->sizeupvalues)); printf("%d local%s, %d constant%s, %d function%s\n", S(f->sizelocvars),S(f->sizek),S(f->sizep)); } -static void PrintConstants(const Proto* f) +static void PrintDebug(const Proto* f) { - int i,n=f->sizek; + int i,n; + n=f->sizek; printf("constants (%d) for %p:\n",n,VOID(f)); for (i=0; isizelocvars; + n=f->sizelocvars; printf("locals (%d) for %p:\n",n,VOID(f)); for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); } -} - -static void PrintUpvalues(const Proto* f) -{ - int i,n=f->sizeupvalues; + n=f->sizeupvalues; printf("upvalues (%d) for %p:\n",n,VOID(f)); if (f->upvalues==NULL) return; for (i=0; iupvalues[i])); + printf("\t%d\t%s\n",i,getstr(f->upvalues[i].name)); } } @@ -217,11 +213,6 @@ void PrintFunction(const Proto* f, int full) int i,n=f->sizep; PrintHeader(f); PrintCode(f); - if (full) - { - PrintConstants(f); - PrintLocals(f); - PrintUpvalues(f); - } + if (full) PrintDebug(f); for (i=0; ip[i],full); } diff --git a/test/ALL.lua b/test/ALL.lua new file mode 100644 index 0000000000..0045fc36a0 --- /dev/null +++ b/test/ALL.lua @@ -0,0 +1,26 @@ +function run(x) + print("\n-------------------------------------------------------------") + print(x) + os.execute("../src/lua "..x) + print("DONE",x) +end + +run"bisect.lua" +run"cf.lua" +run"echo.lua jan feb mar apr may jun jul aug sep oct nov dec" +run"env.lua" +run"factorial.lua" +run"fib.lua" +run"fibfor.lua" +--run"globals.lua" +run"hello.lua" +run"luac.lua" +run"printf.lua" +run"readonly.lua" +run"sieve.lua" +run"sort.lua" +run"table.lua" +run"trace-calls.lua" +run"trace-globals.lua" +run"xd.lua < hello.lua" +run"life.lua" diff --git a/test/sieve.lua b/test/sieve.lua index 0871bb2125..e27c1a20dd 100644 --- a/test/sieve.lua +++ b/test/sieve.lua @@ -14,7 +14,7 @@ function filter (p, g) while 1 do local n = g() if n == nil then return end - if math.mod(n, p) ~= 0 then coroutine.yield(n) end + if n % p ~= 0 then coroutine.yield(n) end end end) end diff --git a/test/xd.lua b/test/xd.lua index ebc3effc06..8b420394d0 100644 --- a/test/xd.lua +++ b/test/xd.lua @@ -1,14 +1,15 @@ -- hex dump -- usage: lua xd.lua < file +local N=16 local offset=0 while true do - local s=io.read(16) + local s=io.read(N) if s==nil then return end io.write(string.format("%08X ",offset)) string.gsub(s,"(.)", function (c) io.write(string.format("%02X ",string.byte(c))) end) - io.write(string.rep(" ",3*(16-string.len(s)))) + io.write(string.rep(" ",3*(N-string.len(s)))) io.write(" ",string.gsub(s,"%c","."),"\n") - offset=offset+16 + offset=offset+N end From ecd48c2901f08a88db32139b97c35c59eba1f19e Mon Sep 17 00:00:00 2001 From: Lua Team Date: Thu, 14 Jan 2010 12:00:00 +0000 Subject: [PATCH 49/97] Lua 5.2.0-work2 --- Makefile | 4 +- README | 2 +- doc/contents.html | 68 +++++++++++++++-------- doc/lua.css | 5 ++ doc/manual.css | 13 +++++ doc/manual.html | 126 +++++++++++++++++++++++++++++++++++-------- doc/readme.html | 91 ++++++++++++++++++++----------- etc/Makefile | 6 ++- etc/README | 6 +-- etc/luavs.bat | 12 ++--- etc/min.c | 15 +++--- etc/noparser.c | 6 +-- etc/{all.c => one.c} | 2 +- etc/strict.lua | 1 + src/lapi.c | 7 +-- src/lauxlib.h | 4 +- src/lbitlib.c | 5 +- src/lcode.c | 8 +-- src/ldebug.c | 12 ++--- src/ldo.c | 10 ++-- src/loadlib.c | 42 ++++++++++----- src/ltablib.c | 4 +- src/ltm.c | 10 ++-- src/ltm.h | 6 ++- src/lua.h | 8 +-- src/luaconf.h | 10 ++-- 26 files changed, 335 insertions(+), 148 deletions(-) create mode 100644 doc/manual.css rename etc/{all.c => one.c} (95%) diff --git a/Makefile b/Makefile index 62e759a9fb..3e8b4b9850 100644 --- a/Makefile +++ b/Makefile @@ -63,13 +63,13 @@ install: dummy cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) - cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) + #cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) uninstall: cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN) cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC) cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB) - cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN) + #cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN) local: $(MAKE) install INSTALL_TOP=../install diff --git a/README b/README index f2377b0287..678a301ae2 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Lua 5.2 (work1), released on 08 Jan 2010. +This is Lua 5.2 (work2), released on 13 Jan 2010. For information about Lua, including installation instructions and license details, see doc/readme.html. diff --git a/doc/contents.html b/doc/contents.html index beba089fad..66d967e36d 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -32,7 +32,7 @@

      index
      -Copyright © 2006-2010 Lua.org, PUC-Rio. +Copyright © 2010 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -59,6 +59,7 @@

      Contents

    • 2.4.5 - For Statement
    • 2.4.6 - Function Calls as Statements
    • 2.4.7 - Local Declarations +
    • 2.4.8 - Lexical Environments
  • 2.5 - Expressions

  • 4 - The Auxiliary Library @@ -112,9 +114,10 @@

    Contents

  • 5.5 - Table Manipulation
  • 5.6 - Mathematical Functions -
  • 5.7 - Input and Output Facilities -
  • 5.8 - Operating System Facilities -
  • 5.9 - The Debug Library +
  • 5.7 - Bitwise operations +
  • 5.8 - Input and Output Facilities +
  • 5.9 - Operating System Facilities +
  • 5.10 - The Debug Library

  • 6 - Lua Stand-alone @@ -140,10 +143,10 @@

    Lua functions

    collectgarbage
    dofile
    error
    -getfenv
    getmetatable
    ipairs
    load
    +loadin
    loadfile
    loadstring
    module
    @@ -156,15 +159,22 @@

    Lua functions

    rawset
    require
    select
    -setfenv
    setmetatable
    tonumber
    tostring
    type
    -unpack
    xpcall

    +bit.band
    +bit.bnot
    +bit.bor
    +bit.brotate
    +bit.bshift
    +bit.btest
    +bit.bxor
    +

    + coroutine.create
    coroutine.resume
    coroutine.running
    @@ -187,6 +197,8 @@

    Lua functions

    debug.setmetatable
    debug.setupvalue
    debug.traceback
    +debug.upvalueid
    +debug.upvaluejoin
  • @@ -232,7 +244,6 @@

     

    math.huge
    math.ldexp
    math.log
    -math.log10
    math.max
    math.min
    math.modf
    @@ -261,12 +272,14 @@

     

    os.tmpname

    +package.config
    package.cpath
    package.loaded
    package.loaders
    package.loadlib
    package.path
    package.preload
    +package.searchpath
    package.seeall

    @@ -288,9 +301,10 @@

     

    table.concat
    table.insert
    -table.maxn
    +table.pack
    table.remove
    table.sort
    +table.unpack
    @@ -308,21 +322,23 @@

    C API

    lua_atpanic
    lua_call
    +lua_callk
    lua_checkstack
    lua_close
    +lua_compare
    lua_concat
    -lua_cpcall
    +lua_copy
    lua_createtable
    lua_dump
    -lua_equal
    lua_error
    lua_gc
    lua_getallocf
    +lua_getctx
    lua_getfenv
    lua_getfield
    lua_getglobal
    -lua_gethook
    lua_gethookcount
    +lua_gethook
    lua_gethookmask
    lua_getinfo
    lua_getlocal
    @@ -344,15 +360,15 @@

    C API

    lua_istable
    lua_isthread
    lua_isuserdata
    -lua_lessthan
    +lua_len
    lua_load
    lua_newstate
    lua_newtable
    lua_newthread
    lua_newuserdata
    lua_next
    -lua_objlen
    lua_pcall
    +lua_pcallk
    lua_pop
    lua_pushboolean
    lua_pushcclosure
    @@ -369,10 +385,11 @@

    C API

    lua_pushvalue
    lua_pushvfstring
    lua_rawequal
    -lua_rawget
    lua_rawgeti
    -lua_rawset
    +lua_rawget
    +lua_rawlen
    lua_rawseti
    +lua_rawset
    lua_register
    lua_remove
    lua_replace
    @@ -399,9 +416,13 @@

    C API

    lua_touserdata
    lua_type
    lua_typename
    +lua_upvalueid
    lua_upvalueindex
    +lua_upvaluejoin
    +lua_version
    lua_xmove
    lua_yield
    +lua_yieldk
    @@ -430,12 +451,14 @@

    auxiliary library

    luaL_checkstring
    luaL_checktype
    luaL_checkudata
    +luaL_checkversion
    luaL_dofile
    luaL_dostring
    luaL_error
    luaL_getmetafield
    luaL_getmetatable
    luaL_gsub
    +luaL_len
    luaL_loadbuffer
    luaL_loadfile
    luaL_loadstring
    @@ -452,8 +475,11 @@

    auxiliary library

    luaL_pushresult
    luaL_ref
    luaL_register
    +luaL_testudata
    +luaL_tolstring
    +luaL_traceback
    +luaL_typeerror
    luaL_typename
    -luaL_typerror
    luaL_unref
    luaL_where
    @@ -465,10 +491,10 @@

    auxiliary library


    Last update: -Fri Jan 8 16:29:00 BRST 2010 +Wed Jan 13 15:31:47 BRST 2010 diff --git a/doc/lua.css b/doc/lua.css index 039cf11698..40041a478c 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -39,3 +39,8 @@ hr { background-color: #a0a0a0 ; } +:target { + background-color: #F8F8F8 ; + padding: 8px ; + border: solid #a0a0a0 2px ; +} diff --git a/doc/manual.css b/doc/manual.css new file mode 100644 index 0000000000..eed5afd9ee --- /dev/null +++ b/doc/manual.css @@ -0,0 +1,13 @@ +h3 code { + font-family: inherit ; +} + +pre { + font-size: 105% ; +} + +span.apii { + float: right ; + font-family: inherit ; +} + diff --git a/doc/manual.html b/doc/manual.html index 83d2bb0957..6ebd074022 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,31 +1,39 @@ - + Lua 5.2 Reference Manual - + + + - +

    -[Lua logo] + Lua 5.2 Reference Manual

    by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    -Copyright -© 2010 Lua.org, PUC-Rio. All rights reserved. +Copyright © 2010 Lua.org, PUC-Rio. +Freely available under the terms of the +Lua license.


    +

    + +contents +· +index

    - + @@ -166,10 +174,12 @@

    2.1 - Lexical Conventions

    and '\'' (apostrophe [single quote]). Moreover, a backslash followed by a real newline results in a newline in the string. -A character in a string can also be specified by its numerical value -using the escape sequence \ddd, +A character in a string can also be specified by its numerical value. +This can be done with the escape sequence \xXX, +where XX is a sequence of exactly two hexadecimal digits, +and with the escape sequence \ddd, where ddd is a sequence of up to three decimal digits. -(Note that if a numerical escape is to be followed by a digit, +(Note that if a decimal escape is to be followed by a digit, it must be expressed using exactly three digits.) Strings in Lua can contain any 8-bit value, including embedded zeros, which can be specified as '\0'. @@ -2053,7 +2063,8 @@

    2.10 - Garbage Collection

    If you set the step multiplier to a very large number -(such as 2^30), +(larger than 10% of the maximum number of +bytes that the program may use), the collector behaves like a stop-the-world collector. If you then set the pause to 200, the collector behaves as in old Lua versions, @@ -5104,6 +5115,15 @@

    3.9 - The Debug Interface

    +

    lua_upvaluejoin

    +
    void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
    +                                              int fidx2, int n2);

    +TO BE DONE!! + + + + +

    4 - The Auxiliary Library

    @@ -6000,10 +6020,33 @@

    4.1 - Functions and Types

    +

    luaL_tolstring

    +[-0, +1, e] +

    const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
    + +

    +Converts any Lua value at the given acceptable index to a C string +in a reasonable format. +The resulting string is pushed onto the stack and also +returned by the function. +If len is not NULL, +the function also sets *len with the string length. + + +

    +If the value has a metatable with a "__tostring" field, +then luaL_tolstring calls the corresponding metamethod +with the value as argument, +and uses the result of the call as its result. + + + + +


    luaL_traceback

    [-0, +1, m] -

    luaL_traceback (lua_State *L, lua_State *L1,
    -                          const char *msg, int level);
    +
    void luaL_traceback (lua_State *L, lua_State *L1,
    +                               const char *msg, int level);

    Creates and pushes a traceback of the stack L1. @@ -7111,22 +7154,23 @@

    5.3 - Modules

    templates separated by semicolons. For each template, the function changes each interrogation -mark in the template by name, +mark in the template by a copy of name +wherein all dots were replaced by the system's directory separator, and then tries to open the resulting file name. For instance, if the path is the string
          "./?.lua;./?.lc;/usr/local/?/init.lua"
     

    -the search for name foo +the search for the name foo.a will try to open the files -./foo.lua, ./foo.lc, and -/usr/local/foo/init.lua, in that order. +./foo/a.lua, ./foo/a.lc, and +/usr/local/foo/a/init.lua, in that order.

    Returns the resulting name of the first file that it can -open in read mode (after closing it), +open in read mode (after closing the file), or nil plus an error message if none succeeds. (This error message lists all file names it tried to open.) @@ -7950,7 +7994,7 @@

    5.6 - Mathematical Functions

    Returns the logarithm of x in the given base. -The default for base is $e$ +The default for base is e (so that the function returns the natural logarithm of x). @@ -9140,6 +9184,36 @@

    5.10 - The Debug Library

    +

    +


    debug.upvalueid (function, n)

    + + +

    +Returns an unique identifier (as a light userdata) +for the upvalue numbered n +from the given function. + + +

    +These unique identifiers allow a program to check whether different +closures share upvalues. +Lua closures that share an upvalue +(that is, that access a same external local variable) +will return identical ids for those upvalue indices. + + + + +

    +


    debug.upvaluejoin ()

    + + +

    +TO BE DONE!! + + + + @@ -9319,7 +9393,7 @@

    7.1 - Changes in the Language

  • Threads do not have individual environments. -All threads share a sinle fixed environment. +All threads share a single fixed environment.
  • @@ -9367,7 +9441,7 @@

    7.3 - Changes in the API

    • -Pseudoindex LUA_GLOBALSINDEX was deprecated. +Pseudoindex LUA_GLOBALSINDEX was removed. You may use the pseudoindex LUA_ENVIRONINDEX instead, if the C function does not change its standard environment. Otherwise, you should get the global environment from the registry @@ -9484,5 +9558,15 @@

      8 - The Complete Syntax of Lua

      + +
      + +Last update: +Wed Jan 13 15:29:29 BRST 2010 + + + diff --git a/doc/readme.html b/doc/readme.html index 7640d3af9a..6d9e601eee 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -21,6 +21,13 @@ padding-right: 15px; background: transparent url(external.png) no-repeat center right; } + +tt, kbd { + font-size: 120% ; + xcolor: black ; + xpadding: 4px ; + xbackground-color: #E0E0E0 ; +} @@ -80,7 +87,6 @@

      About Lua

      Installing Lua

      -
      how much detail?

      Lua is distributed in source form. You need to build it before using it. @@ -100,7 +106,7 @@

      Installing Lua

      Building Lua

      -In most Unix-like platforms, simply do "make" with a suitable target. +In most Unix-like platforms, simply do "make" with a suitable target. Here are the details.

      @@ -111,13 +117,13 @@

      Building Lua

      The Makefile there controls both the build process and the installation process.

    • - Do "make" and see if your platform is listed. + Do "make" and see if your platform is listed. The platforms currently supported are:
      aix ansi bsd freebsd generic linux macosx mingw posix solaris

      - If your platform is listed, just do "make xxx", where xxx + If your platform is listed, just do "make xxx", where xxx is your platform name.

      If your platform is not listed, try the closest one or posix, generic, @@ -131,7 +137,7 @@

      Building Lua

      and liblua.a (the library).

    • - If you want to check that Lua has been built correctly, do "make test" + If you want to check that Lua has been built correctly, do "make test" after building Lua. This will run the interpreter on a "hello world" Lua program from the test directory. You may want to try other example programs in that directory. @@ -140,19 +146,19 @@

      Building Lua

      Installing Lua

      Once you have built Lua, you may want to install it in an official - place in your system. In this case, do "make install". The official + place in your system. In this case, do "make install". The official place and the way to install files are defined in Makefile. You'll probably need the right permissions to install files.

      - If you want to build and install Lua in one step, do "make xxx install", + If you want to build and install Lua in one step, do "make xxx install", where xxx is your platform name.

      - If you want to install Lua locally, then do "make local". This will - create directories bin, include, lib, man, and install Lua there as - follows: - review! + If you want to install Lua locally, then do "make local". + This will create a directory install with subdirectories + bin, include, lib, man, + and install Lua there as follows:

      @@ -185,15 +191,15 @@

      Installing Lua

      If you want to install Lua locally, but in some other directory, do - "make install INSTALL_TOP=xxx", where xxx is your chosen directory. + "make install INSTALL_TOP=xxx", where xxx is your chosen directory.

      Customization

      Three kinds of things can be customized by editing a file:
        -
      • Where and how to install Lua – edit Makefile. -
      • How to build Lua – edit src/Makefile. -
      • Lua features – edit src/luaconf.h. +
      • Where and how to install Lua — edit Makefile. +
      • How to build Lua — edit src/Makefile. +
      • Lua features — edit src/luaconf.h.

      @@ -205,6 +211,7 @@

      Customization

      to edit src/luaconf.h before building and installing Lua. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. + (Further customization is possible by editing the Lua sources.)

      We strongly recommend that you enable dynamic loading. This is done @@ -223,11 +230,11 @@

      Building Lua on other systems

      library:
      - lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c - lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c - ltable.c ltm.c lundump.c lvm.c lzio.c - lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c - ltablib.c lstrlib.c loadlib.c linit.c +lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c +lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c +ltm.c lundump.c lvm.c lzio.c +lauxlib.c lbaselib.c lbitlib.c ldblib.c liolib.c lmathlib.c loslib.c +ltablib.c lstrlib.c loadlib.c linit.c
      interpreter:
      @@ -238,12 +245,12 @@

      Building Lua on other systems

      library, luac.c print.c
      - If you use Visual Studio .NET, you can use etc/luavs.bat in its + If you use Visual Studio .NET, you can use etc/luavs.bat in its "Command Prompt".

      If all you want is to build the Lua interpreter, you may put all .c files - in a single project, except for luac.c and print.c. Or just use etc/all.c. + in a single project, except for luac.c and print.c. Or just use etc/one.c.

      To use Lua as a library in your own programs you'll need to know how to @@ -254,7 +261,7 @@

      Building Lua on other systems

      into each dynamic library. For Unix, we recommend that the Lua library be linked statically into the host program and its symbols exported for dynamic linking; src/Makefile does this for the Lua interpreter. - For Windows, we recommend that the Lua library be DLL. + For Windows, we recommend that the Lua library be a DLL.

      As mentioned above, you may edit src/luaconf.h to customize @@ -262,10 +269,9 @@

      Building Lua on other systems

      Changes since Lua 5.1

      -
      incomplete!

      Here are the main changes in Lua since its last release. -The +The reference manual lists the incompatibilities that had to be introduced. @@ -274,15 +280,32 @@

      Changes since Lua 5.1

      Language

      • new lexical environments. +
      • no more fenv for threads. +
      • ephemeron tables. +
      • yieldable pcall/metamethods. +
      • tables honor the __len metamethod. +
      • max constants per function raised to 2^26.
      • hex escapes in strings. -
      • tables and strings honor the __len metamethod. +
      • no more verification of opcode consistency. +

      Libraries

        -
      • new function package.searchpath. +
      • new library for bitwise operations.
      • new metamethods __pairs and __ipairs.
      • arguments for function called through xpcall. +
      • optional argument to load (to control binary x text). +
      • loadlib may load libraries with global names (RTLD_GLOBAL). +
      • new function package.searchpath. +
      • optional base in math.log. +
      • file:write returns file. +
      • closing a pipe returns exit status. +
      • os.exit may close state. +
      • new option 'isrunning' for collectgarbage and lua_gc. +
      • frontier patterns. +
      • ipairs now goes until #t. +

      Implementation

      @@ -291,9 +314,12 @@

      Implementation

      (core forces a full collection when allocation fails).
    • ephemeron tables (tables with weak keys only visit value when key is accessible) -
    • handling of non-string error messages. +
    • handling of non-string error messages in the standalone interpreter.
    • udata with finalizers are kept in a separated list for the GC. -relevant? +
    • CallInfo stack now is a linked list. +
    • internal (immutable) version of ctypes. +
    • parser uses much less C-stack space (no more auto arrays). +
    • new hash for floats.
    @@ -317,7 +343,7 @@

    License

    -Copyright © 1994-2010 Lua.org, PUC-Rio. +Copyright © 1994–2010 Lua.org, PUC-Rio.

    Permission is hereby granted, free of charge, to any person obtaining a copy @@ -346,8 +372,11 @@

    License


    Last update: -Fri Jan 8 16:41:16 BRST 2010 +Wed Jan 13 15:35:05 BRST 2010 + diff --git a/etc/Makefile b/etc/Makefile index 6d00008d98..5f6ed87295 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -9,7 +9,7 @@ TST= $(TOP)/test CC= gcc CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) -MYCFLAGS= +MYCFLAGS= MYLDFLAGS= -Wl,-E MYLIBS= -lm #MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses @@ -21,6 +21,8 @@ default: min: min.c $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS) echo 'print"Hello there!"' | ./a.out + ./a.out $(TST)/hello.lua + echo 'print("Hello world, from",_VERSION,"!")' | ./a.out noparser: noparser.o $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) @@ -29,7 +31,7 @@ noparser: noparser.o -./a.out -e'a=1' one: - $(CC) $(CFLAGS) all.c $(MYLIBS) + $(CC) $(CFLAGS) one.c $(MYLIBS) ./a.out $(TST)/hello.lua strict: diff --git a/etc/README b/etc/README index 99cbb5236c..300257ae50 100644 --- a/etc/README +++ b/etc/README @@ -1,10 +1,10 @@ This directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. -If any of the makes fail, you're probably not using the same libraries -used to build Lua. Set MYLIBS in Makefile or in the command line accordingly. +If any of the makes fail, you're probably not using the same libraries used +to build Lua. Set MYLIBS in Makefile or in the command line accordingly. -all.c +one.c Full Lua interpreter in a single file. Do "make one" for a demo. diff --git a/etc/luavs.bat b/etc/luavs.bat index 08c2beddf6..145187131c 100644 --- a/etc/luavs.bat +++ b/etc/luavs.bat @@ -1,6 +1,6 @@ -@rem Script to build Lua under "Visual Studio .NET Command Prompt". +@rem Script to build Lua 5.2 under "Visual Studio .NET Command Prompt". @rem Do not run from this directory; run it from the toplevel: etc\luavs.bat . -@rem It creates lua51.dll, lua51.lib, lua.exe, and luac.exe in src. +@rem It creates lua52.dll, lua52.lib, lua.exe, and luac.exe in src. @rem (contributed by David Manura and Mike Pall) @setlocal @@ -11,11 +11,11 @@ cd src %MYCOMPILE% /DLUA_BUILD_AS_DLL l*.c del lua.obj luac.obj -%MYLINK% /DLL /out:lua51.dll l*.obj -if exist lua51.dll.manifest^ - %MYMT% -manifest lua51.dll.manifest -outputresource:lua51.dll;2 +%MYLINK% /DLL /out:lua52.dll l*.obj +if exist lua52.dll.manifest^ + %MYMT% -manifest lua52.dll.manifest -outputresource:lua52.dll;2 %MYCOMPILE% /DLUA_BUILD_AS_DLL lua.c -%MYLINK% /out:lua.exe lua.obj lua51.lib +%MYLINK% /out:lua.exe lua.obj lua52.lib if exist lua.exe.manifest^ %MYMT% -manifest lua.exe.manifest -outputresource:lua.exe %MYCOMPILE% l*.c print.c diff --git a/etc/min.c b/etc/min.c index 81e3b73d51..0b6a5c3252 100644 --- a/etc/min.c +++ b/etc/min.c @@ -1,6 +1,6 @@ /* * min.c -- a minimal Lua interpreter -* runs one file from the command line or stdin if none given. +* runs one file from the command line or stdin if no file given. * minimal error handling, no traceback, no interaction, no standard library, * only a "print" function. */ @@ -15,22 +15,19 @@ static int print(lua_State *L) { int n=lua_gettop(L); int i; - const char *s=""; for (i=1; i<=n; i++) - { - printf("%s%s",s,luaL_tolstring(L,i,NULL)); - s="\t"; - } + printf("%s ",luaL_tolstring(L,i,NULL)); printf("\n"); return 0; } int main(int argc, char *argv[]) { - lua_State *L=lua_open(); - lua_register(L,"print",print); + lua_State *L=luaL_newstate(); luaL_openlibs(L); - if (luaL_dofile(L,argv[1])!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); + lua_register(L,"print",print); + if (luaL_dofile(L,argv[1])!=0) + fprintf(stderr,"%s: %s\n",argv[0],lua_tostring(L,-1)); lua_close(L); return 0; } diff --git a/etc/noparser.c b/etc/noparser.c index 5e0e203114..f1fd4aea6a 100644 --- a/etc/noparser.c +++ b/etc/noparser.c @@ -34,7 +34,7 @@ LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl UNUSED(z); UNUSED(buff); UNUSED(name); - lua_pushliteral(L,"parser not loaded"); + lua_pushliteral(L,"parser not available"); lua_error(L); return NULL; } @@ -49,7 +49,7 @@ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, UNUSED(w); UNUSED(data); UNUSED(strip); - lua_pushliteral(L,"dumper not loaded"); + lua_pushliteral(L,"dumper not available"); lua_error(L); return 0; } @@ -63,7 +63,7 @@ LUAI_FUNC Proto *luaU_undump (lua_State *L, ZIO *z, Mbuffer *buff, const char *n UNUSED(z); UNUSED(buff); UNUSED(name); - lua_pushliteral(L,"cannot load binary chunks"); + lua_pushliteral(L,"binary loader not available"); lua_error(L); return NULL; } diff --git a/etc/all.c b/etc/one.c similarity index 95% rename from etc/all.c rename to etc/one.c index a7f21b7df0..be1f3a40a5 100644 --- a/etc/all.c +++ b/etc/one.c @@ -1,5 +1,5 @@ /* -* all.c -- Lua core, libraries, and interpreter in a single file +* one.c -- Lua core, libraries, and interpreter in a single file */ /* default is to build the full interpreter */ diff --git a/etc/strict.lua b/etc/strict.lua index 604619dd2e..5ce1aa85bf 100644 --- a/etc/strict.lua +++ b/etc/strict.lua @@ -6,6 +6,7 @@ -- anywhere or assigned to inside a function. -- +require"debug" local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget local mt = getmetatable(_G) diff --git a/src/lapi.c b/src/lapi.c index b822a7259a..56c0c1e9d8 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.109 2010/01/08 15:16:56 roberto Exp $ +** $Id: lapi.c,v 2.111 2010/01/13 16:18:25 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -255,7 +255,7 @@ LUA_API int lua_type (lua_State *L, int idx) { LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); - return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; + return typename(t); } @@ -300,7 +300,8 @@ LUA_API void lua_arith (lua_State *L, int op) { luaO_arith(op, nvalue(L->top - 2), nvalue(L->top - 1))); } else - luaV_arith(L, L->top - 2, L->top - 2, L->top - 1, op - LUA_OPADD + TM_ADD); + luaV_arith(L, L->top - 2, L->top - 2, L->top - 1, + cast(TMS, op - LUA_OPADD + TM_ADD)); L->top--; lua_unlock(L); } diff --git a/src/lauxlib.h b/src/lauxlib.h index d014348179..b8f2e2e51e 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.98 2010/01/06 15:14:15 roberto Exp $ +** $Id: lauxlib.h,v 1.99 2010/01/11 16:00:45 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -29,8 +29,6 @@ typedef struct luaL_Reg { LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); #define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) -LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, - const luaL_Reg *l, int nup); LUALIB_API void (luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); diff --git a/src/lbitlib.c b/src/lbitlib.c index 5b6a6aae06..1d5a26421e 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,9 +1,12 @@ /* -** $Id: lbitlib.c,v 1.2 2009/11/24 12:05:44 roberto Exp $ +** $Id: lbitlib.c,v 1.3 2010/01/12 19:40:02 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ +#define lbitlib_c +#define LUA_LIB + #include "lua.h" #include "lauxlib.h" diff --git a/src/lcode.c b/src/lcode.c index 4f10e09544..c55ebd549d 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.42 2009/09/23 20:33:05 roberto Exp $ +** $Id: lcode.c,v 2.43 2010/01/11 17:38:30 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -830,15 +830,15 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_MOD: case OPR_POW: { - codearith(fs, op - OPR_ADD + OP_ADD, e1, e2); + codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2); break; } case OPR_EQ: case OPR_LT: case OPR_LE: { - codecomp(fs, op - OPR_EQ + OP_EQ, 1, e1, e2); + codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2); break; } case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, op - OPR_NE + OP_EQ, 0, e1, e2); + codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2); break; } default: lua_assert(0); diff --git a/src/ldebug.c b/src/ldebug.c index 1c18d70122..2544a5dd4b 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.61 2010/01/06 14:42:35 roberto Exp $ +** $Id: ldebug.c,v 2.63 2010/01/13 16:18:25 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -363,7 +363,7 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { - TMS tm = 0; + TMS tm; Instruction i; if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous)) return NULL; /* calling function is not Lua (or is unknown) */ @@ -416,7 +416,7 @@ static int isinstack (CallInfo *ci, const TValue *o) { void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { CallInfo *ci = L->ci; const char *name = NULL; - const char *t = luaT_typenames[ttype(o)]; + const char *t = typename(ttype(o)); const char *kind = (isLua(ci) && isinstack(ci, o)) ? getobjname(L, ci, cast_int(o - ci->u.l.base), &name) : NULL; @@ -444,9 +444,9 @@ void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { - const char *t1 = luaT_typenames[ttype(p1)]; - const char *t2 = luaT_typenames[ttype(p2)]; - if (t1[2] == t2[2]) + const char *t1 = typename(ttype(p1)); + const char *t2 = typename(ttype(p2)); + if (t1 == t2) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); diff --git a/src/ldo.c b/src/ldo.c index 555113d3c8..4890ce21c4 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.79 2009/12/22 15:32:50 roberto Exp $ +** $Id: ldo.c,v 2.80 2010/01/13 16:17:32 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -554,8 +554,12 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { luai_userstateyield(L, nresults); lua_lock(L); api_checknelems(L, nresults); - if (L->nny > 0) - luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + if (L->nny > 0) { + if (L != G(L)->mainthread) + luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + else + luaG_runerror(L, "attempt to yield from outside a coroutine"); + } L->status = LUA_YIELD; if (isLua(ci)) { /* inside a hook? */ api_check(L, k == NULL, "hooks cannot continue after yielding"); diff --git a/src/loadlib.c b/src/loadlib.c index 8b2d691194..90c785dc11 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.73 2010/01/06 14:35:17 roberto Exp $ +** $Id: loadlib.c,v 1.80 2010/01/13 16:30:27 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -129,9 +129,18 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { ** ======================================================================= */ +#include #undef setprogdir +/* +** optional flags for LoadLibraryEx +*/ +#if !defined(LUA_LLE_FLAGS) +#define LUA_LLE_FLAGS 0 +#endif + + static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; @@ -158,12 +167,12 @@ static void pusherror (lua_State *L) { } static void ll_unloadlib (void *lib) { - FreeLibrary((HINSTANCE)lib); + FreeLibrary((HMODULE)lib); } static void *ll_load (lua_State *L, const char *path, int seeglb) { - HINSTANCE lib = LoadLibrary(path); + HMODULE lib = LoadLibraryEx(path, NULL, LUA_LLE_FLAGS); (void)(seeglb); /* symbols are 'global' by default? */ if (lib == NULL) pusherror(L); return lib; @@ -171,7 +180,7 @@ static void *ll_load (lua_State *L, const char *path, int seeglb) { static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); + lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); if (f == NULL) pusherror(L); return f; } @@ -344,7 +353,9 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else return function */ + lua_pushcfunction(L, f); /* else create new function... */ + lua_pushglobaltable(L); /* ... and set the standard global table... */ + lua_setfenv(L, -2); /* ... as its environment */ return 0; /* no errors */ } } @@ -394,6 +405,7 @@ static const char *pushnexttemplate (lua_State *L, const char *path) { static const char *searchpath (lua_State *L, const char *name, const char *path) { + name = luaL_gsub(L, name, ".", LUA_DIRSEP); lua_pushliteral(L, ""); /* error accumulator */ while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename = luaL_gsub(L, lua_tostring(L, -1), @@ -423,7 +435,6 @@ static int ll_searchpath (lua_State *L) { static const char *findfile (lua_State *L, const char *name, const char *pname) { const char *path; - name = luaL_gsub(L, name, ".", LUA_DIRSEP); lua_getfield(L, LUA_ENVIRONINDEX, pname); path = lua_tostring(L, -1); if (path == NULL) @@ -449,13 +460,20 @@ static int loader_Lua (lua_State *L) { } -static int loadfunc(lua_State *L, const char *filename, const char *modname) { +static int loadfunc (lua_State *L, const char *filename, const char *modname) { const char *funcname; - const char *mark = strchr(modname, *LUA_IGMARK); - if (mark) modname = mark + 1; - funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); - funcname = lua_pushfstring(L, POF"%s", funcname); - lua_remove(L, -2); /* remove 'gsub' result */ + const char *mark; + modname = luaL_gsub(L, modname, ".", LUA_OFSEP); + mark = strchr(modname, *LUA_IGMARK); + if (mark) { + int stat; + funcname = lua_pushlstring(L, modname, mark - modname); + funcname = lua_pushfstring(L, POF"%s", funcname); + stat = ll_loadfunc(L, filename, funcname); + if (stat != ERRFUNC) return stat; + modname = mark + 1; /* else go ahead and try old-style name */ + } + funcname = lua_pushfstring(L, POF"%s", modname); return ll_loadfunc(L, filename, funcname); } diff --git a/src/ltablib.c b/src/ltablib.c index b2360807c8..6ad6b8e00c 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.53 2009/12/28 16:30:31 roberto Exp $ +** $Id: ltablib.c,v 1.54 2010/01/13 19:59:10 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -178,6 +178,8 @@ static int pack (lua_State *L) { for (; top >= 1; top--) /* assign elements */ lua_rawseti(L, LUA_ENVIRONINDEX, top); lua_pushvalue(L, LUA_ENVIRONINDEX); /* return new table */ + /* remove new table from environment to allow its later collection */ + lua_copy(L, LUA_REGISTRYINDEX, LUA_ENVIRONINDEX); return 1; } diff --git a/src/ltm.c b/src/ltm.c index cf675652db..3a9e73ca79 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.10 2009/11/19 19:06:52 roberto Exp $ +** $Id: ltm.c,v 2.11 2010/01/13 16:18:25 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -19,10 +19,12 @@ #include "ltm.h" +static const char udatatypename[] = "userdata"; -LUAI_DDEF const char *const luaT_typenames[] = { - "nil", "boolean", "userdata", "number", - "string", "table", "function", "userdata", "thread", +LUAI_DDEF const char *const luaT_typenames_[] = { + "no value", + "nil", "boolean", udatatypename, "number", + "string", "table", "function", udatatypename, "thread", "proto", "upval" }; diff --git a/src/ltm.h b/src/ltm.h index ba935d49bd..732aa12d94 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.8 2009/11/19 19:06:52 roberto Exp $ +** $Id: ltm.h,v 2.9 2010/01/13 16:18:25 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -43,7 +43,9 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) -LUAI_DDEC const char *const luaT_typenames[]; +#define typename(x) luaT_typenames_[(x) + 1] + +LUAI_DDEC const char *const luaT_typenames_[]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); diff --git a/src/lua.h b/src/lua.h index b86ac6cf63..f79df970f5 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.260 2010/01/06 15:08:00 roberto Exp $ +** $Id: lua.h,v 1.261 2010/01/11 17:15:11 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -17,9 +17,9 @@ #define LUA_VERSION "Lua 5.2" -#define LUA_RELEASE "Lua 5.2.0 (work1)" +#define LUA_RELEASE "Lua 5.2.0 (work2)" #define LUA_VERSION_NUM 502 -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2010 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -395,7 +395,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2010 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/luaconf.h b/src/luaconf.h index 9cd0beb2fb..b16e99915a 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.127 2010/01/06 15:15:04 roberto Exp $ +** $Id: luaconf.h,v 1.130 2010/01/11 17:15:30 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -34,7 +34,6 @@ #endif #if defined(LUA_WIN) -#include #define LUA_DL_DLL #endif @@ -92,8 +91,8 @@ #else #define LUA_ROOT "/usr/local/" -#define LUA_LDIR LUA_ROOT "share/lua/5.1/" -#define LUA_CDIR LUA_ROOT "lib/lua/5.1/" +#define LUA_LDIR LUA_ROOT "share/lua/5.2/" +#define LUA_CDIR LUA_ROOT "lib/lua/5.2/" #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" @@ -440,8 +439,9 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* On a Microsoft compiler, use assembler */ #if defined(_MSC_VER) -#define lua_number2int(i,d) __asm fld d __asm fistp i +#define lua_number2int(i,d) {__asm fld d __asm fistp i} #define lua_number2integer(i,n) lua_number2int(i, n) +#define lua_number2uint(i,n) lua_number2int(i, n) #else /* the next trick should work on any Pentium, but sometimes clashes From f970e1e83ed07bbcf8a20fc1a95f91a0a2aae620 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 18 May 2010 12:00:00 +0000 Subject: [PATCH 50/97] Lua 5.2.0-work3 --- Makefile | 2 +- README | 2 +- doc/amazon.gif | Bin 797 -> 0 bytes doc/contents.html | 158 +- doc/cover.png | Bin 3305 -> 0 bytes doc/manual.html | 3726 ++++++++++++++++++++-------------------- doc/readme.html | 76 +- etc/Makefile | 48 +- etc/README | 13 +- etc/dummy.c | 11 + etc/one.c | 6 +- src/Makefile | 10 +- src/lapi.c | 240 +-- src/lauxlib.c | 201 +-- src/lauxlib.h | 39 +- src/lbaselib.c | 95 +- src/lbitlib.c | 34 +- src/lcode.c | 51 +- src/lcode.h | 8 +- src/ldblib.c | 30 +- src/ldebug.c | 116 +- src/ldo.c | 75 +- src/ldump.c | 3 +- src/lfunc.c | 23 +- src/lfunc.h | 6 +- src/lgc.c | 692 +++++--- src/lgc.h | 91 +- src/linit.c | 9 +- src/liolib.c | 129 +- src/llex.c | 116 +- src/llex.h | 3 +- src/llimits.h | 13 +- src/lmem.c | 29 +- src/lmem.h | 4 +- src/loadlib.c | 31 +- src/lobject.c | 38 +- src/lobject.h | 58 +- src/lopcodes.c | 10 +- src/lopcodes.h | 9 +- src/lparser.c | 184 +- src/lparser.h | 11 +- src/lstate.c | 80 +- src/lstate.h | 34 +- src/lstring.c | 8 +- src/lstring.h | 12 +- src/lstrlib.c | 132 +- src/ltable.c | 7 +- src/ltablib.c | 20 +- src/ltm.c | 4 +- src/ltm.h | 5 +- src/lua.c | 52 +- src/lua.h | 30 +- src/luac.c | 31 +- src/luaconf.h | 71 +- src/lundump.c | 3 +- src/lvm.c | 334 ++-- src/print.c | 21 +- test/ALL.lua | 26 - test/README | 26 - test/bisect.lua | 27 - test/cf.lua | 16 - test/echo.lua | 5 - test/env.lua | 7 - test/factorial.lua | 32 - test/fib.lua | 40 - test/fibfor.lua | 13 - test/globals.lua | 13 - test/life.lua | 111 -- test/luac.lua | 7 - test/printf.lua | 7 - test/readonly.lua | 12 - test/sieve.lua | 29 - test/sort.lua | 66 - test/table.lua | 12 - test/trace-calls.lua | 32 - test/trace-globals.lua | 38 - test/xd.lua | 15 - 77 files changed, 3827 insertions(+), 3951 deletions(-) delete mode 100644 doc/amazon.gif delete mode 100644 doc/cover.png create mode 100644 etc/dummy.c delete mode 100644 test/ALL.lua delete mode 100644 test/README delete mode 100644 test/bisect.lua delete mode 100644 test/cf.lua delete mode 100644 test/echo.lua delete mode 100644 test/env.lua delete mode 100644 test/factorial.lua delete mode 100644 test/fib.lua delete mode 100644 test/fibfor.lua delete mode 100644 test/globals.lua delete mode 100644 test/life.lua delete mode 100644 test/luac.lua delete mode 100644 test/printf.lua delete mode 100644 test/readonly.lua delete mode 100644 test/sieve.lua delete mode 100644 test/sort.lua delete mode 100644 test/table.lua delete mode 100644 test/trace-calls.lua delete mode 100644 test/trace-globals.lua delete mode 100644 test/xd.lua diff --git a/Makefile b/Makefile index 3e8b4b9850..db263e6615 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ none: @echo " $(PLATS)" @echo "See doc/readme.html for complete instructions." -# make may get confused with test/ and install/ in a case-insensitive OS +# make may get confused with test/ and install/ dummy: # echo config parameters diff --git a/README b/README index 678a301ae2..9153023082 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Lua 5.2 (work2), released on 13 Jan 2010. +This is Lua 5.2 (work3), released on 18 May 2010. For information about Lua, including installation instructions and license details, see doc/readme.html. diff --git a/doc/amazon.gif b/doc/amazon.gif deleted file mode 100644 index f2586d5765361bb8a33a72401449f3abdefe4e16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 797 zcmV+&1LFKgNk%w1VOjtj0K^&q@9)h50%r{k3;+NBK0Y<5t#HiDnQw1j_x9wkua=aQ zf8O4{J3ExYz@^dAvgzr__o-L@ehvGQF7LT?@$1I#;Ij3_g2%_+^3u}mmw|9dEECm0Kc!X!@|#@3&?4Fr)=|m57&HqxlCDW&_KZ+1;`8vSj33YC_e@b zLW(B90kQ_n9Ds8N3z4jU4HiAyWz9`JYknO6suY&Mn*c`+`V13=EEIuKH*uwDKrGlz zo{tDTNaHR5yf%>5cyj}g-^zXgiM@QV=g%Gh303A)7B84EpbPvE-6X=O$DmxJ`b(9|4E82-m%Ds!U< zI=HL8TMx@{~>s4%C(a0wK8Wjd@n+|5vxOvSr(vuAh- z5-e0mzlK5u3lKm6pnB`22G3HYpfaDDC`;MbMg*4 b)M@9Pc;4WH3w-wJ=bwNED(Iksh5!INDePJ9 diff --git a/doc/contents.html b/doc/contents.html index 66d967e36d..b9ae234019 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -20,6 +20,11 @@

    Lua 5.2 Reference Manual

    + +This is a work version of Lua 5.2. +Everything may change in the final version. +

    + The reference manual is the official definition of the Lua language. For a complete introduction to Lua programming, see the book Programming in Lua. @@ -42,94 +47,95 @@

    Contents

    -

     

    file:close
    file:flush
    file:lines
    @@ -228,6 +233,9 @@

     

    io.write

    +

    +

     

    math.abs
    math.acos
    math.asin
    @@ -320,6 +328,7 @@

    C API

    lua_Writer

    +lua_absindex
    lua_atpanic
    lua_call
    lua_callk
    @@ -337,8 +346,8 @@

    C API

    lua_getfenv
    lua_getfield
    lua_getglobal
    -lua_gethookcount
    lua_gethook
    +lua_gethookcount
    lua_gethookmask
    lua_getinfo
    lua_getlocal
    @@ -385,11 +394,11 @@

    C API

    lua_pushvalue
    lua_pushvfstring
    lua_rawequal
    -lua_rawgeti
    lua_rawget
    +lua_rawgeti
    lua_rawlen
    -lua_rawseti
    lua_rawset
    +lua_rawseti
    lua_register
    lua_remove
    lua_replace
    @@ -464,6 +473,7 @@

    auxiliary library

    luaL_loadstring
    luaL_newmetatable
    luaL_newstate
    +luaL_openlib
    luaL_openlibs
    luaL_optint
    luaL_optinteger
    @@ -491,10 +501,10 @@

    auxiliary library


    Last update: -Wed Jan 13 15:31:47 BRST 2010 +Mon May 17 16:58:54 BRT 2010 diff --git a/doc/cover.png b/doc/cover.png deleted file mode 100644 index 2dbb198123f03a7250bfa57c8253739962d69afb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3305 zcmVNc=P)V>IGcGYOVIUw=dB=aTYv^*htKxL4xjCf9X{I|EBQ!hu?+M>5oT>TE}0ye97P9R7S8qXycMFZ&6rBQl2xq6d5z1RT?1tMWggH(oGfxZ3MRwMW* zhWcm<0o+gGDNJLnwySJIYqTbnA(cT&JjHAh%b?&;aM%-PVunbF`4oU{acLCOU~~ed z=Xys9YZpo#i8bMPc#43D)u4sMGKqI^_da6LW&~0K*cO4+ z_PRNFEtj+pK65RYy#Eh+iK_)|A>ml%LRW(G?uWEPuP@)V__gB&q{E^1Drx0`;n)|1&{JZ#-e7eMcd1S~0(ChdB8 zS0!Ap-8R#X^0X5R7@pQ0wmH~jKhYj`l%C2tznfmz5?4vXD&s9-{r%L{8o|B1n{hn> zX-7F)1C|g{Fjw^QO3xSEM8WF{nF8))ijLB@AziK0j<-dAU&NHQAw-4j8oelO%2Dg_ z37hiyuBd>qbbcrr0xb~*rLW9q2cyBcq8kgCW9j_Jd}=!9R2g|I=9{KHXtr2}hFHKH zPZ!2Bg|$47mFu;Duqg$YQfQ4vD~-}9t!+atHYg~SbM=?ElxgB&vnLeLny@Jo1@}ra zw-%pO_5&GLRc)GAp8w;^w0pr+)}6{$xN2*=h1(z&s0B5@zOQ2Cj<++EgPm6D*KdLp^Jc$%i(A&wq1mn{*M;Pu$%2I-|s;8_q`68Jd zLJ$dITeas|8_h>+9GB??ksz(jj7@SsNq-j_f;Mf@l8W*L-v0vui)W9N64OhM7aV?n zo{!IxNC9-U@zPPgc8EYtsn)ggZ<}BOc#01{#gH6*gjm!cMXYMFiJ5! z$8SI7^a#mxl?1n2Bwr+veIkV`2fdd@*by0Naq>o!4A;Y!nrTV7gj#l-OAs* zvT_zQj8DKsyvuDrVn7=m8 z&;O0T{VN_DroW5Nu5jxvQZU%ZlLv@3)#xH@icfQd{R930nH<0P?=qQ<5s3ufc;l~s z^rLTdbhJn*9LK$Q@z$Gf{__VPoYQ~*AN<{S=xOJbXHXg;Sjdpd5Nq1FU!ZP(bkV*K z5BX<_uE(!VaN&B59T#f)0@ixmc3_}Kkful!<-+AYa=bk&rr9RA^GG2#cH|o2Jo3*;M^C0Z#I`l`S@(jjq^e|^t7&J*rAXei$y>%zrcxe zzKVokW{ylvDyoN%5F8rxOC(&6ljrfOA4aT&iHZA4RiB-iOg@n)*W;YNOgdZoU&C~Q zYvZ-d>YDjzn4Be*DQQDPBE@KZ$^kz7@cjMzsnv(*TI*A%M(*BC03b*t8J+ZR_jR(6 zttGy#T|b&jH^^6g-e(O?=xBjqSdb8D)Kd$tjjQa}6Izo*l=AOHBZzP@%TWj?-Z2yYmt`$ryp=SGWT>kg8zlLgEEs(4iVm;4Q>56I~!I5E_!W;Hjvwox?Uqoq) z@&EyI&Dg6UFbzN8)tb&2Y&=@c`Y|NW9`Pe8A!)AFN8A)Nk)Urp8ZM1e+_>zsWuw3Gwz#h*<|ZTYWyBV&rD^+OOrPXFnaE_T4H3gMI7NJvIPCeSU~lbZRURtjFJ3 zOtR_n9@p1NEV@-WX*<9pdwg@TE&lANPj7A1!>6YW%k<@shB-1^pOm#iGtfhChrf42 zsVsLR)XYafILOn7Dzbrs7oH##T<@vPK}ueH!cSN`F26lfqvKnrf9<;5xmTWYf?eG_ zeX!9}PBYlclLvflOw3@&T9Q?4=KSZAi+(6#NWSqr9j%R{qzT%*cARj9+M7Z={YZ`Z zkUIHTCXWs=UG`IipsSVd{5f`@zJAseNAl`14({FT2Xbx{9&lM)RVZ}_{lVes;w@a^N+fz49V zNXZM2^W9f`Rcp=JFX(8gt1f+0`B4G4?=d#PKzC_k7?Qz0y4x6=B$uz#sndjmeCtJC zJ5DgL%uYf!d*Z&jYQX0B2)f!R6lrVmT}CPC?c~T_GI?g_YxBM}hQWc|eD9k)^C*Fe z?D1?8AQoMD2D71Pn?G+{G@(R_)@FY(T|5yQo#5loxID%}wj5$qei{Hm5DK!lj~Ach z@X#`~XwB_uPF>*Z&(R#ISEvU#FA)Nz`TQED$+JgFvs?%)ll=n>_cNbnY=Y|(+?{11 zL&3o^iG=8GW2ldzK00F6PjxbRUOh&1<7lUfP!D<@?6{2FWT>x{XIvqi2CY#FPoWf2 zVo0P!tZu2v=D9u1zJZdTwyAHS9=M*uGC8uBNRUK|GgrvwmU;C8q`)+=EkZW7g=ru~ z6RQpkqkiq>Ru+?vAkXbSVK7dSLn?*gy_ zjjN{!SUh^+iEFRr=;K9At8qQ=c=~M}HT#)sT^Fg(`nT>?C{y%_^R>wBb&6$ nh%8`n`v3p{2XskIMF-Xh6%#iZwFs;u00000NkvXXu0mjfd@Wp4 diff --git a/doc/manual.html b/doc/manual.html index 6ebd074022..aed41ceb32 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -16,6 +16,11 @@

    Lua 5.2 Reference Manual

    + +This is a work version of Lua 5.2. +Everything may change in the final version. +

    + by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    @@ -33,7 +38,7 @@

    - + @@ -84,179 +89,14 @@

    1 - Introduction

    -

    2 - The Language

    - -

    -This section describes the lexis, the syntax, and the semantics of Lua. -In other words, -this section describes -which tokens are valid, -how they can be combined, -and what their combinations mean. - - -

    -The language constructs will be explained using the usual extended BNF notation, -in which -{a} means 0 or more a's, and -[a] means an optional a. -Non-terminals are shown like non-terminal, -keywords are shown like kword, -and other terminal symbols are shown like `=´. -The complete syntax of Lua can be found in §8 -at the end of this manual. - - - -

    2.1 - Lexical Conventions

    - -

    -Lua is a free-form language. -It ignores spaces (including new lines) and comments -between lexical elements (tokens), -except as delimiters between names and keywords. - - -

    -Names -(also called identifiers) -in Lua can be any string of letters, -digits, and underscores, -not beginning with a digit. -This coincides with the definition of names in most languages. -Identifiers are used to name variables and table fields. - - -

    -The following keywords are reserved -and cannot be used as names: - - -

    -     and       break     do        else      elseif
    -     end       false     for       function  if
    -     in        local     nil       not       or
    -     repeat    return    then      true      until     while
    -
    - -

    -Lua is a case-sensitive language: -and is a reserved word, but And and AND -are two different, valid names. -As a convention, names starting with an underscore followed by -uppercase letters (such as _VERSION) -are reserved for internal global variables used by Lua. - - -

    -The following strings denote other tokens: - -

    -     +     -     *     /     %     ^     #
    -     ==    ~=    <=    >=    <     >     =
    -     (     )     {     }     [     ]
    -     ;     :     ,     .     ..    ...
    -
    - -

    -Literal strings -can be delimited by matching single or double quotes, -and can contain the following C-like escape sequences: -'\a' (bell), -'\b' (backspace), -'\f' (form feed), -'\n' (newline), -'\r' (carriage return), -'\t' (horizontal tab), -'\v' (vertical tab), -'\\' (backslash), -'\"' (quotation mark [double quote]), -and '\'' (apostrophe [single quote]). -Moreover, a backslash followed by a real newline -results in a newline in the string. -A character in a string can also be specified by its numerical value. -This can be done with the escape sequence \xXX, -where XX is a sequence of exactly two hexadecimal digits, -and with the escape sequence \ddd, -where ddd is a sequence of up to three decimal digits. -(Note that if a decimal escape is to be followed by a digit, -it must be expressed using exactly three digits.) -Strings in Lua can contain any 8-bit value, including embedded zeros, -which can be specified as '\0'. - - -

    -Literal strings can also be defined using a long format -enclosed by long brackets. -We define an opening long bracket of level n as an opening -square bracket followed by n equal signs followed by another -opening square bracket. -So, an opening long bracket of level 0 is written as [[, -an opening long bracket of level 1 is written as [=[, -and so on. -A closing long bracket is defined similarly; -for instance, a closing long bracket of level 4 is written as ]====]. -A long string starts with an opening long bracket of any level and -ends at the first closing long bracket of the same level. -It can contain any text except a closing bracket of the proper level. -Literals in this bracketed form can run for several lines, -do not interpret any escape sequences, -and ignore long brackets of any other level. -Any kind of end-of-line sequence -(carriage return, newline, carriage return followed by newline, -or newline followed by carriage return) -is converted to a simple newline. -You should not use long strings for non-text data; -Use instead a regular quoted literal with explicit escape sequences -for control characters. - - -

    -For convenience, -when the opening long bracket is immediately followed by a newline, -the newline is not included in the string. -As an example, in a system using ASCII -(in which 'a' is coded as 97, -newline is coded as 10, and '1' is coded as 49), -the five literal strings below denote the same string: - -

    -     a = 'alo\n123"'
    -     a = "alo\n123\""
    -     a = '\97lo\10\04923"'
    -     a = [[alo
    -     123"]]
    -     a = [==[
    -     alo
    -     123"]==]
    -
    - -

    -A numerical constant can be written with an optional decimal part -and an optional decimal exponent. -Lua also accepts integer hexadecimal constants, -by prefixing them with 0x. -Examples of valid numerical constants are - -

    -     3   3.0   3.1416   314.16e-2   0.31416E1   0xff   0x56
    -
    +

    2 - Basic Concepts

    -A comment starts with a double hyphen (--) -anywhere outside a string. -If the text immediately after -- is not an opening long bracket, -the comment is a short comment, -which runs until the end of the line. -Otherwise, it is a long comment, -which runs until the corresponding closing long bracket. -Long comments are frequently used to disable code temporarily. - - +This section describes some basic concepts of the language. -

    2.2 - Values and Types

    +

    2.1 - Values and Types

    Lua is a dynamically typed language. @@ -291,14 +131,14 @@

    2.2 - Values and Types

    String represents arrays of characters. Lua is 8-bit clean: -strings can contain any 8-bit character, -including embedded zeros ('\0') (see §2.1). +strings can contain any 8-bit value, +including embedded zeros ('\0').

    Lua can call (and manipulate) functions written in Lua and functions written in C -(see §2.5.8). +(see §3.4.9).

    @@ -309,7 +149,7 @@

    2.2 - Values and Types

    except assignment and identity test. However, by using metatables, the programmer can define operations for userdata values -(see §2.8). +(see §2.4). Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program. @@ -317,7 +157,7 @@

    2.2 - Values and Types

    The type thread represents independent threads of execution -and it is used to implement coroutines (see §2.11). +and it is used to implement coroutines (see §2.6). Do not confuse Lua threads with operating-system threads. Lua supports coroutines on all systems, even those that do not support threads. @@ -336,7 +176,7 @@

    2.2 - Values and Types

    The language supports this representation by providing a.name as syntactic sugar for a["name"]. There are several convenient ways to create tables in Lua -(see §2.5.7). +(see §3.4.8).

    @@ -345,7 +185,7 @@

    2.2 - Values and Types

    In particular, because functions are first-class values, table fields can contain functions. -Thus tables can also carry methods (see §2.5.9). +Thus tables can also carry methods (see §3.4.10).

    @@ -363,458 +203,480 @@

    2.2 - Values and Types

    -

    2.2.1 - Coercion

    -

    -Lua provides automatic conversion between -string and number values at run time. -Any arithmetic operation applied to a string tries to convert -this string to a number, following the usual conversion rules. -Conversely, whenever a number is used where a string is expected, -the number is converted to a string, in a reasonable format. -For complete control over how numbers are converted to strings, -use the format function from the string library -(see string.format). +

    2.2 - Environments and the Global Environment

    +

    +As discussed in §3.2 and §3.3.3, +any reference to a global name var is syntactically translated +to _ENV.var. +Moreover, any chunk is compiled in the scope of an external +variable called _ENV (see §3.3.1). +Any table used as the value of _ENV is usually called +an environment. +

    +Lua keeps a distinguished environment called the global environment. +This value is kept at a special index in the C registry (see §4.5). +In Lua, the variable _G is initialized with this same value. +

    +When Lua compiles a chunk, +it initializes the value of its _ENV variable +with the global environment (see load). +Therefore, by default, +global variables in Lua code refer to entries in the global environment. +Moreover, all standard libraries are loaded in the global environment, +and several functions there operate on that environment. +You can use loadin to load a chunk with a different environment. +(In C, you have to load the chunk and then change the value +of its first upvalue.) -

    2.3 - Variables

    -Variables are places that store values. +If you change the global environment in the registry +(through C code or the debug library), +all chunks loaded after the change will get the new environment. +Previously loaded chunks are not affected, however, +as each has its own copy of the environment in its _ENV variable. +Moreover, the variable _G +(which is stored in the original global environment) +is never updated by Lua. -There are three kinds of variables in Lua: -global variables, local variables, and table fields. -

    -A single name can denote a global variable or a local variable -(or a function's formal parameter, -which is a particular kind of local variable): -

    -	var ::= Name
    -

    -Name denotes identifiers, as defined in §2.1. +

    2.3 - Error Handling

    -Any variable is assumed to be global unless explicitly declared -as a local (see §2.4.7). -Local variables are lexically scoped: -local variables can be freely accessed by functions -defined inside their scope (see §2.6). +Because Lua is an embedded extension language, +all Lua actions start from C code in the host program +calling a function from the Lua library (see lua_pcall). +Whenever an error occurs during Lua compilation or execution, +control returns to C, +which can take appropriate measures +(such as printing an error message).

    -Before the first assignment to a variable, its value is nil. - +Lua code can explicitly generate an error by calling the +error function. +If you need to catch errors in Lua, +you can use the pcall function. -

    -Square brackets are used to index a table: -

    -	var ::= prefixexp `[´ exp `]´
    -

    -The meaning of accesses to global variables -and table fields can be changed via metatables. -An access to an indexed variable t[i] is equivalent to -a call gettable_event(t,i). -(See §2.8 for a complete description of the -gettable_event function. -This function is not defined or callable in Lua. -We use it here only for explanatory purposes.) -

    -The syntax var.Name is just syntactic sugar for -var["Name"]: -

    -	var ::= prefixexp `.´ Name
    -
    +

    2.4 - Metatables

    -All global variables live as fields in ordinary Lua tables, -called environment tables or simply -environments (see §2.9). -An access to a global variable x -is equivalent to _env.x, -which in turn is equivalent to - -

    -     gettable_event(_env, "x")
    -

    -where _env is the current environment (see §2.9). -(See §2.8 for a complete description of the -gettable_event function. -This function is not defined or callable in Lua. -Similarly, the _env variable is not defined in Lua. -We use them here only for explanatory purposes.) +Every value in Lua can have a metatable. +This metatable is an ordinary Lua table +that defines the behavior of the original value +under certain special operations. +You can change several aspects of the behavior +of operations over a value by setting specific fields in its metatable. +For instance, when a non-numeric value is the operand of an addition, +Lua checks for a function in the field "__add" in its metatable. +If it finds one, +Lua calls this function to perform the addition. +

    +We call the keys in a metatable events +and the values metamethods. +In the previous example, the event is "add" +and the metamethod is the function that performs the addition. +

    +You can query the metatable of any value +through the getmetatable function. -

    2.4 - Statements

    -Lua supports an almost conventional set of statements, -similar to those in Pascal or C. -This set includes -assignments, control structures, function calls, -and variable declarations. +You can replace the metatable of tables +through the setmetatable +function. +You cannot change the metatable of other types from Lua +(except by using the debug library); +you must use the C API for that. +

    +Tables and full userdata have individual metatables +(although multiple tables and userdata can share their metatables). +Values of all other types share one single metatable per type; +that is, there is one single metatable for all numbers, +one for all strings, etc. +By default, a value has no metatable, +but the string library sets a metatable for the string type (see §6.4). -

    2.4.1 - Chunks

    -The unit of execution of Lua is called a chunk. -A chunk is simply a sequence of statements, -which are executed sequentially. -Each statement can be optionally followed by a semicolon: - -

    -	chunk ::= {stat [`;´]}
    -

    -There are no empty statements and thus ';;' is not legal. - - -

    -Lua handles a chunk as the body of an anonymous function -with a variable number of arguments -(see §2.5.9). -As such, chunks can define local variables, -receive arguments, and return values. +A metatable controls how an object behaves in arithmetic operations, +order comparisons, concatenation, length operation, and indexing. +A metatable also can define a function to be called when a userdata +is garbage collected. +For each of these operations Lua associates a specific key +called an event. +When Lua performs one of these operations over a value, +it checks whether this value has a metatable with the corresponding event. +If so, the value associated with that key (the metamethod) +controls how Lua will perform the operation.

    -A chunk can be stored in a file or in a string inside the host program. -To execute a chunk, -Lua first pre-compiles the chunk into instructions for a virtual machine, -and then it executes the compiled code -with an interpreter for the virtual machine. +Metatables control the operations listed next. +Each operation is identified by its corresponding name. +The key for each operation is a string with its name prefixed by +two underscores, '__'; +for instance, the key for operation "add" is the +string "__add". +The semantics of these operations is better explained by a Lua function +describing how the interpreter executes the operation.

    -Chunks can also be pre-compiled into binary form; -see program luac for details. -Programs in source and compiled forms are interchangeable; -Lua automatically detects the file type and acts accordingly. - - - - - - -

    2.4.2 - Blocks

    -A block is a list of statements; -syntactically, a block is the same as a chunk: +The code shown here in Lua is only illustrative; +the real behavior is hard coded in the interpreter +and it is much more efficient than this simulation. +All functions used in these descriptions +(rawget, tonumber, etc.) +are described in §6.1. +In particular, to retrieve the metamethod of a given object, +we use the expression

    -	block ::= chunk
    -
    - -

    -A block can be explicitly delimited to produce a single statement: + metatable(obj)[event] +

    +This should be read as

    -	stat ::= do block end
    +     rawget(getmetatable(obj) or {}, event)
     

    -Explicit blocks are useful -to control the scope of variable declarations. -Explicit blocks are also sometimes used to -add a return or break statement in the middle -of another block (see §2.4.4). - +That is, the access to a metamethod does not invoke other metamethods, +and the access to objects with no metatables does not fail +(it simply results in nil). +

    +For the unary - and # operators, +the metamethod is called repeating the first argument as a second argument. +This extra argument is only to simplify Lua's internals; +it may be removed in future versions and therefore it is not present +in the following code. +(For most uses this extra argument is irrelevant.) -

    2.4.3 - Assignment

    -

    -Lua allows multiple assignments. -Therefore, the syntax for assignment -defines a list of variables on the left side -and a list of expressions on the right side. -The elements in both lists are separated by commas: -

    -	stat ::= varlist `=´ explist
    -	varlist ::= var {`,´ var}
    -	explist ::= exp {`,´ exp}
    -

    -Expressions are discussed in §2.5. +

      +
    • "add": +the + operation. -

      -Before the assignment, -the list of values is adjusted to the length of -the list of variables. -If there are more values than needed, -the excess values are thrown away. -If there are fewer values than needed, -the list is extended with as many nil's as needed. -If the list of expressions ends with a function call, -then all values returned by that call enter the list of values, -before the adjustment -(except when the call is enclosed in parentheses; see §2.5).

      -The assignment statement first evaluates all its expressions -and only then are the assignments performed. -Thus the code - -

      -     i = 3
      -     i, a[i] = i+1, 20
      -

      -sets a[3] to 20, without affecting a[4] -because the i in a[i] is evaluated (to 3) -before it is assigned 4. -Similarly, the line +The function getbinhandler below defines how Lua chooses a handler +for a binary operation. +First, Lua tries the first operand. +If its type does not define a handler for the operation, +then Lua tries the second operand.

      -     x, y = y, x
      +     function getbinhandler (op1, op2, event)
      +       return metatable(op1)[event] or metatable(op2)[event]
      +     end
       

      -exchanges the values of x and y, -and +By using this function, +the behavior of the op1 + op2 is

      -     x, y, z = y, z, x
      +     function add_event (op1, op2)
      +       local o1, o2 = tonumber(op1), tonumber(op2)
      +       if o1 and o2 then  -- both operands are numeric?
      +         return o1 + o2   -- '+' here is the primitive 'add'
      +       else  -- at least one of the operands is not numeric
      +         local h = getbinhandler(op1, op2, "__add")
      +         if h then
      +           -- call the handler with both operands
      +           return (h(op1, op2))
      +         else  -- no handler available: default behavior
      +           error(···)
      +         end
      +       end
      +     end
       

      -cyclically permutes the values of x, y, and z. - +

    • -

      -The meaning of assignments to global variables -and table fields can be changed via metatables. -An assignment to an indexed variable t[i] = val is equivalent to -settable_event(t,i,val). -(See §2.8 for a complete description of the -settable_event function. -This function is not defined or callable in Lua. -We use it here only for explanatory purposes.) +

    • "sub": +the - operation. +Behavior similar to the "add" operation. +
    • -

      -An assignment to a global variable x = val -is equivalent to the assignment -_env.x = val, -which in turn is equivalent to +

    • "mul": +the * operation. -
      -     settable_event(_env, "x", val)
      -

      -where _env is the environment of the running function. -(The _env variable is not defined in Lua. -We use it here only for explanatory purposes.) +Behavior similar to the "add" operation. +

    • +
    • "div": +the / operation. +Behavior similar to the "add" operation. +
    • +
    • "mod": +the % operation. +Behavior similar to the "add" operation, +with the operation +o1 - floor(o1/o2)*o2 as the primitive operation. +
    • -

      2.4.4 - Control Structures

      -The control structures -if, while, and repeat have the usual meaning and -familiar syntax: +

    • "pow": +the ^ (exponentiation) operation. +Behavior similar to the "add" operation, +with the function pow (from the C math library) +as the primitive operation. +
    • +
    • "unm": +the unary - operation.
      -	stat ::= while exp do block end
      -	stat ::= repeat block until exp
      -	stat ::= if exp then block {elseif exp then block} [else block] end
      +     function unm_event (op)
      +       local o = tonumber(op)
      +       if o then  -- operand is numeric?
      +         return -o  -- '-' here is the primitive 'unm'
      +       else  -- the operand is not numeric.
      +         -- Try to get a handler from the operand
      +         local h = metatable(op).__unm
      +         if h then
      +           -- call the handler with the operand
      +           return (h(op))
      +         else  -- no handler available: default behavior
      +           error(···)
      +         end
      +       end
      +     end
       

      -Lua also has a for statement, in two flavors (see §2.4.5). +

    • +
    • "concat": +the .. (concatenation) operation. -

      -The condition expression of a -control structure can return any value. -Both false and nil are considered false. -All values different from nil and false are considered true -(in particular, the number 0 and the empty string are also true). +

      +     function concat_event (op1, op2)
      +       if (type(op1) == "string" or type(op1) == "number") and
      +          (type(op2) == "string" or type(op2) == "number") then
      +         return op1 .. op2  -- primitive string concatenation
      +       else
      +         local h = getbinhandler(op1, op2, "__concat")
      +         if h then
      +           return (h(op1, op2))
      +         else
      +           error(···)
      +         end
      +       end
      +     end
      +

      +

    • + +
    • "len": +the # operation. -

      -In the repeatuntil loop, -the inner block does not end at the until keyword, -but only after the condition. -So, the condition can refer to local variables -declared inside the loop block. +

      +     function len_event (op)
      +       if type(op) == "string" then
      +         return strlen(op)      -- primitive string length
      +       else
      +         local h = metatable(op).__len
      +         if h then
      +           return (h(op))       -- call handler with the operand
      +         elseif type(op) == "table" then
      +           return #op              -- primitive table length
      +         else  -- no handler available: error
      +           error(···)
      +         end
      +       end
      +     end
      +

      +See §3.4.6 for a description of the length of a table. +

    • -

      -The return statement is used to return values -from a function or a chunk (which is just a function). +

    • "eq": +the == operation. -Functions and chunks can return more than one value, -and so the syntax for the return statement is +The function getequalhandler defines how Lua chooses a metamethod +for equality. +A metamethod is selected only when both values +being compared have the same type +and the same metamethod for the selected operation.
      -	stat ::= return [explist]
      -
      - -

      -The break statement is used to terminate the execution of a -while, repeat, or for loop, -skipping to the next statement after the loop: - - -

      -	stat ::= break
      +     function getequalhandler (op1, op2, event)
      +       if type(op1) ~= type(op2) then return nil end
      +       local mm1 = metatable(op1)[event]
      +       local mm2 = metatable(op2)[event]
      +       if mm1 == mm2 then return mm1 else return nil end
      +     end
       

      -A break ends the innermost enclosing loop. - - -

      -The return and break -statements can only be written as the last statement of a block. -If it is really necessary to return or break in the -middle of a block, -then an explicit inner block can be used, -as in the idioms -do return end and do break end, -because now return and break are the last statements in -their (inner) blocks. - - - - - -

      2.4.5 - For Statement

      - -

      - -The for statement has two forms: -one numeric and one generic. - - -

      -The numeric for loop repeats a block of code while a -control variable runs through an arithmetic progression. -It has the following syntax: +The "eq" event is defined as follows:

      -	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end
      +     function eq_event (op1, op2)
      +       if type(op1) ~= type(op2) then  -- different types?
      +         return false   -- different values
      +       end
      +       if op1 == op2 then   -- primitive equal?
      +         return true   -- values are equal
      +       end
      +       -- try metamethod
      +       local h = getequalhandler(op1, op2, "__eq")
      +       if h then
      +         return (h(op1, op2))
      +       else
      +         return false
      +       end
      +     end
       

      -The block is repeated for name starting at the value of -the first exp, until it passes the second exp by steps of the -third exp. -More precisely, a for statement like +

    • + +
    • "lt": +the < operation. -
      -     for v = e1, e2, e3 do block end
      -

      -is equivalent to the code:

      -     do
      -       local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
      -       if not (var and limit and step) then error() end
      -       while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
      -         local v = var
      -         block
      -         var = var + step
      +     function lt_event (op1, op2)
      +       if type(op1) == "number" and type(op2) == "number" then
      +         return op1 < op2   -- numeric comparison
      +       elseif type(op1) == "string" and type(op2) == "string" then
      +         return op1 < op2   -- lexicographic comparison
      +       else
      +         local h = getbinhandler(op1, op2, "__lt")
      +         if h then
      +           return (h(op1, op2))
      +         else
      +           error(···)
      +         end
              end
            end
       

      -Note the following: - -

        - -
      • -All three control expressions are evaluated only once, -before the loop starts. -They must all result in numbers. -
      • - -
      • -var, limit, and step are invisible variables. -The names shown here are for explanatory purposes only.
      • -
      • -If the third expression (the step) is absent, -then a step of 1 is used. -
      • +
      • "le": +the <= operation. -
      • -You can use break to exit a for loop. -
      • -
      • -The loop variable v is local to the loop; -you cannot use its value after the for ends or is broken. -If you need this value, -assign it to another variable before breaking or exiting the loop. +
        +     function le_event (op1, op2)
        +       if type(op1) == "number" and type(op2) == "number" then
        +         return op1 <= op2   -- numeric comparison
        +       elseif type(op1) == "string" and type(op2) == "string" then
        +         return op1 <= op2   -- lexicographic comparison
        +       else
        +         local h = getbinhandler(op1, op2, "__le")
        +         if h then
        +           return (h(op1, op2))
        +         else
        +           h = getbinhandler(op1, op2, "__lt")
        +           if h then
        +             return not h(op2, op1)
        +           else
        +             error(···)
        +           end
        +         end
        +       end
        +     end
        +

        +Note that, in the absence of a "le" metamethod, +Lua tries the "lt", assuming that a <= b is +equivalent to not (b < a).

      • -
      +
    • "index": +The indexing access table[key]. -

      -The generic for statement works over functions, -called iterators. -On each iteration, the iterator function is called to produce a new value, -stopping when this new value is nil. -The generic for loop has the following syntax:

      -	stat ::= for namelist in explist do block end
      -	namelist ::= Name {`,´ Name}
      +     function gettable_event (table, key)
      +       local h
      +       if type(table) == "table" then
      +         local v = rawget(table, key)
      +         if v ~= nil then return v end
      +         h = metatable(table).__index
      +         if h == nil then return nil end
      +       else
      +         h = metatable(table).__index
      +         if h == nil then
      +           error(···)
      +         end
      +       end
      +       if type(h) == "function" then
      +         return (h(table, key))     -- call the handler
      +       else return h[key]           -- or repeat operation on it
      +       end
      +     end
       

      -A for statement like +

    • + +
    • "newindex": +The indexing assignment table[key] = value. -
      -     for var_1, ···, var_n in explist do block end
      -

      -is equivalent to the code:

      -     do
      -       local f, s, var = explist
      -       while true do
      -         local var_1, ···, var_n = f(s, var)
      -         var = var_1
      -         if var == nil then break end
      -         block
      +     function settable_event (table, key, value)
      +       local h
      +       if type(table) == "table" then
      +         local v = rawget(table, key)
      +         if v ~= nil then rawset(table, key, value); return end
      +         h = metatable(table).__newindex
      +         if h == nil then rawset(table, key, value); return end
      +       else
      +         h = metatable(table).__newindex
      +         if h == nil then
      +           error(···)
      +         end
      +       end
      +       if type(h) == "function" then
      +         h(table, key,value)           -- call the handler
      +       else h[key] = value             -- or repeat operation on it
              end
            end
       

      -Note the following: - -

        - -
      • -explist is evaluated only once. -Its results are an iterator function, -a state, -and an initial value for the first iterator variable.
      • -
      • -f, s, and var are invisible variables. -The names are here for explanatory purposes only. -
      • +
      • "call": +called when Lua calls a value. -
      • -You can use break to exit a for loop. -
      • -
      • -The loop variables var_i are local to the loop; -you cannot use their values after the for ends. -If you need these values, -then assign them to other variables before breaking or exiting the loop. +
        +     function function_event (func, ...)
        +       if type(func) == "function" then
        +         return func(...)   -- primitive call
        +       else
        +         local h = metatable(func).__call
        +         if h then
        +           return h(func, ...)
        +         else
        +           error(···)
        +         end
        +       end
        +     end
        +

      @@ -822,1481 +684,1581 @@

      2.4.5 - For Statement

      -

      2.4.6 - Function Calls as Statements

      -To allow possible side-effects, -function calls can be executed as statements: - -

      -	stat ::= functioncall
      -

      -In this case, all returned values are thrown away. -Function calls are explained in §2.5.8. +

      2.5 - Garbage Collection

      +

      +Lua performs automatic memory management. +This means that +you have to worry neither about allocating memory for new objects +nor about freeing it when the objects are no longer needed. +Lua manages memory automatically by running +a garbage collector to collect all dead objects +(that is, objects that are no longer accessible from Lua). +All memory used by Lua is subject to automatic management: +tables, userdata, functions, threads, strings, etc. +

      +Lua implements an incremental mark-and-sweep collector. +It uses two numbers to control its garbage-collection cycles: +the garbage-collector pause and +the garbage-collector step multiplier. +Both use percentage points as units +(so that a value of 100 means an internal value of 1). -

      2.4.7 - Local Declarations

      -Local variables can be declared anywhere inside a block. -The declaration can include an initial assignment: - -

      -	stat ::= local namelist [`=´ explist]
      -

      -If present, an initial assignment has the same semantics -of a multiple assignment (see §2.4.3). -Otherwise, all variables are initialized with nil. +

      +The garbage-collector pause +controls how long the collector waits before starting a new cycle. +Larger values make the collector less aggressive. +Values smaller than 100 mean the collector will not wait to +start a new cycle. +A value of 200 means that the collector waits for the total memory in use +to double before starting a new cycle.

      -A chunk is also a block (see §2.4.1), -and so local variables can be declared in a chunk outside any explicit block. -The scope of such local variables extends until the end of the chunk. +The step multiplier +controls the relative speed of the collector relative to +memory allocation. +Larger values make the collector more aggressive but also increase +the size of each incremental step. +Values smaller than 100 make the collector too slow and +can result in the collector never finishing a cycle. +The default, 200, means that the collector runs at "twice" +the speed of memory allocation.

      -The visibility rules for local variables are explained in §2.6. +If you set the step multiplier to a very large number +(larger than 10% of the maximum number of +bytes that the program may use), +the collector behaves like a stop-the-world collector. +If you then set the pause to 200, +the collector behaves as in old Lua versions, +doing a complete collection every time Lua doubles its +memory usage. +

      +You can change these numbers by calling lua_gc in C +or collectgarbage in Lua. +With these functions you can also control +the collector directly (e.g., stop and restart it). -

      2.4.8 - Lexical Environments

      +

      2.5.1 - Garbage-Collection Metamethods

      -A lexical environment defines a new current environment (see §2.9) -for the code inside its block: - -

      -	stat ::= in exp do block end
      -

      -That is, a lexical environment changes the -table used to resolve all accesses -to global (free) variables inside a block. +Using the C API, +you can set garbage-collector metamethods for userdata (see §2.4). +These metamethods are also called finalizers. +Finalizers allow you to coordinate Lua's garbage collection +with external resource management +(such as closing files, network or database connections, +or freeing your own memory).

      -Inside a lexical environment, -the result of exp becomes the current environment. -Expression exp is evaluated only once in the beginning of -the statement and it is stored in a hidden local variable named -(environment). -Then, any global variable -(that is, a variable not declared as a local) -var inside block is accessed as -(environment).var. -Moreover, functions defined inside the block also use the -current environment as their environments (see §2.9). +Garbage userdata with a field __gc in their metatables are not +collected immediately by the garbage collector. +Instead, Lua puts them in a list. +After the collection, +Lua does the equivalent of the following function +for each userdata in that list: +

      +     function gc_event (udata)
      +       local h = metatable(udata).__gc
      +       if h then
      +         h(udata)
      +       end
      +     end
      +

      -A lexical environment does not shadow local declarations. -That is, any local variable that is visible just before -a lexical environment is still visible inside the environment. - - +At the end of each garbage-collection cycle, +the finalizers for userdata are called in reverse +order of their creation, +among those collected in that cycle. +That is, the first finalizer to be called is the one associated +with the userdata created last in the program. +The userdata itself is freed only in the next garbage-collection cycle. -

      2.5 - Expressions

      +

      2.5.2 - Weak Tables

      -The basic expressions in Lua are the following: +A weak table is a table whose elements are +weak references. +A weak reference is ignored by the garbage collector. +In other words, +if the only references to an object are weak references, +then the garbage collector will collect this object. -

      -	exp ::= prefixexp
      -	exp ::= nil | false | true
      -	exp ::= Number
      -	exp ::= String
      -	exp ::= function
      -	exp ::= tableconstructor
      -	exp ::= `...´
      -	exp ::= exp binop exp
      -	exp ::= unop exp
      -	prefixexp ::= var | functioncall | `(´ exp `)´
      -

      -Numbers and literal strings are explained in §2.1; -variables are explained in §2.3; -function definitions are explained in §2.5.9; -function calls are explained in §2.5.8; -table constructors are explained in §2.5.7. -Vararg expressions, -denoted by three dots ('...'), can only be used when -directly inside a vararg function; -they are explained in §2.5.9. +A weak table can have weak keys, weak values, or both. +A table with weak keys allows the collection of its keys, +but prevents the collection of its values. +A table with both weak keys and weak values allows the collection of +both keys and values. +In any case, if either the key or the value is collected, +the whole pair is removed from the table. +The weakness of a table is controlled by the +__mode field of its metatable. +If the __mode field is a string containing the character 'k', +the keys in the table are weak. +If __mode contains 'v', +the values in the table are weak.

      -Binary operators comprise arithmetic operators (see §2.5.1), -relational operators (see §2.5.2), logical operators (see §2.5.3), -and the concatenation operator (see §2.5.4). -Unary operators comprise the unary minus (see §2.5.1), -the unary not (see §2.5.3), -and the unary length operator (see §2.5.5). +A table with weak keys and strong values +is also called an ephemeron table. +In an ephemeron table, +a value is considered reachable only if its key is reachable. +In particular, +if the only reference to a key comes from its value, +the pair is removed.

      -Both function calls and vararg expressions can result in multiple values. -If an expression is used as a statement -(only possible for function calls (see §2.4.6)), -then its return list is adjusted to zero elements, -thus discarding all returned values. -If an expression is used as the last (or the only) element -of a list of expressions, -then no adjustment is made -(unless the call is enclosed in parentheses). -In all other contexts, -Lua adjusts the result list to one element, -discarding all values except the first one. +After you use a table as a metatable, +you should not change the value of its __mode field. +Otherwise, the weak behavior of the tables controlled by this +metatable is undefined.

      -Here are some examples: +Only objects that have an explicit construction +can be removed from weak tables. +Values, such as numbers and booleans, +are not subject to garbage collection, +and therefore are not removed from weak tables +(unless its associated value is collected). +Lua treats strings and light C functions as non-object values. -

      -     f()                -- adjusted to 0 results
      -     g(f(), x)          -- f() is adjusted to 1 result
      -     g(x, f())          -- g gets x plus all results from f()
      -     a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
      -     a,b = ...          -- a gets the first vararg parameter, b gets
      -                        -- the second (both a and b can get nil if there
      -                        -- is no corresponding vararg parameter)
      -     
      -     a,b,c = x, f()     -- f() is adjusted to 2 results
      -     a,b,c = f()        -- f() is adjusted to 3 results
      -     return f()         -- returns all results from f()
      -     return ...         -- returns all received vararg parameters
      -     return x,y,f()     -- returns x, y, and all results from f()
      -     {f()}              -- creates a list with all results from f()
      -     {...}              -- creates a list with all vararg parameters
      -     {f(), nil}         -- f() is adjusted to 1 result
      -

      -Any expression enclosed in parentheses always results in only one value. -Thus, -(f(x,y,z)) is always a single value, -even if f returns several values. -(The value of (f(x,y,z)) is the first value returned by f -or nil if f does not return any values.) +Userdata with finalizers has a special behavior in weak tables. +When a userdata is a value in a weak table, +it is removed from the table the first time it is collected, +before running its finalizer. +When it is a key, however, +it is removed from the table only when it is really freed, +after running its finalizer. +This behavior allows the finalizer to access values +associated with the userdata through weak tables. -

      2.5.1 - Arithmetic Operators

      -Lua supports the usual arithmetic operators: -the binary + (addition), -- (subtraction), * (multiplication), -/ (division), % (modulo), and ^ (exponentiation); -and unary - (negation). -If the operands are numbers, or strings that can be converted to -numbers (see §2.2.1), -then all operations have the usual meaning. -Exponentiation works for any exponent. -For instance, x^(-0.5) computes the inverse of the square root of x. -Modulo is defined as -

      -     a % b == a - math.floor(a/b)*b
      -

      -That is, it is the remainder of a division that rounds -the quotient towards minus infinity. +

      2.6 - Coroutines

      +

      +Lua supports coroutines, +also called collaborative multithreading. +A coroutine in Lua represents an independent thread of execution. +Unlike threads in multithread systems, however, +a coroutine only suspends its execution by explicitly calling +a yield function. -

      2.5.2 - Relational Operators

      -The relational operators in Lua are -

      -     ==    ~=    <     >     <=    >=
      -

      -These operators always result in false or true. +

      +You create a coroutine with a call to coroutine.create. +Its sole argument is a function +that is the main function of the coroutine. +The create function only creates a new coroutine and +returns a handle to it (an object of type thread); +it does not start the coroutine execution.

      -Equality (==) first compares the type of its operands. -If the types are different, then the result is false. -Otherwise, the values of the operands are compared. -Numbers and strings are compared in the usual way. -Objects (tables, userdata, threads, and functions) -are compared by reference: -two objects are considered equal only if they are the same object. -Every time you create a new object -(a table, userdata, thread, or function), -this new object is different from any previously existing object. +When you first call coroutine.resume, +passing as its first argument +a thread returned by coroutine.create, +the coroutine starts its execution, +at the first line of its main function. +Extra arguments passed to coroutine.resume are passed on +to the coroutine main function. +After the coroutine starts running, +it runs until it terminates or yields.

      -You can change the way that Lua compares tables and userdata -by using the "eq" metamethod (see §2.8). +A coroutine can terminate its execution in two ways: +normally, when its main function returns +(explicitly or implicitly, after the last instruction); +and abnormally, if there is an unprotected error. +In the first case, coroutine.resume returns true, +plus any values returned by the coroutine main function. +In case of errors, coroutine.resume returns false +plus an error message.

      -The conversion rules of §2.2.1 -do not apply to equality comparisons. -Thus, "0"==0 evaluates to false, -and t[0] and t["0"] denote different -entries in a table. +A coroutine yields by calling coroutine.yield. +When a coroutine yields, +the corresponding coroutine.resume returns immediately, +even if the yield happens inside nested function calls +(that is, not in the main function, +but in a function directly or indirectly called by the main function). +In the case of a yield, coroutine.resume also returns true, +plus any values passed to coroutine.yield. +The next time you resume the same coroutine, +it continues its execution from the point where it yielded, +with the call to coroutine.yield returning any extra +arguments passed to coroutine.resume.

      -The operator ~= is exactly the negation of equality (==). +Like coroutine.create, +the coroutine.wrap function also creates a coroutine, +but instead of returning the coroutine itself, +it returns a function that, when called, resumes the coroutine. +Any arguments passed to this function +go as extra arguments to coroutine.resume. +coroutine.wrap returns all the values returned by coroutine.resume, +except the first one (the boolean error code). +Unlike coroutine.resume, +coroutine.wrap does not catch errors; +any error is propagated to the caller.

      -The order operators work as follows. -If both arguments are numbers, then they are compared as such. -Otherwise, if both arguments are strings, -then their values are compared according to the current locale. -Otherwise, Lua tries to call the "lt" or the "le" -metamethod (see §2.8). -A comparison a > b is translated to b < a -and a >= b is translated to b <= a. +As an example, +consider the following code: +

      +     function foo (a)
      +       print("foo", a)
      +       return coroutine.yield(2*a)
      +     end
      +     
      +     co = coroutine.create(function (a,b)
      +           print("co-body", a, b)
      +           local r = foo(a+1)
      +           print("co-body", r)
      +           local r, s = coroutine.yield(a+b, a-b)
      +           print("co-body", r, s)
      +           return b, "end"
      +     end)
      +            
      +     print("main", coroutine.resume(co, 1, 10))
      +     print("main", coroutine.resume(co, "r"))
      +     print("main", coroutine.resume(co, "x", "y"))
      +     print("main", coroutine.resume(co, "x", "y"))
      +

      +When you run it, it produces the following output: +

      +     co-body 1       10
      +     foo     2
      +     
      +     main    true    4
      +     co-body r
      +     main    true    11      -9
      +     co-body x       y
      +     main    true    10      end
      +     main    false   cannot resume dead coroutine
      +
      -

      2.5.3 - Logical Operators

      -The logical operators in Lua are -and, or, and not. -Like the control structures (see §2.4.4), -all logical operators consider both false and nil as false -and anything else as true. +

      3 - The Language

      -The negation operator not always returns false or true. -The conjunction operator and returns its first argument -if this value is false or nil; -otherwise, and returns its second argument. -The disjunction operator or returns its first argument -if this value is different from nil and false; -otherwise, or returns its second argument. -Both and and or use short-cut evaluation; -that is, -the second operand is evaluated only if necessary. -Here are some examples: +This section describes the lexis, the syntax, and the semantics of Lua. +In other words, +this section describes +which tokens are valid, +how they can be combined, +and what their combinations mean. -

      -     10 or 20            --> 10
      -     10 or error()       --> 10
      -     nil or "a"          --> "a"
      -     nil and 10          --> nil
      -     false and error()   --> false
      -     false and nil       --> false
      -     false or nil        --> nil
      -     10 and 20           --> 20
      -

      -(In this manual, ---> indicates the result of the preceding expression.) +

      +The language constructs will be explained using the usual extended BNF notation, +in which +{a} means 0 or more a's, and +[a] means an optional a. +Non-terminals are shown like non-terminal, +keywords are shown like kword, +and other terminal symbols are shown like &lsquo=’. +The complete syntax of Lua can be found in §9 +at the end of this manual. +

      3.1 - Lexical Conventions

      + +

      +Lua is a free-form language. +It ignores spaces (including new lines) and comments +between lexical elements (tokens), +except as delimiters between names and keywords. -

      2.5.4 - Concatenation

      -The string concatenation operator in Lua is -denoted by two dots ('..'). -If both operands are strings or numbers, then they are converted to -strings according to the rules mentioned in §2.2.1. -Otherwise, the "concat" metamethod is called (see §2.8). +

      +Names +(also called identifiers) +in Lua can be any string of letters, +digits, and underscores, +not beginning with a digit. +This coincides with the definition of names in most languages. +Identifiers are used to name variables and table fields. +

      +The following keywords are reserved +and cannot be used as names: -

      2.5.5 - The Length Operator

      +
      +     and       break     do        else      elseif
      +     end       false     for       function  if
      +     in        local     nil       not       or
      +     repeat    return    then      true      until     while
      +

      -The length operator is denoted by the unary prefix operator #. -The length of a string is its number of bytes -(that is, the usual meaning of string length when each -character is one byte). +Lua is a case-sensitive language: +and is a reserved word, but And and AND +are two different, valid names. +As a convention, names starting with an underscore followed by +uppercase letters (such as _VERSION) +are reserved for variables used by Lua.

      -The length of a table t is defined to be any -integer index n -such that t[n] is not nil and t[n+1] is nil; -moreover, if t[1] is nil, n can be zero. -For a regular array, where all non-nil values -have keys from 1 to a given n, -its length is exactly that n, -the index of its last value. -If the array has "holes" -(that is, nil values between other non-nil values), -then #t can be any of the indices that -directly precedes a nil value -(that is, it may consider any such nil value as the end of -the array). +The following strings denote other tokens: + +

      +     +     -     *     /     %     ^     #
      +     ==    ~=    <=    >=    <     >     =
      +     (     )     {     }     [     ]
      +     ;     :     ,     .     ..    ...
      +
      + +

      +Literal strings +can be delimited by matching single or double quotes, +and can contain the following C-like escape sequences: +'\a' (bell), +'\b' (backspace), +'\f' (form feed), +'\n' (newline), +'\r' (carriage return), +'\t' (horizontal tab), +'\v' (vertical tab), +'\\' (backslash), +'\"' (quotation mark [double quote]), +and '\'' (apostrophe [single quote]). +A backslash followed by a real newline +results in a newline in the string. +The escape sequence '\*' skips the following span +of white-space characters, +including line breaks; +it is particularly useful to break and ident a string +into multiple lines without adding the newlines and spaces +into the string contents.

      -A program can modify the behavior of the length operator for -any value but strings through metamethods (see §2.8). +A character in a literal string can also be specified by its numerical value. +This can be done with the escape sequence \xXX, +where XX is a sequence of exactly two hexadecimal digits, +or with the escape sequence \ddd, +where ddd is a sequence of up to three decimal digits. +(Note that if a decimal escape is to be followed by a digit, +it must be expressed using exactly three digits.) +Strings in Lua can contain any 8-bit value, including embedded zeros, +which can be specified as '\0'. +

      +Literal strings can also be defined using a long format +enclosed by long brackets. +We define an opening long bracket of level n as an opening +square bracket followed by n equal signs followed by another +opening square bracket. +So, an opening long bracket of level 0 is written as [[, +an opening long bracket of level 1 is written as [=[, +and so on. +A closing long bracket is defined similarly; +for instance, a closing long bracket of level 4 is written as ]====]. +A long string starts with an opening long bracket of any level and +ends at the first closing long bracket of the same level. +It can contain any text except a closing bracket of the proper level. +Literals in this bracketed form can run for several lines, +do not interpret any escape sequences, +and ignore long brackets of any other level. +Any kind of end-of-line sequence +(carriage return, newline, carriage return followed by newline, +or newline followed by carriage return) +is converted to a simple newline. +You should not use long strings for non-text data; +Use instead a regular quoted literal with explicit escape sequences +for control characters. +

      +For convenience, +when the opening long bracket is immediately followed by a newline, +the newline is not included in the string. +As an example, in a system using ASCII +(in which 'a' is coded as 97, +newline is coded as 10, and '1' is coded as 49), +the five literal strings below denote the same string: -

      2.5.6 - Precedence

      -Operator precedence in Lua follows the table below, -from lower to higher priority: +

      +     a = 'alo\n123"'
      +     a = "alo\n123\""
      +     a = '\97lo\10\04923"'
      +     a = [[alo
      +     123"]]
      +     a = [==[
      +     alo
      +     123"]==]
      +
      + +

      +A numerical constant can be written with an optional decimal part +and an optional decimal exponent. +Lua also accepts integer hexadecimal constants, +by prefixing them with 0x. +Examples of valid numerical constants are

      -     or
      -     and
      -     <     >     <=    >=    ~=    ==
      -     ..
      -     +     -
      -     *     /     %
      -     not   #     - (unary)
      -     ^
      -

      -As usual, -you can use parentheses to change the precedences of an expression. -The concatenation ('..') and exponentiation ('^') -operators are right associative. -All other binary operators are left associative. + 3 3.0 3.1416 314.16e-2 0.31416E1 0xff 0x56 + +

      +A comment starts with a double hyphen (--) +anywhere outside a string. +If the text immediately after -- is not an opening long bracket, +the comment is a short comment, +which runs until the end of the line. +Otherwise, it is a long comment, +which runs until the corresponding closing long bracket. +Long comments are frequently used to disable code temporarily. -

      2.5.7 - Table Constructors

      -Table constructors are expressions that create tables. -Every time a constructor is evaluated, a new table is created. -A constructor can be used to create an empty table -or to create a table and initialize some of its fields. -The general syntax for constructors is -

      -	tableconstructor ::= `{´ [fieldlist] `}´
      -	fieldlist ::= field {fieldsep field} [fieldsep]
      -	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
      -	fieldsep ::= `,´ | `;´
      -
      +

      3.2 - Variables

      -Each field of the form [exp1] = exp2 adds to the new table an entry -with key exp1 and value exp2. -A field of the form name = exp is equivalent to -["name"] = exp. -Finally, fields of the form exp are equivalent to -[i] = exp, where i are consecutive numerical integers, -starting with 1. -Fields in the other formats do not affect this counting. -For example, +Variables are places that store values. -

      -     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
      -

      -is equivalent to +There are three kinds of variables in Lua: +global variables, local variables, and table fields. -

      -     do
      -       local t = {}
      -       t[f(1)] = g
      -       t[1] = "x"         -- 1st exp
      -       t[2] = "y"         -- 2nd exp
      -       t.x = 1            -- t["x"] = 1
      -       t[3] = f(x)        -- 3rd exp
      -       t[30] = 23
      -       t[4] = 45          -- 4th exp
      -       a = t
      -     end
      -

      -If the last field in the list has the form exp -and the expression is a function call or a vararg expression, -then all values returned by this expression enter the list consecutively -(see §2.5.8). -To avoid this, -enclose the function call or the vararg expression -in parentheses (see §2.5). +A single name can denote a global variable or a local variable +(or a function's formal parameter, +which is a particular kind of local variable): + +

      +	var ::= Name
      +

      +Name denotes identifiers, as defined in §3.1.

      -The field list can have an optional trailing separator, -as a convenience for machine-generated code. - +Any variable name is assumed to be global unless explicitly declared +as a local (see §3.3.7). +Local variables are lexically scoped: +local variables can be freely accessed by functions +defined inside their scope (see §3.5). +

      +Before the first assignment to a variable, its value is nil. -

      2.5.8 - Function Calls

      -A function call in Lua has the following syntax: +

      +Square brackets are used to index a table:

      -	functioncall ::= prefixexp args
      +	var ::= prefixexp &lsquo[’ exp &lsquo]

      -In a function call, -first prefixexp and args are evaluated. -If the value of prefixexp has type function, -then this function is called -with the given arguments. -Otherwise, the prefixexp "call" metamethod is called, -having as first parameter the value of prefixexp, -followed by the original call arguments -(see §2.8). +The meaning of accesses to table fields can be changed via metatables. +An access to an indexed variable t[i] is equivalent to +a call gettable_event(t,i). +(See §2.4 for a complete description of the +gettable_event function. +This function is not defined or callable in Lua. +We use it here only for explanatory purposes.)

      -The form +The syntax var.Name is just syntactic sugar for +var["Name"]:

      -	functioncall ::= prefixexp `:´ Name args
      -

      -can be used to call "methods". -A call v:name(args) -is syntactic sugar for v.name(v,args), -except that v is evaluated only once. - + var ::= prefixexp &lsquo.’ Name +

      -Arguments have the following syntax: +An access to a global variable x +is equivalent to _ENV.x. +Due to the way that chunks are compiled, +_ENV is never a global name (see §2.2). + + + -

      -	args ::= `(´ [explist] `)´
      -	args ::= tableconstructor
      -	args ::= String
      -

      -All argument expressions are evaluated before the call. -A call of the form f{fields} is -syntactic sugar for f({fields}); -that is, the argument list is a single new table. -A call of the form f'string' -(or f"string" or f[[string]]) -is syntactic sugar for f('string'); -that is, the argument list is a single literal string. +

      3.3 - Statements

      -As an exception to the free-form character of Lua, -you cannot put a line break before the '(' in a function call. -This restriction avoids some ambiguities in the language. -If you write +Lua supports an almost conventional set of statements, +similar to those in Pascal or C. +This set includes +assignments, control structures, function calls, +and variable declarations. + -

      -     a = f
      -     (g).x(a)
      -

      -Lua would see that as a single statement, a = f(g).x(a). -In this case, if you want two statements, -you must add a semi-colon between them. -If you actually want to call f, -you must remove the line break before (g). +

      3.3.1 - Chunks

      -A call of the form return functioncall is called -a tail call. -Lua implements proper tail calls -(or proper tail recursion): -in a tail call, -the called function reuses the stack entry of the calling function. -Therefore, there is no limit on the number of nested tail calls that -a program can execute. -However, a tail call erases any debug information about the -calling function. -Note that a tail call only happens with a particular syntax, -where the return has one single function call as argument; -this syntax makes the calling function return exactly -the returns of the called function. -So, none of the following examples are tail calls: +The unit of execution of Lua is called a chunk. +A chunk is simply a sequence of statements, +which are executed sequentially.

      -     return (f(x))        -- results adjusted to 1
      -     return 2 * f(x)
      -     return x, f(x)       -- additional results
      -     f(x); return         -- results discarded
      -     return x or f(x)     -- results adjusted to 1
      +	chunk ::= {stat }
      +

      +Lua has empty statements +that allow you to separate statements with semicolons, +start a chunk with a semicolon +or write two semicolons in sequence: + +

      +	stat ::= &lsquo;
      +

      +Lua handles a chunk as the body of an anonymous function +with a variable number of arguments +(see §3.4.10). +As such, chunks can define local variables, +receive arguments, and return values. +Moreover, such anonymous function is compiled as in the +scope of an external local variable called _ENV (see §2.2). +

      +A chunk can be stored in a file or in a string inside the host program. +To execute a chunk, +Lua first pre-compiles the chunk into instructions for a virtual machine, +and then it executes the compiled code +with an interpreter for the virtual machine. -

      2.5.9 - Function Definitions

      -The syntax for function definition is +Chunks can also be pre-compiled into binary form; +see program luac for details. +Programs in source and compiled forms are interchangeable; +Lua automatically detects the file type and acts accordingly. + + + + + + +

      3.3.2 - Blocks

      +A block is a list of statements; +syntactically, a block is the same as a chunk:

      -	function ::= function funcbody
      -	funcbody ::= `(´ [parlist] `)´ block end
      +	block ::= chunk
       

      -The following syntactic sugar simplifies function definitions: +A block can be explicitly delimited to produce a single statement:

      -	stat ::= function funcname funcbody
      -	stat ::= local function Name funcbody
      -	funcname ::= Name {`.´ Name} [`:´ Name]
      +	stat ::= do block end
       

      -The statement +Explicit blocks are useful +to control the scope of variable declarations. +Explicit blocks are also sometimes used to +add a return or break statement in the middle +of another block (see §3.3.4). -

      -     function f () body end
      -

      -translates to -

      -     f = function () body end
      -

      -The statement -

      -     function t.a.b.c.f () body end
      -

      -translates to + + +

      3.3.3 - Assignment

      + +

      +Lua allows multiple assignments. +Therefore, the syntax for assignment +defines a list of variables on the left side +and a list of expressions on the right side. +The elements in both lists are separated by commas:

      -     t.a.b.c.f = function () body end
      +	stat ::= varlist &lsquo=’ explist
      +	varlist ::= var {&lsquo,’ var}
      +	explist ::= exp {&lsquo,’ exp}
       

      -The statement +Expressions are discussed in §3.4. + + +

      +Before the assignment, +the list of values is adjusted to the length of +the list of variables. +If there are more values than needed, +the excess values are thrown away. +If there are fewer values than needed, +the list is extended with as many nil's as needed. +If the list of expressions ends with a function call, +then all values returned by that call enter the list of values, +before the adjustment +(except when the call is enclosed in parentheses; see §3.4). + + +

      +The assignment statement first evaluates all its expressions +and only then are the assignments performed. +Thus the code

      -     local function f () body end
      +     i = 3
      +     i, a[i] = i+1, 20
       

      -translates to +sets a[3] to 20, without affecting a[4] +because the i in a[i] is evaluated (to 3) +before it is assigned 4. +Similarly, the line

      -     local f; f = function () body end
      +     x, y = y, x
       

      -not to +exchanges the values of x and y, +and

      -     local f = function () body end
      +     x, y, z = y, z, x
       

      -(This only makes a difference when the body of the function -contains references to f.) +cyclically permutes the values of x, y, and z.

      -A function definition is an executable expression, -whose value has type function. -When Lua pre-compiles a chunk, -all its function bodies are pre-compiled too. -Then, whenever Lua executes the function definition, -the function is instantiated (or closed). -This function instance (or closure) -is the final value of the expression. -Different instances of the same function -can refer to different external local variables -and can have different environment tables. +The meaning of assignments to global variables +and table fields can be changed via metatables. +An assignment to an indexed variable t[i] = val is equivalent to +settable_event(t,i,val). +(See §2.4 for a complete description of the +settable_event function. +This function is not defined or callable in Lua. +We use it here only for explanatory purposes.)

      -Parameters act as local variables that are -initialized with the argument values: +An assignment to a global variable x = val +is equivalent to the assignment +_ENV.x = val (see §2.2). -

      -	parlist ::= namelist [`,´ `...´] | `...´
      -

      -When a function is called, -the list of arguments is adjusted to -the length of the list of parameters, -unless the function is a variadic or vararg function, -which is -indicated by three dots ('...') at the end of its parameter list. -A vararg function does not adjust its argument list; -instead, it collects all extra arguments and supplies them -to the function through a vararg expression, -which is also written as three dots. -The value of this expression is a list of all actual extra arguments, -similar to a function with multiple results. -If a vararg expression is used inside another expression -or in the middle of a list of expressions, -then its return list is adjusted to one element. -If the expression is used as the last element of a list of expressions, -then no adjustment is made -(unless that last expression is enclosed in parentheses). -

      -As an example, consider the following definitions: -

      -     function f(a, b) end
      -     function g(a, b, ...) end
      -     function r() return 1,2,3 end
      -

      -Then, we have the following mapping from arguments to parameters and -to the vararg expression: -

      -     CALL            PARAMETERS
      -     
      -     f(3)             a=3, b=nil
      -     f(3, 4)          a=3, b=4
      -     f(3, 4, 5)       a=3, b=4
      -     f(r(), 10)       a=1, b=10
      -     f(r())           a=1, b=2
      -     
      -     g(3)             a=3, b=nil, ... -->  (nothing)
      -     g(3, 4)          a=3, b=4,   ... -->  (nothing)
      -     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
      -     g(5, r())        a=5, b=1,   ... -->  2  3
      -
      +

      3.3.4 - Control Structures

      +The control structures +if, while, and repeat have the usual meaning and +familiar syntax: -

      -Results are returned using the return statement (see §2.4.4). -If control reaches the end of a function -without encountering a return statement, -then the function returns with no results. -

      -The colon syntax -is used for defining methods, -that is, functions that have an implicit extra parameter self. -Thus, the statement

      -     function t.a.b.c:f (params) body end
      +	stat ::= while exp do block end
      +	stat ::= repeat block until exp
      +	stat ::= if exp then block {elseif exp then block} [else block] end
       

      -is syntactic sugar for - -

      -     t.a.b.c.f = function (self, params) body end
      -
      - +Lua also has a for statement, in two flavors (see §3.3.5). +

      +The condition expression of a +control structure can return any value. +Both false and nil are considered false. +All values different from nil and false are considered true +(in particular, the number 0 and the empty string are also true). +

      +In the repeatuntil loop, +the inner block does not end at the until keyword, +but only after the condition. +So, the condition can refer to local variables +declared inside the loop block. -

      2.6 - Visibility Rules

      +The return statement is used to return values +from a function or a chunk (which is just a function). -Lua is a lexically scoped language. -The scope of variables begins at the first statement after -their declaration and lasts until the end of the innermost block that -includes the declaration. -Consider the following example: +Functions and chunks can return more than one value, +and so the syntax for the return statement is

      -     x = 10                -- global variable
      -     do                    -- new block
      -       local x = x         -- new 'x', with value 10
      -       print(x)            --> 10
      -       x = x+1
      -       do                  -- another block
      -         local x = x+1     -- another 'x'
      -         print(x)          --> 12
      -       end
      -       print(x)            --> 11
      -     end
      -     print(x)              --> 10  (the global one)
      +	stat ::= return [explist] [&lsquo;’]
       

      -Notice that, in a declaration like local x = x, -the new x being declared is not in scope yet, -and so the second x refers to the outside variable. - - -

      -Because of the lexical scoping rules, -local variables can be freely accessed by functions -defined inside their scope. -A local variable used by an inner function is called -an upvalue, or external local variable, -inside the inner function. - +The break statement is used to terminate the execution of a +while, repeat, or for loop, +skipping to the next statement after the loop: -

      -Notice that each execution of a local statement -defines new local variables. -Consider the following example:

      -     a = {}
      -     local x = 20
      -     for i=1,10 do
      -       local y = 0
      -       a[i] = function () y=y+1; return x+y end
      -     end
      +	stat ::= break [&lsquo;’]
       

      -The loop creates ten closures -(that is, ten instances of the anonymous function). -Each of these closures uses a different y variable, -while all of them share the same x. - - - - - -

      2.7 - Error Handling

      - -

      -Because Lua is an embedded extension language, -all Lua actions start from C code in the host program -calling a function from the Lua library (see lua_pcall). -Whenever an error occurs during Lua compilation or execution, -control returns to C, -which can take appropriate measures -(such as printing an error message). +A break ends the innermost enclosing loop.

      -Lua code can explicitly generate an error by calling the -error function. -If you need to catch errors in Lua, -you can use the pcall function. +The return and break +statements can only be written as the last statement of a block. +If it is really necessary to return or break in the +middle of a block, +then an explicit inner block can be used, +as in the idioms +do return end and do break end, +because now return and break are the last statements in +their (inner) blocks. -

      2.8 - Metatables

      +

      3.3.5 - For Statement

      -Every value in Lua can have a metatable. -This metatable is an ordinary Lua table -that defines the behavior of the original value -under certain special operations. -You can change several aspects of the behavior -of operations over a value by setting specific fields in its metatable. -For instance, when a non-numeric value is the operand of an addition, -Lua checks for a function in the field "__add" in its metatable. -If it finds one, -Lua calls this function to perform the addition. - -

      -We call the keys in a metatable events -and the values metamethods. -In the previous example, the event is "add" -and the metamethod is the function that performs the addition. +The for statement has two forms: +one numeric and one generic.

      -You can query the metatable of any value -through the getmetatable function. +The numeric for loop repeats a block of code while a +control variable runs through an arithmetic progression. +It has the following syntax: +

      +	stat ::= for Name &lsquo=’ exp &lsquo,’ exp [&lsquo,’ exp] do block end
      +

      +The block is repeated for name starting at the value of +the first exp, until it passes the second exp by steps of the +third exp. +More precisely, a for statement like -

      -You can replace the metatable of tables -through the setmetatable -function. -You cannot change the metatable of other types from Lua -(except by using the debug library); -you must use the C API for that. +

      +     for v = e1, e2, e3 do block end
      +

      +is equivalent to the code: + +

      +     do
      +       local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
      +       if not (var and limit and step) then error() end
      +       while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
      +         local v = var
      +         block
      +         var = var + step
      +       end
      +     end
      +

      +Note the following: +

        -

        -Tables and full userdata have individual metatables -(although multiple tables and userdata can share their metatables). -Values of all other types share one single metatable per type; -that is, there is one single metatable for all numbers, -one for all strings, etc. -By default, a value has no metatable, -but the string library sets a metatable for the string type (see §5.4). +

      • +All three control expressions are evaluated only once, +before the loop starts. +They must all result in numbers. +
      • +
      • +var, limit, and step are invisible variables. +The names shown here are for explanatory purposes only. +
      • -

        -A metatable controls how an object behaves in arithmetic operations, -order comparisons, concatenation, length operation, and indexing. -A metatable also can define a function to be called when a userdata -is garbage collected. -For each of these operations Lua associates a specific key -called an event. -When Lua performs one of these operations over a value, -it checks whether this value has a metatable with the corresponding event. -If so, the value associated with that key (the metamethod) -controls how Lua will perform the operation. +

      • +If the third expression (the step) is absent, +then a step of 1 is used. +
      • +
      • +You can use break to exit a for loop. +
      • -

        -Metatables control the operations listed next. -Each operation is identified by its corresponding name. -The key for each operation is a string with its name prefixed by -two underscores, '__'; -for instance, the key for operation "add" is the -string "__add". -The semantics of these operations is better explained by a Lua function -describing how the interpreter executes the operation. +

      • +The loop variable v is local to the loop; +you cannot use its value after the for ends or is broken. +If you need this value, +assign it to another variable before breaking or exiting the loop. +
      • +

      -The code shown here in Lua is only illustrative; -the real behavior is hard coded in the interpreter -and it is much more efficient than this simulation. -All functions used in these descriptions -(rawget, tonumber, etc.) -are described in §5.1. -In particular, to retrieve the metamethod of a given object, -we use the expression +The generic for statement works over functions, +called iterators. +On each iteration, the iterator function is called to produce a new value, +stopping when this new value is nil. +The generic for loop has the following syntax:

      -     metatable(obj)[event]
      +	stat ::= for namelist in explist do block end
      +	namelist ::= Name {&lsquo,’ Name}
       

      -This should be read as +A for statement like

      -     rawget(getmetatable(obj) or {}, event)
      +     for var_1, ···, var_n in explist do block end
       

      +is equivalent to the code: -That is, the access to a metamethod does not invoke other metamethods, -and the access to objects with no metatables does not fail -(it simply results in nil). - - +

      +     do
      +       local f, s, var = explist
      +       while true do
      +         local var_1, ···, var_n = f(s, var)
      +         var = var_1
      +         if var == nil then break end
      +         block
      +       end
      +     end
      +

      +Note the following:

        -
      • "add": -the + operation. +
      • +explist is evaluated only once. +Its results are an iterator function, +a state, +and an initial value for the first iterator variable. +
      • +
      • +f, s, and var are invisible variables. +The names are here for explanatory purposes only. +
      • + +
      • +You can use break to exit a for loop. +
      • + +
      • +The loop variables var_i are local to the loop; +you cannot use their values after the for ends. +If you need these values, +then assign them to other variables before breaking or exiting the loop. +
      • + +
      -

      -The function getbinhandler below defines how Lua chooses a handler -for a binary operation. -First, Lua tries the first operand. -If its type does not define a handler for the operation, -then Lua tries the second operand. + + +

      3.3.6 - Function Calls as Statements

      +To allow possible side-effects, +function calls can be executed as statements:

      -     function getbinhandler (op1, op2, event)
      -       return metatable(op1)[event] or metatable(op2)[event]
      -     end
      +	stat ::= functioncall
       

      -By using this function, -the behavior of the op1 + op2 is +In this case, all returned values are thrown away. +Function calls are explained in §3.4.9. + + + + + +

      3.3.7 - Local Declarations

      +Local variables can be declared anywhere inside a block. +The declaration can include an initial assignment:

      -     function add_event (op1, op2)
      -       local o1, o2 = tonumber(op1), tonumber(op2)
      -       if o1 and o2 then  -- both operands are numeric?
      -         return o1 + o2   -- '+' here is the primitive 'add'
      -       else  -- at least one of the operands is not numeric
      -         local h = getbinhandler(op1, op2, "__add")
      -         if h then
      -           -- call the handler with both operands
      -           return (h(op1, op2))
      -         else  -- no handler available: default behavior
      -           error(···)
      -         end
      -       end
      -     end
      +	stat ::= local namelist [&lsquo=’ explist]
       

      -

    • +If present, an initial assignment has the same semantics +of a multiple assignment (see §3.3.3). +Otherwise, all variables are initialized with nil. -
    • "sub": -the - operation. -Behavior similar to the "add" operation. -
    • +

      +A chunk is also a block (see §3.3.1), +and so local variables can be declared in a chunk outside any explicit block. +The scope of such local variables extends until the end of the chunk. -

    • "mul": -the * operation. -Behavior similar to the "add" operation. -
    • +

      +The visibility rules for local variables are explained in §3.5. -

    • "div": -the / operation. -Behavior similar to the "add" operation. -
    • -
    • "mod": -the % operation. -Behavior similar to the "add" operation, -with the operation -o1 - floor(o1/o2)*o2 as the primitive operation. -
    • -
    • "pow": -the ^ (exponentiation) operation. -Behavior similar to the "add" operation, -with the function pow (from the C math library) -as the primitive operation. -
    • -
    • "unm": -the unary - operation. +

      3.4 - Expressions

      +

      +The basic expressions in Lua are the following:

      -     function unm_event (op)
      -       local o = tonumber(op)
      -       if o then  -- operand is numeric?
      -         return -o  -- '-' here is the primitive 'unm'
      -       else  -- the operand is not numeric.
      -         -- Try to get a handler from the operand
      -         local h = metatable(op).__unm
      -         if h then
      -           -- call the handler with the operand
      -           return (h(op))
      -         else  -- no handler available: default behavior
      -           error(···)
      -         end
      -       end
      -     end
      -

      -

    • + exp ::= prefixexp + exp ::= nil | false | true + exp ::= Number + exp ::= String + exp ::= function + exp ::= tableconstructor + exp ::= &lsquo...’ + exp ::= exp binop exp + exp ::= unop exp + prefixexp ::= var | functioncall | &lsquo(’ exp &lsquo)’ + -
    • "concat": -the .. (concatenation) operation. +

      +Numbers and literal strings are explained in §3.1; +variables are explained in §3.2; +function definitions are explained in §3.4.10; +function calls are explained in §3.4.9; +table constructors are explained in §3.4.8. +Vararg expressions, +denoted by three dots ('...'), can only be used when +directly inside a vararg function; +they are explained in §3.4.10. -

      -     function concat_event (op1, op2)
      -       if (type(op1) == "string" or type(op1) == "number") and
      -          (type(op2) == "string" or type(op2) == "number") then
      -         return op1 .. op2  -- primitive string concatenation
      -       else
      -         local h = getbinhandler(op1, op2, "__concat")
      -         if h then
      -           return (h(op1, op2))
      -         else
      -           error(···)
      -         end
      -       end
      -     end
      -

      -

    • +

      +Binary operators comprise arithmetic operators (see §3.4.1), +relational operators (see §3.4.3), logical operators (see §3.4.4), +and the concatenation operator (see §3.4.5). +Unary operators comprise the unary minus (see §3.4.1), +the unary not (see §3.4.4), +and the unary length operator (see §3.4.6). + + +

      +Both function calls and vararg expressions can result in multiple values. +If an expression is used as a statement +(only possible for function calls (see §3.3.6)), +then its return list is adjusted to zero elements, +thus discarding all returned values. +If an expression is used as the last (or the only) element +of a list of expressions, +then no adjustment is made +(unless the call is enclosed in parentheses). +In all other contexts, +Lua adjusts the result list to one element, +discarding all values except the first one. -

    • "len": -the # operation. +

      +Here are some examples:

      -     function len_event (op)
      -       if type(op) == "string" then
      -         return strlen(op)         -- primitive string length
      -       else
      -         local h = metatable(op).__len
      -         if h then
      -           return (h(op))     -- call handler with the operand
      -         elseif type(op) == "table" then
      -           return #op                -- primitive table length
      -         else  -- no handler available: error
      -           error(···)
      -         end
      -       end
      -     end
      -

      -See §2.5.5 for a description of the length of a table. -

    • + f() -- adjusted to 0 results + g(f(), x) -- f() is adjusted to 1 result + g(x, f()) -- g gets x plus all results from f() + a,b,c = f(), x -- f() is adjusted to 1 result (c gets nil) + a,b = ... -- a gets the first vararg parameter, b gets + -- the second (both a and b can get nil if there + -- is no corresponding vararg parameter) + + a,b,c = x, f() -- f() is adjusted to 2 results + a,b,c = f() -- f() is adjusted to 3 results + return f() -- returns all results from f() + return ... -- returns all received vararg parameters + return x,y,f() -- returns x, y, and all results from f() + {f()} -- creates a list with all results from f() + {...} -- creates a list with all vararg parameters + {f(), nil} -- f() is adjusted to 1 result + -
    • "eq": -the == operation. +

      +Any expression enclosed in parentheses always results in only one value. +Thus, +(f(x,y,z)) is always a single value, +even if f returns several values. +(The value of (f(x,y,z)) is the first value returned by f +or nil if f does not return any values.) -The function getcomphandler defines how Lua chooses a metamethod -for comparison operators. -A metamethod only is selected when both objects -being compared have the same type -and the same metamethod for the selected operation. -

      -     function getcomphandler (op1, op2, event)
      -       if type(op1) ~= type(op2) then return nil end
      -       local mm1 = metatable(op1)[event]
      -       local mm2 = metatable(op2)[event]
      -       if mm1 == mm2 then return mm1 else return nil end
      -     end
      -

      -The "eq" event is defined as follows: + +

      3.4.1 - Arithmetic Operators

      +Lua supports the usual arithmetic operators: +the binary + (addition), +- (subtraction), * (multiplication), +/ (division), % (modulo), and ^ (exponentiation); +and unary - (negation). +If the operands are numbers, or strings that can be converted to +numbers (see §3.4.2), +then all operations have the usual meaning. +Exponentiation works for any exponent. +For instance, x^(-0.5) computes the inverse of the square root of x. +Modulo is defined as

      -     function eq_event (op1, op2)
      -       if type(op1) ~= type(op2) then  -- different types?
      -         return false   -- different objects
      -       end
      -       if op1 == op2 then   -- primitive equal?
      -         return true   -- objects are equal
      -       end
      -       -- try metamethod
      -       local h = getcomphandler(op1, op2, "__eq")
      -       if h then
      -         return (h(op1, op2))
      -       else
      -         return false
      -       end
      -     end
      +     a % b == a - math.floor(a/b)*b
       

      -a ~= b is equivalent to not (a == b). -

    • +That is, it is the remainder of a division that rounds +the quotient towards minus infinity. -
    • "lt": -the < operation. -
      -     function lt_event (op1, op2)
      -       if type(op1) == "number" and type(op2) == "number" then
      -         return op1 < op2   -- numeric comparison
      -       elseif type(op1) == "string" and type(op2) == "string" then
      -         return op1 < op2   -- lexicographic comparison
      -       else
      -         local h = getcomphandler(op1, op2, "__lt")
      -         if h then
      -           return (h(op1, op2))
      -         else
      -           error(···)
      -         end
      -       end
      -     end
      -

      -a > b is equivalent to b < a. -

    • -
    • "le": -the <= operation. + +

      3.4.2 - Coercion

      + +

      +Lua provides automatic conversion between +string and number values at run time. +Any arithmetic operation applied to a string tries to convert +this string to a number, following the usual conversion rules. +Conversely, whenever a number is used where a string is expected, +the number is converted to a string, in a reasonable format. +For complete control over how numbers are converted to strings, +use the format function from the string library +(see string.format). -

      -     function le_event (op1, op2)
      -       if type(op1) == "number" and type(op2) == "number" then
      -         return op1 <= op2   -- numeric comparison
      -       elseif type(op1) == "string" and type(op2) == "string" then
      -         return op1 <= op2   -- lexicographic comparison
      -       else
      -         local h = getcomphandler(op1, op2, "__le")
      -         if h then
      -           return (h(op1, op2))
      -         else
      -           h = getcomphandler(op1, op2, "__lt")
      -           if h then
      -             return not h(op2, op1)
      -           else
      -             error(···)
      -           end
      -         end
      -       end
      -     end
      -

      -a >= b is equivalent to b <= a. -Note that, in the absence of a "le" metamethod, -Lua tries the "lt", assuming that a <= b is -equivalent to not (b < a). -

    • -
    • "index": -The indexing access table[key]. +

      3.4.3 - Relational Operators

      +The relational operators in Lua are +

      -     function gettable_event (table, key)
      -       local h
      -       if type(table) == "table" then
      -         local v = rawget(table, key)
      -         if v ~= nil then return v end
      -         h = metatable(table).__index
      -         if h == nil then return nil end
      -       else
      -         h = metatable(table).__index
      -         if h == nil then
      -           error(···)
      -         end
      -       end
      -       if type(h) == "function" then
      -         return (h(table, key))     -- call the handler
      -       else return h[key]           -- or repeat operation on it
      -       end
      -     end
      +     ==    ~=    <     >     <=    >=
       

      -

    • +These operators always result in false or true. + + +

      +Equality (==) first compares the type of its operands. +If the types are different, then the result is false. +Otherwise, the values of the operands are compared. +Numbers and strings are compared in the usual way. +Objects (tables, userdata, threads, and functions) +are compared by reference: +two objects are considered equal only if they are the same object. +Every time you create a new object +(a table, userdata, thread, or function), +this new object is different from any previously existing object. + + +

      +You can change the way that Lua compares tables and userdata +by using the "eq" metamethod (see §2.4). + + +

      +The conversion rules of §3.4.2 +do not apply to equality comparisons. +Thus, "0"==0 evaluates to false, +and t[0] and t["0"] denote different +entries in a table. + + +

      +The operator ~= is exactly the negation of equality (==). + + +

      +The order operators work as follows. +If both arguments are numbers, then they are compared as such. +Otherwise, if both arguments are strings, +then their values are compared according to the current locale. +Otherwise, Lua tries to call the "lt" or the "le" +metamethod (see §2.4). +A comparison a > b is translated to b < a +and a >= b is translated to b <= a. -

    • "newindex": -The indexing assignment table[key] = value. + + +

      3.4.4 - Logical Operators

      +The logical operators in Lua are +and, or, and not. +Like the control structures (see §3.3.4), +all logical operators consider both false and nil as false +and anything else as true. + + +

      +The negation operator not always returns false or true. +The conjunction operator and returns its first argument +if this value is false or nil; +otherwise, and returns its second argument. +The disjunction operator or returns its first argument +if this value is different from nil and false; +otherwise, or returns its second argument. +Both and and or use short-cut evaluation; +that is, +the second operand is evaluated only if necessary. +Here are some examples: +

      -     function settable_event (table, key, value)
      -       local h
      -       if type(table) == "table" then
      -         local v = rawget(table, key)
      -         if v ~= nil then rawset(table, key, value); return end
      -         h = metatable(table).__newindex
      -         if h == nil then rawset(table, key, value); return end
      -       else
      -         h = metatable(table).__newindex
      -         if h == nil then
      -           error(···)
      -         end
      -       end
      -       if type(h) == "function" then
      -         h(table, key,value)           -- call the handler
      -       else h[key] = value             -- or repeat operation on it
      -       end
      -     end
      +     10 or 20            --> 10
      +     10 or error()       --> 10
      +     nil or "a"          --> "a"
      +     nil and 10          --> nil
      +     false and error()   --> false
      +     false and nil       --> false
      +     false or nil        --> nil
      +     10 and 20           --> 20
       

      -

    • +(In this manual, +--> indicates the result of the preceding expression.) -
    • "call": -called when Lua calls a value. -
      -     function function_event (func, ...)
      -       if type(func) == "function" then
      -         return func(...)   -- primitive call
      -       else
      -         local h = metatable(func).__call
      -         if h then
      -           return h(func, ...)
      -         else
      -           error(···)
      -         end
      -       end
      -     end
      -

      -

    • -
    +

    3.4.5 - Concatenation

    +The string concatenation operator in Lua is +denoted by two dots ('..'). +If both operands are strings or numbers, then they are converted to +strings according to the rules mentioned in §3.4.2. +Otherwise, the "concat" metamethod is called (see §2.4). -

    2.9 - Environments

    -

    -Each function and userdata in Lua -has a table associated with it, -called its environment. -Like metatables, environments are regular tables and -multiple objects can share the same environment. ->From Lua, -you can manipulate the environment of an object -only through the debug library (see §5.10). +

    3.4.6 - The Length Operator

    -Userdata and C functions are created sharing the environment -of the creating C function. -Non-nested Lua functions -(created by loadfile, loadstring or load) -are created sharing the global environment. -Nested Lua functions are created sharing the current environment -of where it is defined. +The length operator is denoted by the unary prefix operator #. +The length of a string is its number of bytes +(that is, the usual meaning of string length when each +character is one byte).

    -Environments associated with userdata have no meaning for Lua. -It is only a convenience feature for programmers to associate a table to -a userdata. +The length of a table t is defined to be any +integer index n +such that t[n] is not nil and t[n+1] is nil; +moreover, if t[1] is nil, n can be zero. +For a regular array, where all non-nil values +have keys from 1 to a given n, +its length is exactly that n, +the index of its last value. +If the array has "holes" +(that is, nil values between other non-nil values), +then #t can be any of the indices that +directly precedes a nil value +(that is, it may consider any such nil value as the end of +the array).

    -The environment associated with a C function can be directly -accessed by C code (see §3.3). -It is used as the default environment for other C functions -and userdata created by the function. +A program can modify the behavior of the length operator for +any value but strings through metamethods (see §2.4). -

    -The environment associated with a Lua function is used as the -current environment of all code in the function outside -a lexical environment (see §2.4.8). -A lexical environment changes the -current environment inside its scope. -In any case, -the current environment is the table -Lua uses to resolve global variables and to initialize -the environment of nested functions. +

    3.4.7 - Precedence

    +Operator precedence in Lua follows the table below, +from lower to higher priority: + +

    +     or
    +     and
    +     <     >     <=    >=    ~=    ==
    +     ..
    +     +     -
    +     *     /     %
    +     not   #     - (unary)
    +     ^
    +

    +As usual, +you can use parentheses to change the precedences of an expression. +The concatenation ('..') and exponentiation ('^') +operators are right associative. +All other binary operators are left associative. -

    2.10 - Garbage Collection

    -

    -Lua performs automatic memory management. -This means that -you have to worry neither about allocating memory for new objects -nor about freeing it when the objects are no longer needed. -Lua manages memory automatically by running -a garbage collector from time to time -to collect all dead objects -(that is, objects that are no longer accessible from Lua). -All memory used by Lua is subject to automatic management: -tables, userdata, functions, threads, strings, etc. -

    -Lua implements an incremental mark-and-sweep collector. -It uses two numbers to control its garbage-collection cycles: -the garbage-collector pause and -the garbage-collector step multiplier. -Both use percentage points as units -(so that a value of 100 means an internal value of 1). +

    3.4.8 - Table Constructors

    +Table constructors are expressions that create tables. +Every time a constructor is evaluated, a new table is created. +A constructor can be used to create an empty table +or to create a table and initialize some of its fields. +The general syntax for constructors is +

    +	tableconstructor ::= &lsquo{’ [fieldlist] &lsquo}’
    +	fieldlist ::= field {fieldsep field} [fieldsep]
    +	field ::= &lsquo[’ exp &lsquo]’ &lsquo=’ exp | Name &lsquo=’ exp | exp
    +	fieldsep ::= &lsquo,’ | &lsquo;’
    +

    -The garbage-collector pause -controls how long the collector waits before starting a new cycle. -Larger values make the collector less aggressive. -Values smaller than 100 mean the collector will not wait to -start a new cycle. -A value of 200 means that the collector waits for the total memory in use -to double before starting a new cycle. +Each field of the form [exp1] = exp2 adds to the new table an entry +with key exp1 and value exp2. +A field of the form name = exp is equivalent to +["name"] = exp. +Finally, fields of the form exp are equivalent to +[i] = exp, where i are consecutive numerical integers, +starting with 1. +Fields in the other formats do not affect this counting. +For example, + +

    +     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
    +

    +is equivalent to +

    +     do
    +       local t = {}
    +       t[f(1)] = g
    +       t[1] = "x"         -- 1st exp
    +       t[2] = "y"         -- 2nd exp
    +       t.x = 1            -- t["x"] = 1
    +       t[3] = f(x)        -- 3rd exp
    +       t[30] = 23
    +       t[4] = 45          -- 4th exp
    +       a = t
    +     end
    +

    -The step multiplier -controls the relative speed of the collector relative to -memory allocation. -Larger values make the collector more aggressive but also increase -the size of each incremental step. -Values smaller than 100 make the collector too slow and -can result in the collector never finishing a cycle. -The default, 200, means that the collector runs at "twice" -the speed of memory allocation. +If the last field in the list has the form exp +and the expression is a function call or a vararg expression, +then all values returned by this expression enter the list consecutively +(see §3.4.9). +To avoid this, +enclose the function call or the vararg expression +in parentheses (see §3.4).

    -If you set the step multiplier to a very large number -(larger than 10% of the maximum number of -bytes that the program may use), -the collector behaves like a stop-the-world collector. -If you then set the pause to 200, -the collector behaves as in old Lua versions, -doing a complete collection every time Lua doubles its -memory usage. +The field list can have an optional trailing separator, +as a convenience for machine-generated code. + + + + + +

    3.4.9 - Function Calls

    +A function call in Lua has the following syntax: + +

    +	functioncall ::= prefixexp args
    +

    +In a function call, +first prefixexp and args are evaluated. +If the value of prefixexp has type function, +then this function is called +with the given arguments. +Otherwise, the prefixexp "call" metamethod is called, +having as first parameter the value of prefixexp, +followed by the original call arguments +(see §2.4).

    -You can change these numbers by calling lua_gc in C -or collectgarbage in Lua. -With these functions you can also control -the collector directly (e.g., stop and restart it). +The form + +

    +	functioncall ::= prefixexp &lsquo:’ Name args
    +

    +can be used to call "methods". +A call v:name(args) +is syntactic sugar for v.name(v,args), +except that v is evaluated only once. +

    +Arguments have the following syntax: + +

    +	args ::= &lsquo(’ [explist] &lsquo)’
    +	args ::= tableconstructor
    +	args ::= String
    +

    +All argument expressions are evaluated before the call. +A call of the form f{fields} is +syntactic sugar for f({fields}); +that is, the argument list is a single new table. +A call of the form f'string' +(or f"string" or f[[string]]) +is syntactic sugar for f('string'); +that is, the argument list is a single literal string. -

    2.10.1 - Garbage-Collection Metamethods

    -Using the C API, -you can set garbage-collector metamethods for userdata (see §2.8). -These metamethods are also called finalizers. -Finalizers allow you to coordinate Lua's garbage collection -with external resource management -(such as closing files, network or database connections, -or freeing your own memory). +A call of the form return functioncall is called +a tail call. +Lua implements proper tail calls +(or proper tail recursion): +in a tail call, +the called function reuses the stack entry of the calling function. +Therefore, there is no limit on the number of nested tail calls that +a program can execute. +However, a tail call erases any debug information about the +calling function. +Note that a tail call only happens with a particular syntax, +where the return has one single function call as argument; +this syntax makes the calling function return exactly +the returns of the called function. +So, none of the following examples are tail calls: + +

    +     return (f(x))        -- results adjusted to 1
    +     return 2 * f(x)
    +     return x, f(x)       -- additional results
    +     f(x); return         -- results discarded
    +     return x or f(x)     -- results adjusted to 1
    +
    + + +

    3.4.10 - Function Definitions

    +

    -Garbage userdata with a field __gc in their metatables are not -collected immediately by the garbage collector. -Instead, Lua puts them in a list. -After the collection, -Lua does the equivalent of the following function -for each userdata in that list: +The syntax for function definition is

    -     function gc_event (udata)
    -       local h = metatable(udata).__gc
    -       if h then
    -         h(udata)
    -       end
    -     end
    +	function ::= function funcbody
    +	funcbody ::= &lsquo(’ [parlist] &lsquo)’ block end
     

    -At the end of each garbage-collection cycle, -the finalizers for userdata are called in reverse -order of their creation, -among those collected in that cycle. -That is, the first finalizer to be called is the one associated -with the userdata created last in the program. -The userdata itself is freed only in the next garbage-collection cycle. +The following syntactic sugar simplifies function definitions: +

    +	stat ::= function funcname funcbody
    +	stat ::= local function Name funcbody
    +	funcname ::= Name {&lsquo.’ Name} [&lsquo:’ Name]
    +

    +The statement +

    +     function f () body end
    +

    +translates to +

    +     f = function () body end
    +

    +The statement +

    +     function t.a.b.c.f () body end
    +

    +translates to -

    2.10.2 - Weak Tables

    +
    +     t.a.b.c.f = function () body end
    +

    +The statement -

    -A weak table is a table whose elements are -weak references. -A weak reference is ignored by the garbage collector. -In other words, -if the only references to an object are weak references, -then the garbage collector will collect this object. +

    +     local function f () body end
    +

    +translates to +

    +     local f; f = function () body end
    +

    +not to -

    -A weak table can have weak keys, weak values, or both. -A table with weak keys allows the collection of its keys, -but prevents the collection of its values. -A table with both weak keys and weak values allows the collection of -both keys and values. -In any case, if either the key or the value is collected, -the whole pair is removed from the table. -The weakness of a table is controlled by the -__mode field of its metatable. -If the __mode field is a string containing the character 'k', -the keys in the table are weak. -If __mode contains 'v', -the values in the table are weak. +

    +     local f = function () body end
    +

    +(This only makes a difference when the body of the function +contains references to f.)

    -Userdata with finalizers has a special behavior in weak tables. -When a userdata is a value in a weak table, -it is removed from the table the first time it is collected, -before running its finalizer. -When it is a key, however, -it is removed from the table only when it is really freed, -after running its finalizer. -This behavior allows the finalizer to access values -associated with the userdata through weak tables. +A function definition is an executable expression, +whose value has type function. +When Lua pre-compiles a chunk, +all its function bodies are pre-compiled too. +Then, whenever Lua executes the function definition, +the function is instantiated (or closed). +This function instance (or closure) +is the final value of the expression. +Different instances of the same function +can refer to different external local variables +and can have different environment tables.

    -A table with weak keys and strong values -is also called an ephemeron table. -In an ephemeron table, -a value is considered reachable only if its key is reachable. -In particular, -if the only reference to a key comes from its value, -the pair is removed. +Parameters act as local variables that are +initialized with the argument values: + +

    +	parlist ::= namelist [&lsquo,’ &lsquo...’] | &lsquo...’
    +

    +When a function is called, +the list of arguments is adjusted to +the length of the list of parameters, +unless the function is a variadic or vararg function, +which is +indicated by three dots ('...') at the end of its parameter list. +A vararg function does not adjust its argument list; +instead, it collects all extra arguments and supplies them +to the function through a vararg expression, +which is also written as three dots. +The value of this expression is a list of all actual extra arguments, +similar to a function with multiple results. +If a vararg expression is used inside another expression +or in the middle of a list of expressions, +then its return list is adjusted to one element. +If the expression is used as the last element of a list of expressions, +then no adjustment is made +(unless that last expression is enclosed in parentheses).

    -After you use a table as a metatable, -you should not change the value of its __mode field. -Otherwise, the weak behavior of the tables controlled by this -metatable is undefined. +As an example, consider the following definitions: +

    +     function f(a, b) end
    +     function g(a, b, ...) end
    +     function r() return 1,2,3 end
    +

    +Then, we have the following mapping from arguments to parameters and +to the vararg expression: +

    +     CALL            PARAMETERS
    +     
    +     f(3)             a=3, b=nil
    +     f(3, 4)          a=3, b=4
    +     f(3, 4, 5)       a=3, b=4
    +     f(r(), 10)       a=1, b=10
    +     f(r())           a=1, b=2
    +     
    +     g(3)             a=3, b=nil, ... -->  (nothing)
    +     g(3, 4)          a=3, b=4,   ... -->  (nothing)
    +     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
    +     g(5, r())        a=5, b=1,   ... -->  2  3
    +
    +

    +Results are returned using the return statement (see §3.3.4). +If control reaches the end of a function +without encountering a return statement, +then the function returns with no results. +

    +The colon syntax +is used for defining methods, +that is, functions that have an implicit extra parameter self. +Thus, the statement +

    +     function t.a.b.c:f (params) body end
    +

    +is syntactic sugar for -

    2.11 - Coroutines

    +
    +     t.a.b.c.f = function (self, params) body end
    +
    -

    -Lua supports coroutines, -also called collaborative multithreading. -A coroutine in Lua represents an independent thread of execution. -Unlike threads in multithread systems, however, -a coroutine only suspends its execution by explicitly calling -a yield function. -

    -You create a coroutine with a call to coroutine.create. -Its sole argument is a function -that is the main function of the coroutine. -The create function only creates a new coroutine and -returns a handle to it (an object of type thread); -it does not start the coroutine execution. -

    -When you first call coroutine.resume, -passing as its first argument -a thread returned by coroutine.create, -the coroutine starts its execution, -at the first line of its main function. -Extra arguments passed to coroutine.resume are passed on -to the coroutine main function. -After the coroutine starts running, -it runs until it terminates or yields. +

    3.5 - Visibility Rules

    -A coroutine can terminate its execution in two ways: -normally, when its main function returns -(explicitly or implicitly, after the last instruction); -and abnormally, if there is an unprotected error. -In the first case, coroutine.resume returns true, -plus any values returned by the coroutine main function. -In case of errors, coroutine.resume returns false -plus an error message. +Lua is a lexically scoped language. +The scope of variables begins at the first statement after +their declaration and lasts until the end of the innermost block that +includes the declaration. +Consider the following example: + +

    +     x = 10                -- global variable
    +     do                    -- new block
    +       local x = x         -- new 'x', with value 10
    +       print(x)            --> 10
    +       x = x+1
    +       do                  -- another block
    +         local x = x+1     -- another 'x'
    +         print(x)          --> 12
    +       end
    +       print(x)            --> 11
    +     end
    +     print(x)              --> 10  (the global one)
    +

    -A coroutine yields by calling coroutine.yield. -When a coroutine yields, -the corresponding coroutine.resume returns immediately, -even if the yield happens inside nested function calls -(that is, not in the main function, -but in a function directly or indirectly called by the main function). -In the case of a yield, coroutine.resume also returns true, -plus any values passed to coroutine.yield. -The next time you resume the same coroutine, -it continues its execution from the point where it yielded, -with the call to coroutine.yield returning any extra -arguments passed to coroutine.resume. +Notice that, in a declaration like local x = x, +the new x being declared is not in scope yet, +and so the second x refers to the outside variable.

    -Like coroutine.create, -the coroutine.wrap function also creates a coroutine, -but instead of returning the coroutine itself, -it returns a function that, when called, resumes the coroutine. -Any arguments passed to this function -go as extra arguments to coroutine.resume. -coroutine.wrap returns all the values returned by coroutine.resume, -except the first one (the boolean error code). -Unlike coroutine.resume, -coroutine.wrap does not catch errors; -any error is propagated to the caller. +Because of the lexical scoping rules, +local variables can be freely accessed by functions +defined inside their scope. +A local variable used by an inner function is called +an upvalue, or external local variable, +inside the inner function.

    -As an example, -consider the following code: +Notice that each execution of a local statement +defines new local variables. +Consider the following example:

    -     function foo (a)
    -       print("foo", a)
    -       return coroutine.yield(2*a)
    +     a = {}
    +     local x = 20
    +     for i=1,10 do
    +       local y = 0
    +       a[i] = function () y=y+1; return x+y end
          end
    -     
    -     co = coroutine.create(function (a,b)
    -           print("co-body", a, b)
    -           local r = foo(a+1)
    -           print("co-body", r)
    -           local r, s = coroutine.yield(a+b, a-b)
    -           print("co-body", r, s)
    -           return b, "end"
    -     end)
    -            
    -     print("main", coroutine.resume(co, 1, 10))
    -     print("main", coroutine.resume(co, "r"))
    -     print("main", coroutine.resume(co, "x", "y"))
    -     print("main", coroutine.resume(co, "x", "y"))
     

    -When you run it, it produces the following output: +The loop creates ten closures +(that is, ten instances of the anonymous function). +Each of these closures uses a different y variable, +while all of them share the same x. -

    -     co-body 1       10
    -     foo     2
    -     
    -     main    true    4
    -     co-body r
    -     main    true    11      -9
    -     co-body x       y
    -     main    true    10      end
    -     main    false   cannot resume dead coroutine
    -
    -

    3 - The Application Program Interface

    +

    4 - The Application Program Interface

    @@ -2324,7 +2286,7 @@

    3 - The Application Program Interface

    -

    3.1 - The Stack

    +

    4.1 - The Stack

    Lua uses a virtual stack to pass values to and from C. @@ -2366,7 +2328,7 @@

    3.1 - The Stack

    -

    3.2 - Stack Size

    +

    4.2 - Stack Size

    When you interact with Lua API, @@ -2412,37 +2374,22 @@

    3.2 - Stack Size

    -

    3.3 - Pseudo-Indices

    +

    4.3 - Pseudo-Indices

    Unless otherwise noted, any function that accepts valid indices also accepts pseudo-indices, which represent some Lua values that are accessible to C code but which are not in the stack. -Pseudo-indices are used to access the thread environment, -the function environment, -the registry, -and the upvalues of a C function (see §3.4). - - -

    -The environment of the running C function is always -at pseudo-index LUA_ENVIRONINDEX. +Pseudo-indices are used to access +the registry +and the upvalues of a C function (see §4.4). -

    -To access and change the value of global variables, -you can use regular table operations over an environment table. -For instance, to access the value of a global variable, do - -

    -     lua_getfield(L, LUA_ENVIRONINDEX, varname);
    -
    - -

    3.4 - C Closures

    +

    4.4 - C Closures

    When a C function is created, @@ -2469,7 +2416,7 @@

    3.4 - C Closures

    -

    3.5 - Registry

    +

    4.5 - Registry

    Lua provides a registry, @@ -2503,29 +2450,6 @@

    3.5 - Registry

    the main thread of the state. (The main thread is the one created together with the state.) -
  • LUA_RIDX_CPCALL: At this index the registry has -the cpcall function. -This function allows you to call any -lua_CFunction without creating a closure for it, -therefore preventing an unprotected memory allocation error. - - -

    -The address of the function to be called must be stored in a variable, -whose address is passed as the first argument to cpcall, -as a light userdata. -Note that the light userdata in the first argument should not -point to the function to be called, -but to a variable containing the pointer to the function. -ANSI C does not allow the direct assignment of a function address to -the void* in a light userdata. - - -

    -Other arguments to cpcall are passed to the called function. -The cpcall function itself should be called with lua_pcall, -like any C function. -

  • LUA_RIDX_GLOBALS: At this index the registry has the global environment. @@ -2536,7 +2460,7 @@

    3.5 - Registry

    -

    3.6 - Error Handling in C

    +

    4.6 - Error Handling in C

    Internally, Lua uses the C longjmp facility to handle errors. @@ -2575,7 +2499,7 @@

    3.6 - Error Handling in C

    -

    3.7 - Handling Yields in C

    +

    4.7 - Handling Yields in C

    Internally, Lua uses the C longjmp facility to yield a coroutine. @@ -2600,10 +2524,10 @@

    3.7 - Handling Yields in C

    let us set some terminology. We have a C function called from Lua which we will call the original function. -This original function may call one of those three functions in the C API, +This original function then calls one of those three functions in the C API, which we will call the callee function, -that may yield the current thread. -(This will happen when the callee function is lua_yieldk, +that then yields the current thread. +(This can happen when the callee function is lua_yieldk, or when the callee function is either lua_callk or lua_pcallk and the function called by them yields.) @@ -2643,7 +2567,7 @@

    3.7 - Handling Yields in C

    -

    3.8 - Functions and Types

    +

    4.8 - Functions and Types

    Here we list all functions and types from the C API in @@ -2675,6 +2599,18 @@

    3.8 - Functions and Types

    +

    lua_absindex

    +[-0, +0, -] +

    void lua_absindex (lua_State *L, int idx);
    + +

    +Converts the acceptable index idx into an absolute index +(that is, one that does not depend on the stack top). + + + + +


    lua_Alloc

    typedef void * (*lua_Alloc) (void *ud,
                                  void *ptr,
    @@ -2768,12 +2704,12 @@ 

    3.8 - Functions and Types

    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

    -Sets a new panic function and returns the old one (see §3.6). +Sets a new panic function and returns the old one (see §4.6).

    The panic function should not try to run anything on the failed Lua state. -However, it can still use the debug API (see §3.9) +However, it can still use the debug API (see §4.9) to gather information about the state. In particular, the error message is at the top of the stack. @@ -2824,14 +2760,14 @@

    3.8 - Functions and Types

    Here it is in C:
    -     lua_getfield(L, LUA_ENVIRONINDEX, "f"); /* function to be called */
    +     lua_getglobal(L, "f");                  /* function to be called */
          lua_pushstring(L, "how");                        /* 1st argument */
    -     lua_getfield(L, LUA_ENVIRONINDEX, "t");   /* table to be indexed */
    +     lua_getglobal(L, "t");                    /* table to be indexed */
          lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
          lua_remove(L, -2);                  /* remove 't' from the stack */
          lua_pushinteger(L, 14);                          /* 3rd argument */
          lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
    -     lua_setfield(L, LUA_ENVIRONINDEX, "a");        /* set global 'a' */
    +     lua_setglobal(L, "a");                         /* set global 'a' */
     

    Note that the code above is "balanced": at its end, the stack is back to its original configuration. @@ -2848,7 +2784,7 @@

    3.8 - Functions and Types

    This function behaves exactly like lua_call, -but allows the called function to yield (see §3.7). +but allows the called function to yield (see §4.7). @@ -2980,7 +2916,7 @@

    3.8 - Functions and Types

    (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is performed following the usual semantics of Lua -(see §2.5.4). +(see §3.4.5). @@ -3108,13 +3044,13 @@

    3.8 - Functions and Types

  • LUA_GCSETPAUSE: sets data as the new value -for the pause of the collector (see §2.10). +for the pause of the collector (see §2.5). The function returns the previous value of the pause.
  • LUA_GCSETSTEPMUL: sets data as the new value for the step multiplier of -the collector (see §2.10). +the collector (see §2.5). The function returns the previous value of the step multiplier.
  • @@ -3146,7 +3082,7 @@

    3.8 - Functions and Types

    int lua_getctx  (lua_State *L, int *ctx);

    -This function is called by a continuation function (see §3.7) +This function is called by a continuation function (see §4.7) to retrieve the status of the thread and a context information. @@ -3197,7 +3133,7 @@

    3.8 - Functions and Types

    Pushes onto the stack the value t[k], where t is the value at the given valid index. As in Lua, this function may trigger a metamethod -for the "index" event (see §2.8). +for the "index" event (see §2.4). @@ -3209,11 +3145,8 @@

    3.8 - Functions and Types

    Pushes onto the stack the value of the global name. -It is defined as a macro: +It is defined as a macro. -

    -     #define lua_getglobal(L,s)  lua_getfield(L, LUA_ENVIRONINDEX, s)
    -
    @@ -3247,7 +3180,7 @@

    3.8 - Functions and Types

    This function pops the key from the stack (putting the resulting value in its place). As in Lua, this function may trigger a metamethod -for the "index" event (see §2.8). +for the "index" event (see §2.4). @@ -3452,7 +3385,7 @@

    3.8 - Functions and Types

    Returns the "length" of the value at the given acceptable index; -it is equivalent to the '#' operator in Lua (see §2.5.5). +it is equivalent to the '#' operator in Lua (see §3.4.6). The result is pushed on the stack. @@ -3510,7 +3443,15 @@

    3.8 - Functions and Types

    The source argument gives a name to the chunk, -which is used for error messages and in debug information (see §3.9). +which is used for error messages and in debug information (see §4.9). + + +

    +If the resulting function has upvalues, +the first upvalue is set to the value of the global environment +stored at index LUA_RIDX_GLOBALS in the registry (see §4.5). +(When loading main chunks, +this upvalue will be the _ENV variable (see §2.2).) @@ -3729,7 +3670,7 @@

    3.8 - Functions and Types

    This function behaves exactly like lua_pcall, -but allows the called function to yield (see §3.7). +but allows the called function to yield (see §4.7). @@ -3768,7 +3709,7 @@

    3.8 - Functions and Types

    When a C function is created, it is possible to associate some values with it, -thus creating a C closure (see §3.4); +thus creating a C closure (see §4.4); these values are then accessible to the function whenever it is called. To associate values with a C function, first these values should be pushed onto the stack @@ -3784,11 +3725,18 @@

    3.8 - Functions and Types

    The maximum value for n is 255. +

    +When n is zero, +this function creates a light C function, +which is just a pointer to the C function. +In that case, it cannot throw a memory error. + +


    lua_pushcfunction

    -[-0, +1, m] +[-0, +1, -]

    void lua_pushcfunction (lua_State *L, lua_CFunction f);

    @@ -3946,7 +3894,7 @@

    3.8 - Functions and Types

    Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. -The string cannot contain embedded zeros; +The string should not contain embedded zeros; it is assumed to end at the first zero. @@ -3954,6 +3902,10 @@

    3.8 - Functions and Types

    Returns a pointer to the internal copy of the string. +

    +If s is NULL, pushes nil and returns NULL. + + @@ -4232,7 +4184,7 @@

    3.8 - Functions and Types

    This function pops the value from the stack. As in Lua, this function may trigger a metamethod -for the "newindex" event (see §2.8). +for the "newindex" event (see §2.4). @@ -4245,11 +4197,8 @@

    3.8 - Functions and Types

    Pops a value from the stack and sets it as the new value of global name. -It is defined as a macro: +It is defined as a macro. -

    -     #define lua_setglobal(L,s)   lua_setfield(L, LUA_ENVIRONINDEX, s)
    -
    @@ -4281,7 +4230,7 @@

    3.8 - Functions and Types

    This function pops both the key and the value from the stack. As in Lua, this function may trigger a metamethod -for the "newindex" event (see §2.8). +for the "newindex" event (see §2.4). @@ -4379,7 +4328,7 @@

    3.8 - Functions and Types

    Converts the Lua value at the given acceptable index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number -(see §2.2.1); +(see §3.4.2); otherwise, lua_tointeger returns 0. @@ -4430,7 +4379,7 @@

    3.8 - Functions and Types

    Converts the Lua value at the given acceptable index to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number -(see §2.2.1); +(see §3.4.2); otherwise, lua_tonumber returns 0. @@ -4596,7 +4545,7 @@

    3.8 - Functions and Types

    This function is equivalent to lua_yieldk, -but it has no continuation (see §3.7). +but it has no continuation (see §4.7). Therefore, when the thread resumes, it returns to the function that called the function calling lua_yield. @@ -4631,7 +4580,7 @@

    3.8 - Functions and Types

    When the coroutine is resumed again, Lua calls the given continuation function k to continue -the execution of the C function that yielded (see §3.7). +the execution of the C function that yielded (see §4.7). This continuation function receives the same stack from the previous function, with the results removed and @@ -4646,7 +4595,7 @@

    3.8 - Functions and Types

    -

    3.9 - The Debug Interface

    +

    4.9 - The Debug Interface

    Lua has no built-in debugging facilities. @@ -4830,7 +4779,7 @@

    3.9 - The Debug Interface

          lua_Debug ar;
    -     lua_getfield(L, LUA_ENVIRONINDEX, "f");  /* get global 'f' */
    +     lua_getglobal(L, "f");  /* get global 'f' */
          lua_getinfo(L, ">S", &ar);
          printf("%d\n", ar.linedefined);
     
    @@ -5126,7 +5075,7 @@

    3.9 - The Debug Interface

    -

    4 - The Auxiliary Library

    +

    5 - The Auxiliary Library

    @@ -5150,6 +5099,14 @@

    4 - The Auxiliary Library

    and so they provide nothing that cannot be done with that API. +

    +Several functions in the auxiliary library use internally some +extra stack slots. +When a function in the auxiliary library uses less than five slots, +it does not check the stack size; +it simply assumes that there are enough slots. + +

    Several functions in the auxiliary library are used to check C function arguments. @@ -5164,7 +5121,7 @@

    4 - The Auxiliary Library

    -

    4.1 - Functions and Types

    +

    5.1 - Functions and Types

    Here we list all functions and types from the auxiliary library @@ -5192,7 +5149,7 @@

    4.1 - Functions and Types

    Adds the string pointed to by s with length l to the buffer B (see luaL_Buffer). -The string may contain embedded zeros. +The string can contain embedded zeros. @@ -5219,7 +5176,7 @@

    4.1 - Functions and Types

    Adds the zero-terminated string pointed to by s to the buffer B (see luaL_Buffer). -The string may not contain embedded zeros. +The string should not contain embedded zeros. @@ -5661,9 +5618,9 @@

    4.1 - Functions and Types

    Returns the "length" of the value at the given acceptable index as a number; -it is equivalent to the '#' operator in Lua (see §2.5.5). +it is equivalent to the '#' operator in Lua (see §3.4.6). Raises an error if the result of the operation is not a number. -(This only may happen through metamethods.) +(This only can happen through metamethods.) @@ -5769,7 +5726,7 @@

    4.1 - Functions and Types

    Creates a new Lua state. It calls lua_newstate with an allocator based on the standard C realloc function -and then sets a panic function (see §3.6) that prints +and then sets a panic function (see §4.6) that prints an error message to the standard error output in case of fatal errors. @@ -5782,8 +5739,54 @@

    4.1 - Functions and Types

    +

    luaL_openlib

    +[-(nup + (0|1)), +1, e] +

    void luaL_openlib (lua_State *L,
    +                             const char *libname,
    +                             const luaL_Reg *l,
    +                             int nup);
    + +

    +Opens a library. + + +

    +When called with libname equal to NULL, +it simply registers all functions in the array l +(see luaL_Reg) into the table on the top of the stack. +The pointer l may be NULL, +representing an empty list. + + +

    +When called with a non-null libname, +luaL_openlib creates a new table t, +sets it as the value of the global variable libname, +sets it as the value of package.loaded[libname], +and registers on it all functions in the list l. +If there is a table in package.loaded[libname] or +in global variable libname, +reuses this table instead of creating a new one. + + +

    +In any case the function leaves the table +on the top of the stack. + + +

    +When nup is not zero, +all functions are created sharing nup upvalues, +which must be previously pushed on the stack +(on top of the library table, if present). +These values are popped from the stack after the registration. + + + + +


    luaL_openlibs

    -[-0, +0, m] +[-0, +0, e]

    void luaL_openlibs (lua_State *L);

    @@ -5960,7 +5963,7 @@

    4.1 - Functions and Types

    Type for arrays of functions to be registered by -luaL_register. +luaL_openlib. name is the function name and func is a pointer to the function. Any array of luaL_Reg must end with an sentinel entry @@ -5977,31 +5980,8 @@

    4.1 - Functions and Types

    const luaL_Reg *l);

    -Opens a library. - - -

    -When called with libname equal to NULL, -it simply registers all functions in the array l -(see luaL_Reg) into the table on the top of the stack. -The pointer l may be NULL, -representing an empty list. - - -

    -When called with a non-null libname, -luaL_register creates a new table t, -sets it as the value of the global variable libname, -sets it as the value of package.loaded[libname], -and registers on it all functions in the list l. -If there is a table in package.loaded[libname] or in -variable libname, -reuses this table instead of creating a new one. - - -

    -In any case the function leaves the table -on the top of the stack. +This macro is equivalent to calling luaL_openlib +with no upvalues. @@ -6134,7 +6114,7 @@

    4.1 - Functions and Types

    -

    5 - Standard Libraries

    +

    6 - Standard Libraries

    The standard Lua libraries provide useful functions @@ -6200,7 +6180,7 @@

    5 - Standard Libraries

    -

    5.1 - Basic Functions

    +

    6.1 - Basic Functions

    The basic library provides some core functions to Lua. @@ -6266,13 +6246,13 @@

    5.1 - Basic Functions

  • "setpause": sets arg as the new value for the pause of -the collector (see §2.10). +the collector (see §2.5). Returns the previous value for pause.
  • "setstepmul": sets arg as the new value for the step multiplier of -the collector (see §2.10). +the collector (see §2.5). Returns the previous value for step.
  • @@ -6321,7 +6301,7 @@

    5.1 - Basic Functions


    _G

    A global variable (not a function) that -holds the global environment (so that _G._G = _G). +holds the global environment (see §2.2). Lua itself does not use this variable; changing its value does not affect any environment, nor vice-versa. @@ -6343,31 +6323,6 @@

    5.1 - Basic Functions

    -

    -


    ipairs (t)

    - - -

    -If t has a metamethod __ipairs, -calls it with t as argument and returns the first three -results from the call. - - -

    -Otherwise, -returns three values: an iterator function, the table t, and 0, -so that the construction - -

    -     for i,v in ipairs(t) do body end
    -

    -will iterate over the pairs (1,t[1]), (2,t[2]), ···, -up to the length of the table, -as defined by the length operator (see §2.5.5). - - - -


    load (ld [, source [, mode]])

    @@ -6392,12 +6347,15 @@

    5.1 - Basic Functions

    If there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. -The environment of the returned function is the global environment. +If the resulting function has upvalues, +the first upvalue is set to the value of the global environment +(When loading main chunks, +this upvalue will be the _ENV variable (see §2.2).)

    source is used as the source of the chunk for error messages -and debug information (see §3.9). +and debug information (see §4.9). When absent, it defaults to "=(load)". @@ -6418,8 +6376,9 @@

    5.1 - Basic Functions

    This function is similar to load, -but sets env as the environment +but sets env as the value of the first upvalue of the created function in case of success. +(Usually this first upvalue will be _ENV (see §2.2).) The parameters after env are similar to those of load, too. @@ -6486,7 +6445,7 @@

    5.1 - Basic Functions

    The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, -use a numerical for or the ipairs function.) +use a numerical for.)

    @@ -6641,7 +6600,7 @@

    5.1 - Basic Functions

    represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. In base 10 (the default), the number can have a decimal part, -as well as an optional exponent part (see §2.1). +as well as an optional exponent part (see §3.1). In other bases, only unsigned integers are accepted. @@ -6703,12 +6662,12 @@

    5.1 - Basic Functions

    -

    5.2 - Coroutine Manipulation

    +

    6.2 - Coroutine Manipulation

    The operations related to coroutines comprise a sub-library of the basic library and come inside the table coroutine. -See §2.11 for a general description of coroutines. +See §2.6 for a general description of coroutines.

    @@ -6813,7 +6772,7 @@

    5.2 - Coroutine Manipulation

    -

    5.3 - Modules

    +

    6.3 - Modules

    The package library provides basic @@ -7194,7 +7153,7 @@

    5.3 - Modules

    -

    5.4 - String Manipulation

    +

    6.4 - String Manipulation

    This library provides generic functions for string manipulation, @@ -7377,6 +7336,7 @@

    5.4 - String Manipulation

    which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred. +The name gsub comes from Global SUBstitution.

    @@ -7517,7 +7477,7 @@

    5.4 - String Manipulation

    -

    5.4.1 - Patterns

    +

    6.4.1 - Patterns

    Character Class:

    @@ -7552,8 +7512,6 @@

    Character Class:

  • %x: represents all hexadecimal digits.
  • -
  • %z: represents the character with representation 0.
  • -
  • %x: (where x is any non-alphanumeric character) represents the character x. This is the standard way to escape the magic characters. @@ -7702,9 +7660,6 @@

    Captures:

    string "flaaap", there will be two captures: 3 and 5. -

    -A pattern cannot contain embedded zeros. Use %z instead. - @@ -7714,8 +7669,7 @@

    Captures:

    - -

    5.5 - Table Manipulation

    +

    6.5 - Table Manipulation

    This library provides generic functions for table manipulation. It provides all its functions inside the table table. @@ -7747,7 +7701,7 @@

    5.5 - Table Manipulation

    Inserts element value at position pos in table, shifting up other elements to open space, if necessary. The default value for pos is n+1, -where n is the length of the table (see §2.5.5), +where n is the length of the table (see §3.4.6), so that a call table.insert(t,x) inserts x at the end of table t. @@ -7788,9 +7742,9 @@

    5.5 - Table Manipulation

    from table[1] to table[n], where n is the length of the table. If comp is given, -then it must be a function that receives two table elements, -and returns true -when the first is less than the second +then it must be a function that receives two table elements +and returns true when the first element must come +before the second in the final order (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead. @@ -7815,7 +7769,7 @@

    5.5 - Table Manipulation

    except that the above code can be written only for a fixed number of elements. By default, i is 1 and j is the length of the list, -as defined by the length operator (see §2.5.5). +as defined by the length operator (see §3.4.6). @@ -7823,7 +7777,7 @@

    5.5 - Table Manipulation

    -

    5.6 - Mathematical Functions

    +

    6.6 - Mathematical Functions

    This library is an interface to the standard C math library. @@ -8036,7 +7990,7 @@

    5.6 - Mathematical Functions

    -The value of pi. +The value of π. @@ -8152,7 +8106,7 @@

    5.6 - Mathematical Functions

    -

    5.7 - Bitwise operations

    +

    6.7 - Bitwise operations

    This library provides bitwise operations. @@ -8202,29 +8156,28 @@

    5.7 - Bitwise operations

    -


    bit.brotate (x, disp)

    +

    bit.btest (···)

    -Returns the number x rotated disp bits to the left. -The number disp may be any representable integer. +Returns a boolean signaling +whether the bitwise and of its operands is different from zero. + +

    -For any valid displacement, -the following identity holds: +


    bit.bxor (···)

    -
    -     assert(bit.rotate(x, disp) == bit.rotate(x, disp % 32))
    -

    -This allows you to consider that -negative displacements rotate to the right. + +

    +Returns the bitwise exclusive or of its operands.

    -


    bit.bshift (x, disp)

    +

    bit.lshift (x, disp)

    @@ -8243,42 +8196,82 @@

    5.7 - Bitwise operations

    the following equality holds:
    -     assert(bit.bshift(b, disp) == (b * 2^disp) % 2^32)
    +     assert(bit.lshift(b, disp) == (b * 2^disp) % 2^32)
     
    + +

    -For negative displacements, -the following equality holds: +


    bit.rol (x, disp)

    + + +

    +Returns the number x rotated disp bits to the left. +The number disp may be any representable integer. + + +

    +For any valid displacement, +the following identity holds:

    -     assert(bit.bshift(b, disp) == math.floor(b * 2^disp))
    -
    + assert(bit.rol(x, disp) == bit.rol(x, disp % 32)) +

    +In particular, +negative displacements rotate to the right. + + +

    -This shift operation is what is called logical shift. -For an arithmetic shift, -you should use the arithmetic operators. +


    bit.ror (x, disp)

    +

    +Returns the number x rotated disp bits to the right. +The number disp may be any representable integer.

    -


    bit.btest (···)

    +For any valid displacement, +the following identity holds: + +
    +     assert(bit.ror(x, disp) == bit.ror(x, disp % 32))
    +

    +In particular, +negative displacements rotate to the left. + +

    -Returns a boolean signaling -whether the bitwise and of its operands is different from zero. +


    bit.rshift (x, disp)

    +

    +Returns the number x shifted disp bits to the right. +The number disp may be any representable integer. +Negative displacements shift to the left. +In any direction, vacant bits are filled with zeros. +In particular, +displacements with absolute values higher than +the total number of bits in the representation of x +result in zero (all bits are shifted out).

    -


    bit.bxor (···)

    +For positive displacements, +the following equality holds: +
    +     assert(bit.rshift(b, disp) == math.floor(b * 2^-disp))
    +

    -Returns the bitwise exclusive or of its operands. +This shift operation is what is called logical shift. +For an arithmetic shift, +you should use the arithmetic operators. @@ -8286,7 +8279,7 @@

    5.7 - Bitwise operations

    -

    5.8 - Input and Output Facilities

    +

    6.8 - Input and Output Facilities

    The I/O library provides two different styles for file manipulation. @@ -8362,7 +8355,7 @@

    5.8 - Input and Output Facilities

    -


    io.lines ([filename])

    +

    io.lines ([filename] [, keepNL])

    @@ -8387,6 +8380,11 @@

    5.8 - Input and Output Facilities

    In this case it does not close the file when the loop ends. +

    +By default, lines removes the newline at the end of each line. +If keepNL is true, it will keep the newlines. + +

    @@ -8521,7 +8519,7 @@

    5.8 - Input and Output Facilities

    -


    file:lines ()

    +

    file:lines ([keepNL])

    @@ -8533,11 +8531,17 @@

    5.8 - Input and Output Facilities

          for line in file:lines() do body end
     

    -will iterate over all lines of the file. +will iterate over all lines of the file, +starting at the current position. (Unlike io.lines, this function does not close the file when the loop ends.) +

    +By default, lines removes the newline at the end of each line. +If keepNL is true, it will keep the newlines. + +

    @@ -8551,7 +8555,7 @@

    5.8 - Input and Output Facilities

    the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, -it uses a default format that reads the entire next line +it uses a default format that reads the next line (see below). @@ -8571,11 +8575,16 @@

    5.8 - Input and Output Facilities

  • "*l": -reads the next line (skipping the end of line), +reads the next line skipping the end of line, returning nil on end of file. This is the default format.
  • +
  • "*L": +reads the next line keeping the end of line (if present), +returning nil on end of file. +
  • +
  • number: reads a string with up to this number of characters, returning nil on end of file. @@ -8678,7 +8687,7 @@

    5.8 - Input and Output Facilities

    -

    5.9 - Operating System Facilities

    +

    6.9 - Operating System Facilities

    This library is implemented through table os. @@ -8904,23 +8913,20 @@

    5.9 - Operating System Facilities

    -

    5.10 - The Debug Library

    +

    6.10 - The Debug Library

    This library provides the functionality of the debug interface to Lua programs. You should exert care when using this library. -The functions provided here should be used exclusively for debugging -and similar tasks, such as profiling. -Please resist the temptation to use them as a -usual programming tool: -they can be very slow. -Moreover, several of these functions -violate some assumptions about Lua code +Several of these functions +violate basic assumptions about Lua code (e.g., that variables local to a function -cannot be accessed from outside or -that userdata metatables cannot be changed by Lua code) +cannot be accessed from outside; +that userdata metatables cannot be changed by Lua code; +that Lua programs do not crash) and therefore can compromise otherwise secure code. +Moreover, some functions in this library may be slow.

    @@ -9055,7 +9061,7 @@

    5.10 - The Debug Library

    -Returns the registry table (see §3.5). +Returns the registry table (see §4.5). @@ -9217,7 +9223,7 @@

    5.10 - The Debug Library

    -

    6 - Lua Stand-alone

    +

    7 - Lua Stand-alone

    Although Lua has been designed as an extension language, @@ -9268,7 +9274,7 @@

    6 - Lua Stand-alone

    will first set a to 1, then print the value of a (which is '1'), and finally run the file script.lua with no arguments. -(Here $ is the shell prompt. Your prompt may be different.) +(Here $ is the shell prompt. Your prompt can be different.)

    @@ -9352,7 +9358,7 @@

    6 - Lua Stand-alone

    #!/usr/local/bin/lua

    (Of course, -the location of the Lua interpreter may be different in your machine. +the location of the Lua interpreter can be different in your machine. If lua is in your PATH, then @@ -9363,10 +9369,10 @@

    6 - Lua Stand-alone

    -

    7 - Incompatibilities with the Previous Version

    +

    8 - Incompatibilities with the Previous Version

    -Here we list the incompatibilities that you may find when moving a program +Here we list the incompatibilities that you can find when moving a program from Lua 5.1 to Lua 5.2. You can avoid some incompatibilities compiling Lua with appropriate options (see file luaconf.h). @@ -9375,7 +9381,7 @@

    7 - Incompatibilities with the Previous Version

    -

    7.1 - Changes in the Language

    +

    8.1 - Changes in the Language

    • @@ -9396,12 +9402,19 @@

      7.1 - Changes in the Language

      All threads share a single fixed environment.
    • +
    • +The event tail return in debug hooks was removed. +Instead, tail calls generate a special new event, +tail call, so that the debuger can know there will +not be a corresponding return event. +
    • +
    -

    7.2 - Changes in the Libraries

    +

    8.2 - Changes in the Libraries

    • @@ -9412,9 +9425,13 @@

      7.2 - Changes in the Libraries

    • Functions setfenv and getfenv are deprecated. To set the environment of a Lua function, -use lexical environments or the new function loadin. -(If you really need them, -you may use their equivalents in the debug library.) +use the variable _ENV or the new function loadin. +
    • + +
    • +Function ipairs is deprecated. +Use a numerical for loop instead, +or write it in Lua.
    • @@ -9432,20 +9449,44 @@

      7.2 - Changes in the Libraries

      and therefore must be called as table.unpack.
    • +
    • +Character class %z in patterns is deprecated, +as now patterns may contain '\0' as a regular character. +
    • + +
    • +Lua does not have bytecode verification anymore. +So, all functions that load code +(load, loadfile, loadstring) +are potentially insecure when loading untrusted binary data. +(Actually, those functions were already insecure because +of bugs in the verification algorithm.) +When in doubt, +use the mode argument in function load +to restrict it to loading textual chunks. +
    • +
    -

    7.3 - Changes in the API

    +

    8.3 - Changes in the API

    • Pseudoindex LUA_GLOBALSINDEX was removed. -You may use the pseudoindex LUA_ENVIRONINDEX instead, -if the C function does not change its standard environment. -Otherwise, you should get the global environment from the registry -(see §3.5). +You must get the global environment from the registry +(see §4.5). +
    • + +
    • +Pseudoindex LUA_ENVIRONINDEX was removed. +C functions do not have environments any more. +Use an upvalue with a shared table if you need to keep +shared state among several C functions. +(You may use luaL_openlib to open a C library +with all functions sharing a common upvalue.)
    • @@ -9462,8 +9503,8 @@

      7.3 - Changes in the API

    • Function lua_cpcall is deprecated. -Use the new cpcall function defined in the registry instead -(see §3.5). +You can simply push the function with lua_pushcfunction +and call it with lua_pcall.
    • @@ -9480,7 +9521,7 @@

      7.3 - Changes in the API

      -

      8 - The Complete Syntax of Lua

      +

      9 - The Complete Syntax of Lua

      Here is the complete syntax of Lua in extended BNF. @@ -9491,63 +9532,64 @@

      8 - The Complete Syntax of Lua

       
      -	chunk ::= {stat [`;´]} [laststat [`;´]]
      +	chunk ::= {stat} [laststat [&lsquo;’]]
       
       	block ::= chunk
       
      -	stat ::=  varlist `=´ explist | 
      +	stat ::=  &lsquo;’ | 
      +		 varlist &lsquo=’ explist | 
       		 functioncall | 
       		 do block end | 
       		 while exp do block end | 
       		 repeat block until exp | 
       		 if exp then block {elseif exp then block} [else block] end | 
      -		 for Name `=´ exp `,´ exp [`,´ exp] do block end | 
      +		 for Name &lsquo=’ exp &lsquo,’ exp [&lsquo,’ exp] do block end | 
       		 for namelist in explist do block end | 
       		 function funcname funcbody | 
       		 local function Name funcbody | 
      -		 local namelist [`=´ explist] | 
      +		 local namelist [&lsquo=’ explist] | 
       		 in exp do block end 
       
       	laststat ::= return [explist] | break
       
      -	funcname ::= Name {`.´ Name} [`:´ Name]
      +	funcname ::= Name {&lsquo.’ Name} [&lsquo:’ Name]
       
      -	varlist ::= var {`,´ var}
      +	varlist ::= var {&lsquo,’ var}
       
      -	var ::=  Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name 
      +	var ::=  Name | prefixexp &lsquo[’ exp &lsquo]’ | prefixexp &lsquo.’ Name 
       
      -	namelist ::= Name {`,´ Name}
      +	namelist ::= Name {&lsquo,’ Name}
       
      -	explist ::= {exp `,´} exp
      +	explist ::= {exp &lsquo,’} exp
       
      -	exp ::=  nil | false | true | Number | String | `...´ | function | 
      +	exp ::=  nil | false | true | Number | String | &lsquo...’ | function | 
       		 prefixexp | tableconstructor | exp binop exp | unop exp 
       
      -	prefixexp ::= var | functioncall | `(´ exp `)´
      +	prefixexp ::= var | functioncall | &lsquo(’ exp &lsquo)’
       
      -	functioncall ::=  prefixexp args | prefixexp `:´ Name args 
      +	functioncall ::=  prefixexp args | prefixexp &lsquo:’ Name args 
       
      -	args ::=  `(´ [explist] `)´ | tableconstructor | String 
      +	args ::=  &lsquo(’ [explist] &lsquo)’ | tableconstructor | String 
       
       	function ::= function funcbody
       
      -	funcbody ::= `(´ [parlist] `)´ block end
      +	funcbody ::= &lsquo(’ [parlist] &lsquo)’ block end
       
      -	parlist ::= namelist [`,´ `...´] | `...´
      +	parlist ::= namelist [&lsquo,’ &lsquo...’] | &lsquo...’
       
      -	tableconstructor ::= `{´ [fieldlist] `}´
      +	tableconstructor ::= &lsquo{’ [fieldlist] &lsquo}’
       
       	fieldlist ::= field {fieldsep field} [fieldsep]
       
      -	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
      +	field ::= &lsquo[’ exp &lsquo]’ &lsquo=’ exp | Name &lsquo=’ exp | exp
       
      -	fieldsep ::= `,´ | `;´
      +	fieldsep ::= &lsquo,’ | &lsquo;’
       
      -	binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | 
      -		 `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | 
      +	binop ::= &lsquo+’ | &lsquo-’ | &lsquo*’ | &lsquo/’ | &lsquo^’ | &lsquo%’ | &lsquo..’ | 
      +		 &lsquo<’ | &lsquo<=’ | &lsquo>’ | &lsquo>=’ | &lsquo==’ | &lsquo~=’ | 
       		 and | or
       
      -	unop ::= `-´ | not | `#´
      +	unop ::= &lsquo-’ | not | &lsquo#
      @@ -9562,10 +9604,10 @@

      8 - The Complete Syntax of Lua


      Last update: -Wed Jan 13 15:29:29 BRST 2010 +Mon May 17 16:24:08 BRT 2010 diff --git a/doc/readme.html b/doc/readme.html index 6d9e601eee..076dd81fad 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -9,25 +9,31 @@ color: black ; padding: 8px ; border: solid #a0a0a0 2px ; - background-color: #EFEFFF ; + xbackground-color: #EFEFFF ; margin-left: 0px ; } -.review { - color: red ; -} - .external { padding-right: 15px; background: transparent url(external.png) no-repeat center right; } -tt, kbd { +tt, kbd, code { font-size: 120% ; xcolor: black ; xpadding: 4px ; xbackground-color: #E0E0E0 ; } + +kbd { + color: black ; + background-color: #E8E8E8 ; +} + +.review { + color: red ; +} + @@ -39,6 +45,11 @@

      Welcome to Lua 5.2

      + +This is a work version of Lua 5.2. +Everything may change in the final version. +

      + about · installation @@ -51,11 +62,6 @@


      -

      - -This is a work version of Lua 5.2. -All details may change in the final version. -

      About Lua

      Lua is a powerful, fast, lightweight, embeddable scripting language @@ -270,6 +276,24 @@

      Building Lua on other systems

      Changes since Lua 5.1

      + +Everything may change in the final version. +

      + +Here are the main changes since the previous work version: +

        +
      • new _ENV proposal +
      • generational collector (very experimental) +
      • light C functions + +
      • order tag methods follow the same rules of other binary operators +
      • lua_absindex +
      • \0 in patterns +
      • empty statement +
      • options in io.lines +
      +

      + Here are the main changes in Lua since its last release. The reference manual @@ -281,13 +305,13 @@

      Language

      • new lexical environments.
      • no more fenv for threads. -
      • ephemeron tables. -
      • yieldable pcall/metamethods. +
      • ephemeron tables + (tables with weak keys only visit value when key is accessible). +
      • yieldable pcall and metamethods.
      • tables honor the __len metamethod.
      • max constants per function raised to 2^26.
      • hex escapes in strings.
      • no more verification of opcode consistency. -

      Libraries

      @@ -299,27 +323,39 @@

      Libraries

    • loadlib may load libraries with global names (RTLD_GLOBAL).
    • new function package.searchpath.
    • optional base in math.log. -
    • file:write returns file. +
    • file:write returns file.
    • closing a pipe returns exit status.
    • os.exit may close state.
    • new option 'isrunning' for collectgarbage and lua_gc.
    • frontier patterns.
    • ipairs now goes until #t. +
    +

    C API

    +
      +
    • mainthread predefined in the registry. +
    • lua_cpcall changed to a predefined function in the registry. +
    • new constants LUA_OK and LUA_ERRGCMM. +
    • new lua_compare, lua_arith, and lua_len. +
    • new lua_version and luaL_version. +
    • lua_pushstring and pushlstring return string. +
    • new luaL_testudata. +
    • new luaL_tolstring. +
    • new lua_copy. +
    • new lua_upvalueid and lua_upvaluejoin. +
    • nparams and isvarag available in debug API.

    Implementation

    • emergency garbage collector (core forces a full collection when allocation fails). -
    • ephemeron tables - (tables with weak keys only visit value when key is accessible) -
    • handling of non-string error messages in the standalone interpreter.
    • udata with finalizers are kept in a separated list for the GC.
    • CallInfo stack now is a linked list.
    • internal (immutable) version of ctypes.
    • parser uses much less C-stack space (no more auto arrays).
    • new hash for floats. +
    • handling of non-string error messages in the standalone interpreter.
    @@ -372,10 +408,10 @@

    License


    Last update: -Wed Jan 13 15:35:05 BRST 2010 +Tue May 18 13:59:06 BRT 2010 diff --git a/etc/Makefile b/etc/Makefile index 5f6ed87295..34d8571a6c 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -7,32 +7,48 @@ BIN= $(TOP)/src SRC= $(TOP)/src TST= $(TOP)/test +T= test CC= gcc CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) MYCFLAGS= -MYLDFLAGS= -Wl,-E -MYLIBS= -lm -#MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses +MYLIBS= -lm # -ldl -lreadline -lncurses -Wl,-E RM= rm -f + default: - @echo 'Please choose a target: min noparser one strict clean' + @echo 'Please choose a target: min noparser one one-lua one-lib one-luac so strict clean' min: min.c - $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS) - echo 'print"Hello there!"' | ./a.out - ./a.out $(TST)/hello.lua - echo 'print("Hello world, from",_VERSION,"!")' | ./a.out + $(CC) $(CFLAGS) -o $T min.c -L$(LIB) -llua $(MYLIBS) + echo 'print"Hello there!"' | ./$T + ./$T $(TST)/hello.lua + echo 'print("Hello world, from",_VERSION,"!")' | ./$T noparser: noparser.o - $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) + $(CC) -o $T noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) $(BIN)/luac $(TST)/hello.lua - -./a.out luac.out - -./a.out -e'a=1' + -./$T luac.out + -./$T -e'a=1' + +one: one-lua one-lib one-luac + +one-lua: + $(CC) $(CFLAGS) -o $T one.c $(MYLIBS) + ./$T $(TST)/hello.lua + +one-lib: + $(CC) $(CFLAGS) -DMAKE_LIB -o liblua.o -c one.c + $(CC) $(CFLAGS) -o $T min.c liblua.o $(MYLIBS) + ./$T $(TST)/hello.lua + +one-luac: + $(CC) $(CFLAGS) -o $T -DMAKE_LUAC one.c $(MYLIBS) + ./$T -l $(TST)/hello.lua -one: - $(CC) $(CFLAGS) one.c $(MYLIBS) - ./a.out $(TST)/hello.lua +so: + $(CC) $(CFLAGS) -shared -o dummy.so dummy.c + @#env MACOSX_DEPLOYMENT_TARGET=10.3 $(CC) $(CFLAGS) -bundle -undefined dynamic_lookup -o dummy.so dummy.c + $(BIN)/lua -v -ldummy strict: -$(BIN)/lua -e 'print(a);b=2' @@ -41,6 +57,6 @@ strict: -$(BIN)/lua -lstrict -e 'function f() b=2 end f()' clean: - $(RM) a.out core core.* *.o luac.out + $(RM) $T a.out core core.* *.o luac.out dummy.so -.PHONY: default min noparser one strict clean +.PHONY: default min noparser one one-lua one-lib one-luac so strict clean diff --git a/etc/README b/etc/README index 300257ae50..0eda3bd3e0 100644 --- a/etc/README +++ b/etc/README @@ -4,23 +4,26 @@ Unlike the code in ../src, everything here is in the public domain. If any of the makes fail, you're probably not using the same libraries used to build Lua. Set MYLIBS in Makefile or in the command line accordingly. -one.c - Full Lua interpreter in a single file. - Do "make one" for a demo. +dummy.c: + A minimal Lua library for testing dynamic loading. + Do "make so" for a demo. luavs.bat Script to build Lua under "Visual Studio .NET Command Prompt". Run it from the toplevel as etc\luavs.bat. min.c - A minimal Lua interpreter. - Good for learning and for starting your own. + A minimal Lua interpreter for learning and for starting your own. Do "make min" for a demo. noparser.c Linking with noparser.o avoids loading the parsing modules in lualib.a. Do "make noparser" for a demo. +one.c + Full Lua interpreter in a single file. Also library and compiler. + Do "make one" for a demo. + strict.lua Traps uses of undeclared global variables. Do "make strict" for a demo. diff --git a/etc/dummy.c b/etc/dummy.c new file mode 100644 index 0000000000..1d40e8be39 --- /dev/null +++ b/etc/dummy.c @@ -0,0 +1,11 @@ +/* +* dummy.c -- a minimal Lua library for testing dynamic loading +*/ + +#include +#include "lua.h" + +int luaopen_dummy (lua_State *L) { + puts("Hello from dummy"); + return 0; +} diff --git a/etc/one.c b/etc/one.c index be1f3a40a5..372543a64b 100644 --- a/etc/one.c +++ b/etc/one.c @@ -5,10 +5,11 @@ /* default is to build the full interpreter */ #ifndef MAKE_LIB #ifndef MAKE_LUAC -#undef MAKE_LUA +#ifndef MAKE_LUA #define MAKE_LUA #endif #endif +#endif /* choose suitable platform-specific features */ /* some of these may need extra libraries such as -ldl -lreadline -lncurses */ @@ -16,7 +17,6 @@ #define LUA_USE_LINUX #define LUA_USE_MACOSX #define LUA_USE_POSIX -#define LUA_USE_DLOPEN #define LUA_ANSI #endif @@ -58,11 +58,11 @@ #include "loslib.c" #include "lstrlib.c" #include "ltablib.c" +#include "linit.c" #endif /* lua */ #ifdef MAKE_LUA -#include "linit.c" #include "lua.c" #endif diff --git a/src/Makefile b/src/Makefile index a3942a5bdd..83185e3484 100644 --- a/src/Makefile +++ b/src/Makefile @@ -27,7 +27,7 @@ CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ ltm.o lundump.o lvm.o lzio.o LIB_O= lauxlib.o lbaselib.o lbitlib.o ldblib.o liolib.o lmathlib.o loslib.o \ - ltablib.o lstrlib.o loadlib.o linit.o + lstrlib.o ltablib.o loadlib.o linit.o LUA_T= lua LUA_O= lua.o @@ -103,7 +103,7 @@ macosx: $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_MACOSX" MYLIBS="-lreadline" mingw: - $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ + $(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe @@ -137,8 +137,8 @@ ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ lstring.h ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h lundump.h -lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ - lopcodes.h lstate.h ltm.h lzio.h +lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \ + lstate.h ltm.h lzio.h lmem.h lopcodes.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h @@ -163,7 +163,7 @@ lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h + ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ lmem.h lstring.h lgc.h ltable.h diff --git a/src/lapi.c b/src/lapi.c index 56c0c1e9d8..8a0378f96f 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.111 2010/01/13 16:18:25 roberto Exp $ +** $Id: lapi.c,v 2.129 2010/05/14 13:15:26 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -39,16 +39,6 @@ const char lua_ident[] = "invalid index") -static Table *getcurrenv (lua_State *L) { - if (L->ci->previous == NULL) /* no enclosing function? */ - return G(L)->l_gt; /* use global table as environment */ - else { - Closure *func = curr_func(L); - return func->c.env; - } -} - - static TValue *index2addr (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { @@ -61,26 +51,25 @@ static TValue *index2addr (lua_State *L, int idx) { api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } - else switch (idx) { /* pseudo-indices */ - case LUA_REGISTRYINDEX: return &G(L)->l_registry; - case LUA_ENVIRONINDEX: { - sethvalue(L, &L->env, getcurrenv(L)); - return &L->env; - } - default: { - Closure *func = curr_func(L); - idx = LUA_ENVIRONINDEX - idx; - api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large"); + else if (idx == LUA_REGISTRYINDEX) + return &G(L)->l_registry; + else { /* upvalues */ + idx = LUA_REGISTRYINDEX - idx; + api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large"); + if (ttislcf(ci->func)) /* light C function? */ + return cast(TValue *, luaO_nilobject); /* it has no upvalues */ + else { + Closure *func = clvalue(ci->func); return (idx <= func->c.nupvalues) - ? &func->c.upvalue[idx-1] - : cast(TValue *, luaO_nilobject); + ? &func->c.upvalue[idx-1] + : cast(TValue *, luaO_nilobject); } } } /* -** to be caled by 'lua_checkstack' in protected mode, to grow stack +** to be called by 'lua_checkstack' in protected mode, to grow stack ** capturing memory errors */ static void growstack (lua_State *L, void *ud) { @@ -147,6 +136,16 @@ LUA_API const lua_Number *lua_version (lua_State *L) { */ +/* +** convert an acceptable stack index into an absolute index +*/ +LUA_API int lua_absindex (lua_State *L, int idx) { + return (idx > 0 || idx <= LUA_REGISTRYINDEX) + ? idx + : cast_int(L->top - L->ci->func + idx); +} + + LUA_API int lua_gettop (lua_State *L) { return cast_int(L->top - (L->ci->func + 1)); } @@ -195,16 +194,10 @@ LUA_API void lua_insert (lua_State *L, int idx) { static void moveto (lua_State *L, TValue *fr, int idx) { TValue *to = index2addr(L, idx); api_checkvalidindex(L, to); - if (idx == LUA_ENVIRONINDEX) { - Closure *func = curr_func(L); - api_check(L, ttistable(fr), "table expected"); - func->c.env = hvalue(fr); - luaC_barrier(L, func, fr); - } - else { - setobj(L, to, fr); - if (idx < LUA_ENVIRONINDEX) /* function upvalue? */ - luaC_barrier(L, curr_func(L), fr); + setobj(L, to, fr); + if (idx < LUA_REGISTRYINDEX) { /* function upvalue? */ + lua_assert(ttisclosure(L->ci->func)); + luaC_barrier(L, clvalue(L->ci->func), fr); } /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ @@ -213,9 +206,6 @@ static void moveto (lua_State *L, TValue *fr, int idx) { LUA_API void lua_replace (lua_State *L, int idx) { lua_lock(L); - /* explicit test for incompatible code */ - if (idx == LUA_ENVIRONINDEX && L->ci->previous == NULL) - luaG_runerror(L, "no calling environment"); api_checknelems(L, 1); moveto(L, L->top - 1, idx); L->top--; @@ -249,19 +239,19 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); + return (o == luaO_nilobject) ? LUA_TNONE : ttypenv(o); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); - return typename(t); + return ttypename(t); } LUA_API int lua_iscfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return iscfunction(o); + return (ttislcf(o) || (ttisclosure(o) && clvalue(o)->c.isC)); } @@ -387,7 +377,10 @@ LUA_API size_t lua_rawlen (lua_State *L, int idx) { LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; + if (ttislcf(o)) return fvalue(o); + else if (ttisclosure(o) && clvalue(o)->c.isC) + return clvalue(o)->c.f; + else return NULL; /* not a C function */ } @@ -412,6 +405,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) { switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); + case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: @@ -468,8 +462,16 @@ LUA_API const char *lua_pushstring (lua_State *L, const char *s) { lua_pushnil(L); return NULL; } - else - return lua_pushlstring(L, s, strlen(s)); + else { + TString *ts; + lua_lock(L); + luaC_checkGC(L); + ts = luaS_new(L, s); + setsvalue2s(L, L->top, ts); + api_incr_top(L); + lua_unlock(L); + return getstr(ts); + } } @@ -498,18 +500,22 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - Closure *cl; lua_lock(L); - api_checknelems(L, n); - api_check(L, n <= UCHAR_MAX, "upvalue index too large"); - luaC_checkGC(L); - cl = luaF_newCclosure(L, n, getcurrenv(L)); - cl->c.f = fn; - L->top -= n; - while (n--) - setobj2n(L, &cl->c.upvalue[n], L->top+n); - setclvalue(L, L->top, cl); - lua_assert(iswhite(obj2gco(cl))); + if (n == 0) { + setfvalue(L->top, fn); + } + else { + Closure *cl; + api_checknelems(L, n); + api_check(L, n <= UCHAR_MAX, "upvalue index too large"); + luaC_checkGC(L); + cl = luaF_newCclosure(L, n); + cl->c.f = fn; + L->top -= n; + while (n--) + setobj2n(L, &cl->c.upvalue[n], L->top + n); + setclvalue(L, L->top, cl); + } api_incr_top(L); lua_unlock(L); } @@ -616,7 +622,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { mt = uvalue(obj)->metatable; break; default: - mt = G(L)->mt[ttype(obj)]; + mt = G(L)->mt[ttypenv(obj)]; break; } if (mt == NULL) @@ -631,22 +637,16 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { } -LUA_API void lua_getfenv (lua_State *L, int idx) { +LUA_API void lua_getenv (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); api_checkvalidindex(L, o); - switch (ttype(o)) { - case LUA_TFUNCTION: - sethvalue(L, L->top, clvalue(o)->c.env); - break; - case LUA_TUSERDATA: - sethvalue(L, L->top, uvalue(o)->env); - break; - default: - setnilvalue(L->top); - break; - } + api_check(L, ttisuserdata(o), "userdata expected"); + if (uvalue(o)->env) { + sethvalue(L, L->top, uvalue(o)->env); + } else + setnilvalue(L->top); api_incr_top(L); lua_unlock(L); } @@ -737,7 +737,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { break; } default: { - G(L)->mt[ttype(obj)] = mt; + G(L)->mt[ttypenv(obj)] = mt; break; } } @@ -747,29 +747,22 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { } -LUA_API int lua_setfenv (lua_State *L, int idx) { +LUA_API void lua_setenv (lua_State *L, int idx) { StkId o; - int res = 1; lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); api_checkvalidindex(L, o); - api_check(L, ttistable(L->top - 1), "table expected"); - switch (ttype(o)) { - case LUA_TFUNCTION: - clvalue(o)->c.env = hvalue(L->top - 1); - break; - case LUA_TUSERDATA: - uvalue(o)->env = hvalue(L->top - 1); - break; - default: - res = 0; - break; + api_check(L, ttisuserdata(o), "userdata expected"); + if (ttisnil(L->top - 1)) + uvalue(o)->env = NULL; + else { + api_check(L, ttistable(L->top - 1), "table expected"); + uvalue(o)->env = hvalue(L->top - 1); + luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); } - if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); L->top--; lua_unlock(L); - return res; } @@ -857,7 +850,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, ci->u.c.k = k; /* save continuation */ ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ - ci->u.c.oldtop = savestack(L, c.func); + ci->u.c.extra = savestack(L, c.func); ci->u.c.old_allowhook = L->allowhook; ci->u.c.old_errfunc = L->errfunc; L->errfunc = func; @@ -882,6 +875,18 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname); + if (status == LUA_OK) { /* no errors? */ + Closure *f = clvalue(L->top - 1); /* get newly created function */ + lua_assert(!f->c.isC); + if (f->l.nupvalues == 1) { /* does it have one upvalue? */ + /* get global table from registry */ + Table *reg = hvalue(&G(L)->l_registry); + const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + /* set global table as 1st upvalue of 'f' (may be _ENV) */ + setobj(L, f->l.upvals[0]->v, gt); + luaC_barrier(L, f->l.upvals[0], gt); + } + } lua_unlock(L); return status; } @@ -918,11 +923,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g = G(L); switch (what) { case LUA_GCSTOP: { - g->GCthreshold = MAX_LUMEM; + stopgc(g); break; } case LUA_GCRESTART: { - g->GCthreshold = g->totalbytes; + g->GCdebt = 0; break; } case LUA_GCCOLLECT: { @@ -939,18 +944,22 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCSTEP: { - lu_mem oldts = g->GCthreshold; - lu_mem a = (cast(lu_mem, data) << 10); - g->GCthreshold = (a <= g->totalbytes) ? g->totalbytes - a : 0; - while (g->GCthreshold <= g->totalbytes) { - luaC_step(L); - if (g->gcstate == GCSpause) { /* end of cycle? */ - res = 1; /* signal it */ - break; + int stopped = gcstopped(g); + if (g->gckind == KGC_GEN) { /* generational mode? */ + res = (g->lastmajormem == 0); /* 1 if will do major collection */ + luaC_step(L); /* do a single step */ + } + else { + while (data-- >= 0) { + luaC_step(L); + if (g->gcstate == GCSpause) { /* end of cycle? */ + res = 1; /* signal it */ + break; + } } } - if (oldts == MAX_LUMEM) /* collector was stopped? */ - g->GCthreshold = oldts; /* keep it that way */ + if (stopped) /* collector was stopped? */ + stopgc(g); /* keep it that way */ break; } case LUA_GCSETPAUSE: { @@ -964,7 +973,15 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCISRUNNING: { - res = (g->GCthreshold != MAX_LUMEM); + res = !gcstopped(g); + break; + } + case LUA_GCGEN: { /* change collector to generational mode */ + luaC_changemode(L, KGC_GEN); + break; + } + case LUA_GCINC: { /* change collector to incremental mode */ + luaC_changemode(L, KGC_NORMAL); break; } default: res = -1; /* invalid option */ @@ -1054,7 +1071,7 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); - u = luaS_newudata(L, size, getcurrenv(L)); + u = luaS_newudata(L, size, NULL); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); @@ -1064,19 +1081,22 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { -static const char *aux_upvalue (StkId fi, int n, TValue **val) { +static const char *aux_upvalue (StkId fi, int n, TValue **val, + GCObject **owner) { Closure *f; - if (!ttisfunction(fi)) return NULL; + if (!ttisclosure(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { if (!(1 <= n && n <= f->c.nupvalues)) return NULL; *val = &f->c.upvalue[n-1]; + if (owner) *owner = obj2gco(f); return ""; } else { Proto *p = f->l.p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; + if (owner) *owner = obj2gco(f->l.upvals[n - 1]); return getstr(p->upvalues[n-1].name); } } @@ -1086,7 +1106,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1099,15 +1119,16 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; + GCObject *owner; StkId fi; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val); + name = aux_upvalue(fi, n, &val, &owner); if (name) { L->top--; setobj(L, val, L->top); - luaC_barrier(L, clvalue(fi), L->top); + luaC_barrier(L, owner, L->top); } lua_unlock(L); return name; @@ -1118,7 +1139,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { Closure *f; Proto *p; StkId fi = index2addr(L, fidx); - api_check(L, ttisfunction(fi), "function expected"); + api_check(L, ttisclosure(fi), "Lua function expected"); f = clvalue(fi); api_check(L, !f->c.isC, "Lua function expected"); p = f->l.p; @@ -1131,7 +1152,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { Closure *f; StkId fi = index2addr(L, fidx); - api_check(L, ttisfunction(fi), "function expected"); + api_check(L, ttisclosure(fi), "function expected"); f = clvalue(fi); if (f->c.isC) { api_check(L, 1 <= n && n <= f->c.nupvalues, "invalid upvalue index"); @@ -1150,12 +1171,3 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, luaC_objbarrier(L, f1, *up2); } - -#if defined(LUA_COMPAT_CPCALL) -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); - lua_pushlightuserdata(L, &func); - lua_pushlightuserdata(L, ud); - return lua_pcall(L, 2, 0, 0); -} -#endif diff --git a/src/lauxlib.c b/src/lauxlib.c index 9972555e34..8ebc18fa7c 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.196 2009/12/22 15:32:50 roberto Exp $ +** $Id: lauxlib.c,v 1.212 2010/05/18 17:21:24 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -24,11 +24,6 @@ #include "lauxlib.h" -/* convert a stack index to positive */ -#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ - lua_gettop(L) + (i) + 1) - - /* ** {====================================================== ** Traceback @@ -347,54 +342,40 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, ** ======================================================= */ - -#define bufflen(B) ((B)->p - (B)->buffer) -#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) - -#define LIMIT (LUA_MINSTACK/2) - - -static int emptybuffer (luaL_Buffer *B) { - size_t l = bufflen(B); - if (l == 0) return 0; /* put nothing on stack */ - else { - lua_pushlstring(B->L, B->buffer, l); - B->p = B->buffer; - B->lvl++; - return 1; - } -} +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->initb) -static void adjuststack (luaL_Buffer *B) { - if (B->lvl > 1) { - lua_State *L = B->L; - int toget = 1; /* number of levels to concat */ - size_t toplen = lua_rawlen(L, -1); - do { - size_t l = lua_rawlen(L, -(toget+1)); - if (B->lvl - toget + 1 >= LIMIT || toplen > l) { - toplen += l; - toget++; - } - else break; - } while (toget < B->lvl); - lua_concat(L, toget); - B->lvl = B->lvl - toget + 1; +/* +** returns a pointer to a free area with at least 'sz' bytes +*/ +LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { + lua_State *L = B->L; + if (B->size - B->n < sz) { /* not enough space? */ + char *newbuff; + size_t newsize = B->size * 2; /* double buffer size */ + if (newsize - B->n < sz) /* not bit enough? */ + newsize = B->n + sz; + if (newsize < B->n || newsize - B->n < sz) + luaL_error(L, "string too large"); + newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */ + memcpy(newbuff, B->b, B->n); /* move content to new buffer */ + if (buffonstack(B)) + lua_remove(L, -2); /* remove old buffer */ + B->b = newbuff; + B->size = newsize; } -} - - -LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { - if (emptybuffer(B)) - adjuststack(B); - return B->buffer; + return &B->b[B->n]; } LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - while (l--) - luaL_addchar(B, *s++); + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l); + luaL_addsize(B, l); } @@ -404,35 +385,41 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) { - emptybuffer(B); - lua_concat(B->L, B->lvl); - B->lvl = 1; + lua_State *L = B->L; + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) + lua_remove(L, -2); /* remove old buffer */ +} + + +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { + luaL_addsize(B, sz); + luaL_pushresult(B); } LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; - size_t vl; - const char *s = lua_tolstring(L, -1, &vl); - if (vl <= bufffree(B)) { /* fit into buffer? */ - memcpy(B->p, s, vl); /* put it there */ - B->p += vl; - lua_pop(L, 1); /* remove from stack */ - } - else { - if (emptybuffer(B)) - lua_insert(L, -2); /* put buffer before new value */ - B->lvl++; /* add new value into B stack */ - adjuststack(B); - } + size_t l; + const char *s = lua_tolstring(L, -1, &l); + if (buffonstack(B)) + lua_insert(L, -2); /* put value below buffer */ + luaL_addlstring(B, s, l); + lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ } LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { - luaL_checkstack(L, LIMIT + LUA_MINSTACK, "no space for new buffer"); B->L = L; - B->p = B->buffer; - B->lvl = 0; + B->b = B->initb; + B->n = 0; + B->size = LUAL_BUFFERSIZE; +} + + +LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { + luaL_buffinit(L, B); + return luaL_prepbuffsize(B, sz); } /* }====================================================== */ @@ -444,32 +431,26 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { ** ======================================================= */ -/* number of prereserved references (for internal use) */ -#define FREELIST_REF (LUA_RIDX_LAST + 1) /* free list of references */ +/* index of free-list header */ +#define freelist "lua-freelist" LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; - t = abs_index(L, t); + t = lua_absindex(L, t); if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* `nil' has a unique fixed reference */ } - lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ + lua_getfield(L, t, freelist); /* get first free element */ ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ - lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ + lua_setfield(L, t, freelist); /* (t[freelist] = t[ref]) */ } - else { /* no free elements */ + else /* no free elements */ ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ - if (ref == FREELIST_REF) { /* FREELIST_REF not initialized? */ - lua_pushinteger(L, 0); - lua_rawseti(L, t, FREELIST_REF); - ref = FREELIST_REF + 1; - } - } lua_rawseti(L, t, ref); return ref; } @@ -477,11 +458,11 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { - t = abs_index(L, t); - lua_rawgeti(L, t, FREELIST_REF); - lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ + t = lua_absindex(L, t); + lua_getfield(L, t, freelist); + lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ lua_pushinteger(L, ref); - lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ + lua_setfield(L, t, freelist); /* t[freelist] = ref */ } } @@ -495,7 +476,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { */ typedef struct LoadF { - int extraline; + int first; FILE *f; char buff[LUAL_BUFFERSIZE]; } LoadF; @@ -504,17 +485,19 @@ typedef struct LoadF { static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; - if (lf->extraline) { - lf->extraline = 0; + if (lf->first != EOF) { *size = 1; - return "\n"; + lf->buff[0] = (char)lf->first; + lf->first = EOF; + } + else { + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); } - /* 'fread' can return > 0 *and* set the EOF flag. If next call to - 'getF' calls 'fread', terminal may still wait for user input. - The next check avoids this problem. */ - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); - return (*size > 0) ? lf->buff : NULL; + return lf->buff; } @@ -532,7 +515,6 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - lf.extraline = 0; if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; @@ -544,18 +526,14 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { } c = getc(lf.f); if (c == '#') { /* Unix exec. file? */ - lf.extraline = 1; while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ - if (c == '\n') c = getc(lf.f); } - if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ + else if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - /* skip eventual `#!...' */ - while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; - lf.extraline = 0; + c = getc(lf.f); /* re-read first character */ } - ungetc(c, lf.f); + lf.first = c; /* 'c' is the first character of the stream */ status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ @@ -618,7 +596,7 @@ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = abs_index(L, obj); + obj = lua_absindex(L, obj); if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ return 0; lua_pushvalue(L, obj); @@ -663,13 +641,13 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { static int libsize (const luaL_Reg *l) { int size = 0; - for (; l->name; l++) size++; + for (; l && l->name; l++) size++; return size; } -LUALIB_API void luaL_register (lua_State *L, const char *libname, - const luaL_Reg *l) { +LUALIB_API void luaL_openlib (lua_State *L, const char *libname, + const luaL_Reg *l, int nup) { luaL_checkversion(L); if (libname) { /* check whether lib already exists */ @@ -685,12 +663,17 @@ LUALIB_API void luaL_register (lua_State *L, const char *libname, lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ } lua_remove(L, -2); /* remove _LOADED table */ + lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ } - if (l == NULL) return; /* nothing to register? */ - for (; l->name; l++) { /* else fill the table with given functions */ - lua_pushcfunction(L, l->func); - lua_setfield(L, -2, l->name); + luaL_checkstack(L, nup, "too many upvalues"); + for (; l && l->name; l++) { /* fill the table with given functions */ + int i; + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -nup); + lua_pushcclosure(L, l->func, nup); + lua_setfield(L, -(nup + 2), l->name); } + lua_pop(L, nup); /* remove upvalues */ } @@ -751,7 +734,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { static int panic (lua_State *L) { - fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); return 0; /* return to Lua to abort */ } diff --git a/src/lauxlib.h b/src/lauxlib.h index b8f2e2e51e..ae2e2c7571 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.99 2010/01/11 16:00:45 roberto Exp $ +** $Id: lauxlib.h,v 1.105 2010/05/04 17:21:08 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -29,11 +29,11 @@ typedef struct luaL_Reg { LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); #define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) -LUALIB_API void (luaL_register) (lua_State *L, const char *libname, - const luaL_Reg *l); +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); +LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); LUALIB_API int (luaL_typeerror) (lua_State *L, int narg, const char *tname); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, @@ -71,7 +71,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); -LUALIB_API int luaL_len (lua_State *L, int idx); +LUALIB_API int (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -79,9 +79,8 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, const char *fname, int szhint); -LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, - const char *msg, int level); - +LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); /* @@ -111,34 +110,40 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) +#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) + + /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ - - typedef struct luaL_Buffer { - char *p; /* current position in buffer */ - int lvl; /* number of strings in the stack (level) */ + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ lua_State *L; - char buffer[LUAL_BUFFERSIZE]; + char initb[LUAL_BUFFERSIZE]; /* initial buffer */ } luaL_Buffer; + #define luaL_addchar(B,c) \ - ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ - (*(B)->p++ = (char)(c))) + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) -#define luaL_addsize(B,n) ((B)->p += (n)) +#define luaL_addsize(B,s) ((B)->n += (s)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); -LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); +LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); +#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) /* }====================================================== */ diff --git a/src/lbaselib.c b/src/lbaselib.c index 162c06f202..946ecea5e9 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.235 2009/12/28 16:30:31 roberto Exp $ +** $Id: lbaselib.c,v 1.243 2010/04/19 17:02:02 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -23,7 +23,7 @@ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; - lua_getfield(L, LUA_ENVIRONINDEX, "tostring"); + lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; size_t l; @@ -107,50 +107,12 @@ static int luaB_setmetatable (lua_State *L) { } - -#if defined(LUA_COMPAT_FENV) - -static void getfunc (lua_State *L, int opt) { - if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); - else { - lua_Debug ar; - int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); - luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); - if (lua_getstack(L, level, &ar) == 0) - luaL_argerror(L, 1, "invalid level"); - lua_getinfo(L, "f", &ar); - } -} - -static int luaB_getfenv (lua_State *L) { - getfunc(L, 1); - if (lua_iscfunction(L, -1)) /* is a C function? */ - lua_pushglobaltable(L); /* return the global env. */ - else - lua_getfenv(L, -1); - return 1; -} - -static int luaB_setfenv (lua_State *L) { - luaL_checktype(L, 2, LUA_TTABLE); - getfunc(L, 0); - lua_pushvalue(L, 2); - if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) - return luaL_error(L, - LUA_QL("setfenv") " cannot change environment of given object"); - return 1; -} - -#else - static int luaB_getfenv (lua_State *L) { return luaL_error(L, "getfenv/setfenv deprecated"); } #define luaB_setfenv luaB_getfenv -#endif - static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); @@ -178,18 +140,13 @@ static int luaB_rawset (lua_State *L) { } -static int luaB_gcinfo (lua_State *L) { - lua_pushinteger(L, lua_gc(L, LUA_GCCOUNT, 0)); - return 1; -} - - static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", "isrunning", NULL}; + "count", "step", "setpause", "setstepmul", "isrunning", + "gen", "inc", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, - LUA_GCISRUNNING}; + LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; int ex = luaL_optint(L, 2, 0); int res = lua_gc(L, o, ex); @@ -219,10 +176,11 @@ static int luaB_type (lua_State *L) { } -static int pairsmeta (lua_State *L, const char *method, int iszero) { +static int pairsmeta (lua_State *L, const char *method, int iszero, + lua_CFunction iter) { if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ - lua_pushvalue(L, lua_upvalueindex(1)); /* will return generator, */ + lua_pushcfunction(L, iter); /* will return generator, */ lua_pushvalue(L, 1); /* state, */ if (iszero) lua_pushinteger(L, 0); /* and initial value */ else lua_pushnil(L); @@ -248,10 +206,12 @@ static int luaB_next (lua_State *L) { static int luaB_pairs (lua_State *L) { - return pairsmeta(L, "__pairs", 0); + return pairsmeta(L, "__pairs", 0, luaB_next); } +#if defined(LUA_COMPAT_IPAIRS) + static int ipairsaux (lua_State *L) { int i = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TTABLE); @@ -263,9 +223,17 @@ static int ipairsaux (lua_State *L) { static int luaB_ipairs (lua_State *L) { - return pairsmeta(L, "__ipairs", 1); + return pairsmeta(L, "__ipairs", 1, ipairsaux); +} + +#else + +static int luaB_ipairs (lua_State *L) { + return luaL_error(L, "'ipairs' deprecated"); } +#endif + static int load_aux (lua_State *L, int status) { if (status == LUA_OK) @@ -376,7 +344,7 @@ static int luaB_loadin (lua_State *L) { n = luaB_load_aux(L, 2); if (n == 1) { /* success? */ lua_pushvalue(L, 1); /* environment for loaded function */ - lua_setfenv(L, -2); + lua_setupvalue(L, -2, 1); } return n; } @@ -507,14 +475,15 @@ static const luaL_Reg base_funcs[] = { {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, - {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, {"getmetatable", luaB_getmetatable}, + {"ipairs", luaB_ipairs}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, {"loadin", luaB_loadin}, {"loadstring", luaB_loadstring}, {"next", luaB_next}, + {"pairs", luaB_pairs}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"rawequal", luaB_rawequal}, @@ -668,25 +637,15 @@ static const luaL_Reg co_funcs[] = { /* }====================================================== */ -static void auxopen (lua_State *L, const char *name, - lua_CFunction f, lua_CFunction u) { - lua_pushcfunction(L, u); - lua_pushcclosure(L, f, 1); - lua_setfield(L, -2, name); -} - - static void base_open (lua_State *L) { /* set global _G */ lua_pushglobaltable(L); - lua_setfield(L, LUA_ENVIRONINDEX, "_G"); + lua_pushglobaltable(L); + lua_setfield(L, -2, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, LUA_ENVIRONINDEX, "_VERSION"); /* set global _VERSION */ - /* `ipairs' and `pairs' need auxiliary functions as upvalues */ - auxopen(L, "ipairs", luaB_ipairs, ipairsaux); - auxopen(L, "pairs", luaB_pairs, luaB_next); + lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ /* `newproxy' needs a weaktable as upvalue */ lua_createtable(L, 0, 1); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ @@ -694,7 +653,7 @@ static void base_open (lua_State *L) { lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); - lua_setfield(L, LUA_ENVIRONINDEX, "newproxy"); /* set global `newproxy' */ + lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ } diff --git a/src/lbitlib.c b/src/lbitlib.c index 1d5a26421e..b367d0c654 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.3 2010/01/12 19:40:02 roberto Exp $ +** $Id: lbitlib.c,v 1.4 2010/02/11 15:55:29 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -80,9 +80,8 @@ static int b_not (lua_State *L) { } -static int b_shift (lua_State *L) { +static int b_shift (lua_State *L, int i) { b_uint r = getuintarg(L, 1); - lua_Integer i = luaL_checkinteger(L, 2); if (i < 0) { /* shift right? */ i = -i; if (i >= NBITS) r = 0; @@ -97,9 +96,18 @@ static int b_shift (lua_State *L) { } -static int b_rotate (lua_State *L) { +static int b_lshift (lua_State *L) { + return b_shift(L, luaL_checkint(L, 2)); +} + + +static int b_rshift (lua_State *L) { + return b_shift(L, -luaL_checkint(L, 2)); +} + + +static int b_rot (lua_State *L, int i) { b_uint r = getuintarg(L, 1); - lua_Integer i = luaL_checkinteger(L, 2); i &= (NBITS - 1); /* i = i % NBITS */ r = (r << i) | (r >> (NBITS - i)); lua_pushnumber(L, lua_uint2number(r)); @@ -107,14 +115,26 @@ static int b_rotate (lua_State *L) { } +static int b_rol (lua_State *L) { + return b_rot(L, luaL_checkint(L, 2)); +} + + +static int b_ror (lua_State *L) { + return b_rot(L, -luaL_checkint(L, 2)); +} + + static const luaL_Reg bitlib[] = { {"band", b_and}, {"btest", b_test}, {"bor", b_or}, {"bxor", b_xor}, {"bnot", b_not}, - {"bshift", b_shift}, - {"brotate", b_rotate}, + {"lshift", b_lshift}, + {"rshift", b_rshift}, + {"rol", b_rol}, + {"ror", b_ror}, {NULL, NULL} }; diff --git a/src/lcode.c b/src/lcode.c index c55ebd549d..d060b5f0d5 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.43 2010/01/11 17:38:30 roberto Exp $ +** $Id: lcode.c,v 2.46 2010/04/17 12:46:32 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -372,11 +372,6 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { e->k = VRELOCABLE; break; } - case VGLOBAL: { - e->u.s.info = luaK_codeABxX(fs, OP_GETGLOBAL, 0, e->u.s.info); - e->k = VRELOCABLE; - break; - } case VINDEXED: { freereg(fs, e->u.s.aux); freereg(fs, e->u.s.info); @@ -384,6 +379,12 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { e->k = VRELOCABLE; break; } + case VINDEXEDUP: { + freereg(fs, e->u.s.aux); + e->u.s.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.s.info, e->u.s.aux); + e->k = VRELOCABLE; + break; + } case VVARARG: case VCALL: { luaK_setoneret(fs, e); @@ -493,6 +494,12 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { } +void luaK_exp2anyregup (FuncState *fs, expdesc *e) { + if (e->k != VUPVAL || hasjumps(e)) + luaK_exp2anyreg(fs, e); +} + + void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); @@ -543,16 +550,16 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); break; } - case VGLOBAL: { - int e = luaK_exp2anyreg(fs, ex); - luaK_codeABxX(fs, OP_SETGLOBAL, e, var->u.s.info); - break; - } case VINDEXED: { int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); break; } + case VINDEXEDUP: { + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, OP_SETTABUP, var->u.s.info, var->u.s.aux, e); + break; + } default: { lua_assert(0); /* invalid var kind to store */ break; @@ -567,9 +574,9 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { luaK_exp2anyreg(fs, e); freeexp(fs, e); func = fs->freereg; - luaK_reserveregs(fs, 2); luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); freeexp(fs, key); + luaK_reserveregs(fs, 2); e->u.s.info = func; e->k = VNONRELOC; } @@ -695,8 +702,9 @@ static void codenot (FuncState *fs, expdesc *e) { void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + lua_assert(!hasjumps(t)); t->u.s.aux = luaK_exp2RK(fs, k); - t->k = VINDEXED; + t->k = (t->k == VUPVAL) ? VINDEXEDUP : VINDEXED; } @@ -711,7 +719,8 @@ static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { } -static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { +static void codearith (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { if (constfolding(op, e1, e2)) return; else { @@ -727,6 +736,7 @@ static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { } e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); e1->k = VRELOCABLE; + luaK_fixline(fs, line); } } @@ -747,7 +757,7 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, } -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { expdesc e2; e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { @@ -756,14 +766,14 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ else { luaK_exp2anyreg(fs, e); - codearith(fs, OP_UNM, e, &e2); + codearith(fs, OP_UNM, e, &e2, line); } break; } case OPR_NOT: codenot(fs, e); break; case OPR_LEN: { luaK_exp2anyreg(fs, e); /* cannot operate on constants */ - codearith(fs, OP_LEN, e, &e2); + codearith(fs, OP_LEN, e, &e2, line); break; } default: lua_assert(0); @@ -798,7 +808,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } -void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { +void luaK_posfix (FuncState *fs, BinOpr op, + expdesc *e1, expdesc *e2, int line) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ @@ -824,13 +835,13 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codearith(fs, OP_CONCAT, e1, e2); + codearith(fs, OP_CONCAT, e1, e2, line); } break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_MOD: case OPR_POW: { - codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2); + codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); break; } case OPR_EQ: case OPR_LT: case OPR_LE: { diff --git a/src/lcode.h b/src/lcode.h index 8ef67e55fa..d7f7dd62f0 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.52 2009/09/23 20:33:05 roberto Exp $ +** $Id: lcode.h,v 1.54 2010/04/17 12:46:32 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -57,6 +57,7 @@ LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); @@ -72,9 +73,10 @@ LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); -LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); +LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); -LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); +LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, + expdesc *v2, int line); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); diff --git a/src/ldblib.c b/src/ldblib.c index eeaedc1f1a..28e671dfd2 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.119 2010/01/06 14:42:35 roberto Exp $ +** $Id: ldblib.c,v 1.121 2010/03/26 20:58:11 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -44,19 +44,19 @@ static int db_setmetatable (lua_State *L) { } -static int db_getfenv (lua_State *L) { - luaL_checkany(L, 1); - lua_getfenv(L, 1); +static int db_getenv (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + lua_getenv(L, 1); return 1; } -static int db_setfenv (lua_State *L) { - luaL_checktype(L, 2, LUA_TTABLE); +static int db_setenv (lua_State *L) { + luaL_checktype(L, 1, LUA_TUSERDATA); + if (!lua_isnoneornil(L, 2)) + luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); - if (lua_setfenv(L, 1) == 0) - luaL_error(L, LUA_QL("setfenv") - " cannot change environment of given object"); + lua_setenv(L, 1); return 1; } @@ -339,15 +339,13 @@ static int db_gethook (lua_State *L) { static int db_debug (lua_State *L) { for (;;) { char buffer[250]; - fputs("lua_debug> ", stderr); + luai_writestringerror("%s", "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || - lua_pcall(L, 0, 0, 0)) { - fputs(lua_tostring(L, -1), stderr); - fputs("\n", stderr); - } + lua_pcall(L, 0, 0, 0)) + luai_writestringerror("%s\n", lua_tostring(L, -1)); lua_settop(L, 0); /* remove eventual returns */ } } @@ -369,7 +367,7 @@ static int db_traceback (lua_State *L) { static const luaL_Reg dblib[] = { {"debug", db_debug}, - {"getfenv", db_getfenv}, + {"getenv", db_getenv}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, @@ -378,7 +376,7 @@ static const luaL_Reg dblib[] = { {"getupvalue", db_getupvalue}, {"upvaluejoin", db_upvaluejoin}, {"upvalueid", db_upvalueid}, - {"setfenv", db_setfenv}, + {"setenv", db_setenv}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, diff --git a/src/ldebug.c b/src/ldebug.c index 2544a5dd4b..dcc8ca9970 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.63 2010/01/13 16:18:25 roberto Exp $ +** $Id: ldebug.c,v 2.70 2010/04/13 20:48:12 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -144,7 +144,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { static void funcinfo (lua_Debug *ar, Closure *cl) { - if (cl->c.isC) { + if (cl == NULL || cl->c.isC) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; @@ -191,8 +191,8 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'u': { - ar->nups = f->c.nupvalues; - if (f->c.isC) { + ar->nups = (f == NULL) ? 0 : f->c.nupvalues; + if (f == NULL || f->c.isC) { ar->isvararg = 1; ar->nparams = 0; } @@ -226,28 +226,30 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; - Closure *f = NULL; - CallInfo *ci = NULL; + Closure *cl; + CallInfo *ci; + StkId func; lua_lock(L); if (*what == '>') { - StkId func = L->top - 1; + ci = NULL; + func = L->top - 1; luai_apicheck(L, ttisfunction(func)); what++; /* skip the '>' */ - f = clvalue(func); L->top--; /* pop function */ } else { ci = ar->i_ci; + func = ci->func; lua_assert(ttisfunction(ci->func)); - f = clvalue(ci->func); } - status = auxgetinfo(L, what, ar, f, ci); + cl = ttisclosure(func) ? clvalue(func) : NULL; + status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { - setclvalue(L, L->top, f); + setobjs2s(L, L->top, func); incr_top(L); } if (strchr(what, 'L')) - collectvalidlines(L, f); + collectvalidlines(L, cl); lua_unlock(L); return status; } @@ -260,22 +262,23 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { */ -static const char *kname (Proto *p, int c) { - if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) - return svalue(&p->k[INDEXK(c)]); +static void kname (Proto *p, int c, int reg, const char *what, + const char **name) { + if (c == reg && *what == 'c') + return; /* index is a constant; name already correct */ + else if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) + *name = svalue(&p->k[INDEXK(c)]); else - return "?"; + *name = "?"; } static const char *getobjname (lua_State *L, CallInfo *ci, int reg, const char **name) { - Proto *p; - int lastpc, pc; + Proto *p = ci_func(ci)->l.p; const char *what = NULL; - lua_assert(isLua(ci)); - p = ci_func(ci)->l.p; - lastpc = currentpc(ci); + int lastpc = currentpc(ci); + int pc; *name = luaF_getlocalname(p, reg + 1, lastpc); if (*name) /* is a local? */ return "local"; @@ -285,17 +288,6 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, OpCode op = GET_OPCODE(i); int a = GETARG_A(i); switch (op) { - case OP_GETGLOBAL: { - if (reg == a) { - int g = GETARG_Bx(i); - if (g != 0) g--; - else g = GETARG_Ax(p->code[++pc]); - lua_assert(ttisstring(&p->k[g])); - *name = svalue(&p->k[g]); - what = "global"; - } - break; - } case OP_MOVE: { if (reg == a) { int b = GETARG_B(i); /* move from 'b' to 'a' */ @@ -305,11 +297,16 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, } break; } + case OP_GETTABUP: case OP_GETTABLE: { if (reg == a) { int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - what = "field"; + int t = GETARG_B(i); + const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ + ? luaF_getlocalname(p, t + 1, pc) + : getstr(p->upvalues[t].name); + kname(p, k, a, what, name); + what = (vn && strcmp(vn, "_ENV") == 0) ? "global" : "field"; } break; } @@ -322,6 +319,17 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, } break; } + case OP_LOADK: { + if (reg == a) { + int b = GETARG_Bx(i); + b = (b > 0) ? b - 1 : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) { + what = "constant"; + *name = svalue(&p->k[b]); + } + } + break; + } case OP_LOADNIL: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (a <= reg && reg <= b) /* set registers from 'a' to 'b' */ @@ -331,7 +339,7 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, case OP_SELF: { if (reg == a) { int k = GETARG_C(i); /* key index */ - *name = kname(p, k); + kname(p, k, a, what, name); what = "method"; } break; @@ -374,12 +382,15 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: - case OP_TFORLOOP: return getobjname(L, ci, GETARG_A(i), name); - case OP_GETGLOBAL: + case OP_TFORCALL: { + *name = "for iterator"; + return "for iterator"; + } case OP_SELF: + case OP_GETTABUP: case OP_GETTABLE: tm = TM_INDEX; break; - case OP_SETGLOBAL: + case OP_SETTABUP: case OP_SETTABLE: tm = TM_NEWINDEX; break; case OP_EQ: tm = TM_EQ; break; case OP_ADD: tm = TM_ADD; break; @@ -413,13 +424,30 @@ static int isinstack (CallInfo *ci, const TValue *o) { } +static const char *getupvalname (CallInfo *ci, const TValue *o, + const char **name) { + LClosure *c = &ci_func(ci)->l; + int i; + for (i = 0; i < c->nupvalues; i++) { + if (c->upvals[i]->v == o) { + *name = getstr(c->p->upvalues[i].name); + return "upvalue"; + } + } + return NULL; +} + + void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { CallInfo *ci = L->ci; const char *name = NULL; - const char *t = typename(ttype(o)); - const char *kind = (isLua(ci) && isinstack(ci, o)) ? - getobjname(L, ci, cast_int(o - ci->u.l.base), &name) : - NULL; + const char *t = objtypename(o); + const char *kind = NULL; + if (isLua(ci)) { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind && isinstack(ci, o)) /* no? try a register */ + kind = getobjname(L, ci, cast_int(o - ci->u.l.base), &name); + } if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); @@ -444,8 +472,8 @@ void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { - const char *t1 = typename(ttype(p1)); - const char *t2 = typename(ttype(p2)); + const char *t1 = objtypename(p1); + const char *t2 = objtypename(p2); if (t1 == t2) luaG_runerror(L, "attempt to compare two %s values", t1); else diff --git a/src/ldo.c b/src/ldo.c index 4890ce21c4..5b0e766e95 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.80 2010/01/13 16:17:32 roberto Exp $ +** $Id: ldo.c,v 2.87 2010/05/05 18:49:56 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -48,7 +48,7 @@ */ #if !defined(LUAI_THROW) -#if defined(__cplusplus) +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) \ @@ -83,8 +83,8 @@ struct lua_longjmp { static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { - case LUA_ERRMEM: { - setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); + case LUA_ERRMEM: { /* memory error? */ + setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ break; } case LUA_ERRERR: { @@ -293,18 +293,43 @@ static StkId tryfuncTM (lua_State *L, StkId func) { ** returns true if function has been executed (C function) */ int luaD_precall (lua_State *L, StkId func, int nresults) { - LClosure *cl; + Closure *cl; + lua_CFunction f; ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); - cl = &clvalue(func)->l; L->ci->nresults = nresults; - if (!cl->isC) { /* Lua function? prepare its call */ + if (ttislcf(func)) { /* light C function? */ + f = fvalue(func); /* get it */ + goto isCfunc; /* go to call it */ + } + cl = clvalue(func); + if (cl->c.isC) { /* C closure? */ + CallInfo *ci; + int n; + f = cl->c.f; + isCfunc: /* call C function 'f' */ + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci = next_ci(L); /* now 'enter' new function */ + ci->func = restorestack(L, funcr); + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->callstatus = 0; + if (L->hookmask & LUA_MASKCALL) + luaD_hook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, L->top - n); + return 1; + } + else { /* Lua function: prepare its call */ CallInfo *ci; int nparams, nargs; StkId base; - Proto *p = cl->p; + Proto *p = cl->l.p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); nargs = cast_int(L->top - func) - 1; /* number of real arguments */ @@ -327,24 +352,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { callhook(L, ci); return 0; } - else { /* if is a C function, call it */ - CallInfo *ci; - int n; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = next_ci(L); /* now 'enter' new function */ - ci->func = restorestack(L, funcr); - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - ci->callstatus = 0; - if (L->hookmask & LUA_MASKCALL) - luaD_hook(L, LUA_HOOKCALL, -1); - lua_unlock(L); - n = (*curr_func(L)->c.f)(L); /* do the actual call */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, L->top - n); - return 1; - } } @@ -452,7 +459,7 @@ static int recover (lua_State *L, int status) { CallInfo *ci = findpcall(L); if (ci == NULL) return 0; /* no recovery point */ /* "finish" luaD_pcall */ - oldtop = restorestack(L, ci->u.c.oldtop); + oldtop = restorestack(L, ci->u.c.extra); luaF_close(L, oldtop); seterrorobj(L, status, oldtop); L->ci = ci; @@ -469,7 +476,7 @@ static int recover (lua_State *L, int status) { /* ** signal an error in the call to 'resume', not in the execution of the ** coroutine itself. (Such errors should not be handled by any coroutine -** error hanlder and should not kill the coroutine.) +** error handler and should not kill the coroutine.) */ static void resume_error (lua_State *L, const char *msg, StkId firstArg) { L->top = firstArg; /* remove args from the stack */ @@ -501,11 +508,11 @@ static void resume (lua_State *L, void *ud) { if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ + ci->func = restorestack(L, ci->u.c.extra); if (ci->u.c.k != NULL) { /* does it have a continuation? */ int n; ci->u.c.status = LUA_YIELD; /* 'default' status */ ci->callstatus |= CIST_YIELDED; - ci->func = restorestack(L, ci->u.c.oldtop); lua_unlock(L); n = (*ci->u.c.k)(L); /* call continuation */ lua_lock(L); @@ -526,6 +533,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { luai_userstateresume(L, nargs); ++G(L)->nCcalls; /* count resume */ L->nny = 0; /* allow yields */ + api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status == -1) /* error calling 'lua_resume'? */ status = LUA_ERRRUN; @@ -565,11 +573,10 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { api_check(L, k == NULL, "hooks cannot continue after yielding"); } else { - if ((ci->u.c.k = k) != NULL) { /* is there a continuation? */ + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ ci->u.c.ctx = ctx; /* save context */ - ci->u.c.oldtop = savestack(L, ci->func); /* save current 'func' */ - } - ci->func = L->top - nresults - 1; /* protect stack slots below */ + ci->u.c.extra = savestack(L, ci->func); /* save current 'func' */ + ci->func = L->top - nresults - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ @@ -623,7 +630,7 @@ static void f_parser (lua_State *L, void *ud) { : luaY_parser(L, p->z, &p->buff, &p->varl, p->name); setptvalue2s(L, L->top, tf); incr_top(L); - cl = luaF_newLclosure(L, tf->sizeupvalues, G(L)->l_gt); + cl = luaF_newLclosure(L, tf->sizeupvalues); cl->l.p = tf; setclvalue(L, L->top - 1, cl); for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ diff --git a/src/ldump.c b/src/ldump.c index f95381abae..b2c1e70992 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ +** $Id: ldump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -145,7 +145,6 @@ static void DumpFunction(const Proto* f, const TString* p, DumpState* D) DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); - DumpChar(f->envreg,D); DumpCode(f,D); DumpConstants(f,D); DumpUpvalues(f,D); diff --git a/src/lfunc.c b/src/lfunc.c index afc097c608..e95dad017e 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.19 2009/12/16 16:42:58 roberto Exp $ +** $Id: lfunc.c,v 2.24 2010/05/10 18:23:45 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -21,19 +21,17 @@ -Closure *luaF_newCclosure (lua_State *L, int n, Table *e) { +Closure *luaF_newCclosure (lua_State *L, int n) { Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl; c->c.isC = 1; - c->c.env = e; c->c.nupvalues = cast_byte(n); return c; } -Closure *luaF_newLclosure (lua_State *L, int n, Table *e) { +Closure *luaF_newLclosure (lua_State *L, int n) { Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; c->l.isC = 0; - c->l.env = e; c->l.nupvalues = cast_byte(n); while (n--) c->l.upvals[n] = NULL; return c; @@ -54,12 +52,14 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { UpVal *p; UpVal *uv; while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { + GCObject *o = obj2gco(p); lua_assert(p->v != &p->u.value); if (p->v == level) { /* found a corresponding upvalue? */ - if (isdead(g, obj2gco(p))) /* is it dead? */ - changewhite(obj2gco(p)); /* ressurrect it */ + if (isdead(g, o)) /* is it dead? */ + changewhite(o); /* ressurrect it */ return p; } + resetoldbit(o); /* may create a newer upval after this one */ pp = &p->next; } /* not found: create a new one */ @@ -98,10 +98,12 @@ void luaF_close (lua_State *L, StkId level) { if (isdead(g, o)) luaF_freeupval(L, uv); /* free upvalue */ else { - unlinkupval(uv); - setobj(L, &uv->u.value, uv->v); + unlinkupval(uv); /* remove upvalue from 'uvhead' list */ + setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ uv->v = &uv->u.value; /* now current value lives here */ - luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ + g->allgc = o; + luaC_checkupvalcolor(g, uv); } } } @@ -127,7 +129,6 @@ Proto *luaF_newproto (lua_State *L) { f->linedefined = 0; f->lastlinedefined = 0; f->source = NULL; - f->envreg = NO_REG; return f; } diff --git a/src/lfunc.h b/src/lfunc.h index 2e02419bd6..d11182b0e3 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ +** $Id: lfunc.h,v 2.5 2010/03/26 20:58:11 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -19,8 +19,8 @@ LUAI_FUNC Proto *luaF_newproto (lua_State *L); -LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); diff --git a/src/lgc.c b/src/lgc.c index 2094d386ae..276edacd7c 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.67 2009/12/22 15:32:50 roberto Exp $ +** $Id: lgc.c,v 2.96 2010/05/17 20:39:31 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -23,21 +23,49 @@ #include "ltm.h" -#define GCSTEPSIZE 1024u + +/* how much to allocate before next GC step */ +#define GCSTEPSIZE 1024 + +/* maximum numer of elements to sweep in each single step */ #define GCSWEEPMAX 40 -#define GCSWEEPCOST 10 -#define GCFINALIZECOST 100 +/* cost of sweeping one element */ +#define GCSWEEPCOST 1 + +/* maximum number of finalizers to call in each GC step */ +#define GCFINALIZENUM 4 + +/* cost of marking the root set */ +#define GCROOTCOST 10 + +/* cost of atomic step */ +#define GCATOMICCOST 1000 + +/* basic cost to traverse one object (to be added to the links the + object may have) */ +#define TRAVCOST 5 -#define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) +/* +** standard negative debt for GC; a reasonable "time" to wait before +** starting a new cycle +*/ +#define stddebt(g) (-cast(l_mem, g->totalbytes/100) * g->gcpause) + + +/* +** 'makewhite' erases all color bits plus the old bit and then +** sets only the current white bit +*/ +#define maskcolors (~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS)) #define makewhite(g,x) \ (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) -#define stringmark(s) resetbits((s)->tsv.marked, WHITEBITS) +#define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS))) #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) @@ -51,7 +79,6 @@ #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } - static void reallymarkobject (global_State *g, GCObject *o); @@ -61,12 +88,16 @@ static void reallymarkobject (global_State *g, GCObject *o); ** ======================================================= */ -static void linktable (Table *h, GCObject **p) { - h->gclist = *p; - *p = obj2gco(h); -} + +/* +** link table 'h' into list pointed by 'p' +*/ +#define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h)) +/* +** mark a table entry as dead (therefore removing it from the table) +*/ static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (iscollectable(gkey(n))) @@ -75,8 +106,8 @@ static void removeentry (Node *n) { /* -** The next function tells whether a key or value can be cleared from -** a weak table. Non-collectable objects are never removed from weak +** tells whether a key or value can be cleared from a weak +** table. Non-collectable objects are never removed from weak ** tables. Strings behave as `values', so are never removed too. for ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values @@ -92,24 +123,32 @@ static int iscleared (const TValue *o, int iskey) { } +/* +** barrier that moves collector forward, that is, mark the white object +** being pointed by a black object. +*/ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + lua_assert(isgenerational(g) || g->gcstate != GCSpause); lua_assert(gch(o)->tt != LUA_TTABLE); - /* must keep invariant? */ - if (g->gcstate == GCSpropagate) + if (keepinvariant(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ - else /* don't mind */ - makewhite(g, o); /* mark as white just to avoid other barriers */ + else { /* sweep phase */ + lua_assert(issweepphase(g)); + makewhite(g, o); /* mark main obj. as white to avoid other barriers */ + } } +/* +** barrier that moves collector backward, that is, mark the black object +** pointing to a white object as gray again. +*/ void luaC_barrierback (lua_State *L, Table *t) { global_State *g = G(L); GCObject *o = obj2gco(t); lua_assert(isblack(o) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); black2gray(o); /* make table gray (again) */ t->gclist = g->grayagain; g->grayagain = o; @@ -117,14 +156,37 @@ void luaC_barrierback (lua_State *L, Table *t) { /* -** create a new collectable object and link it to '*list' +** check color (and invariants) for an upvalue that was closed, +** i.e., moved into the 'allgc' list +*/ +void luaC_checkupvalcolor (global_State *g, UpVal *uv) { + GCObject *o = obj2gco(uv); + lua_assert(!isblack(o)); /* open upvalues are never black */ + if (isgray(o)) { + if (keepinvariant(g)) { + resetoldbit(o); /* see MOVE OLD rule */ + gray2black(o); /* it is being visited now */ + markvalue(g, uv->v); + } + else { + lua_assert(issweepphase(g)); + makewhite(g, o); + } + } +} + + +/* +** create a new collectable object (with given type and size) and link +** it to '*list'. 'offset' tells how many bytes to allocate before the +** object itself (used only by states). */ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, int offset) { global_State *g = G(L); GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); if (list == NULL) - list = &g->rootgc; /* standard list for collectable objects */ + list = &g->allgc; /* standard list for collectable objects */ gch(o)->marked = luaC_white(g); gch(o)->tt = tt; gch(o)->next = *list; @@ -132,24 +194,6 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, return o; } - -void luaC_linkupval (lua_State *L, UpVal *uv) { - global_State *g = G(L); - GCObject *o = obj2gco(uv); - gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ - g->rootgc = o; - if (isgray(o)) { - if (g->gcstate == GCSpropagate) { - gray2black(o); /* closed upvalues need barrier */ - luaC_barrier(L, uv, uv->v); - } - else { /* sweep phase: sweep it (turning it into white) */ - makewhite(g, o); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); - } - } -} - /* }====================================================== */ @@ -160,25 +204,33 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { ** ======================================================= */ + +/* +** mark an object. Userdata and closed upvalues are visited and turned +** black here. Strings remain gray (it is the same as making them +** black). Other objects are marked gray and added to appropriate list +** to be visited (and turned black) later. (Open upvalues are already +** linked in 'headuv' list.) +*/ static void reallymarkobject (global_State *g, GCObject *o) { lua_assert(iswhite(o) && !isdead(g, o)); white2gray(o); switch (gch(o)->tt) { case LUA_TSTRING: { - return; + return; /* for strings, gray is as good as black */ } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; - gray2black(o); /* udata are never gray */ markobject(g, mt); markobject(g, gco2u(o)->env); + gray2black(o); /* all pointers marked */ return; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); - if (uv->v == &uv->u.value) /* closed? */ - gray2black(o); /* open upvalues are never black */ + if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */ + gray2black(o); /* make it black */ return; } case LUA_TFUNCTION: { @@ -205,48 +257,55 @@ static void reallymarkobject (global_State *g, GCObject *o) { } +/* +** mark tag methods for basic types +*/ static void markmt (global_State *g) { int i; - for (i=0; imt[i]); } +/* +** mark all objects in list of being-finalized +*/ static void markbeingfnz (global_State *g) { GCObject *o; for (o = g->tobefnz; o != NULL; o = gch(o)->next) { - lua_assert(testbit(gch(o)->marked, SEPARATED)); makewhite(g, o); reallymarkobject(g, o); } } -/* mark root set */ -static void markroot (lua_State *L) { - global_State *g = G(L); - g->gray = NULL; - g->grayagain = NULL; - g->weak = g->ephemeron = g->allweak = NULL; - markobject(g, g->mainthread); - /* make global table and registry to be traversed before main stack */ - markobject(g, g->l_gt); - markvalue(g, &g->l_registry); - markmt(g); - markbeingfnz(g); /* mark any finalizing object left from previous cycle */ - g->gcstate = GCSpropagate; -} - - +/* +** mark all values stored in marked open upvalues. (See comment in +** 'lstate.h'.) +*/ static void remarkupvals (global_State *g) { UpVal *uv; for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); if (isgray(obj2gco(uv))) markvalue(g, uv->v); } } + +/* +** mark root set and reset all gray lists, to start a new +** incremental (or full) collection +*/ +static void markroot (lua_State *L) { + global_State *g = G(L); + g->gray = g->grayagain = NULL; + g->weak = g->allweak = g->ephemeron = NULL; + markobject(g, g->mainthread); + markvalue(g, &g->l_registry); + markmt(g); + markbeingfnz(g); /* mark any finalizing object left from previous cycle */ +} + /* }====================================================== */ @@ -257,49 +316,48 @@ static void remarkupvals (global_State *g) { */ static void traverseweakvalue (global_State *g, Table *h) { - int i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + Node *n, *limit = gnode(h, sizenode(h)); + for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); - if (ttisnil(gval(n))) - removeentry(n); /* remove empty entries */ + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); + markvalue(g, gkey(n)); /* mark key */ } } - linktable(h, &g->weak); + linktable(h, &g->weak); /* link into appropriate list */ } static int traverseephemeron (global_State *g, Table *h) { - int marked = 0; - int hasclears = 0; - int i = h->sizearray; - while (i--) { /* mark array part (numeric keys are 'strong') */ + int marked = 0; /* true if an object is marked in this traversal */ + int hasclears = 0; /* true if table has unmarked pairs */ + Node *n, *limit = gnode(h, sizenode(h)); + int i; + /* traverse array part (numeric keys are 'strong') */ + for (i = 0; i < h->sizearray; i++) { if (valiswhite(&h->array[i])) { marked = 1; reallymarkobject(g, gcvalue(&h->array[i])); } } - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + /* traverse hash part */ + for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ - else if (valiswhite(gval(n))) { - /* value is not marked yet */ + else if (valiswhite(gval(n))) { /* value not marked yet? */ if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ hasclears = 1; /* may have to propagate mark from key to value */ - else { /* mark value only if key is marked */ - marked = 1; /* some mark changed status */ + else { /* key is marked, so mark value */ + marked = 1; /* value was not marked */ reallymarkobject(g, gcvalue(gval(n))); } } } - if (hasclears) - linktable(h, &g->ephemeron); + if (hasclears) /* does table have unmarked pairs? */ + linktable(h, &g->ephemeron); /* will have to propagate again */ else /* nothing to propagate */ linktable(h, &g->weak); /* avoid convergence phase */ return marked; @@ -307,26 +365,24 @@ static int traverseephemeron (global_State *g, Table *h) { static void traversestrongtable (global_State *g, Table *h) { + Node *n, *limit = gnode(h, sizenode(h)); int i; - i = h->sizearray; - while (i--) + for (i = 0; i < h->sizearray; i++) /* traverse array part */ markvalue(g, &h->array[i]); - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ checkdeadkey(n); - if (ttisnil(gval(n))) - removeentry(n); /* remove empty entries */ + if (ttisnil(gval(n))) /* entry is empty? */ + removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); - markvalue(g, gkey(n)); - markvalue(g, gval(n)); + markvalue(g, gkey(n)); /* mark key */ + markvalue(g, gval(n)); /* mark value */ } } } -static void traversetable (global_State *g, Table *h) { +static int traversetable (global_State *g, Table *h) { const TValue *mode = gfasttm(g, h->metatable, TM_MODE); markobject(g, h->metatable); if (mode && ttisstring(mode)) { /* is there a weak mode? */ @@ -334,43 +390,41 @@ static void traversetable (global_State *g, Table *h) { int weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ black2gray(obj2gco(h)); /* keep table gray */ - if (!weakkey) /* strong keys? */ + if (!weakkey) { /* strong keys? */ traverseweakvalue(g, h); - else if (!weakvalue) /* strong values? */ + return TRAVCOST + sizenode(h); + } + else if (!weakvalue) { /* strong values? */ traverseephemeron(g, h); - else + return TRAVCOST + h->sizearray + sizenode(h); + } + else { linktable(h, &g->allweak); /* nothing to traverse now */ - return; + return TRAVCOST; + } } /* else go through */ } traversestrongtable(g, h); + return TRAVCOST + h->sizearray + (2 * sizenode(h)); } -/* -** All marks are conditional because a GC may happen while the -** prototype is still being created -*/ -static void traverseproto (global_State *g, Proto *f) { +static int traverseproto (global_State *g, Proto *f) { int i; - if (f->source) stringmark(f->source); - for (i=0; isizek; i++) /* mark literals */ + stringmark(f->source); + for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); - for (i=0; isizeupvalues; i++) { /* mark upvalue names */ - if (f->upvalues[i].name) - stringmark(f->upvalues[i].name); - } - for (i=0; isizep; i++) /* mark nested protos */ + for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ + stringmark(f->upvalues[i].name); + for (i = 0; i < f->sizep; i++) /* mark nested protos */ markobject(g, f->p[i]); - for (i=0; isizelocvars; i++) { /* mark local-variable names */ - if (f->locvars[i].varname) - stringmark(f->locvars[i].varname); - } + for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ + stringmark(f->locvars[i].varname); + return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; } -static void traverseclosure (global_State *g, Closure *cl) { - markobject(g, cl->c.env); +static l_mem traverseclosure (global_State *g, Closure *cl) { if (cl->c.isC) { int i; for (i=0; ic.nupvalues; i++) /* mark its upvalues */ @@ -379,32 +433,35 @@ static void traverseclosure (global_State *g, Closure *cl) { else { int i; lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); - markobject(g, cl->l.p); + markobject(g, cl->l.p); /* mark its prototype */ for (i=0; il.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); } + return TRAVCOST + cl->c.nupvalues; } -static void traversestack (global_State *g, lua_State *L) { - StkId o; - if (L->stack == NULL) - return; /* stack not completely built yet */ - for (o = L->stack; o < L->top; o++) +static int traversestack (global_State *g, lua_State *L) { + StkId o = L->stack; + if (o == NULL) + return 1; /* stack not completely built yet */ + for (; o < L->top; o++) markvalue(g, o); if (g->gcstate == GCSatomic) { /* final traversal? */ StkId lim = L->stack + L->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); } + return TRAVCOST + cast_int(o - L->stack); } /* -** traverse one gray object, turning it to black. -** Returns `quantity' traversed. +** traverse one gray object, turning it to black (except for threads, +** which are always gray). +** Returns number of values traversed. */ -static l_mem propagatemark (global_State *g) { +static int propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); @@ -412,16 +469,12 @@ static l_mem propagatemark (global_State *g) { case LUA_TTABLE: { Table *h = gco2t(o); g->gray = h->gclist; - traversetable(g, h); - return sizeof(Table) + sizeof(TValue) * h->sizearray + - sizeof(Node) * sizenode(h); + return traversetable(g, h); } case LUA_TFUNCTION: { Closure *cl = gco2cl(o); g->gray = cl->c.gclist; - traverseclosure(g, cl); - return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : - sizeLclosure(cl->l.nupvalues); + return traverseclosure(g, cl); } case LUA_TTHREAD: { lua_State *th = gco2th(o); @@ -429,19 +482,12 @@ static l_mem propagatemark (global_State *g) { th->gclist = g->grayagain; g->grayagain = o; black2gray(o); - traversestack(g, th); - return sizeof(lua_State) + sizeof(TValue) * th->stacksize; + return traversestack(g, th); } case LUA_TPROTO: { Proto *p = gco2p(o); g->gray = p->gclist; - traverseproto(g, p); - return sizeof(Proto) + sizeof(Instruction) * p->sizecode + - sizeof(Proto *) * p->sizep + - sizeof(TValue) * p->sizek + - sizeof(int) * p->sizelineinfo + - sizeof(LocVar) * p->sizelocvars + - sizeof(TString *) * p->sizeupvalues; + return traverseproto(g, p); } default: lua_assert(0); return 0; } @@ -465,14 +511,14 @@ static void convergeephemerons (global_State *g) { int changed; do { GCObject *w; - GCObject *next = g->ephemeron; - g->ephemeron = NULL; + GCObject *next = g->ephemeron; /* get ephemeron list */ + g->ephemeron = NULL; /* tables will return to this list when traversed */ changed = 0; while ((w = next) != NULL) { next = gco2t(w)->gclist; - if (traverseephemeron(g, gco2t(w))) { - changed = 1; - propagateall(g); + if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ + propagateall(g); /* propagate changes */ + changed = 1; /* will have to revisit all ephemeron tables */ } } } while (changed); @@ -487,26 +533,26 @@ static void convergeephemerons (global_State *g) { ** ======================================================= */ -/* clear collected entries from weaktables */ +/* +** clear collected entries from all weaktables in list 'l' +*/ static void cleartable (GCObject *l) { - while (l) { + for (; l != NULL; l = gco2t(l)->gclist) { Table *h = gco2t(l); - int i = h->sizearray; - while (i--) { + Node *n, *limit = gnode(h, sizenode(h)); + int i; + for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; if (iscleared(o, 0)) /* value was collected? */ setnilvalue(o); /* remove value */ } - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); + for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && /* non-empty entry? */ (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* remove entry from table */ + removeentry(n); /* and remove entry from table */ } } - l = h->gclist; } } @@ -533,33 +579,63 @@ static void freeobj (lua_State *L, GCObject *o) { static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); -static void sweepthread (lua_State *L, lua_State *L1, int alive) { +/* +** sweep the (open) upvalues of a thread and resize its stack and +** list of call-info structures. +*/ +static void sweepthread (lua_State *L, lua_State *L1) { if (L1->stack == NULL) return; /* stack not completely built yet */ sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ luaE_freeCI(L1); /* free extra CallInfo slots */ /* should not change the stack during an emergency gc cycle */ - if (alive && G(L)->gckind != KGC_EMERGENCY) + if (G(L)->gckind != KGC_EMERGENCY) luaD_shrinkstack(L1); } +/* +** sweep at most 'count' elements from a list of GCObjects erasing dead +** objects, where a dead (not alive) object is one marked with the "old" +** (non current) white and not fixed. +** In non-generational mode, change all non-dead objects back to white, +** preparing for next collection cycle. +** In generational mode, keep black objects black, and also mark them as +** old; stop when hitting an old object, as all objects after that +** one will be old too. +** When object is a thread, sweep its list of open upvalues too. +*/ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { - GCObject *curr; global_State *g = G(L); - int deadmask = otherwhite(g); - while ((curr = *p) != NULL && count-- > 0) { - int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; - if (gch(curr)->tt == LUA_TTHREAD) - sweepthread(L, gco2th(curr), alive); - if (alive) { - lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); - makewhite(g, curr); /* make it white (for next cycle) */ - p = &gch(curr)->next; - } - else { /* must erase `curr' */ - lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); + int ow = otherwhite(g); + int toclear, toset; /* bits to clear and to set in all live objects */ + int tostop; /* stop sweep when this is true */ + if (isgenerational(g)) { /* generational mode? */ + toclear = ~0; /* clear nothing */ + toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ + tostop = bitmask(OLDBIT); /* do not sweep old generation */ + } + else { /* normal mode */ + toclear = maskcolors; /* clear all color bits + old bit */ + toset = luaC_white(g); /* make object white */ + tostop = 0; /* do not stop */ + } + while (*p != NULL && count-- > 0) { + GCObject *curr = *p; + int marked = gch(curr)->marked; + if (isdeadm(ow, marked)) { /* is 'curr' dead? */ *p = gch(curr)->next; /* remove 'curr' from list */ - freeobj(L, curr); + freeobj(L, curr); /* erase 'curr' */ + } + else { + if (gch(curr)->tt == LUA_TTHREAD) + sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ + if (testbits(marked, tostop)) { + static GCObject *nullp = NULL; + return &nullp; /* stop sweeping this list */ + } + /* update marks */ + gch(curr)->marked = cast_byte((marked & toclear) | toset); + p = &gch(curr)->next; /* go to next element */ } } return p; @@ -576,25 +652,28 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { static void checkSizes (lua_State *L) { global_State *g = G(L); - if (g->strt.nuse < cast(lu_int32, g->strt.size)) { - /* string-table size could be the smaller power of 2 larger than 'nuse' */ - int size = 1 << luaO_ceillog2(g->strt.nuse); - if (size < g->strt.size) /* current table too large? */ - luaS_resize(L, size); /* shrink it */ + if (g->gckind != KGC_EMERGENCY) { /* do not change sizes in emergency */ + int hs = g->strt.size / 2; /* half the size of the string table */ + if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */ + luaS_resize(L, hs); /* halve its size */ + luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */ } - luaZ_freebuffer(L, &g->buff); } static Udata *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ - g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ - gch(o)->next = g->rootgc; /* return it to `root' list */ - g->rootgc = o; - lua_assert(isfinalized(gch(o))); - resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ - makewhite(g, o); - return rawgco2u(o); + Udata *u = rawgco2u(o); + lua_assert(isfinalized(&u->uv)); + lua_assert(!isold(o)); + g->tobefnz = u->uv.next; /* remove it from 'tobefnz' list */ + u->uv.next = g->allgc; /* return it to 'allgc' list */ + g->allgc = o; + resetbit(u->uv.marked, SEPARATED); /* mark that it is not in 'tobefnz' */ + resetoldbit(o); /* see MOVE OLD rule */ + if (!keepinvariant(g)) /* not keeping invariant? */ + makewhite(g, o); /* "sweep" object */ + return u; } @@ -608,18 +687,18 @@ static void GCTM (lua_State *L, int propagateerrors) { global_State *g = G(L); Udata *udata = udata2finalize(g); const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC); - if (tm != NULL && ttisfunction(tm)) { + if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ int status; lu_byte oldah = L->allowhook; - lu_mem oldt = g->GCthreshold; + lu_mem oldd = g->GCdebt; L->allowhook = 0; /* stop debug hooks during GC tag method */ - g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ - setobj2s(L, L->top, tm); - setuvalue(L, L->top+1, udata); - L->top += 2; + stopgc(g); /* avoid GC steps */ + setobj2s(L, L->top, tm); /* push finalizer... */ + setuvalue(L, L->top+1, udata); /* ... and its argument */ + L->top += 2; /* and (next line) call the finalizer */ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ - g->GCthreshold = oldt; /* restore threshold */ + g->GCdebt = oldd; /* restore threshold */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status == LUA_ERRRUN) { /* is there an error msg.? */ luaO_pushfstring(L, "error in __gc tag method (%s)", @@ -632,14 +711,18 @@ static void GCTM (lua_State *L, int propagateerrors) { } -/* move 'dead' udata that need finalization to list 'tobefnz' */ +/* +** move all unreachable udata that need finalization from list 'udgc' to +** list 'tobefnz' +*/ void luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); - GCObject **p = &g->mainthread->next; + GCObject **p = &g->udgc; GCObject *curr; GCObject **lastnext = &g->tobefnz; - /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ - while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; + /* find last 'next' field in 'tobefnz' list (to add elements in its end) */ + while (*lastnext != NULL) + lastnext = &gch(*lastnext)->next; while ((curr = *p) != NULL) { /* traverse all finalizable objects */ lua_assert(gch(curr)->tt == LUA_TUSERDATA && !isfinalized(gco2u(curr))); lua_assert(testbit(gch(curr)->marked, SEPARATED)); @@ -647,9 +730,8 @@ void luaC_separateudata (lua_State *L, int all) { p = &gch(curr)->next; /* don't bother with it */ else { l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ - *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */ - /* link 'curr' at the end of 'tobefnz' list */ - gch(curr)->next = *lastnext; + *p = gch(curr)->next; /* remove 'curr' from 'udgc' list */ + gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; lastnext = &gch(curr)->next; } @@ -657,20 +739,24 @@ void luaC_separateudata (lua_State *L, int all) { } +/* +** if userdata 'u' has a finalizer, remove it from 'allgc' list (must +** search the list to find it) and link it in 'udgc' list. +*/ void luaC_checkfinalizer (lua_State *L, Udata *u) { global_State *g = G(L); - if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */ - isfinalized(&u->uv) || /* ... or is finalized... */ - gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ + if (testbit(u->uv.marked, SEPARATED) || /* udata is already separated... */ + isfinalized(&u->uv) || /* ... or is finalized... */ + gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalizer? */ return; /* nothing to be done */ - else { /* move 'u' to 2nd part of root list */ + else { /* move 'u' to 'udgc' list */ GCObject **p; - for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) - lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */ + for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ; *p = u->uv.next; /* remove 'u' from root list */ - u->uv.next = g->mainthread->next; /* re-link it in list */ - g->mainthread->next = obj2gco(u); + u->uv.next = g->udgc; /* link it in list 'udgc' */ + g->udgc = obj2gco(u); l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ + resetoldbit(obj2gco(u)); /* see MOVE OLD rule */ } } @@ -683,15 +769,52 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) { ** ======================================================= */ + +#define sweepphases \ + (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) + +/* +** change GC mode +*/ +void luaC_changemode (lua_State *L, int mode) { + global_State *g = G(L); + if (mode == g->gckind) return; /* nothing to change */ + if (mode == KGC_GEN) { /* change to generational mode */ + /* make sure gray lists are consistent */ + luaC_runtilstate(L, bitmask(GCSpropagate)); + g->lastmajormem = g->totalbytes; + g->gckind = KGC_GEN; + } + else { /* change to incremental mode */ + /* sweep all objects to turn them back to white + (as white has not changed, nothing extra will be collected) */ + g->sweepstrgc = 0; + g->gcstate = GCSsweepstring; + g->gckind = KGC_NORMAL; + luaC_runtilstate(L, ~sweepphases); + } +} + + +/* +** call all pending finalizers */ +static void callallpendingfinalizers (lua_State *L, int propagateerrors) { + global_State *g = G(L); + while (g->tobefnz) GCTM(L, propagateerrors); +} + + void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); int i; - while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */ + callallpendingfinalizers(L, 0); /* following "white" makes all objects look dead */ - g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); - sweepwholelist(L, &g->rootgc); - lua_assert(g->rootgc == obj2gco(g->mainthread) && - g->mainthread->next == NULL); + g->currentwhite = WHITEBITS; + g->gckind = KGC_NORMAL; + sweepwholelist(L, &g->udgc); + lua_assert(g->udgc == NULL); + sweepwholelist(L, &g->allgc); + lua_assert(g->allgc == NULL); for (i = 0; i < g->strt.size; i++) /* free all string lists */ sweepwholelist(L, &g->strt.hash[i]); lua_assert(g->strt.nuse == 0); @@ -700,7 +823,6 @@ void luaC_freeallobjects (lua_State *L) { static void atomic (lua_State *L) { global_State *g = G(L); - g->gcstate = GCSatomic; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ @@ -710,12 +832,11 @@ static void atomic (lua_State *L) { remarkupvals(g); /* traverse objects caught by write barrier and by 'remarkupvals' */ propagateall(g); - /* at this point, all strongly accessible objects are marked. - Start marking weakly accessible objects. */ traverselistofgrays(g, &g->weak); /* remark weak tables */ traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ traverselistofgrays(g, &g->grayagain); /* remark gray again */ convergeephemerons(g); + /* at this point, all strongly accessible objects are marked. */ luaC_separateudata(L, 0); /* separate userdata to be finalized */ markbeingfnz(g); /* mark userdata that will be finalized */ propagateall(g); /* remark, to propagate `preserveness' */ @@ -724,51 +845,68 @@ static void atomic (lua_State *L) { cleartable(g->weak); cleartable(g->ephemeron); cleartable(g->allweak); - g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ - g->sweepstrgc = 0; /* go to sweep phase */ + g->sweepstrgc = 0; /* prepare to sweep strings */ g->gcstate = GCSsweepstring; + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + /*lua_checkmemory(L);*/ } static l_mem singlestep (lua_State *L) { global_State *g = G(L); - /*lua_checkmemory(L);*/ switch (g->gcstate) { case GCSpause: { - markroot(L); /* start a new collection */ - return 0; + if (!isgenerational(g)) + markroot(L); /* start a new collection */ + /* in any case, root must be marked */ + lua_assert(!iswhite(obj2gco(g->mainthread)) + && !iswhite(gcvalue(&g->l_registry))); + g->gcstate = GCSpropagate; + return GCROOTCOST; } case GCSpropagate: { if (g->gray) return propagatemark(g); else { /* no more `gray' objects */ - atomic(L); /* finish mark phase */ - return 0; + g->gcstate = GCSatomic; /* finish mark phase */ + atomic(L); + return GCATOMICCOST; } } case GCSsweepstring: { - sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); - if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ - g->sweepgc = &g->rootgc; - g->gcstate = GCSsweep; /* sweep all other objects */ + if (g->sweepstrgc < g->strt.size) { + sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); + return GCSWEEPCOST; + } + else { /* no more strings to sweep */ + g->sweepgc = &g->udgc; /* prepare to sweep userdata */ + g->gcstate = GCSsweepudata; + return 0; } - return GCSWEEPCOST; } - case GCSsweep: { - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - if (*g->sweepgc == NULL) /* nothing more to sweep? */ - g->gcstate = GCSfinalize; /* end sweep phase */ - return GCSWEEPMAX*GCSWEEPCOST; + case GCSsweepudata: { + if (*g->sweepgc) { + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + return GCSWEEPMAX*GCSWEEPCOST; + } + else { + g->sweepgc = &g->allgc; /* go to next phase */ + g->gcstate = GCSsweep; + return GCSWEEPCOST; + } } - case GCSfinalize: { - if (g->tobefnz) { - GCTM(L, 1); - return GCFINALIZECOST; + case GCSsweep: { + if (*g->sweepgc) { + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + return GCSWEEPMAX*GCSWEEPCOST; } else { + /* sweep main thread */ + GCObject *mt = obj2gco(g->mainthread); + sweeplist(L, &mt, 1); checkSizes(L); - g->gcstate = GCSpause; /* end collection */ - return 0; + g->gcstate = GCSpause; /* finish collection */ + return GCSWEEPCOST; } } default: lua_assert(0); return 0; @@ -776,22 +914,6 @@ static l_mem singlestep (lua_State *L) { } -void luaC_step (lua_State *L) { - global_State *g = G(L); - l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */ - lu_mem debt = g->totalbytes - g->GCthreshold; - lua_assert(g->gckind == KGC_NORMAL); - do { /* always perform at least one single step */ - lim -= singlestep(L); - } while (lim > 0 && g->gcstate != GCSpause); - g->GCthreshold = (g->gcstate != GCSpause) - ? g->totalbytes + GCSTEPSIZE - : (g->totalbytes/100) * g->gcpause; - /* compensate if GC is "behind schedule" (has some debt to pay) */ - if (g->GCthreshold > debt) g->GCthreshold -= debt; -} - - /* ** advances the garbage collector until it reaches a state allowed ** by 'statemask' @@ -803,29 +925,73 @@ void luaC_runtilstate (lua_State *L, int statesmask) { } +static void generationalcollection (lua_State *L) { + global_State *g = G(L); + if (g->lastmajormem == 0) { /* signal for another major collection? */ + luaC_fullgc(L, 0); /* perform a full regular collection */ + g->lastmajormem = g->totalbytes; /* update control */ + } + else { + luaC_runtilstate(L, bitmask(GCSpause)); /* run collection */ + if (g->totalbytes > g->lastmajormem/100 * g->gcpause) + g->lastmajormem = 0; /* signal for a major collection */ + } + g->GCdebt = stddebt(g); +} + + +static void step (lua_State *L) { + global_State *g = G(L); + l_mem lim = g->gcstepmul; /* how much to work */ + do { /* always perform at least one single step */ + lim -= singlestep(L); + } while (lim > 0 && g->gcstate != GCSpause); + if (g->gcstate != GCSpause) + g->GCdebt -= GCSTEPSIZE; + else + g->GCdebt = stddebt(g); +} + + +void luaC_step (lua_State *L) { + int i; + if (isgenerational(G(L))) generationalcollection(L); + else step(L); + for (i = 0; i < GCFINALIZENUM && G(L)->tobefnz; i++) + GCTM(L, 1); /* Call a few pending finalizers */ +} + + /* -** performs a full GC cycle; if "isememrgency", does not call +** performs a full GC cycle; if "isemergency", does not call ** finalizers (which could change stack positions) */ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); - lua_assert(g->gckind == KGC_NORMAL); - g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; - if (g->gcstate == GCSpropagate) { /* marking phase? */ + int origkind = g->gckind; + lua_assert(origkind != KGC_EMERGENCY); + if (!isemergency) /* do not run finalizers during emergency GC */ + callallpendingfinalizers(L, 1); + if (keepinvariant(g)) { /* marking phase? */ /* must sweep all objects to turn them back to white - (as white does not change, nothing will be collected) */ + (as white has not changed, nothing will be collected) */ g->sweepstrgc = 0; g->gcstate = GCSsweepstring; } - /* finish any pending sweep phase */ - luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep)); - markroot(L); /* start a new collection */ - /* run collector up to finalizers */ - luaC_runtilstate(L, bitmask(GCSfinalize)); - g->gckind = KGC_NORMAL; + g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL; + /* finish any pending sweep phase to start a new cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); + /* run entire collector */ + luaC_runtilstate(L, ~bitmask(GCSpause)); + luaC_runtilstate(L, bitmask(GCSpause)); + if (origkind == KGC_GEN) { /* generational mode? */ + /* generational mode must always start in propagate phase */ + luaC_runtilstate(L, bitmask(GCSpropagate)); + } + g->gckind = origkind; + g->GCdebt = stddebt(g); if (!isemergency) /* do not run finalizers during emergency GC */ - luaC_runtilstate(L, ~bitmask(GCSfinalize)); - g->GCthreshold = (g->totalbytes/100) * g->gcpause; + callallpendingfinalizers(L, 1); } /* }====================================================== */ diff --git a/src/lgc.h b/src/lgc.h index bab2e85022..18eb70fdf2 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 roberto Exp $ +** $Id: lgc.h,v 2.41 2010/05/10 18:23:45 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -9,18 +9,51 @@ #include "lobject.h" +#include "lstate.h" + +/* +** Collectable objects may have one of three colors: white, which +** means the object is not marked; gray, which means the +** object is marked, but its references may be not marked; and +** black, which means that the object and all its references are marked. +** The main invariant of the garbage collector, while marking objects, +** is that a black object can never point to a white one. Moreover, +** any gray object must be in a "gray list" (gray, grayagain, weak, +** allweak, ephemeron) so that it can be visited again before finishing +** the collection cycle. These lists have no meaning when the invariant +** is not being enforced (e.g., sweep phase). +*/ /* ** Possible states of the Garbage Collector */ -#define GCSpause 0 -#define GCSpropagate 1 -#define GCSatomic 2 -#define GCSsweepstring 3 +#define GCSpropagate 0 +#define GCSatomic 1 +#define GCSsweepstring 2 +#define GCSsweepudata 3 #define GCSsweep 4 -#define GCSfinalize 5 +#define GCSpause 5 + + +#define issweepphase(g) \ + (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) + +#define isgenerational(g) ((g)->gckind == KGC_GEN) + +/* +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a non-generational collection, the sweep +** phase may brak the invariant, as objects turned white may point to +** still-black objects. The invariant is restored when sweep ends and +** all objects are white again. During a generational collection, the +** invariant must be kept all times. +*/ +#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) + +#define gcstopped(g) ((g)->GCdebt == MIN_LMEM) +#define stopgc(g) ((g)->GCdebt = MIN_LMEM) /* @@ -39,34 +72,33 @@ -/* -** Layout for bit use in `marked' field: -** bit 0 - object is white (type 0) -** bit 1 - object is white (type 1) -** bit 2 - object is black -** bit 3 - for userdata: has been finalized -** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz -** bit 5 - object is fixed (should not be collected) -** bit 6 - object is "super" fixed (only the main thread) -*/ - +/* Layout for bit use in `marked' field: */ +#define WHITE0BIT 0 /* object is white (type 0) */ +#define WHITE1BIT 1 /* object is white (type 1) */ +#define BLACKBIT 2 /* object is black */ +#define FINALIZEDBIT 3 /* for userdata: has been finalized */ +#define SEPARATED 4 /* " ": it's in 'udgc' list or in 'tobefnz' */ +#define FIXEDBIT 5 /* object is fixed (should not be collected) */ +#define OLDBIT 6 /* object is old (only in generational mode) */ +/* bit 7 is currently used by tests (luaL_checkmemory) */ -#define WHITE0BIT 0 -#define WHITE1BIT 1 -#define BLACKBIT 2 -#define FINALIZEDBIT 3 -#define SEPARATED 4 -#define FIXEDBIT 5 -#define SFIXEDBIT 6 #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define iswhite(x) testbits((x)->gch.marked, WHITEBITS) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) -#define isgray(x) (!isblack(x) && !iswhite(x)) +#define isgray(x) /* neither white nor black */ \ + (!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT))) + +#define isold(x) testbit((x)->gch.marked, OLDBIT) + +/* MOVE OLD rule: whenever an object is moved to the beginning of + a GC list, its old bit must be cleared */ +#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT) #define otherwhite(g) (g->currentwhite ^ WHITEBITS) -#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) +#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) #define changewhite(x) ((x)->gch.marked ^= WHITEBITS) #define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) @@ -76,8 +108,7 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_checkGC(L) \ - {condchangemem(L); if (G(L)->totalbytes >= G(L)->GCthreshold) luaC_step(L);} +#define luaC_checkGC(L) {condchangemem(L); if (G(L)->GCdebt > 0) luaC_step(L);} #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ @@ -100,10 +131,10 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, int offset); -LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); - +LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); +LUAI_FUNC void luaC_changemode (lua_State *L, int mode); #endif diff --git a/src/linit.c b/src/linit.c index a9430605f5..ff296cd78f 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.23 2009/12/22 15:32:50 roberto Exp $ +** $Id: linit.c,v 1.24 2010/03/26 20:58:11 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ @@ -52,9 +52,9 @@ LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* call open functions from 'loadedlibs' */ for (lib = loadedlibs; lib->func; lib++) { - lua_pushcfunction(L, lib->func); + lua_settop(L, 0); lua_pushstring(L, lib->name); - lua_call(L, 1, 0); + (lib->func)(L); } /* add open functions from 'preloadedlibs' into 'package.preload' table */ lua_pushglobaltable(L); @@ -65,8 +65,7 @@ LUALIB_API void luaL_openlibs (lua_State *L) { } lua_pop(L, 1); /* remove package.preload table */ #if defined(LUA_COMPAT_DEBUGLIB) - lua_pushglobaltable(L); - lua_getfield(L, -1, "require"); + lua_getglobal(L, "require"); lua_pushliteral(L, LUA_DBLIBNAME); lua_call(L, 1, 0); /* call 'require"debug"' */ lua_pop(L, 1); /* remove global table */ diff --git a/src/liolib.c b/src/liolib.c index 64fa43b4d1..c453cb956b 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.85 2009/12/17 16:20:01 roberto Exp $ +** $Id: liolib.c,v 2.88 2010/03/26 20:58:11 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -103,13 +103,12 @@ static FILE *tofile (lua_State *L) { } - /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ -static FILE **newfile (lua_State *L) { +static FILE **newprefile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ luaL_getmetatable(L, LUA_FILEHANDLE); @@ -118,6 +117,14 @@ static FILE **newfile (lua_State *L) { } +static FILE **newfile (lua_State *L) { + FILE **pf = newprefile(L); + lua_pushvalue(L, lua_upvalueindex(1)); /* set upvalue... */ + lua_setenv(L, -2); /* ... as environment for new file */ + return pf; +} + + /* ** function to (not) close the standard files stdin, stdout, and stderr */ @@ -156,7 +163,7 @@ static int io_fclose (lua_State *L) { static int aux_close (lua_State *L) { - lua_getfenv(L, 1); + lua_getenv(L, 1); lua_getfield(L, -1, "__close"); return (lua_tocfunction(L, -1))(L); } @@ -164,7 +171,7 @@ static int aux_close (lua_State *L) { static int io_close (lua_State *L) { if (lua_isnone(L, 1)) - lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); tofile(L); /* make sure argument is a file */ return aux_close(L); } @@ -229,7 +236,7 @@ static int io_tmpfile (lua_State *L) { static FILE *getiofile (lua_State *L, int findex) { FILE *f; - lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + lua_rawgeti(L, lua_upvalueindex(1), findex); f = *(FILE **)lua_touserdata(L, -1); if (f == NULL) luaL_error(L, "standard %s file is closed", fnames[findex - 1]); @@ -250,10 +257,10 @@ static int g_iofile (lua_State *L, int f, const char *mode) { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } - lua_rawseti(L, LUA_ENVIRONINDEX, f); + lua_rawseti(L, lua_upvalueindex(1), f); } /* return current value */ - lua_rawgeti(L, LUA_ENVIRONINDEX, f); + lua_rawgeti(L, lua_upvalueindex(1), f); return 1; } @@ -271,35 +278,46 @@ static int io_output (lua_State *L) { static int io_readline (lua_State *L); -static void aux_lines (lua_State *L, int idx, int toclose) { - lua_pushvalue(L, idx); +static void aux_lines (lua_State *L, int toclose) { + int i; + int n = lua_gettop(L) - 1; /* number of arguments to read */ + /* ensure that arguments will fit here and into 'io_readline' stack */ + luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options"); + lua_pushvalue(L, 1); /* file handle */ + lua_pushinteger(L, n); /* number of arguments to read */ lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_pushcclosure(L, io_readline, 2); + for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */ + lua_pushcclosure(L, io_readline, 3 + n); } static int f_lines (lua_State *L) { tofile(L); /* check that it's a valid file handle */ - aux_lines(L, 1, 0); + aux_lines(L, 0); return 1; } static int io_lines (lua_State *L) { - if (lua_isnoneornil(L, 1)) { /* no arguments? */ - /* will iterate over default input */ - lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); - return f_lines(L); + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ } - else { + else { /* open a new file */ const char *filename = luaL_checkstring(L, 1); FILE **pf = newfile(L); *pf = fopen(filename, "r"); if (*pf == NULL) fileerror(L, 1, filename); - aux_lines(L, lua_gettop(L), 1); - return 1; + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ } + aux_lines(L, toclose); + return 1; } @@ -316,7 +334,10 @@ static int read_number (lua_State *L, FILE *f) { lua_pushnumber(L, d); return 1; } - else return 0; /* read fails */ + else { + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } } @@ -328,7 +349,7 @@ static int test_eof (lua_State *L, FILE *f) { } -static int read_line (lua_State *L, FILE *f) { +static int read_line (lua_State *L, FILE *f, int chop) { luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { @@ -342,7 +363,7 @@ static int read_line (lua_State *L, FILE *f) { if (l == 0 || p[l-1] != '\n') luaL_addsize(&b, l); else { - luaL_addsize(&b, l - 1); /* do not include `eol' */ + luaL_addsize(&b, l - chop); /* chop 'eol' if needed */ luaL_pushresult(&b); /* close buffer */ return 1; /* read at least an `eol' */ } @@ -375,7 +396,7 @@ static int g_read (lua_State *L, FILE *f, int first) { int n; clearerr(f); if (nargs == 0) { /* no arguments? */ - success = read_line(L, f); + success = read_line(L, f, 1); n = first+1; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ @@ -394,7 +415,10 @@ static int g_read (lua_State *L, FILE *f, int first) { success = read_number(L, f); break; case 'l': /* line */ - success = read_line(L, f); + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); break; case 'a': /* file */ read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ @@ -428,15 +452,22 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); - int success; + int i; + int n = lua_tointeger(L, lua_upvalueindex(2)); if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); - success = read_line(L, f); - if (ferror(f)) - return luaL_error(L, "%s", strerror(errno)); - if (success) return 1; - else { /* EOF */ - if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ + lua_settop(L , 1); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (!lua_isnil(L, -n)) /* read at least one value? */ + return n; /* return them */ + else { /* first result is nil: EOF or error */ + if (!lua_isnil(L, -1)) /* is there error information? */ + return luaL_error(L, "%s", lua_tostring(L, -1)); /* error */ + /* else EOF */ + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ @@ -552,23 +583,27 @@ static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, NULL, flib); /* file methods */ + luaL_register(L, NULL, flib); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ } static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { - *newfile(L) = f; + *newprefile(L) = f; if (k > 0) { - lua_pushvalue(L, -1); - lua_rawseti(L, LUA_ENVIRONINDEX, k); + lua_pushvalue(L, -1); /* copy new file */ + lua_rawseti(L, 1, k); /* add it to common upvalue */ } - lua_pushvalue(L, -2); /* copy environment */ - lua_setfenv(L, -2); /* set it */ - lua_setfield(L, -3, fname); + lua_pushvalue(L, 3); /* get environment for default files */ + lua_setenv(L, -2); /* set it as environment for file */ + lua_setfield(L, 2, fname); /* add file to module */ } -static void newfenv (lua_State *L, lua_CFunction cls) { +/* +** pushes a new table with {__close = cls} +*/ +static void newenv (lua_State *L, lua_CFunction cls) { lua_createtable(L, 0, 1); lua_pushcfunction(L, cls); lua_setfield(L, -2, "__close"); @@ -576,21 +611,21 @@ static void newfenv (lua_State *L, lua_CFunction cls) { LUAMOD_API int luaopen_io (lua_State *L) { + lua_settop(L, 0); createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ - newfenv(L, io_fclose); - lua_replace(L, LUA_ENVIRONINDEX); - /* open library */ - luaL_register(L, LUA_IOLIBNAME, iolib); + newenv(L, io_fclose); /* upvalue for all io functions at index 1 */ + lua_pushvalue(L, -1); /* copy to be consumed by 'openlib' */ + luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* new module at index 2 */ /* create (and set) default files */ - newfenv(L, io_noclose); /* close function for default files */ + newenv(L, io_noclose); /* environment for default files at index 3 */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, 0, "stderr"); lua_pop(L, 1); /* pop environment for default files */ - lua_getfield(L, -1, "popen"); - newfenv(L, io_pclose); /* create environment for 'popen' */ - lua_setfenv(L, -2); /* set fenv for 'popen' */ + lua_getfield(L, 2, "popen"); + newenv(L, io_pclose); /* create environment for 'popen' streams */ + lua_setupvalue(L, -2, 1); /* set it as upvalue for 'popen' */ lua_pop(L, 1); /* pop 'popen' */ return 1; } diff --git a/src/llex.c b/src/llex.c index 3cfdbca176..e380910d6b 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.34 2009/11/17 16:33:38 roberto Exp $ +** $Id: llex.c,v 2.37 2010/04/16 12:31:07 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -117,21 +117,30 @@ void luaX_syntaxerror (LexState *ls, const char *msg) { } +/* +** creates a new string and anchors it in function's table so that +** it will not be collected until the end of the function's compilation +** (by that time it should be anchored in function's prototype) +*/ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; TValue *o; /* entry for `str' */ - TString *ts = luaS_newlstr(L, str, l); - setsvalue2s(L, L->top++, ts); /* anchor string */ - o = luaH_setstr(L, ls->fs->h, ts); + TString *ts = luaS_newlstr(L, str, l); /* create new string */ + setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ + o = luaH_setstr(L, ls->fs->h, ts); if (ttisnil(o)) { - setbvalue(o, 1); /* make sure `str' will not be collected */ + setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); } - L->top--; + L->top--; /* remove string from stack */ return ts; } +/* +** increment line number and skips newline sequence (any of +** \n, \r, \n\r, or \r\n) +*/ static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); @@ -152,6 +161,8 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->linenumber = 1; ls->lastline = 1; ls->source = source; + ls->envn = luaS_new(L, "_ENV"); /* create env name */ + luaS_fix(ls->envn); /* never collect this name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ next(ls); /* read first char */ } @@ -174,6 +185,9 @@ static int check_next (LexState *ls, const char *set) { } +/* +** change all characters 'from' in buffer to 'to' +*/ static void buffreplace (LexState *ls, char from, char to) { size_t n = luaZ_bufflen(ls->buff); char *p = luaZ_buffer(ls->buff); @@ -186,11 +200,14 @@ static void buffreplace (LexState *ls, char from, char to) { #define getlocaledecpoint() (localeconv()->decimal_point[0]) #endif +/* +** in case of format error, try to change decimal point separator to +** the one defined in the current locale and check again +*/ static void trydecpoint (LexState *ls, SemInfo *seminfo) { - /* format error: try to update decimal point separator */ char old = ls->decpoint; ls->decpoint = getlocaledecpoint(); - buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ + buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ @@ -216,6 +233,10 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { } +/* +** skip a sequence '[=*=[' or ']=*]' and return its number of '='s or +** -1 if sequence is malformed +*/ static int skip_sep (LexState *ls) { int count = 0; int s = ls->current; @@ -246,8 +267,7 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } break; } - case '\n': - case '\r': { + case '\n': case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ @@ -308,16 +328,16 @@ static int readdecesc (LexState *ls) { static void read_string (LexState *ls, int del, SemInfo *seminfo) { - save_and_next(ls); + save_and_next(ls); /* keep delimiter (for error messages) */ while (ls->current != del) { switch (ls->current) { case EOZ: lexerror(ls, "unfinished string", TK_EOS); - continue; /* to avoid warnings */ + break; /* to avoid warnings */ case '\n': case '\r': lexerror(ls, "unfinished string", TK_STRING); - continue; /* to avoid warnings */ + break; /* to avoid warnings */ case '\\': { /* escape sequences */ int c; /* final character to be saved */ next(ls); /* do not save the `\' */ @@ -333,6 +353,14 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { case '\n': case '\r': save(ls, '\n'); inclinenumber(ls); continue; case EOZ: continue; /* will raise an error next loop */ + case '*': { /* skip following span of spaces */ + next(ls); /* skip the '*' */ + while (lisspace(ls->current)) { + if (currIsNewline(ls)) inclinenumber(ls); + else next(ls); + } + continue; /* do not save 'c' */ + } default: { if (!lisdigit(ls->current)) c = ls->current; /* handles \\, \", \', and \? */ @@ -343,7 +371,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { } next(ls); save(ls, c); - continue; + break; } default: save_and_next(ls); @@ -359,31 +387,34 @@ static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); for (;;) { switch (ls->current) { - case '\n': - case '\r': { + case '\n': case '\r': { /* line breaks */ inclinenumber(ls); - continue; + break; } - case '-': { + case ' ': case '\f': case '\t': case '\v': { /* spaces */ + next(ls); + break; + } + case '-': { /* '-' or '--' (comment) */ next(ls); if (ls->current != '-') return '-'; /* else is a comment */ next(ls); - if (ls->current == '[') { + if (ls->current == '[') { /* long comment? */ int sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ if (sep >= 0) { - read_long_string(ls, NULL, sep); /* long comment */ - luaZ_resetbuffer(ls->buff); - continue; + read_long_string(ls, NULL, sep); /* skip long comment */ + luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ + break; } } /* else short comment */ while (!currIsNewline(ls) && ls->current != EOZ) - next(ls); - continue; + next(ls); /* skip until end of line (or end of file) */ + break; } - case '[': { + case '[': { /* long string or simply '[' */ int sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); @@ -412,39 +443,30 @@ static int llex (LexState *ls, SemInfo *seminfo) { if (ls->current != '=') return '~'; else { next(ls); return TK_NE; } } - case '"': - case '\'': { + case '"': case '\'': { /* short literal strings */ read_string(ls, ls->current, seminfo); return TK_STRING; } - case '.': { + case '.': { /* '.', '..', '...', or number */ save_and_next(ls); if (check_next(ls, ".")) { if (check_next(ls, ".")) - return TK_DOTS; /* ... */ - else return TK_CONCAT; /* .. */ + return TK_DOTS; /* '...' */ + else return TK_CONCAT; /* '..' */ } else if (!lisdigit(ls->current)) return '.'; - else { - read_numeral(ls, seminfo); - return TK_NUMBER; - } + /* else go through */ + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + read_numeral(ls, seminfo); + return TK_NUMBER; } case EOZ: { return TK_EOS; } default: { - if (lisspace(ls->current)) { - lua_assert(!currIsNewline(ls)); - next(ls); - continue; - } - else if (lisdigit(ls->current)) { - read_numeral(ls, seminfo); - return TK_NUMBER; - } - else if (lislalpha(ls->current)) { - /* identifier or reserved word */ + if (lislalpha(ls->current)) { /* identifier or reserved word? */ TString *ts; do { save_and_next(ls); @@ -458,10 +480,10 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_NAME; } } - else { + else { /* single-char tokens (+ - / ...) */ int c = ls->current; next(ls); - return c; /* single-char tokens (+ - / ...) */ + return c; } } } diff --git a/src/llex.h b/src/llex.h index d687fb8d4d..1a811dce5c 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.62 2009/10/11 20:02:19 roberto Exp $ +** $Id: llex.h,v 1.65 2010/04/05 16:35:37 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -60,6 +60,7 @@ typedef struct LexState { Mbuffer *buff; /* buffer for tokens */ struct Varlist *varl; /* list of all active local variables */ TString *source; /* current source name */ + TString *envn; /* environment variable name */ char decpoint; /* locale decimal point */ } LexState; diff --git a/src/llimits.h b/src/llimits.h index 6bf49840a3..02be816eda 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.77 2009/12/17 12:50:20 roberto Exp $ +** $Id: llimits.h,v 1.80 2010/05/07 18:44:12 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -30,6 +30,7 @@ typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) +#define MIN_LMEM ((l_mem)~((~(lu_mem)0)>>1)) #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ @@ -59,7 +60,7 @@ typedef LUAI_UACNUMBER l_uacNumber; #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) #else -#define lua_assert(c) ((void)0) +#define lua_assert(c) /* empty */ #define check_exp(c,e) (e) #endif @@ -139,19 +140,19 @@ typedef lu_int32 Instruction; ** created/deleted/resumed/yielded. */ #if !defined(luai_userstateopen) -#define luai_userstateopen(L) ((void)L) +#define luai_userstateopen(L) ((void)L) #endif #if !defined(luai_userstateclose) -#define luai_userstateclose(L) ((void)L) +#define luai_userstateclose(L) ((void)L) #endif #if !defined(luai_userstatethread) -#define luai_userstatethread(L,L1) ((void)L) +#define luai_userstatethread(L,L1) ((void)L) #endif #if !defined(luai_userstatefree) -#define luai_userstatefree(L) ((void)L) +#define luai_userstatefree(L,L1) ((void)L) #endif #if !defined(luai_userstateresume) diff --git a/src/lmem.c b/src/lmem.c index 022ccfd3cf..0f3178a279 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.74 2009/12/16 16:42:58 roberto Exp $ +** $Id: lmem.c,v 1.79 2010/05/05 18:49:56 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -79,13 +79,14 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { size_t realosize = (block) ? osize : 0; lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) - if (nsize > realosize && g->GCthreshold != MAX_LUMEM) + if (nsize > realosize && !gcstopped(g)) luaC_fullgc(L, 1); /* force a GC whenever possible */ #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { - lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ - if (g->GCthreshold != MAX_LUMEM) { + api_check(L, nsize > realosize, + "realloc cannot fail when shrinking a block"); + if (!gcstopped(g)) { luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } @@ -94,6 +95,26 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { } lua_assert((nsize == 0) == (newblock == NULL)); g->totalbytes = (g->totalbytes - realosize) + nsize; + if (!gcstopped(g)) + g->GCdebt += nsize; /* give some credit to garbage collector */ +#if defined(TRACEMEM) + { /* auxiliary patch to monitor garbage collection. + ** To plot, gnuplot with following command: + ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines + */ + static unsigned long total = 0; /* our "time" */ + static FILE *f = NULL; /* output file */ + total++; /* "time" always grows */ + if ((total % 200) == 0) { + if (f == NULL) f = fopen(TRACEMEM, "w"); + fprintf(f, "%lu %u %d %d\n", total, + g->totalbytes, + gcstopped(g) ? 0 : g->GCdebt, + g->gcstate * 1000); + } + } +#endif + return newblock; } diff --git a/src/lmem.h b/src/lmem.h index b8b3bae94a..ff324f89e4 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.35 2009/12/16 16:42:58 roberto Exp $ +** $Id: lmem.h,v 1.36 2010/04/08 17:16:46 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -13,8 +13,6 @@ #include "llimits.h" #include "lua.h" -#define MEMERRMSG "not enough memory" - #define luaM_reallocv(L,b,on,n,e) \ ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ diff --git a/src/loadlib.c b/src/loadlib.c index 90c785dc11..793c658e86 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.80 2010/01/13 16:30:27 roberto Exp $ +** $Id: loadlib.c,v 1.82 2010/03/19 15:02:34 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -353,9 +353,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); /* else create new function... */ - lua_pushglobaltable(L); /* ... and set the standard global table... */ - lua_setfenv(L, -2); /* ... as its environment */ + lua_pushcfunction(L, f); /* else create new function */ return 0; /* no errors */ } } @@ -435,7 +433,7 @@ static int ll_searchpath (lua_State *L) { static const char *findfile (lua_State *L, const char *name, const char *pname) { const char *path; - lua_getfield(L, LUA_ENVIRONINDEX, pname); + lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); @@ -509,7 +507,7 @@ static int loader_Croot (lua_State *L) { static int loader_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + lua_getfield(L, lua_upvalueindex(1), "preload"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); @@ -535,7 +533,7 @@ static int ll_require (lua_State *L) { return 1; /* package is already loaded */ } /* else must load it; iterate over available loaders */ - lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + lua_getfield(L, lua_upvalueindex(1), "loaders"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.loaders") " must be a table"); lua_pushliteral(L, ""); /* error message accumulator */ @@ -579,14 +577,18 @@ static int ll_require (lua_State *L) { */ -static void setfenv (lua_State *L) { +/* +** FOR COMPATIBILITY ONLY: changes the _ENV variable of +** calling function +*/ +static void set_env (lua_State *L) { lua_Debug ar; if (lua_getstack(L, 1, &ar) == 0 || lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_iscfunction(L, -1)) luaL_error(L, LUA_QL("module") " not called from a Lua function"); lua_pushvalue(L, -2); /* copy new environment table to top */ - lua_setfenv(L, -2); + lua_setupvalue(L, -2, 1); lua_pop(L, 1); /* remove function */ } @@ -639,7 +641,7 @@ static int ll_module (lua_State *L) { modinit(L, modname); } lua_pushvalue(L, -1); - setfenv(L); + set_env(L); dooptions(L, loaded - 1); return 1; } @@ -709,12 +711,12 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_setfield(L, -2, "__gc"); /* create `package' table */ luaL_register(L, LUA_LOADLIBNAME, pk_funcs); - lua_copy(L, -1, LUA_ENVIRONINDEX); /* create `loaders' table */ lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { - lua_pushcfunction(L, loaders[i]); + lua_pushvalue(L, -2); /* set 'package' as upvalue for all loaders */ + lua_pushcclosure(L, loaders[i], 1); lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ @@ -731,8 +733,9 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_newtable(L); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); - luaL_register(L, NULL, ll_funcs); /* open lib into global table */ - lua_pop(L, 1); + lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ + luaL_openlib(L, NULL, ll_funcs, 1); /* open lib into global table */ + lua_pop(L, 1); /* pop global table */ return 1; /* return 'package' table */ } diff --git a/src/lobject.c b/src/lobject.c index 8f5c5691da..d4fff394bd 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.34 2009/11/26 11:39:20 roberto Exp $ +** $Id: lobject.c,v 2.40 2010/04/18 13:22:48 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -81,6 +81,10 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) { return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TSTRING: + return rawtsvalue(t1) == rawtsvalue(t2); + case LUA_TLCF: + return fvalue(t1) == fvalue(t2); default: lua_assert(iscollectable(t1)); return gcvalue(t1) == gcvalue(t2); @@ -96,7 +100,7 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { case LUA_OPDIV: return luai_numdiv(NULL, v1, v2); case LUA_OPMOD: return luai_nummod(NULL, v1, v2); case LUA_OPPOW: return luai_numpow(NULL, v1, v2); - case LUA_OPUNM: return luai_numunm(N, v1); + case LUA_OPUNM: return luai_numunm(NULL, v1); default: lua_assert(0); return 0; } } @@ -108,24 +112,21 @@ int luaO_str2d (const char *s, lua_Number *result) { if (endptr == s) return 0; /* conversion failed */ if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ *result = cast_num(strtoul(s, &endptr, 16)); - if (*endptr == '\0') return 1; /* most common case */ while (lisspace(cast(unsigned char, *endptr))) endptr++; - if (*endptr != '\0') return 0; /* invalid trailing characters? */ - return 1; + return (*endptr == '\0'); /* OK if no trailing characters */ } -static void pushstr (lua_State *L, const char *str) { - setsvalue2s(L, L->top, luaS_new(L, str)); +static void pushstr (lua_State *L, const char *str, size_t l) { + setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); incr_top(L); } /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { - int n = 1; - pushstr(L, ""); + int n = 0; for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; @@ -135,14 +136,13 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { case 's': { const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; - pushstr(L, s); + pushstr(L, s, strlen(s)); break; } case 'c': { - char buff[2]; - buff[0] = cast(char, va_arg(argp, int)); - buff[1] = '\0'; - pushstr(L, buff); + char buff; + buff = cast(char, va_arg(argp, int)); + pushstr(L, &buff, 1); break; } case 'd': { @@ -157,12 +157,12 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ - sprintf(buff, "%p", va_arg(argp, void *)); - pushstr(L, buff); + int l = sprintf(buff, "%p", va_arg(argp, void *)); + pushstr(L, buff, l); break; } case '%': { - pushstr(L, "%"); + pushstr(L, "%", 1); break; } default: { @@ -175,8 +175,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { n += 2; fmt = e+2; } - pushstr(L, fmt); - luaV_concat(L, n+1); + pushstr(L, fmt, strlen(fmt)); + if (n > 0) luaV_concat(L, n + 1); return svalue(L->top - 1); } diff --git a/src/lobject.h b/src/lobject.h index 2969fe7d62..736342206f 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.34 2010/01/08 20:00:20 roberto Exp $ +** $Id: lobject.h,v 2.40 2010/05/07 18:44:46 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -16,20 +16,20 @@ #include "lua.h" -/* tags for values visible from Lua */ -#define LAST_TAG LUA_TTHREAD - -#define NUM_TAGS (LAST_TAG+1) - - /* ** Extra tags for non-values */ -#define LUA_TPROTO (LAST_TAG+1) -#define LUA_TUPVAL (LAST_TAG+2) -#define LUA_TDEADKEY (LAST_TAG+3) +#define LUA_TPROTO LUA_NUMTAGS +#define LUA_TUPVAL (LUA_NUMTAGS+1) +#define LUA_TDEADKEY (LUA_NUMTAGS+2) +/* +** Variant tag for light C functions (negative to be considered +** non collectable by 'iscollectable') +*/ +#define LUA_TLCF (~0x0F | LUA_TFUNCTION) + /* ** Union of all collectable objects */ @@ -60,6 +60,7 @@ typedef union { void *p; lua_Number n; int b; + lua_CFunction f; } Value; @@ -79,12 +80,26 @@ typedef struct lua_TValue { #define NILCONSTANT {NULL}, LUA_TNIL +/* +** type tag of a TValue +*/ +#define ttype(o) ((o)->tt_) + + +/* +** type tag of a TValue with no variants +*/ +#define ttypenv(o) (ttype(o) & 0x0F) + + /* Macros to test type */ #define ttisnil(o) (ttype(o) == LUA_TNIL) #define ttisnumber(o) (ttype(o) == LUA_TNUMBER) #define ttisstring(o) (ttype(o) == LUA_TSTRING) #define ttistable(o) (ttype(o) == LUA_TTABLE) -#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) +#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION) +#define ttisclosure(o) (ttype(o) == LUA_TFUNCTION) +#define ttislcf(o) (ttype(o) == LUA_TLCF) #define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) #define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) #define ttisthread(o) (ttype(o) == LUA_TTHREAD) @@ -92,7 +107,6 @@ typedef struct lua_TValue { #define ttisdeadkey(o) (ttype(o) == LUA_TDEADKEY) /* Macros to access values */ -#define ttype(o) ((o)->tt_) #define gcvalue(o) check_exp(iscollectable(o), (o)->value_.gc) #define pvalue(o) check_exp(ttislightuserdata(o), (o)->value_.p) #define nvalue(o) check_exp(ttisnumber(o), (o)->value_.n) @@ -100,16 +114,15 @@ typedef struct lua_TValue { #define tsvalue(o) (&rawtsvalue(o)->tsv) #define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value_.gc->u) #define uvalue(o) (&rawuvalue(o)->uv) -#define clvalue(o) check_exp(ttisfunction(o), &(o)->value_.gc->cl) +#define clvalue(o) check_exp(ttisclosure(o), &(o)->value_.gc->cl) +#define fvalue(o) check_exp(ttislcf(o), (o)->value_.f) #define hvalue(o) check_exp(ttistable(o), &(o)->value_.gc->h) #define bvalue(o) check_exp(ttisboolean(o), (o)->value_.b) #define thvalue(o) check_exp(ttisthread(o), &(o)->value_.gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) -/* -** for internal debug only -*/ + #define iscollectable(o) (ttype(o) >= LUA_TSTRING) #define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) @@ -126,8 +139,10 @@ typedef struct lua_TValue { #define setnvalue(obj,x) \ { TValue *i_o=(obj); i_o->value_.n=(x); i_o->tt_=LUA_TNUMBER; } -#define changenvalue(obj,x) \ - ( lua_assert((obj)->tt_==LUA_TNUMBER), (obj)->value_.n=(x) ) +#define setfvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value_.f=(x); i_o->tt_=LUA_TLCF; } + +#define changenvalue(o,x) check_exp((o)->tt_==LUA_TNUMBER, (o)->value_.n=(x)) #define setpvalue(obj,x) \ { TValue *i_o=(obj); i_o->value_.p=(x); i_o->tt_=LUA_TLIGHTUSERDATA; } @@ -264,7 +279,6 @@ typedef struct Proto { lu_byte numparams; lu_byte is_vararg; lu_byte maxstacksize; - lu_byte envreg; /* register in outer function with initial environment */ } Proto; @@ -298,8 +312,7 @@ typedef struct UpVal { */ #define ClosureHeader \ - CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ - struct Table *env + CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist typedef struct CClosure { ClosureHeader; @@ -321,8 +334,7 @@ typedef union Closure { } Closure; -#define iscfunction(o) (ttisfunction(o) && clvalue(o)->c.isC) -#define isLfunction(o) (ttisfunction(o) && !clvalue(o)->c.isC) +#define isLfunction(o) (ttisclosure(o) && !clvalue(o)->c.isC) #define getproto(o) (clvalue(o)->l.p) diff --git a/src/lopcodes.c b/src/lopcodes.c index 188c7a5503..cc1acb134e 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.41 2009/11/19 19:06:52 roberto Exp $ +** $Id: lopcodes.c,v 1.43 2010/03/12 19:14:06 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -19,9 +19,9 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "LOADBOOL", "LOADNIL", "GETUPVAL", - "GETGLOBAL", + "GETTABUP", "GETTABLE", - "SETGLOBAL", + "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", @@ -67,9 +67,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ - ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */ + ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ - ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ + ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ diff --git a/src/lopcodes.h b/src/lopcodes.h index 19ddfea30f..4140db3a74 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.133 2009/11/19 19:06:52 roberto Exp $ +** $Id: lopcodes.h,v 1.135 2010/03/12 19:14:06 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -171,10 +171,10 @@ OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ OP_GETUPVAL,/* A B R(A) := UpValue[B] */ -OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx - 1)] */ +OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */ OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ -OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx - 1)] := R(A) */ +OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */ OP_SETUPVAL,/* A B UpValue[B] := R(A) */ OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ @@ -243,8 +243,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next 'instruction' is EXTRAARG(real C). - (*) In OP_LOADK, OP_GETGLOBAL, and OP_SETGLOBAL, if (Bx == 0) then next - 'instruction' is EXTRAARG(real Bx). + (*) In OP_LOADK, if (Bx == 0) then next 'instruction' is EXTRAARG(real Bx). (*) For comparisons, A specifies what condition the test should accept (true or false). diff --git a/src/lparser.c b/src/lparser.c index cc21f67fcd..762cb4fc59 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp $ +** $Id: lparser.c,v 2.86 2010/05/15 13:32:02 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -74,9 +74,10 @@ static void error_expected (LexState *ls, int token) { static void errorlimit (FuncState *fs, int limit, const char *what) { const char *msg; - const char *where = (fs->f->linedefined == 0) ? - "main function" : - luaO_pushfstring(fs->L, "function at line %d", fs->f->linedefined); + int line = fs->f->linedefined; + const char *where = (line == 0) + ? "main function" + : luaO_pushfstring(fs->L, "function at line %d", line); msg = luaO_pushfstring(fs->L, "too many %s (limit is %d) in %s", what, limit, where); luaX_syntaxerror(fs->ls, msg); @@ -207,27 +208,27 @@ static void removevars (FuncState *fs, int tolevel) { } -static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { +static int searchupvalue (FuncState *fs, TString *name) { int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (eqstr(up[i].name, name)) return i; + } + return -1; /* not found */ +} + + +static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; - int instk = (v->k == VLOCAL); - lua_assert(instk || v->k == VUPVAL); - for (i=0; inups; i++) { - if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) { - lua_assert(f->upvalues[i].name == name); - return i; - } - } - /* new one */ checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues"); luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, Upvaldesc, UCHAR_MAX, "upvalues"); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; + f->upvalues[fs->nups].instack = (v->k == VLOCAL); + f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->L, f, name); - f->upvalues[fs->nups].instack = cast_byte(instk); - f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); return fs->nups++; } @@ -235,13 +236,17 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { static int searchvar (FuncState *fs, TString *n) { int i; for (i=fs->nactvar-1; i >= 0; i--) { - if (n == getlocvar(fs, i)->varname) + if (eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ } +/* + Mark block where variable at given level was defined + (to emit OP_CLOSE later). +*/ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; while (bl && bl->nactvar > level) bl = bl->previous; @@ -249,22 +254,30 @@ static void markupval (FuncState *fs, int level) { } +/* + Find variable with given name 'n'. If it is an upvalue, add this + upvalue into all intermediate functions. +*/ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) /* no more levels? */ - return VGLOBAL; /* default is global variable */ + return VVOID; /* default is global */ else { - int v = searchvar(fs, n); /* look up at current level */ - if (v >= 0) { - init_exp(var, VLOCAL, v); + int v = searchvar(fs, n); /* look up locals at current level */ + if (v >= 0) { /* found? */ + init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ return VLOCAL; } - else { /* not found at current level; try upper one */ - if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) - return VGLOBAL; - var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ - var->k = VUPVAL; /* upvalue in this level */ + else { /* not found as local at current level; try upvalues */ + int idx = searchupvalue(fs, n); /* try existing upvalues */ + if (idx < 0) { /* not found? */ + if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ + return VVOID; /* not found; is a global */ + /* else was LOCAL or UPVAL */ + idx = newupvalue(fs, n, var); /* will be a new upvalue */ + } + init_exp(var, VUPVAL, idx); return VUPVAL; } } @@ -274,15 +287,12 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; - if (singlevaraux(fs, varname, var, 1) == VGLOBAL) { - if (fs->envreg == NO_REG) /* regular global? */ - init_exp(var, VGLOBAL, luaK_stringK(fs, varname)); - else { /* "globals" are in current lexical environment */ - expdesc key; - init_exp(var, VLOCAL, fs->envreg); /* current environment */ - codestring(ls, &key, varname); /* key is variable name */ - luaK_indexed(fs, var, &key); /* env[varname] */ - } + if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ + expdesc key; + singlevaraux(fs, ls->envn, var, 1); /* get _ENV variable */ + lua_assert(var->k == VLOCAL || var->k == VUPVAL); + codestring(ls, &key, varname); /* key is variable name */ + luaK_indexed(fs, var, &key); /* env[varname] */ } } @@ -351,7 +361,6 @@ static void pushclosure (LexState *ls, Proto *clp, expdesc *v) { while (oldsize < f->sizep) f->p[oldsize++] = NULL; f->p[fs->np++] = clp; /* initial environment for new function is current lexical environment */ - clp->envreg = fs->envreg; luaC_objbarrier(ls->L, f, clp); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); } @@ -374,7 +383,6 @@ static void open_func (LexState *ls, FuncState *fs) { fs->nlocvars = 0; fs->nactvar = 0; fs->firstlocal = ls->varl->nactvar; - fs->envreg = NO_REG; fs->bl = NULL; f = luaF_newproto(L); fs->f = f; @@ -418,26 +426,36 @@ static void close_func (LexState *ls) { } +/* +** opens the main function, which is a regular vararg function with an +** upvalue named '_ENV' +*/ +static void open_mainfunc (LexState *ls, FuncState *fs) { + expdesc v; + open_func(ls, fs); + fs->f->is_vararg = 1; /* main function is always vararg */ + init_exp(&v, VLOCAL, 0); + newupvalue(fs, ls->envn, &v); /* create '_ENV' upvalue */ +} + + Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, const char *name) { - struct LexState lexstate; - struct FuncState funcstate; + LexState lexstate; + FuncState funcstate; TString *tname = luaS_new(L, name); setsvalue2s(L, L->top, tname); /* push name to protect it */ incr_top(L); lexstate.buff = buff; lexstate.varl = varl; luaX_setinput(L, &lexstate, z, tname); - open_func(&lexstate, &funcstate); - funcstate.f->is_vararg = 1; /* main function is always vararg */ + open_mainfunc(&lexstate, &funcstate); luaX_next(&lexstate); /* read first token */ - chunk(&lexstate); + chunk(&lexstate); /* read main chunk */ check(&lexstate, TK_EOS); close_func(&lexstate); L->top--; /* pop name */ - lua_assert(funcstate.prev == NULL); - lua_assert(funcstate.nups == 0); - lua_assert(lexstate.fs == NULL); + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); return funcstate.f; } @@ -452,7 +470,7 @@ static void fieldsel (LexState *ls, expdesc *v) { /* fieldsel -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; - luaK_exp2anyreg(fs, v); + luaK_exp2anyregup(fs, v); luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); @@ -653,15 +671,12 @@ static int explist1 (LexState *ls, expdesc *v) { } -static void funcargs (LexState *ls, expdesc *f) { +static void funcargs (LexState *ls, expdesc *f, int line) { FuncState *fs = ls->fs; expdesc args; int base, nparams; - int line = ls->linenumber; switch (ls->t.token) { case '(': { /* funcargs -> `(' [ explist1 ] `)' */ - if (line != ls->lastline) - luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; @@ -738,6 +753,7 @@ static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; + int line = ls->linenumber; prefixexp(ls, v); for (;;) { switch (ls->t.token) { @@ -747,7 +763,7 @@ static void primaryexp (LexState *ls, expdesc *v) { } case '[': { /* `[' exp1 `]' */ expdesc key; - luaK_exp2anyreg(fs, v); + luaK_exp2anyregup(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; @@ -757,12 +773,12 @@ static void primaryexp (LexState *ls, expdesc *v) { luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); - funcargs(ls, v); + funcargs(ls, v, line); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); - funcargs(ls, v); + funcargs(ls, v, line); break; } default: return; @@ -877,9 +893,10 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { + int line = ls->linenumber; luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); - luaK_prefix(ls->fs, uop, v); + luaK_prefix(ls->fs, uop, v, line); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ @@ -887,11 +904,12 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; + int line = ls->linenumber; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); - luaK_posfix(ls->fs, op, v, &v2); + luaK_posfix(ls->fs, op, v, &v2, line); op = nextop; } leavelevel(ls); @@ -951,24 +969,27 @@ struct LHS_assign { ** local value in a safe place and use this safe copy in the previous ** assignment. */ -static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v, + expkind ix, OpCode op) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { - if (lh->v.k == VINDEXED) { + if (lh->v.k == ix) { if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ conflict = 1; + lh->v.k = VINDEXED; lh->v.u.s.info = extra; /* previous assignment will use safe copy */ } - if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ + if (v->k == VLOCAL && lh->v.u.s.aux == v->u.s.info) { /* conflict? */ conflict = 1; + lua_assert(lh->v.k == VINDEXED); lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ } } } if (conflict) { - luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ + luaK_codeABC(fs, op, fs->freereg, v->u.s.info, 0); /* make copy */ luaK_reserveregs(fs, 1); } } @@ -976,14 +997,16 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; - check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, + check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXEDUP, "syntax error"); if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ struct LHS_assign nv; nv.prev = lh; primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) - check_conflict(ls, lh, &nv.v); + check_conflict(ls, lh, &nv.v, VINDEXED, OP_MOVE); + else if (nv.v.k == VUPVAL) + check_conflict(ls, lh, &nv.v, VINDEXEDUP, OP_GETUPVAL); checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls, "variable names"); assignment(ls, &nv, nvars+1); @@ -1274,24 +1297,6 @@ static void funcstat (LexState *ls, int line) { } -static void instat (LexState *ls, int line) { - /* instat -> IN exp DO block END */ - FuncState *fs = ls->fs; - int oldenv = fs->envreg; /* save current environment */ - BlockCnt bl; - luaX_next(ls); /* skip IN */ - enterblock(fs, &bl, 0); /* scope for environment variable */ - new_localvarliteral(ls, "(environment)"); - fs->envreg = exp1(ls); /* new environment */ - adjustlocalvars(ls, 1); - checknext(ls, TK_DO); - block(ls); - leaveblock(fs); - check_match(ls, TK_END, TK_IN, line); - fs->envreg = oldenv; /* restore outer environment */ -} - - static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; @@ -1311,7 +1316,6 @@ static void retstat (LexState *ls) { FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ - luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { @@ -1342,6 +1346,10 @@ static void retstat (LexState *ls) { static int statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->t.token) { + case ';': { /* stat -> ';' (empty statement) */ + luaX_next(ls); /* skip ';' */ + return 0; + } case TK_IF: { /* stat -> ifstat */ ifstat(ls, line); return 0; @@ -1356,10 +1364,6 @@ static int statement (LexState *ls) { check_match(ls, TK_END, TK_DO, line); return 0; } - case TK_IN: { - instat(ls, line); - return 0; - } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); return 0; @@ -1368,8 +1372,8 @@ static int statement (LexState *ls) { repeatstat(ls, line); return 0; } - case TK_FUNCTION: { - funcstat(ls, line); /* stat -> funcstat */ + case TK_FUNCTION: { /* stat -> funcstat */ + funcstat(ls, line); return 0; } case TK_LOCAL: { /* stat -> localstat */ @@ -1381,6 +1385,7 @@ static int statement (LexState *ls) { return 0; } case TK_RETURN: { /* stat -> retstat */ + luaX_next(ls); /* skip RETURN */ retstat(ls); return 1; /* must be last statement */ } @@ -1389,9 +1394,9 @@ static int statement (LexState *ls) { breakstat(ls); return 1; /* must be last statement */ } - default: { + default: { /* stat -> func | assignment */ exprstat(ls); - return 0; /* to avoid warnings */ + return 0; } } } @@ -1403,7 +1408,8 @@ static void chunk (LexState *ls) { enterlevel(ls); while (!islast && !block_follow(ls->t.token)) { islast = statement(ls); - testnext(ls, ';'); + if (islast) + testnext(ls, ';'); lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ diff --git a/src/lparser.h b/src/lparser.h index 2ad0a5099f..9e406a7b49 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.61 2009/10/11 20:02:19 roberto Exp $ +** $Id: lparser.h,v 1.63 2010/03/12 19:14:06 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,10 +23,10 @@ typedef enum { VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ - VLOCAL, /* info = local register; aux = read only */ - VUPVAL, /* info = index of upvalue in 'upvalues'; aux = read only */ - VGLOBAL, /* info = index of table; aux = index of global name in `k' */ - VINDEXED, /* info = table register; aux = index register (or `k') */ + VLOCAL, /* info = local register */ + VUPVAL, /* info = index of upvalue in 'upvalues' */ + VINDEXED, /* info = table R/K; aux = index R/K */ + VINDEXEDUP, /* info = table upvalue; aux = R/K */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ VNONRELOC, /* info = result register */ @@ -80,7 +80,6 @@ typedef struct FuncState { short nlocvars; /* number of elements in `locvars' */ lu_byte nactvar; /* number of active local variables */ lu_byte nups; /* number of upvalues */ - lu_byte envreg; /* register holding current lexical environment */ } FuncState; diff --git a/src/lstate.c b/src/lstate.c index 426fdec629..6ea00b62f5 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.68 2009/12/22 15:32:50 roberto Exp $ +** $Id: lstate.c,v 2.85 2010/04/30 18:36:22 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -26,7 +26,7 @@ #if !defined(LUAI_GCPAUSE) -#define LUAI_GCPAUSE 162 /* 162% (wait memory to double before next GC) */ +#define LUAI_GCPAUSE 200 /* 200% */ #endif #if !defined(LUAI_GCMUL) @@ -34,6 +34,9 @@ #endif +#define MEMERRMSG "not enough memory" + + /* ** thread state + extra space */ @@ -87,7 +90,7 @@ void luaE_freeCI (lua_State *L) { static void stack_init (lua_State *L1, lua_State *L) { - int i; + int i; CallInfo *ci; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); L1->stacksize = BASIC_STACK_SIZE; @@ -96,32 +99,22 @@ static void stack_init (lua_State *L1, lua_State *L) { L1->top = L1->stack; L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; /* initialize first ci */ - L1->ci->func = L1->top; + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ - L1->ci->top = L1->top + LUA_MINSTACK; - L1->ci->callstatus = 0; + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; } static void freestack (lua_State *L) { - L->ci = &L->base_ci; /* reset 'ci' list */ + if (L->stack == NULL) + return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ luaE_freeCI(L); - luaM_freearray(L, L->stack, L->stacksize); -} - - -/* -** Calls the function in variable pointed to by userdata in first argument -** (Userdata cannot point directly to the function because pointer to -** function is not compatible with void*.) -*/ -static int cpcall (lua_State *L) { - lua_CFunction f = *(lua_CFunction *)lua_touserdata(L, 1); - lua_remove(L, 1); /* remove f from stack */ - /* restore original environment for 'cpcall' */ - lua_pushglobaltable(L); - lua_replace(L, LUA_ENVIRONINDEX); - return f(L); + luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ } @@ -129,7 +122,6 @@ static int cpcall (lua_State *L) { ** Create registry table and its predefined values */ static void init_registry (lua_State *L, global_State *g) { - Closure *cp; TValue mt; /* create registry */ Table *registry = luaH_new(L); @@ -138,13 +130,8 @@ static void init_registry (lua_State *L, global_State *g) { /* registry[LUA_RIDX_MAINTHREAD] = L */ setthvalue(L, &mt, L); setobj2t(L, luaH_setint(L, registry, LUA_RIDX_MAINTHREAD), &mt); - /* registry[LUA_RIDX_CPCALL] = cpcall */ - cp = luaF_newCclosure(L, 0, g->l_gt); - cp->c.f = cpcall; - setclvalue(L, &mt, cp); - setobj2t(L, luaH_setint(L, registry, LUA_RIDX_CPCALL), &mt); - /* registry[LUA_RIDX_GLOBALS] = l_gt */ - sethvalue(L, &mt, g->l_gt); + /* registry[LUA_RIDX_GLOBALS] = table of globals */ + sethvalue(L, &mt, luaH_new(L)); setobj2t(L, luaH_setint(L, registry, LUA_RIDX_GLOBALS), &mt); } @@ -156,13 +143,14 @@ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ - g->l_gt = luaH_new(L); /* table of globals */ init_registry(L, g); luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); - luaS_fix(luaS_newliteral(L, MEMERRMSG)); - g->GCthreshold = 4*g->totalbytes; + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaS_fix(g->memerrmsg); /* it should never be collected */ + g->GCdebt = 0; } @@ -173,6 +161,7 @@ static void f_luaopen (lua_State *L, void *ud) { static void preinit_state (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; + L->ci = NULL; L->stacksize = 0; L->errorJmp = NULL; L->hook = NULL; @@ -183,8 +172,6 @@ static void preinit_state (lua_State *L, global_State *g) { L->openupval = NULL; L->nny = 1; L->status = LUA_OK; - L->base_ci.next = L->base_ci.previous = NULL; - L->ci = &L->base_ci; L->errfunc = 0; } @@ -209,14 +196,13 @@ LUA_API lua_State *lua_newthread (lua_State *L) { setthvalue(L, L->top, L1); api_incr_top(L); preinit_state(L1, G(L)); - stack_init(L1, L); /* init stack */ L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); - lua_assert(iswhite(obj2gco(L1))); - lua_unlock(L); luai_userstatethread(L, L1); + stack_init(L1, L); /* init stack */ + lua_unlock(L); return L1; } @@ -225,7 +211,7 @@ void luaE_freethread (lua_State *L, lua_State *L1) { LX *l = fromstate(L1); luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); - luai_userstatefree(L1); + luai_userstatefree(L, L1); freestack(L1); luaM_free(L, l); } @@ -235,7 +221,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; - LG *l = cast(LG *, (*f)(ud, NULL, 0, sizeof(LG))); + LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); if (l == NULL) return NULL; L = &l->l.l; g = &l->g; @@ -245,29 +231,31 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { L->marked = luaC_white(g); g->gckind = KGC_NORMAL; g->nCcalls = 0; - set2bits(L->marked, FIXEDBIT, SFIXEDBIT); preinit_state(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; - g->GCthreshold = MAX_LUMEM; /* no GC while building state */ + stopgc(g); /* no GC while building state */ + g->lastmajormem = 0; g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); - g->l_gt = NULL; luaZ_initbuffer(L, &g->buff); g->panic = NULL; g->version = lua_version(NULL); g->gcstate = GCSpause; - g->rootgc = obj2gco(L); + g->allgc = NULL; + g->udgc = NULL; g->tobefnz = NULL; + g->gray = g->grayagain = NULL; + g->weak = g->ephemeron = g->allweak = NULL; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; - for (i=0; imt[i] = NULL; + for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { /* memory allocation error: free partial state */ close_state(L); diff --git a/src/lstate.h b/src/lstate.h index 4ca3e02f42..e829ed4aee 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.52 2009/12/22 15:32:50 roberto Exp $ +** $Id: lstate.h,v 2.65 2010/05/03 17:39:48 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -19,7 +19,7 @@ ** Some notes about garbage-collected objects: All objects in Lua must ** be kept somehow accessible until being freed. ** -** Lua keeps most objects linked in list g->rootgc. The link uses field +** Lua keeps most objects linked in list g->allgc. The link uses field ** 'next' of the CommonHeader. ** ** Strings are kept in several lists headed by the array g->strt.hash. @@ -32,9 +32,7 @@ ** when traversing the respective threads, but the thread may already be ** dead, while the upvalue is still accessible through closures.) ** -** Userdata with finalizers are kept in the list g->rootgc, but after -** the mainthread, which should be otherwise the last element in the -** list, as it was the first one inserted there. +** Userdata with finalizers are kept in the list g->udgc. ** ** The list g->tobefnz links all userdata being finalized. @@ -56,8 +54,8 @@ struct lua_longjmp; /* defined in ldo.c */ /* kinds of Garbage Collection */ #define KGC_NORMAL 0 -#define KGC_FORCED 1 /* gc was forced by the program */ -#define KGC_EMERGENCY 2 /* gc was forced by an allocation failure */ +#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ +#define KGC_GEN 2 /* generational collection */ typedef struct stringtable { @@ -85,7 +83,7 @@ typedef struct CallInfo { int ctx; /* context info. in case of yields */ lua_CFunction k; /* continuation in case of yields */ ptrdiff_t old_errfunc; - ptrdiff_t oldtop; + ptrdiff_t extra; lu_byte old_allowhook; lu_byte status; } c; @@ -106,7 +104,6 @@ typedef struct CallInfo { #define CIST_TAIL (1<<6) /* call was tail called */ -#define curr_func(L) (clvalue(L->ci->func)) #define ci_func(ci) (clvalue((ci)->func)) #define isLua(ci) ((ci)->callstatus & CIST_LUA) @@ -115,15 +112,20 @@ typedef struct CallInfo { ** `global state', shared by all threads of this state */ typedef struct global_State { - stringtable strt; /* hash table for strings */ lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ + lu_mem totalbytes; /* number of bytes currently allocated */ + l_mem GCdebt; /* when positive, run a GC step */ + lu_mem lastmajormem; /* memory in use after last major collection */ + stringtable strt; /* hash table for strings */ + TValue l_registry; unsigned short nCcalls; /* number of nested C calls */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ int sweepstrgc; /* position of sweep in `strt' */ - GCObject *rootgc; /* list of all collectable objects */ + GCObject *allgc; /* list of all collectable objects */ + GCObject *udgc; /* list of collectable userdata with finalizers */ GCObject **sweepgc; /* current position of sweep */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ @@ -131,19 +133,16 @@ typedef struct global_State { GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *allweak; /* list of all-weak tables */ GCObject *tobefnz; /* list of userdata to be GC */ + UpVal uvhead; /* head of double-linked list of all open upvalues */ Mbuffer buff; /* temporary buffer for string concatenation */ - lu_mem GCthreshold; /* when totalbytes > GCthreshold, run GC step */ - lu_mem totalbytes; /* number of bytes currently allocated */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ - TValue l_registry; - struct Table *l_gt; /* table of globals */ struct lua_State *mainthread; - UpVal uvhead; /* head of double-linked list of all open upvalues */ const lua_Number *version; /* pointer to version number */ - struct Table *mt[NUM_TAGS]; /* metatables for basic types */ + TString *memerrmsg; /* memory-error message */ TString *tmname[TM_N]; /* array with tag-method names */ + struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ } global_State; @@ -166,7 +165,6 @@ struct lua_State { int basehookcount; int hookcount; lua_Hook hook; - TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ diff --git a/src/lstring.c b/src/lstring.c index 69b96d027a..145621b697 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.16 2009/12/16 16:42:58 roberto Exp $ +** $Id: lstring.c,v 2.18 2010/05/10 18:23:45 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -37,6 +37,7 @@ void luaS_resize (lua_State *L, int newsize) { unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ gch(p)->next = tb->hash[h]; /* chain it */ tb->hash[h] = p; + resetoldbit(p); /* see MOVE OLD rule */ p = next; } } @@ -94,6 +95,11 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { } +TString *luaS_new (lua_State *L, const char *str) { + return luaS_newlstr(L, str, strlen(str)); +} + + Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) diff --git a/src/lstring.h b/src/lstring.h index 1d2e91ea13..d708a1b099 100644 --- a/src/lstring.h +++ b/src/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ +** $Id: lstring.h,v 1.46 2010/04/05 16:26:37 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -7,7 +7,6 @@ #ifndef lstring_h #define lstring_h - #include "lgc.h" #include "lobject.h" #include "lstate.h" @@ -17,15 +16,22 @@ #define sizeudata(u) (sizeof(union Udata)+(u)->len) -#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) #define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) + +/* +** as all string are internalized, string equality becomes +** pointer equality +*/ +#define eqstr(a,b) ((a) == (b)) + LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); +LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); #endif diff --git a/src/lstrlib.c b/src/lstrlib.c index 0c03b493a6..a5c3a2043f 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.148 2010/01/04 16:37:19 roberto Exp $ +** $Id: lstrlib.c,v 1.152 2010/05/04 17:20:33 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -65,12 +65,13 @@ static int str_sub (lua_State *L) { static int str_reverse (lua_State *L) { - size_t l; + size_t l, i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); - while (l--) luaL_addchar(&b, s[l]); - luaL_pushresult(&b); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); return 1; } @@ -80,10 +81,10 @@ static int str_lower (lua_State *L) { size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, l); for (i=0; ip_end) luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ - if (*p == '\0') + if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); - if (*(p++) == L_ESC && *p != '\0') + if (*(p++) == L_ESC && p < ms->p_end) p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; @@ -245,7 +247,7 @@ static int match_class (int c, int cl) { case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; + case 'z' : res = (c == 0); break; /* deprecated option */ default: return (cl == c); } return (islower(cl) ? res : !res); @@ -290,8 +292,9 @@ static const char *match (MatchState *ms, const char *s, const char *p); static const char *matchbalance (MatchState *ms, const char *s, const char *p) { - if (*p == 0 || *(p+1) == 0) - luaL_error(ms->L, "unbalanced pattern"); + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern " + "(missing arguments to " LUA_QL("%%b") ")"); if (*s != *p) return NULL; else { int b = *p; @@ -374,6 +377,8 @@ static const char *match_capture (MatchState *ms, const char *s, int l) { static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ + if (p == ms->p_end) /* end of pattern? */ + return s; /* match succeeded */ switch (*p) { case '(': { /* start capture */ if (*(p+1) == ')') /* position capture? */ @@ -384,11 +389,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case ')': { /* end capture */ return end_capture(ms, s, p+1); } - case '\0': { /* end of pattern */ - return s; /* match succeeded */ - } case '$': { - if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */ return (s == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; } @@ -418,12 +420,12 @@ static const char *match (MatchState *ms, const char *s, const char *p) { if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } - default: break; /* go through to 'dflt' */ + default: goto dflt; } } default: dflt: { /* pattern class plus optional sufix */ const char *ep = classend(ms, p); /* points to what is next */ - int m = ssrc_end && singlematch(uchar(*s), p, ep); + int m = s < ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; @@ -503,32 +505,36 @@ static int push_captures (MatchState *ms, const char *s, const char *e) { static int str_find_aux (lua_State *L, int find) { - size_t l1, l2; - const char *s = luaL_checklstring(L, 1, &l1); - const char *p = luaL_checklstring(L, 2, &l2); - size_t init = posrelat(luaL_optinteger(L, 3, 1), l1); + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + size_t init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; - else if (init > l1 + 1) { /* start after string's end? */ + else if (init > ls + 1) { /* start after string's end? */ lua_pushnil(L); /* cannot find anything */ return 1; } if (find && (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, l1 - init + 1, p, l2); + const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp); if (s2) { lua_pushinteger(L, s2 - s + 1); - lua_pushinteger(L, s2 - s + l2); + lua_pushinteger(L, s2 - s + lp); return 2; } } else { MatchState ms; - int anchor = (*p == '^') ? (p++, 1) : 0; const char *s1 = s + init - 1; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } ms.L = L; ms.src_init = s; - ms.src_end = s + l1; + ms.src_end = s + ls; + ms.p_end = p + lp; do { const char *res; ms.level = 0; @@ -560,13 +566,14 @@ static int str_match (lua_State *L) { static int gmatch_aux (lua_State *L) { MatchState ms; - size_t ls; + size_t ls, lp; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); - const char *p = lua_tostring(L, lua_upvalueindex(2)); + const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); const char *src; ms.L = L; ms.src_init = s; ms.src_end = s+ls; + ms.p_end = p + lp; for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { @@ -658,12 +665,12 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, static int str_gsub (lua_State *L) { - size_t srcl; + size_t srcl, lp; const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checkstring(L, 2); + const char *p = luaL_checklstring(L, 2, &lp); int tr = lua_type(L, 3); size_t max_s = luaL_optinteger(L, 4, srcl+1); - int anchor = (*p == '^') ? (p++, 1) : 0; + int anchor = (*p == '^'); size_t n = 0; MatchState ms; luaL_Buffer b; @@ -671,9 +678,13 @@ static int str_gsub (lua_State *L) { tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, "string/function/table expected"); luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } ms.L = L; ms.src_init = src; ms.src_end = src+srcl; + ms.p_end = p + lp; while (n < max_s) { const char *e; ms.level = 0; @@ -698,11 +709,18 @@ static int str_gsub (lua_State *L) { /* }====================================================== */ + /* -** length modifier for integer conversions ** in 'string.format' and -** integer type corresponding to the previous length +** {====================================================== +** STRING FORMAT +** ======================================================= */ +/* +** LUA_INTFRMLEN is the length modifier for integer conversions in +** 'string.format'; LUA_INTFRM_T is the integer type corresponding to +** the previous length +*/ #if defined(LUA_USELONGLONG) #define LUA_INTFRMLEN "ll" @@ -738,7 +756,7 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { } else if (*s == '\0' || iscntrl(uchar(*s))) { char buff[10]; - if (*s != '\0' && !isdigit(uchar(*(s+1)))) + if (!isdigit(uchar(*(s+1)))) sprintf(buff, "\\%d", uchar(*s)); else sprintf(buff, "\\%03d", uchar(*s)); @@ -773,6 +791,9 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { } +/* +** add length modifier into integer formats +*/ static void addintlen (char *form) { size_t l = strlen(form); char spec = form[l - 1]; @@ -783,6 +804,7 @@ static void addintlen (char *form) { static int str_format (lua_State *L) { + int top = lua_gettop(L); int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); @@ -796,12 +818,14 @@ static int str_format (lua_State *L) { luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ - char buff[MAX_ITEM]; /* to store the formatted item */ - arg++; + char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ + if (++arg > top) + luaL_argerror(L, arg, "no value"); strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - sprintf(buff, form, luaL_checkint(L, arg)); + nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } case 'd': case 'i': @@ -810,17 +834,17 @@ static int str_format (lua_State *L) { LUA_INTFRM_T r = (n < 0) ? (LUA_INTFRM_T)n : (LUA_INTFRM_T)(unsigned LUA_INTFRM_T)n; addintlen(form); - sprintf(buff, form, r); + nb = sprintf(buff, form, r); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { - sprintf(buff, form, (double)luaL_checknumber(L, arg)); + nb = sprintf(buff, form, (double)luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); - continue; /* skip the 'addsize' at the end */ + break; } case 's': { size_t l; @@ -830,10 +854,10 @@ static int str_format (lua_State *L) { keep original string */ lua_pushvalue(L, arg); luaL_addvalue(&b); - continue; /* skip the `addsize' at the end */ + break; } else { - sprintf(buff, form, s); + nb = sprintf(buff, form, s); break; } } @@ -842,13 +866,15 @@ static int str_format (lua_State *L) { LUA_QL("format"), *(strfrmt - 1)); } } - luaL_addlstring(&b, buff, strlen(buff)); + luaL_addsize(&b, nb); } } luaL_pushresult(&b); return 1; } +/* }====================================================== */ + static const luaL_Reg strlib[] = { {"byte", str_byte}, diff --git a/src/ltable.c b/src/ltable.c index 78ff1d7402..dc6604dd9b 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.47 2009/12/17 15:46:44 roberto Exp $ +** $Id: ltable.c,v 2.50 2010/04/18 13:22:48 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -31,6 +31,7 @@ #include "lmem.h" #include "lobject.h" #include "lstate.h" +#include "lstring.h" #include "ltable.h" @@ -108,6 +109,8 @@ static Node *mainposition (const Table *t, const TValue *key) { return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: return hashpointer(t, pvalue(key)); + case LUA_TLCF: + return hashpointer(t, fvalue(key)); default: return hashpointer(t, gcvalue(key)); } @@ -452,7 +455,7 @@ const TValue *luaH_getint (Table *t, int key) { const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) + if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); diff --git a/src/ltablib.c b/src/ltablib.c index 6ad6b8e00c..2e00da29cf 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.54 2010/01/13 19:59:10 roberto Exp $ +** $Id: ltablib.c,v 1.55 2010/03/13 03:57:46 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -171,15 +171,15 @@ static int tconcat (lua_State *L) { static int pack (lua_State *L) { int top = lua_gettop(L); lua_createtable(L, top, 1); /* create result table */ - /* use function environment as a temporary place to keep new table */ - lua_replace(L, LUA_ENVIRONINDEX); lua_pushinteger(L, top); /* number of elements */ - lua_setfield(L, LUA_ENVIRONINDEX, "n"); /* t.n = number of elements */ - for (; top >= 1; top--) /* assign elements */ - lua_rawseti(L, LUA_ENVIRONINDEX, top); - lua_pushvalue(L, LUA_ENVIRONINDEX); /* return new table */ - /* remove new table from environment to allow its later collection */ - lua_copy(L, LUA_REGISTRYINDEX, LUA_ENVIRONINDEX); + lua_setfield(L, -2, "n"); /* t.n = number of elements */ + if (top > 0) { /* at least one element? */ + lua_pushvalue(L, 1); + lua_rawseti(L, -2, 1); /* insert first element */ + lua_replace(L, 1); /* move table into its position (index 1) */ + for (; top >= 2; top--) /* assign other elements */ + lua_rawseti(L, 1, top); + } return 1; } @@ -328,7 +328,7 @@ LUAMOD_API int luaopen_table (lua_State *L) { #if defined(LUA_COMPAT_UNPACK) /* _G.unpack = table.unpack */ lua_getfield(L, -1, "unpack"); - lua_setfield(L, LUA_ENVIRONINDEX, "unpack"); + lua_setglobal(L, "unpack"); #endif return 1; } diff --git a/src/ltm.c b/src/ltm.c index 3a9e73ca79..faa8f57d2b 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.11 2010/01/13 16:18:25 roberto Exp $ +** $Id: ltm.c,v 2.12 2010/04/13 20:48:12 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -70,7 +70,7 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { mt = uvalue(o)->metatable; break; default: - mt = G(L)->mt[ttype(o)]; + mt = G(L)->mt[ttypenv(o)]; } return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } diff --git a/src/ltm.h b/src/ltm.h index 732aa12d94..05abc40bd2 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.9 2010/01/13 16:18:25 roberto Exp $ +** $Id: ltm.h,v 2.10 2010/04/13 20:48:12 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -43,7 +43,8 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) -#define typename(x) luaT_typenames_[(x) + 1] +#define ttypename(x) luaT_typenames_[(x) + 1] +#define objtypename(x) ttypename(ttypenv(x)) LUAI_DDEC const char *const luaT_typenames_[]; diff --git a/src/lua.c b/src/lua.c index 757adb6cee..2b1c61613d 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.182 2009/12/22 16:47:12 roberto Exp $ +** $Id: lua.c,v 1.190 2010/04/14 15:14:21 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -102,26 +102,31 @@ static void laction (int i) { } -static void print_usage (void) { - fprintf(stderr, +static void print_usage (const char *badoption) { + if (badoption[1] == 'e' || badoption[1] == 'l') { + luai_writestringerror("%s: ", progname); + luai_writestringerror("'%s' needs argument\n", badoption); + } else { + luai_writestringerror("%s: ", progname); + luai_writestringerror("unrecognized option '%s'\n", badoption); + } + luai_writestringerror( "usage: %s [options] [script [args]]\n" "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" - " -l name require library " LUA_QL("name") "\n" " -i enter interactive mode after executing " LUA_QL("script") "\n" + " -l name require library " LUA_QL("name") "\n" " -v show version information\n" " -- stop handling options\n" - " - execute stdin and stop handling options\n" + " - stop handling options and execute stdin\n" , progname); - fflush(stderr); } static void l_message (const char *pname, const char *msg) { - if (pname) fprintf(stderr, "%s: ", pname); - fprintf(stderr, "%s\n", msg); - fflush(stderr); + if (pname) luai_writestringerror("%s: ", pname); + luai_writestringerror("%s\n", msg); } @@ -214,7 +219,7 @@ static int dostring (lua_State *L, const char *s, const char *name) { static int dolibrary (lua_State *L, const char *name) { - lua_getfield(L, LUA_ENVIRONINDEX, "require"); + lua_getglobal(L, "require"); lua_pushstring(L, name); return report(L, docall(L, 1, 1)); } @@ -222,7 +227,7 @@ static int dolibrary (lua_State *L, const char *name) { static const char *get_prompt (lua_State *L, int firstline) { const char *p; - lua_getfield(L, LUA_ENVIRONINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ @@ -296,7 +301,7 @@ static void dotty (lua_State *L) { report(L, status); if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); - lua_getfield(L, LUA_ENVIRONINDEX, "print"); + lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK) l_message(progname, lua_pushfstring(L, @@ -306,7 +311,6 @@ static void dotty (lua_State *L) { } lua_settop(L, 0); /* clear stack */ luai_writestring("\n", 1); - fflush(stdout); progname = oldprogname; } @@ -315,7 +319,7 @@ static int handle_script (lua_State *L, char **argv, int n) { int status; const char *fname; int narg = getargs(L, argv, n); /* collect arguments */ - lua_setfield(L, LUA_ENVIRONINDEX, "arg"); + lua_setglobal(L, "arg"); fname = argv[n]; if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ @@ -356,10 +360,11 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { case 'l': if (argv[i][2] == '\0') { i++; - if (argv[i] == NULL) return -1; + if (argv[i] == NULL) return -(i - 1); } break; - default: return -1; /* invalid option */ + default: /* invalid option; return its index... */ + return -i; /* ...as a negative value */ } } return 0; @@ -369,7 +374,6 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { static int runargs (lua_State *L, char **argv, int n) { int i; for (i = 1; i < n; i++) { - if (argv[i] == NULL) continue; lua_assert(argv[i][0] == '-'); switch (argv[i][1]) { /* option */ case 'e': { @@ -412,8 +416,8 @@ static int pmain (lua_State *L) { int has_i = 0, has_v = 0, has_e = 0; if (argv[0] && argv[0][0]) progname = argv[0]; script = collectargs(argv, &has_i, &has_v, &has_e); - if (script < 0) { /* invalid args? */ - print_usage(); + if (script < 0) { /* invalid arg? */ + print_usage(argv[-script]); return 0; } if (has_v) print_version(); @@ -443,7 +447,6 @@ static int pmain (lua_State *L) { int main (int argc, char **argv) { - static lua_CFunction ppmain = &pmain; int status, result; lua_State *L = luaL_newstate(); /* create state */ if (L == NULL) { @@ -451,11 +454,10 @@ int main (int argc, char **argv) { return EXIT_FAILURE; } /* call 'pmain' in protected mode */ - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); /* calling function */ - lua_pushlightuserdata(L, &ppmain); - lua_pushinteger(L, argc); - lua_pushlightuserdata(L, argv); - status = lua_pcall(L, 3, 1, 0); + lua_pushcfunction(L, &pmain); + lua_pushinteger(L, argc); /* 1st argument */ + lua_pushlightuserdata(L, argv); /* 2nd argument */ + status = lua_pcall(L, 2, 1, 0); result = lua_toboolean(L, -1); /* get result */ finalreport(L, status); lua_close(L); diff --git a/src/lua.h b/src/lua.h index f79df970f5..09a9ab7661 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.261 2010/01/11 17:15:11 roberto Exp $ +** $Id: lua.h,v 1.270 2010/05/12 14:09:20 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -17,7 +17,7 @@ #define LUA_VERSION "Lua 5.2" -#define LUA_RELEASE "Lua 5.2.0 (work2)" +#define LUA_RELEASE "Lua 5.2.0 (work3)" #define LUA_VERSION_NUM 502 #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2010 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -34,8 +34,7 @@ ** pseudo-indices */ #define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX -#define LUA_ENVIRONINDEX (LUA_REGISTRYINDEX - 1) -#define lua_upvalueindex(i) (LUA_ENVIRONINDEX - (i)) +#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) /* thread status */ @@ -82,6 +81,8 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 +#define LUA_NUMTAGS 9 + /* minimum Lua stack available to a C function */ @@ -90,8 +91,7 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* predefined values in the registry */ #define LUA_RIDX_MAINTHREAD 1 -#define LUA_RIDX_CPCALL 2 -#define LUA_RIDX_GLOBALS 3 +#define LUA_RIDX_GLOBALS 2 #define LUA_RIDX_LAST LUA_RIDX_GLOBALS @@ -129,6 +129,7 @@ LUA_API const lua_Number *(lua_version) (lua_State *L); /* ** basic stack manipulation */ +LUA_API int (lua_absindex) (lua_State *L, int idx); LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); @@ -212,7 +213,7 @@ LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API void (lua_getfenv) (lua_State *L, int idx); +LUA_API void (lua_getenv) (lua_State *L, int idx); /* @@ -223,7 +224,7 @@ LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API int (lua_setfenv) (lua_State *L, int idx); +LUA_API void (lua_setenv) (lua_State *L, int idx); /* @@ -267,6 +268,8 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 #define LUA_GCISRUNNING 8 +#define LUA_GCGEN 9 +#define LUA_GCINC 10 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -297,11 +300,14 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define lua_newtable(L) lua_createtable(L, 0, 0) -#define lua_setglobal(L,s) lua_setfield(L, LUA_ENVIRONINDEX, (s)) -#define lua_getglobal(L,s) lua_getfield(L, LUA_ENVIRONINDEX, (s)) +#define lua_setglobal(L,s) \ + (lua_pushglobaltable(L), lua_pushvalue(L, -2), \ + lua_setfield(L, -2, (s)), lua_pop(L, 2)) + +#define lua_getglobal(L,s) \ + (lua_pushglobaltable(L), lua_getfield(L, -1, (s)), lua_remove(L, -2)) -#define lua_register(L,n,f) \ - (lua_pushcfunction(L, (f)), lua_setfield(L, LUA_ENVIRONINDEX, (n))) +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) diff --git a/src/luac.c b/src/luac.c index 451bfffce1..ee2026ba75 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.57 2008/03/26 13:40:18 lhf Exp $ +** $Id: luac.c,v 1.61 2010/05/14 11:40:22 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -60,7 +60,7 @@ static void usage(const char* message) " -s strip debug information\n" " -v show version information\n" " -- stop handling options\n" - " - process stdin and stop handling options\n" + " - stop handling options and process stdin\n" ,progname,Output); exit(EXIT_FAILURE); } @@ -89,7 +89,7 @@ static int doargs(int argc, char* argv[]) else if (IS("-o")) /* output file */ { output=argv[++i]; - if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument"); + if (output==NULL || *output==0 || *output=='-') usage(LUA_QL("-o") " needs argument"); if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ @@ -150,16 +150,10 @@ static int writer(lua_State* L, const void* p, size_t size, void* u) return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } -struct Smain { - int argc; - char** argv; -}; - static int pmain(lua_State* L) { - struct Smain* s = (struct Smain*)lua_touserdata(L, 1); - int argc=s->argc; - char** argv=s->argv; + int argc=lua_tointeger(L,1); + char** argv=lua_touserdata(L,2); const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); @@ -183,25 +177,18 @@ static int pmain(lua_State* L) return 0; } -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_CPCALL); - lua_pushlightuserdata(L, &func); - lua_pushlightuserdata(L, ud); - return lua_pcall(L, 2, 0, 0); -} - int main(int argc, char* argv[]) { lua_State* L; - struct Smain s; int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); L=luaL_newstate(); if (L==NULL) fatal("not enough memory for state"); - s.argc=argc; - s.argv=argv; - if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); + lua_pushcfunction(L,&pmain); + lua_pushinteger(L,argc); + lua_pushlightuserdata(L,argv); + if (lua_pcall(L,2,0,0)!=0) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; } diff --git a/src/luaconf.h b/src/luaconf.h index b16e99915a..0606230dae 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.130 2010/01/11 17:15:30 roberto Exp $ +** $Id: luaconf.h,v 1.137 2010/05/12 14:17:36 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -89,7 +89,7 @@ #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" -#else +#else /* _WIN32 */ #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/5.2/" #define LUA_CDIR LUA_ROOT "lib/lua/5.2/" @@ -98,7 +98,7 @@ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" -#endif +#endif /* _WIN32 */ /* @@ -130,11 +130,12 @@ #define LUA_API __declspec(dllimport) #endif -#else +#else /* LUA_BUILD_AS_DLL */ #define LUA_API extern -#endif +#endif /* LUA_BUILD_AS_DLL */ + /* more often than not the libs go together with the core */ #define LUALIB_API LUA_API @@ -166,11 +167,11 @@ #define LUAI_DDEC LUAI_FUNC #define LUAI_DDEF /* empty */ -#else +#else /* luaall_c */ #define LUAI_FUNC extern #define LUAI_DDEC extern #define LUAI_DDEF /* empty */ -#endif +#endif /* luaall_c */ @@ -192,10 +193,17 @@ /* @@ luai_writestring defines how 'print' prints its results. -** CHANGE it if your system does not have a useful stdout. */ +#include #define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +/* +@@ luai_writestringerror defines how to print error messages. +** (A format string with one argument is enough for Lua...) +*/ +#define luai_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) + @@ -220,18 +228,12 @@ #define LUA_COMPAT_UNPACK /* -@@ LUA_COMPAT_CPCALL controls the presence of function 'lua_cpcall'. +@@ LUA_COMPAT_CPCALL controls the presence of macro 'lua_cpcall'. ** You can replace it with the preregistered function 'cpcall'. */ -#define LUA_COMPAT_CPCALL -LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +#define lua_cpcall(L,f,u) \ + (lua_pushlightuserdata(L,(u)), luaL_cpcall(L,(f),1,0)) -/* -@@ LUA_COMPAT_FENV controls the presence of functions 'setfenv/getfenv'. -** You can replace them with lexical environments, 'loadin', or the -** debug library. -*/ -#define LUA_COMPAT_FENV /* @@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. @@ -267,7 +269,7 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* compatibility with previous wrong spelling */ #define luaL_typerror luaL_typeerror -#endif +#endif /* LUA_COMPAT_ALL */ /* }================================================================== */ @@ -421,7 +423,7 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* @@ lua_number2int is a macro to convert lua_Number to int. -@@ lua_number2integer is a macro to convert lua_Number to lUA_INTEGER. +@@ lua_number2integer is a macro to convert lua_Number to LUA_INTEGER. @@ lua_number2uint is a macro to convert a lua_Number to an unsigned @* LUA_INT32. @@ lua_uint2number is a macro to convert an unsigned LUA_INT32 @@ -439,30 +441,31 @@ LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); /* On a Microsoft compiler, use assembler */ #if defined(_MSC_VER) -#define lua_number2int(i,d) {__asm fld d __asm fistp i} +#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} #define lua_number2integer(i,n) lua_number2int(i, n) -#define lua_number2uint(i,n) lua_number2int(i, n) +#define lua_number2uint(i,n) \ + {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} -#else +#else /* _MSC_VER */ /* the next trick should work on any Pentium, but sometimes clashes with a DirectX idiosyncrasy */ union luai_Cast { double l_d; long l_l; }; -#define lua_number2int(i,d) \ - { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } +#define lua_number2int(i,n) \ + { volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; (i) = u.l_l; } #define lua_number2integer(i,n) lua_number2int(i, n) #define lua_number2uint(i,n) lua_number2int(i, n) -#endif +#endif /* _MSC_VER */ -#else +#else /* LUA_NUMBER_DOUBLE ... (Pentium) */ /* this option always works, but may be slow */ -#define lua_number2int(i,d) ((i)=(int)(d)) -#define lua_number2integer(i,d) ((i)=(LUA_INTEGER)(d)) -#define lua_number2uint(i,d) ((i)=(unsigned LUA_INT32)(d)) +#define lua_number2int(i,n) ((i)=(int)(n)) +#define lua_number2integer(i,n) ((i)=(LUA_INTEGER)(n)) +#define lua_number2uint(i,n) ((i)=(unsigned LUA_INT32)(n)) -#endif +#endif /* LUA_NUMBER_DOUBLE ... (Pentium) */ /* on several machines, coercion from unsigned to double is too slow, @@ -483,11 +486,11 @@ union luai_Cast { double l_d; long l_l; }; #include #include -#define luai_hashnum(i,d) { int e; \ - d = frexp(d, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ - lua_number2int(i, d); i += e; } +#define luai_hashnum(i,n) { int e; \ + n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ + lua_number2int(i, n); i += e; } -#endif +#endif /* ltable_c */ /* }================================================================== */ diff --git a/src/lundump.c b/src/lundump.c index 244d6e52b6..e82e195115 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.12 2009/09/30 15:38:37 roberto Exp $ +** $Id: lundump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -180,7 +180,6 @@ static Proto* LoadFunction(LoadState* S, TString* p) f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); - f->envreg=LoadByte(S); LoadCode(S,f); LoadConstants(S,f); LoadUpvalues(S,f); diff --git a/src/lvm.c b/src/lvm.c index a315088848..518a16ba0a 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.102 2009/12/17 16:20:01 roberto Exp $ +** $Id: lvm.c,v 2.120 2010/05/13 19:53:05 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -50,8 +50,8 @@ int luaV_tostring (lua_State *L, StkId obj) { else { char s[LUAI_MAXNUMBER2STR]; lua_Number n = nvalue(obj); - lua_number2str(s, n); - setsvalue2s(L, obj, luaS_new(L, s)); + int l = lua_number2str(s, n); + setsvalue2s(L, obj, luaS_newlstr(L, s, l)); return 1; } } @@ -74,6 +74,10 @@ static void traceexec (lua_State *L) { luaD_hook(L, LUA_HOOKLINE, newline); } L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + luaD_throw(L, LUA_YIELD); + } } @@ -102,7 +106,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(res) || /* result is no nil? */ + if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; @@ -129,7 +133,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ - if (!ttisnil(oldval) || /* result is no nil? */ + if (!ttisnil(oldval) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); @@ -157,12 +161,13 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; + if (event == TM_UNM) p2 = luaO_nilobject; callTM(L, tm, p1, p2, res, 1); return 1; } -static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, +static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { const TValue *tm1 = fasttm(L, mt1, event); const TValue *tm2; @@ -178,14 +183,10 @@ static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { - const TValue *tm1 = luaT_gettmbyobj(L, p1, event); - const TValue *tm2; - if (ttisnil(tm1)) return -1; /* no metamethod? */ - tm2 = luaT_gettmbyobj(L, p2, event); - if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ - return -1; - callTM(L, tm1, p1, p2, L->top, 1); - return !l_isfalse(L->top); + if (!call_binTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); } @@ -213,11 +214,9 @@ static int l_strcmp (const TString *ls, const TString *rs) { int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) + if (ttisnumber(l) && ttisnumber(r)) return luai_numlt(L, nvalue(l), nvalue(r)); - else if (ttisstring(l)) + else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; @@ -227,11 +226,9 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) + if (ttisnumber(l) && ttisnumber(r)) return luai_numle(L, nvalue(l), nvalue(r)); - else if (ttisstring(l)) + else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; @@ -249,14 +246,16 @@ int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) { case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TLCF: return fvalue(t1) == fvalue(t2); + case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); + tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; - tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); @@ -354,14 +353,10 @@ void luaV_finishOp (lua_State *L) { StkId base = ci->u.l.base; Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); - if (op == OP_EXTRAARG) { /* extra argument? */ - inst = *(ci->u.l.savedpc - 2); /* get its 'main' instruction */ - op = GET_OPCODE(inst); - } switch (op) { /* finish its execution */ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: - case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { + case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); break; } @@ -402,7 +397,7 @@ void luaV_finishOp (lua_State *L) { L->top = ci->top; /* adjust results */ break; } - case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE: + case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: break; default: lua_assert(0); } @@ -426,11 +421,13 @@ void luaV_finishOp (lua_State *L) { (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) -#define dojump(i) { ci->u.l.savedpc += (i); luai_threadyield(L);} +#define dojump(i) (ci->u.l.savedpc += (i)) #define Protect(x) { {x;}; base = ci->u.l.base; } +#define checkGC(L) Protect(luaC_checkGC(L); luai_threadyield(L);) + #define arith_op(op,tm) { \ TValue *rb = RKB(i); \ @@ -439,133 +436,109 @@ void luaV_finishOp (lua_State *L) { lua_Number nb = nvalue(rb), nc = nvalue(rc); \ setnvalue(ra, op(L, nb, nc)); \ } \ - else \ - Protect(luaV_arith(L, ra, rb, rc, tm)); \ - } + else { Protect(luaV_arith(L, ra, rb, rc, tm)); } } +#define vmdispatch(o) switch(o) +#define vmcase(l,b) case l: {b} break; void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; - LClosure *cl = &clvalue(ci->func)->l; - TValue *k = cl->p->k; - StkId base = ci->u.l.base; + LClosure *cl; + TValue *k; + StkId base; + newframe: /* reentry point when frame changes (call/return) */ lua_assert(isLua(ci)); + lua_assert(ci == L->ci); + cl = &clvalue(ci->func)->l; + k = cl->p->k; + base = ci->u.l.base; /* main loop of interpreter */ for (;;) { Instruction i = *(ci->u.l.savedpc++); StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L); - if (L->status == LUA_YIELD) { /* did hook yield? */ - ci->u.l.savedpc--; /* undo increment */ - luaD_throw(L, LUA_YIELD); - } - base = ci->u.l.base; + Protect(traceexec(L)); } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == ci->u.l.base); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); - switch (GET_OPCODE(i)) { - case OP_MOVE: { + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE, setobjs2s(L, ra, RB(i)); - continue; - } - case OP_LOADK: { + ) + vmcase(OP_LOADK, TValue *rb = KBx(i); setobj2s(L, ra, rb); - continue; - } - case OP_LOADBOOL: { + ) + vmcase(OP_LOADBOOL, setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - continue; - } - case OP_LOADNIL: { + ) + vmcase(OP_LOADNIL, TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); - continue; - } - case OP_GETUPVAL: { + ) + vmcase(OP_GETUPVAL, int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); - continue; - } - case OP_GETGLOBAL: { - TValue g; - TValue *rb = KBx(i); - sethvalue(L, &g, cl->env); - lua_assert(ttisstring(rb)); - Protect(luaV_gettable(L, &g, rb, ra)); - continue; - } - case OP_GETTABLE: { + ) + vmcase(OP_GETTABUP, + int b = GETARG_B(i); + Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra)); + ) + vmcase(OP_GETTABLE, Protect(luaV_gettable(L, RB(i), RKC(i), ra)); - continue; - } - case OP_SETGLOBAL: { - TValue g; - TValue *rb = KBx(i); - sethvalue(L, &g, cl->env); - lua_assert(ttisstring(rb)); - Protect(luaV_settable(L, &g, rb, ra)); - continue; - } - case OP_SETUPVAL: { + ) + vmcase(OP_SETTABUP, + int a = GETARG_A(i); + Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i))); + ) + vmcase(OP_SETUPVAL, UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); - continue; - } - case OP_SETTABLE: { + ) + vmcase(OP_SETTABLE, Protect(luaV_settable(L, ra, RKB(i), RKC(i))); - continue; - } - case OP_NEWTABLE: { + ) + vmcase(OP_NEWTABLE, int b = GETARG_B(i); int c = GETARG_C(i); Table *t = luaH_new(L); sethvalue(L, ra, t); if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - Protect(luaC_checkGC(L)); - continue; - } - case OP_SELF: { + checkGC(L); + ) + vmcase(OP_SELF, StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); - continue; - } - case OP_ADD: { + ) + vmcase(OP_ADD, arith_op(luai_numadd, TM_ADD); - continue; - } - case OP_SUB: { + ) + vmcase(OP_SUB, arith_op(luai_numsub, TM_SUB); - continue; - } - case OP_MUL: { + ) + vmcase(OP_MUL, arith_op(luai_nummul, TM_MUL); - continue; - } - case OP_DIV: { + ) + vmcase(OP_DIV, arith_op(luai_numdiv, TM_DIV); - continue; - } - case OP_MOD: { + ) + vmcase(OP_MOD, arith_op(luai_nummod, TM_MOD); - continue; - } - case OP_POW: { + ) + vmcase(OP_POW, arith_op(luai_numpow, TM_POW); - continue; - } - case OP_UNM: { + ) + vmcase(OP_UNM, TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); @@ -574,31 +547,26 @@ void luaV_execute (lua_State *L) { else { Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); } - continue; - } - case OP_NOT: { + ) + vmcase(OP_NOT, int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); - continue; - } - case OP_LEN: { + ) + vmcase(OP_LEN, Protect(luaV_objlen(L, ra, RB(i))); - continue; - } - case OP_CONCAT: { + ) + vmcase(OP_CONCAT, int b = GETARG_B(i); int c = GETARG_C(i); L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c-b+1); luaC_checkGC(L)); + Protect(luaV_concat(L, c-b+1); checkGC(L);) L->top = ci->top; /* restore top */ setobjs2s(L, RA(i), base+b); - continue; - } - case OP_JMP: { + ) + vmcase(OP_JMP, dojump(GETARG_sBx(i)); - continue; - } - case OP_EQ: { + ) + vmcase(OP_EQ, TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( @@ -606,62 +574,54 @@ void luaV_execute (lua_State *L) { dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_LT: { + ) + vmcase(OP_LT, Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_LE: { + ) + vmcase(OP_LE, Protect( if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_TEST: { + ) + vmcase(OP_TEST, if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ci->u.l.savedpc++; - continue; - } - case OP_TESTSET: { + ) + vmcase(OP_TESTSET, TValue *rb = RB(i); if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) { setobjs2s(L, ra, rb); dojump(GETARG_sBx(*ci->u.l.savedpc)); } ci->u.l.savedpc++; - continue; - } - case OP_CALL: { + ) + vmcase(OP_CALL, int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (luaD_precall(L, ra, nresults)) { /* C function? */ if (nresults >= 0) L->top = ci->top; /* adjust results */ base = ci->u.l.base; - continue; } else { /* Lua function */ ci = L->ci; ci->callstatus |= CIST_REENTRY; - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_TAILCALL: { + ) + vmcase(OP_TAILCALL, int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */ base = ci->u.l.base; - continue; - } else { /* tail call: put called frame (n) in place of caller one (o) */ CallInfo *nci = L->ci; /* called frame */ @@ -682,10 +642,10 @@ void luaV_execute (lua_State *L) { oci->callstatus |= CIST_TAIL; /* function was tail called */ ci = L->ci = oci; /* remove new frame */ lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_RETURN: { + ) + vmcase(OP_RETURN, int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (cl->p->sizep > 0) luaF_close(L, base); @@ -697,10 +657,10 @@ void luaV_execute (lua_State *L) { if (b) L->top = ci->top; lua_assert(isLua(ci)); lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_FORLOOP: { + ) + vmcase(OP_FORLOOP, lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); @@ -710,9 +670,8 @@ void luaV_execute (lua_State *L) { setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } - continue; - } - case OP_FORPREP: { + ) + vmcase(OP_FORPREP, const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; @@ -724,9 +683,8 @@ void luaV_execute (lua_State *L) { luaG_runerror(L, LUA_QL("for") " step must be a number"); setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); dojump(GETARG_sBx(i)); - continue; - } - case OP_TFORCALL: { + ) + vmcase(OP_TFORCALL, StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); @@ -737,16 +695,16 @@ void luaV_execute (lua_State *L) { i = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(i); lua_assert(GET_OPCODE(i) == OP_TFORLOOP); - /* go through */ - } - case OP_TFORLOOP: { + goto l_tforloop; + ) + vmcase(OP_TFORLOOP, + l_tforloop: if (!ttisnil(ra + 1)) { /* continue loop? */ setobjs2s(L, ra, ra + 1); /* save control variable */ dojump(GETARG_sBx(i)); /* jump back */ } - continue; - } - case OP_SETLIST: { + ) + vmcase(OP_SETLIST, int n = GETARG_B(i); int c = GETARG_C(i); int last; @@ -759,45 +717,34 @@ void luaV_execute (lua_State *L) { h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ - luaH_resizearray(L, h, last); /* pre-alloc it at once */ + luaH_resizearray(L, h, last); /* pre-allocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; setobj2t(L, luaH_setint(L, h, last--), val); luaC_barriert(L, h, val); } L->top = ci->top; /* correct top (in case of previous open call) */ - continue; - } - case OP_CLOSE: { + ) + vmcase(OP_CLOSE, luaF_close(L, ra); - continue; - } - case OP_CLOSURE: { + ) + vmcase(OP_CLOSURE, Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */ int nup = p->sizeupvalues; - Closure *ncl = luaF_newLclosure(L, nup, cl->env); + Closure *ncl = luaF_newLclosure(L, nup); Upvaldesc *uv = p->upvalues; int j; ncl->l.p = p; setclvalue(L, ra, ncl); /* anchor new closure in stack */ - if (p->envreg != NO_REG) { /* lexical environment? */ - StkId env = base + p->envreg; - if (!ttistable(env)) - luaG_runerror(L, "environment is not a table: " - "cannot create closure"); - else - ncl->l.env = hvalue(env); - } for (j = 0; j < nup; j++) { /* fill in upvalues */ if (uv[j].instack) /* upvalue refers to local variable? */ ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx); else /* get upvalue from enclosing function */ ncl->l.upvals[j] = cl->upvals[uv[j].idx]; } - Protect(luaC_checkGC(L)); - continue; - } - case OP_VARARG: { + checkGC(L); + ) + vmcase(OP_VARARG, int b = GETARG_B(i) - 1; int j; int n = cast_int(base - ci->func) - cl->p->numparams - 1; @@ -815,18 +762,11 @@ void luaV_execute (lua_State *L) { setnilvalue(ra + j); } } - continue; - } - case OP_EXTRAARG: { - luaG_runerror(L, "bad opcode"); - return; - } + ) + vmcase(OP_EXTRAARG, + lua_assert(0); + ) } - /* function changed (call/return): update pointers */ - lua_assert(ci == L->ci); - cl = &clvalue(ci->func)->l; - k = cl->p->k; - base = ci->u.l.base; } } diff --git a/src/print.c b/src/print.c index fb491e7e88..6a5b05db92 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.58 2008/09/11 12:05:06 lhf Exp $ +** $Id: print.c,v 1.60 2010/05/17 22:27:10 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -82,6 +82,7 @@ static void PrintCode(const Proto* f) int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); + int ax=GETARG_Ax(i); int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); int line=getfuncline(f,pc); @@ -99,24 +100,32 @@ static void PrintCode(const Proto* f) if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); break; case iABx: - if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); + if (getBMode(o)==OpArgK) printf("%d %d",a,-bx); else printf("%d %d",a,bx); break; case iAsBx: if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); break; + case iAx: + printf("%d",ax); + break; } switch (o) { case OP_LOADK: - printf("\t; "); PrintConstant(f,bx); + printf("\t; "); PrintConstant(f,bx-1); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); break; - case OP_GETGLOBAL: - case OP_SETGLOBAL: - printf("\t; %s",svalue(&f->k[bx])); + case OP_GETTABUP: + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABUP: + printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[a].name) : "-"); + if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; case OP_GETTABLE: case OP_SELF: diff --git a/test/ALL.lua b/test/ALL.lua deleted file mode 100644 index 0045fc36a0..0000000000 --- a/test/ALL.lua +++ /dev/null @@ -1,26 +0,0 @@ -function run(x) - print("\n-------------------------------------------------------------") - print(x) - os.execute("../src/lua "..x) - print("DONE",x) -end - -run"bisect.lua" -run"cf.lua" -run"echo.lua jan feb mar apr may jun jul aug sep oct nov dec" -run"env.lua" -run"factorial.lua" -run"fib.lua" -run"fibfor.lua" ---run"globals.lua" -run"hello.lua" -run"luac.lua" -run"printf.lua" -run"readonly.lua" -run"sieve.lua" -run"sort.lua" -run"table.lua" -run"trace-calls.lua" -run"trace-globals.lua" -run"xd.lua < hello.lua" -run"life.lua" diff --git a/test/README b/test/README deleted file mode 100644 index 0c7f38bc25..0000000000 --- a/test/README +++ /dev/null @@ -1,26 +0,0 @@ -These are simple tests for Lua. Some of them contain useful code. -They are meant to be run to make sure Lua is built correctly and also -to be read, to see how Lua programs look. - -Here is a one-line summary of each program: - - bisect.lua bisection method for solving non-linear equations - cf.lua temperature conversion table (celsius to farenheit) - echo.lua echo command line arguments - env.lua environment variables as automatic global variables - factorial.lua factorial without recursion - fib.lua fibonacci function with cache - fibfor.lua fibonacci numbers with coroutines and generators - globals.lua report global variable usage - hello.lua the first program in every language - life.lua Conway's Game of Life - luac.lua bare-bones luac - printf.lua an implementation of printf - readonly.lua make global variables readonly - sieve.lua the sieve of of Eratosthenes programmed with coroutines - sort.lua two implementations of a sort function - table.lua make table, grouping all data for the same item - trace-calls.lua trace calls - trace-globals.lua trace assigments to global variables - xd.lua hex dump - diff --git a/test/bisect.lua b/test/bisect.lua deleted file mode 100644 index f91e69bfba..0000000000 --- a/test/bisect.lua +++ /dev/null @@ -1,27 +0,0 @@ --- bisection method for solving non-linear equations - -delta=1e-6 -- tolerance - -function bisect(f,a,b,fa,fb) - local c=(a+b)/2 - io.write(n," c=",c," a=",a," b=",b,"\n") - if c==a or c==b or math.abs(a-b) posted to lua-l --- modified to use ANSI terminal escape sequences --- modified to use for instead of while - -local write=io.write - -ALIVE="¥" DEAD="þ" -ALIVE="O" DEAD="-" - -function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary - for i=1,10000 do end - -- local i=os.clock()+1 while(os.clock() 0 do - local xm1,x,xp1,xi=self.w-1,self.w,1,self.w - while xi > 0 do - local sum = self[ym1][xm1] + self[ym1][x] + self[ym1][xp1] + - self[y][xm1] + self[y][xp1] + - self[yp1][xm1] + self[yp1][x] + self[yp1][xp1] - next[y][x] = ((sum==2) and self[y][x]) or ((sum==3) and 1) or 0 - xm1,x,xp1,xi = x,xp1,xp1+1,xi-1 - end - ym1,y,yp1,yi = y,yp1,yp1+1,yi-1 - end -end - --- output the array to screen -function _CELLS:draw() - local out="" -- accumulate to reduce flicker - for y=1,self.h do - for x=1,self.w do - out=out..(((self[y][x]>0) and ALIVE) or DEAD) - end - out=out.."\n" - end - write(out) -end - --- constructor -function CELLS(w,h) - local c = ARRAY2D(w,h) - c.spawn = _CELLS.spawn - c.evolve = _CELLS.evolve - c.draw = _CELLS.draw - return c -end - --- --- shapes suitable for use with spawn() above --- -HEART = { 1,0,1,1,0,1,1,1,1; w=3,h=3 } -GLIDER = { 0,0,1,1,0,1,0,1,1; w=3,h=3 } -EXPLODE = { 0,1,0,1,1,1,1,0,1,0,1,0; w=3,h=4 } -FISH = { 0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0; w=5,h=4 } -BUTTERFLY = { 1,0,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1; w=5,h=5 } - --- the main routine -function LIFE(w,h) - -- create two arrays - local thisgen = CELLS(w,h) - local nextgen = CELLS(w,h) - - -- create some life - -- about 1000 generations of fun, then a glider steady-state - thisgen:spawn(GLIDER,5,4) - thisgen:spawn(EXPLODE,25,10) - thisgen:spawn(FISH,4,12) - - -- run until break - local gen=1 - write("\027[2J") -- ANSI clear screen - while 1 do - thisgen:evolve(nextgen) - thisgen,nextgen = nextgen,thisgen - write("\027[H") -- ANSI home cursor - thisgen:draw() - write("Life - generation ",gen,"\n") - gen=gen+1 - if gen>2000 then break end - --delay() -- no delay - end -end - -LIFE(40,20) diff --git a/test/luac.lua b/test/luac.lua deleted file mode 100644 index 96a0a97ce7..0000000000 --- a/test/luac.lua +++ /dev/null @@ -1,7 +0,0 @@ --- bare-bones luac in Lua --- usage: lua luac.lua file.lua - -assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") -f=assert(io.open("luac.out","wb")) -assert(f:write(string.dump(assert(loadfile(arg[1]))))) -assert(f:close()) diff --git a/test/printf.lua b/test/printf.lua deleted file mode 100644 index 58c63ff518..0000000000 --- a/test/printf.lua +++ /dev/null @@ -1,7 +0,0 @@ --- an implementation of printf - -function printf(...) - io.write(string.format(...)) -end - -printf("Hello %s from %s on %s\n",os.getenv"USER" or "there",_VERSION,os.date()) diff --git a/test/readonly.lua b/test/readonly.lua deleted file mode 100644 index 85c0b4e013..0000000000 --- a/test/readonly.lua +++ /dev/null @@ -1,12 +0,0 @@ --- make global variables readonly - -local f=function (t,i) error("cannot redefine global variable `"..i.."'",2) end -local g={} -local G=getfenv() -setmetatable(g,{__index=G,__newindex=f}) -setfenv(1,g) - --- an example -rawset(g,"x",3) -x=2 -y=1 -- cannot redefine `y' diff --git a/test/sieve.lua b/test/sieve.lua deleted file mode 100644 index e27c1a20dd..0000000000 --- a/test/sieve.lua +++ /dev/null @@ -1,29 +0,0 @@ --- the sieve of of Eratosthenes programmed with coroutines --- typical usage: lua -e N=1000 sieve.lua | column - --- generate all the numbers from 2 to n -function gen (n) - return coroutine.wrap(function () - for i=2,n do coroutine.yield(i) end - end) -end - --- filter the numbers generated by `g', removing multiples of `p' -function filter (p, g) - return coroutine.wrap(function () - while 1 do - local n = g() - if n == nil then return end - if n % p ~= 0 then coroutine.yield(n) end - end - end) -end - -N=N or 1000 -- from command line -x = gen(N) -- generate primes up to N -while 1 do - local n = x() -- pick a number until done - if n == nil then break end - print(n) -- must be a prime number - x = filter(n, x) -- now remove its multiples -end diff --git a/test/sort.lua b/test/sort.lua deleted file mode 100644 index 0bcb15f837..0000000000 --- a/test/sort.lua +++ /dev/null @@ -1,66 +0,0 @@ --- two implementations of a sort function --- this is an example only. Lua has now a built-in function "sort" - --- extracted from Programming Pearls, page 110 -function qsort(x,l,u,f) - if ly end) - show("after reverse selection sort",x) - qsort(x,1,n,function (x,y) return x>> ",string.rep(" ",level)) - if t~=nil and t.currentline>=0 then io.write(t.short_src,":",t.currentline," ") end - t=debug.getinfo(2) - if event=="call" then - level=level+1 - else - level=level-1 if level<0 then level=0 end - end - if t.what=="main" then - if event=="call" then - io.write("begin ",t.short_src) - else - io.write("end ",t.short_src) - end - elseif t.what=="Lua" then --- table.foreach(t,print) - io.write(event," ",t.name or "(Lua)"," <",t.linedefined,":",t.short_src,">") - else - io.write(event," ",t.name or "(C)"," [",t.what,"] ") - end - io.write("\n") -end - -debug.sethook(hook,"cr") -level=0 diff --git a/test/trace-globals.lua b/test/trace-globals.lua deleted file mode 100644 index 295e670caa..0000000000 --- a/test/trace-globals.lua +++ /dev/null @@ -1,38 +0,0 @@ --- trace assigments to global variables - -do - -- a tostring that quotes strings. note the use of the original tostring. - local _tostring=tostring - local tostring=function(a) - if type(a)=="string" then - return string.format("%q",a) - else - return _tostring(a) - end - end - - local log=function (name,old,new) - local t=debug.getinfo(3,"Sl") - local line=t.currentline - io.write(t.short_src) - if line>=0 then io.write(":",line) end - io.write(": ",name," is now ",tostring(new)," (was ",tostring(old),")","\n") - end - - local g={} - local set=function (t,name,value) - log(name,g[name],value) - g[name]=value - end - setmetatable(getfenv(),{__index=g,__newindex=set}) -end - --- an example - -a=1 -b=2 -a=10 -b=20 -b=nil -b=200 -print(a,b,c) diff --git a/test/xd.lua b/test/xd.lua deleted file mode 100644 index 8b420394d0..0000000000 --- a/test/xd.lua +++ /dev/null @@ -1,15 +0,0 @@ --- hex dump --- usage: lua xd.lua < file - -local N=16 -local offset=0 -while true do - local s=io.read(N) - if s==nil then return end - io.write(string.format("%08X ",offset)) - string.gsub(s,"(.)", - function (c) io.write(string.format("%02X ",string.byte(c))) end) - io.write(string.rep(" ",3*(N-string.len(s)))) - io.write(" ",string.gsub(s,"%c","."),"\n") - offset=offset+N -end From 90ac6291217c36341e777586e49968d4a914a32a Mon Sep 17 00:00:00 2001 From: Lua Team Date: Sat, 31 Jul 2010 12:00:00 +0000 Subject: [PATCH 51/97] Lua 5.2.0-work4 --- Makefile | 79 +++----- README | 4 +- doc/contents.html | 189 ++++++++--------- doc/external.png | Bin 165 -> 0 bytes doc/lua.css | 18 ++ doc/manual.css | 7 + doc/manual.html | 501 +++++++++++++++++++++++++++------------------- doc/readme.html | 184 ++++++++--------- etc/Makefile | 62 ------ etc/README | 30 --- etc/dummy.c | 11 - etc/luavs.bat | 28 --- etc/min.c | 33 --- etc/noparser.c | 70 ------- etc/one.c | 73 ------- etc/strict.lua | 42 ---- src/Makefile | 84 ++++---- src/lapi.c | 33 +-- src/lauxlib.c | 222 ++++++++++++++------ src/lauxlib.h | 23 ++- src/lbaselib.c | 163 +-------------- src/lbitlib.c | 9 +- src/lcode.c | 101 +++++----- src/lcode.h | 4 +- src/lcorolib.c | 154 ++++++++++++++ src/ldblib.c | 46 +++-- src/ldebug.c | 23 ++- src/ldo.c | 5 +- src/lfunc.c | 10 +- src/lfunc.h | 4 +- src/lgc.c | 49 ++++- src/lgc.h | 24 ++- src/linit.c | 24 +-- src/liolib.c | 15 +- src/llimits.h | 10 +- src/lmathlib.c | 4 +- src/loadlib.c | 166 +++++---------- src/lobject.h | 71 ++++--- src/loslib.c | 11 +- src/lparser.c | 60 +++--- src/lparser.h | 19 +- src/lstrlib.c | 5 +- src/ltable.c | 16 +- src/ltable.h | 4 +- src/ltablib.c | 4 +- src/lua.c | 43 ++-- src/lua.h | 21 +- src/luaconf.h | 72 ++++--- src/lualib.h | 6 +- src/lvm.c | 72 +++++-- src/print.c | 10 +- 51 files changed, 1425 insertions(+), 1493 deletions(-) delete mode 100644 doc/external.png delete mode 100644 etc/Makefile delete mode 100644 etc/README delete mode 100644 etc/dummy.c delete mode 100644 etc/luavs.bat delete mode 100644 etc/min.c delete mode 100644 etc/noparser.c delete mode 100644 etc/one.c delete mode 100644 etc/strict.lua create mode 100644 src/lcorolib.c diff --git a/Makefile b/Makefile index db263e6615..cbc945d719 100644 --- a/Makefile +++ b/Makefile @@ -7,21 +7,19 @@ PLAT= none # Where to install. The installation starts in the src and doc directories, -# so take care if INSTALL_TOP is not an absolute path. +# so take care if INSTALL_TOP is not an absolute path. See the local target. +# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with +# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h. INSTALL_TOP= /usr/local INSTALL_BIN= $(INSTALL_TOP)/bin INSTALL_INC= $(INSTALL_TOP)/include INSTALL_LIB= $(INSTALL_TOP)/lib INSTALL_MAN= $(INSTALL_TOP)/man/man1 -# -# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with -# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h. INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V -# How to install. -# If your install program does not support "-p", then you may have to run -# ranlib on the installed liblua.a. +# How to install. If your install program does not support "-p", then +# you may have to run ranlib on the installed liblua.a. INSTALL= install -p INSTALL_EXEC= $(INSTALL) -m 0755 INSTALL_DATA= $(INSTALL) -m 0644 @@ -31,7 +29,7 @@ INSTALL_DATA= $(INSTALL) -m 0644 # INSTALL_EXEC= $(INSTALL) # INSTALL_DATA= $(INSTALL) -# Utilities. +# Other utilities. MKDIR= mkdir -p RM= rm -f @@ -50,6 +48,7 @@ TO_MAN= lua.1 luac.1 V= 5.2 R= $V.0 +# Targets start here. all: $(PLAT) $(PLATS) clean: @@ -75,9 +74,7 @@ local: $(MAKE) install INSTALL_TOP=../install none: - @echo "Please do" - @echo " make PLATFORM" - @echo "where PLATFORM is one of these:" + @echo "Please do 'make PLATFORM' where PLATFORM is one of these:" @echo " $(PLATS)" @echo "See doc/readme.html for complete instructions." @@ -86,44 +83,30 @@ dummy: # echo config parameters echo: - @echo "" - @echo "These are the parameters currently set in src/Makefile to build Lua $R:" - @echo "" @cd src && $(MAKE) -s echo - @echo "" - @echo "These are the parameters currently set in Makefile to install Lua $R:" - @echo "" - @echo "PLAT = $(PLAT)" - @echo "INSTALL_TOP = $(INSTALL_TOP)" - @echo "INSTALL_BIN = $(INSTALL_BIN)" - @echo "INSTALL_INC = $(INSTALL_INC)" - @echo "INSTALL_LIB = $(INSTALL_LIB)" - @echo "INSTALL_MAN = $(INSTALL_MAN)" - @echo "INSTALL_LMOD = $(INSTALL_LMOD)" - @echo "INSTALL_CMOD = $(INSTALL_CMOD)" - @echo "INSTALL_EXEC = $(INSTALL_EXEC)" - @echo "INSTALL_DATA = $(INSTALL_DATA)" - @echo "" - @echo "See also src/luaconf.h ." - @echo "" - -# echo private config parameters -pecho: - @echo "V = $V" - @echo "R = $R" - @echo "TO_BIN = $(TO_BIN)" - @echo "TO_INC = $(TO_INC)" - @echo "TO_LIB = $(TO_LIB)" - @echo "TO_MAN = $(TO_MAN)" - -# echo config parameters as Lua code -# uncomment the last sed expression if you want nil instead of empty strings -lecho: - @echo "-- installation parameters for Lua $R" - @echo "VERSION = '$V'" - @echo "RELEASE = '$R'" - @$(MAKE) echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' - @echo "-- EOF" + @echo "PLAT= $(PLAT)" + @echo "V= $V" + @echo "R= $R" + @echo "TO_BIN= $(TO_BIN)" + @echo "TO_INC= $(TO_INC)" + @echo "TO_LIB= $(TO_LIB)" + @echo "TO_MAN= $(TO_MAN)" + @echo "INSTALL_TOP= $(INSTALL_TOP)" + @echo "INSTALL_BIN= $(INSTALL_BIN)" + @echo "INSTALL_INC= $(INSTALL_INC)" + @echo "INSTALL_LIB= $(INSTALL_LIB)" + @echo "INSTALL_MAN= $(INSTALL_MAN)" + @echo "INSTALL_LMOD= $(INSTALL_LMOD)" + @echo "INSTALL_CMOD= $(INSTALL_CMOD)" + @echo "INSTALL_EXEC= $(INSTALL_EXEC)" + @echo "INSTALL_DATA= $(INSTALL_DATA)" + +# echo pkg-config data +pc: + @echo "version=$R" + @echo "prefix=$(INSTALL_TOP)" + @echo "libdir=$(INSTALL_LIB)" + @echo "includedir=$(INSTALL_INC)" # list targets that do not create files (but not all makes understand .PHONY) .PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho diff --git a/README b/README index 9153023082..78c839657d 100644 --- a/README +++ b/README @@ -1,4 +1,6 @@ -This is Lua 5.2 (work3), released on 18 May 2010. + +This is Lua 5.2 (work4), released on 30 July 2010. For information about Lua, including installation instructions and license details, see doc/readme.html. + diff --git a/doc/contents.html b/doc/contents.html index b9ae234019..397c6566af 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -20,16 +20,17 @@

    Lua 5.2 Reference Manual

    - +

    +[!] This is a work version of Lua 5.2. Everything may change in the final version. -

    +

    The reference manual is the official definition of the Lua language. For a complete introduction to Lua programming, see the book Programming in Lua. -

    +

    start · contents @@ -41,101 +42,100 @@

    Freely available under the terms of the Lua license. -

    Contents

    Index

    @@ -143,6 +143,7 @@

    Index

  • Lua functions

    +

    _G
    _VERSION
    assert
    @@ -150,11 +151,11 @@

    Lua functions

    dofile
    error
    getmetatable
    +ipairs
    load
    -loadin
    loadfile
    +loadin
    loadstring
    -module
    next
    pairs
    pcall
    @@ -169,8 +170,8 @@

    Lua functions

    tostring
    type
    xpcall
    -

    +

    bit.band
    bit.bnot
    bit.bor
    @@ -180,25 +181,25 @@

    Lua functions

    bit.rol
    bit.ror
    bit.rshift
    -

    +

    coroutine.create
    coroutine.resume
    coroutine.running
    coroutine.status
    coroutine.wrap
    coroutine.yield
    -

    +

    debug.debug
    -debug.getfenv
    +debug.getuservalue
    debug.gethook
    debug.getinfo
    debug.getlocal
    debug.getmetatable
    debug.getregistry
    debug.getupvalue
    -debug.setfenv
    +debug.setuservalue
    debug.sethook
    debug.setlocal
    debug.setmetatable
    @@ -206,8 +207,8 @@

    Lua functions

    debug.traceback
    debug.upvalueid
    debug.upvaluejoin
    -

    +

    file:close
    file:flush
    file:lines
    @@ -215,8 +216,8 @@

    Lua functions

    file:seek
    file:setvbuf
    file:write
    -

    +

    io.close
    io.flush
    io.input
    @@ -231,11 +232,11 @@

    Lua functions

    io.tmpfile
    io.type
    io.write
    -

     

    +

    math.abs
    math.acos
    math.asin
    @@ -265,8 +266,8 @@

     

    math.sqrt
    math.tan
    math.tanh
    -

    +

    os.clock
    os.date
    os.difftime
    @@ -278,8 +279,8 @@

     

    os.setlocale
    os.time
    os.tmpname
    -

    +

    package.config
    package.cpath
    package.loaded
    @@ -288,9 +289,8 @@

     

    package.path
    package.preload
    package.searchpath
    -package.seeall
    -

    +

    string.byte
    string.char
    string.dump
    @@ -305,8 +305,8 @@

     

    string.reverse
    string.sub
    string.upper
    -

    +

    table.concat
    table.insert
    table.pack
    @@ -317,6 +317,7 @@

     

    C API

    +

    lua_Alloc
    lua_CFunction
    lua_Debug
    @@ -326,9 +327,10 @@

    C API

    lua_Reader
    lua_State
    lua_Writer
    -

    +

    lua_absindex
    +lua_arith
    lua_atpanic
    lua_call
    lua_callk
    @@ -343,7 +345,6 @@

    C API

    lua_gc
    lua_getallocf
    lua_getctx
    -lua_getfenv
    lua_getfield
    lua_getglobal
    lua_gethook
    @@ -356,6 +357,7 @@

    C API

    lua_gettable
    lua_gettop
    lua_getupvalue
    +lua_getuservalue
    lua_insert
    lua_isboolean
    lua_iscfunction
    @@ -404,7 +406,6 @@

    C API

    lua_replace
    lua_resume
    lua_setallocf
    -lua_setfenv
    lua_setfield
    lua_setglobal
    lua_sethook
    @@ -413,12 +414,15 @@

    C API

    lua_settable
    lua_settop
    lua_setupvalue
    +lua_setuservalue
    lua_status
    lua_toboolean
    lua_tocfunction
    lua_tointeger
    +lua_tointegerx
    lua_tolstring
    lua_tonumber
    +lua_tonumberx
    lua_topointer
    lua_tostring
    lua_tothread
    @@ -436,10 +440,11 @@

    C API

    auxiliary library

    +

    luaL_Buffer
    luaL_Reg
    -

    +

    luaL_addchar
    luaL_addlstring
    luaL_addsize
    @@ -471,9 +476,10 @@

    auxiliary library

    luaL_loadbuffer
    luaL_loadfile
    luaL_loadstring
    +luaL_newlib
    luaL_newmetatable
    luaL_newstate
    -luaL_openlib
    +luaL_setfuncs
    luaL_openlibs
    luaL_optint
    luaL_optinteger
    @@ -484,27 +490,26 @@

    auxiliary library

    luaL_prepbuffer
    luaL_pushresult
    luaL_ref
    -luaL_register
    +luaL_requiref
    luaL_testudata
    luaL_tolstring
    luaL_traceback
    -luaL_typeerror
    luaL_typename
    +luaL_typeerror
    luaL_unref
    luaL_where
    -


    Last update: -Mon May 17 16:58:54 BRT 2010 +Fri Jul 30 15:13:14 BRT 2010 diff --git a/doc/external.png b/doc/external.png deleted file mode 100644 index 419c06fb960b0b665791c90044a78621616a4cb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2VGmzZ%#=aj&i3a$DxTeiKV?6WB%rpNP(#|lX z{f7XTR~%D;3fN16{DL7O3{u|AZa^UmPZ!4!iE!1^jzSC$EX7 z>#2$@InOtpuqyg8<+R}9g-+|v&13&5`dCp`{|95_8^+nQkC>(b&0z3!^>bP0l+XkK DO07OF diff --git a/doc/lua.css b/doc/lua.css index 40041a478c..b9d3cca937 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -12,6 +12,24 @@ h1, h2, h3, h4 { font-style: italic ; } +h2 { + padding-top: 0.4em ; + padding-bottom: 0.4em ; + padding-left: 20px ; + margin-left: -20px ; + background-color: #E0E0FF ; +} + +h3 { + padding-left: 8px ; + border-left: solid #E0E0FF 1em ; +} + +table h3 { + padding-left: 0px ; + border-left: none ; +} + a:link { color: #000080 ; background-color: inherit ; diff --git a/doc/manual.css b/doc/manual.css index eed5afd9ee..6d5a3f09b5 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -11,3 +11,10 @@ span.apii { font-family: inherit ; } +p+h1, ul+h1 { + padding-top: 0.4em ; + padding-bottom: 0.4em ; + padding-left: 20px ; + margin-left: -20px ; + background-color: #E0E0FF ; +} diff --git a/doc/manual.html b/doc/manual.html index aed41ceb32..d5220c1150 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -16,7 +16,7 @@

    Lua 5.2 Reference Manual

    - +[!] This is a work version of Lua 5.2. Everything may change in the final version.

    @@ -38,7 +38,7 @@

    - + @@ -212,7 +212,7 @@

    2.2 - Environments and the Global Environment

    any reference to a global name var is syntactically translated to _ENV.var. Moreover, any chunk is compiled in the scope of an external -variable called _ENV (see §3.3.1). +variable called _ENV (see §3.3.2). Any table used as the value of _ENV is usually called an environment. @@ -971,6 +971,12 @@

    2.6 - Coroutines

    main false cannot resume dead coroutine +

    +You can also create and manipulate coroutines through the C API: +see functions lua_newthread, lua_resume, +and lua_yield. + + @@ -1231,25 +1237,51 @@

    3.3 - Statements

    -

    3.3.1 - Chunks

    +

    3.3.1 - Blocks

    -The unit of execution of Lua is called a chunk. -A chunk is simply a sequence of statements, -which are executed sequentially. +A block is a list of statements, +which are executed sequentially:

    -	chunk ::= {stat }
    +	block ::= {stat}
     

    Lua has empty statements that allow you to separate statements with semicolons, -start a chunk with a semicolon +start a block with a semicolon or write two semicolons in sequence:

     	stat ::= &lsquo;
    +

    +A block can be explicitly delimited to produce a single statement: + +

    +	stat ::= do block end
    +

    +Explicit blocks are useful +to control the scope of variable declarations. +Explicit blocks are also sometimes used to +add a return or break statement in the middle +of another block (see §3.3.4). + + + + + +

    3.3.2 - Chunks

    + +

    +The unit of execution of Lua is called a chunk. +Syntactically, +a chunk is simply a block: + +

    +	chunk ::= block
    +
    +

    Lua handles a chunk as the body of an anonymous function with a variable number of arguments @@ -1279,30 +1311,6 @@

    3.3.1 - Chunks

    -

    3.3.2 - Blocks

    -A block is a list of statements; -syntactically, a block is the same as a chunk: - -

    -	block ::= chunk
    -
    - -

    -A block can be explicitly delimited to produce a single statement: - -

    -	stat ::= do block end
    -

    -Explicit blocks are useful -to control the scope of variable declarations. -Explicit blocks are also sometimes used to -add a return or break statement in the middle -of another block (see §3.3.4). - - - - -

    3.3.3 - Assignment

    @@ -1608,7 +1616,7 @@

    3.3.7 - Local Declarations

    -A chunk is also a block (see §3.3.1), +A chunk is also a block (see §3.3.2), and so local variables can be declared in a chunk outside any explicit block. The scope of such local variables extends until the end of the chunk. @@ -1713,7 +1721,7 @@

    3.4.1 - Arithmetic Operators

    the binary + (addition), - (subtraction), * (multiplication), / (division), % (modulo), and ^ (exponentiation); -and unary - (negation). +and unary - (mathematical negation). If the operands are numbers, or strings that can be converted to numbers (see §3.4.2), then all operations have the usual meaning. @@ -1762,12 +1770,15 @@

    3.4.3 - Relational Operators

    If the types are different, then the result is false. Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. -Objects (tables, userdata, threads, and functions) +Tables, userdata, and threads are compared by reference: two objects are considered equal only if they are the same object. Every time you create a new object -(a table, userdata, thread, or function), +(a table, userdata, or thread), this new object is different from any previously existing object. +Closures with the same reference are always equal. +Closures with any detectable difference +(different behavior, different definition) are always different.

    @@ -1860,10 +1871,10 @@

    3.4.6 - The Length Operator

    -The length of a table t is defined to be any -integer index n +The length of a table t can be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. +(All accesses are assumed to be raw for this description.) For a regular array, where all non-nil values have keys from 1 to a given n, its length is exactly that n, @@ -2112,8 +2123,7 @@

    3.4.10 - Function Definitions

    This function instance (or closure) is the final value of the expression. Different instances of the same function -can refer to different external local variables -and can have different environment tables. +can refer to different external local variables.

    @@ -2601,7 +2611,7 @@

    4.8 - Functions and Types


    lua_absindex

    [-0, +0, -] -

    void lua_absindex (lua_State *L, int idx);
    +
    int lua_absindex (lua_State *L, int idx);

    Converts the acceptable index idx into an absolute index @@ -2699,6 +2709,41 @@

    4.8 - Functions and Types

    +

    lua_arith

    +[-2, +1, e] +

    int lua_arith (lua_State *L, int op);
    + +

    +Performs an arithmetic operation over the two values at the top +of the stack (with the value at the top being the second operand), +pops these values, and pushes the result of the operation. +The function follows the semantics of the corresponding Lua operator +(that is, it may call metamethods). + + +

    +The value of op must be one of the following constants: + +

    + +

    +When the operation is LUA_OPUNM, +the caller must push a nil value for the second operand. + + + + +


    lua_atpanic

    [-0, +0, -]

    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
    @@ -2886,7 +2931,7 @@

    4.8 - Functions and Types

    Returns 1 if the value at acceptable index index1 satisfies op when compared with the value at acceptable index index2, following the semantics of the corresponding Lua operator -(that is, may call metamethods). +(that is, it may call metamethods). Otherwise returns 0. Also returns 0 if any of the indices is non valid. @@ -2896,9 +2941,9 @@

    4.8 - Functions and Types

    @@ -3113,13 +3158,14 @@

    4.8 - Functions and Types

    -

    lua_getfenv

    +


    lua_getuservalue

    [-0, +1, -] -

    void lua_getfenv (lua_State *L, int index);
    +
    void lua_getuservalue (lua_State *L, int index);

    -Pushes onto the stack the environment table of -the value at the given index. +Pushes onto the stack the Lua value associated with the userdata +at the given index. +This Lua value must be a table or nil. @@ -4155,16 +4201,15 @@

    4.8 - Functions and Types

    -

    lua_setfenv

    +


    lua_setuservalue

    [-1, +0, -] -

    int lua_setfenv (lua_State *L, int index);
    +
    int lua_setuservalue (lua_State *L, int index);

    -Pops a table from the stack and sets it as -the new environment for the value at the given index. -If the value at the given index is -neither a function nor a userdata, -lua_setfenv returns 0. +Pops a table or nil from the stack and sets it as +the new value associated to the userdata at the given index. +If the value at the given index is not a userdata, +lua_setuservalue returns 0. Otherwise it returns 1. @@ -4255,7 +4300,7 @@

    4.8 - Functions and Types

    typedef struct lua_State lua_State;

    -Opaque structure that keeps the whole state of a Lua interpreter. +An opaque structure that keeps the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. All information about a state is kept in this structure. @@ -4285,6 +4330,13 @@

    4.8 - Functions and Types

    or LUA_YIELD if the thread is suspended. +

    +You can only call functions in threads with status LUA_OK. +You can resume threads with status LUA_OK +(to start a new coroutine) or LUA_YIELD +(to resume a corotine). + + @@ -4324,12 +4376,23 @@

    4.8 - Functions and Types

    [-0, +0, -]
    lua_Integer lua_tointeger (lua_State *L, int index);
    +

    +A macro equivalent to lua_tointegerx(L, index, NULL). + + + + + +


    lua_tointegerx

    +[-0, +0, -] +

    lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);
    +

    Converts the Lua value at the given acceptable index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §3.4.2); -otherwise, lua_tointeger returns 0. +otherwise, lua_tointegerx returns 0.

    @@ -4337,6 +4400,12 @@

    4.8 - Functions and Types

    it is truncated in some non-specified way. +

    +If isnum is different from NULL, +its referent is assigned a boolean value that +indicates whether the operation succeeded. + + @@ -4375,12 +4444,29 @@

    4.8 - Functions and Types

    [-0, +0, -]
    lua_Number lua_tonumber (lua_State *L, int index);
    +

    +A macro equivalent to lua_tonumberx(L, index, NULL). + + + + + +


    lua_tonumberx

    +[-0, +0, -] +

    lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);
    +

    Converts the Lua value at the given acceptable index to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number (see §3.4.2); -otherwise, lua_tonumber returns 0. +otherwise, lua_tonumberx returns 0. + + +

    +If isnum is different from NULL, +its referent is assigned a boolean value that +indicates whether the operation succeeded. @@ -4628,7 +4714,7 @@

    4.9 - The Debug Interface

    A structure used to carry different pieces of -information about an active function. +information about a function or an activation record. lua_getstack fills only the private part of this structure, for later use. To fill the other fields of lua_Debug with useful information, @@ -4836,8 +4922,13 @@

    4.9 - The Debug Interface

    const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);

    -Gets information about a local variable of a given activation record. -The parameter ar must be a valid activation record that was +Gets information about a local variable of +a given activation record or a given function. + + +

    +In the first case, +the parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook). The index n selects which local variable to inspect @@ -4853,6 +4944,14 @@

    4.9 - The Debug Interface

    (loop control variables, temporaries, and C function locals). +

    +In the second case, ar should be NULL and the function +to be inspected must be at the top of the stack. +In this case, only parameters of Lua functions are visible +(as there is no information about what variables are active) +and no values are pushed onto the stack. + +

    Returns NULL (and pushes nothing) when the index is greater than @@ -5697,6 +5796,29 @@

    5.1 - Functions and Types

    +

    luaL_newlib

    +[-0, +1, m] +

    int luaL_newlib (lua_State *L, const luaL_Reg *l);
    + +

    +Equivalent to luaL_setfuncs with no upvalues, +but first creates a new table wherein to register the functions +in list l. + + +

    +Leaves the new table on the stack. + + +

    +It is implemented as a macro. +The array l must be the actual array, +not a pointer to it. + + + + +


    luaL_newmetatable

    [-0, +1, m]

    int luaL_newmetatable (lua_State *L, const char *tname);
    @@ -5739,46 +5861,23 @@

    5.1 - Functions and Types

    -

    luaL_openlib

    -[-(nup + (0|1)), +1, e] -

    void luaL_openlib (lua_State *L,
    -                             const char *libname,
    -                             const luaL_Reg *l,
    -                             int nup);
    - -

    -Opens a library. - +


    luaL_setfuncs

    +[-nup, +0, e] +

    void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);

    -When called with libname equal to NULL, -it simply registers all functions in the array l -(see luaL_Reg) into the table on the top of the stack. +Registers all functions in the array l +(see luaL_Reg) into the table on the top of the stack +(below optional upvalues, see next). The pointer l may be NULL, representing an empty list. -

    -When called with a non-null libname, -luaL_openlib creates a new table t, -sets it as the value of the global variable libname, -sets it as the value of package.loaded[libname], -and registers on it all functions in the list l. -If there is a table in package.loaded[libname] or -in global variable libname, -reuses this table instead of creating a new one. - - -

    -In any case the function leaves the table -on the top of the stack. - -

    When nup is not zero, all functions are created sharing nup upvalues, which must be previously pushed on the stack -(on top of the library table, if present). +on top of the library table. These values are popped from the stack after the registration. @@ -5963,7 +6062,7 @@

    5.1 - Functions and Types

    Type for arrays of functions to be registered by -luaL_openlib. +luaL_setfuncs. name is the function name and func is a pointer to the function. Any array of luaL_Reg must end with an sentinel entry @@ -5973,15 +6072,24 @@

    5.1 - Functions and Types

    -

    luaL_register

    -[-(0|1), +1, m] -

    void luaL_register (lua_State *L,
    -                    const char *libname,
    -                    const luaL_Reg *l);
    +

    luaL_requiref

    +[-0, +1, e] +

    void luaL_requiref (lua_State *L, const char *modname,
    +                              lua_CFunction openf, int glb);
    + +

    +Calls function openf with string modname as an argument +and sets the call result in package.loaded[modname], +as if that function has been called through require. + + +

    +If glb is true, +also stores the result into global modname. +

    -This macro is equivalent to calling luaL_openlib -with no upvalues. +Leaves a copy of that result on the stack. @@ -6134,10 +6242,12 @@

    6 - Standard Libraries

      -
    • basic library, which includes the coroutine sub-library;
    • +
    • basic library;
    • package library;
    • +
    • coroutine library;
    • +
    • string manipulation;
    • table manipulation;
    • @@ -6166,6 +6276,7 @@

      6 - Standard Libraries

      it can open them individually by calling luaopen_base (for the basic library), luaopen_package (for the package library), +luaopen_coroutine (for the coroutine library), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), @@ -6323,6 +6434,30 @@

      6.1 - Basic Functions

      +

      +


      ipairs (t)

      + + +

      +If t has a metamethod __ipairs, +calls it with t as argument and returns the first three +results from the call. + + +

      +Otherwise, +returns three values: an iterator function, the table t, and 0, +so that the construction + +

      +     for i,v in ipairs(t) do body end
      +

      +will iterate over the pairs (1,t[1]), (2,t[2]), ···, +up to the first integer key absent from the table. + + + +


      load (ld [, source [, mode]])

      @@ -6776,61 +6911,12 @@

      6.3 - Modules

      The package library provides basic -facilities for loading and building modules in Lua. -It exports two of its functions directly in the global environment: -require and module. +facilities for loading modules in Lua. +It exports one function directly in the global environment: +require. Everything else is exported in a table package. -

      -


      module (name [, ···])

      - - -

      -Creates and returns a module. -If there is a table in package.loaded[name], -this table is the module. -Otherwise, if there is a global table t with the given name, -this table is the module. -Otherwise creates a new table t and -sets it as the value of the global name and -the value of package.loaded[name]. -This function also initializes t._NAME with the given name, -t._M with the module (t itself), -and t._PACKAGE with the package name -(the full module name minus last component; see below). -Finally, module sets t as the new value of package.loaded[name], -so that require returns t. - - -

      -The module function returns the module table t. - - -

      -If name is a compound name -(that is, one with components separated by dots), -module creates (or reuses, if they already exist) -tables for each component. -For instance, if name is a.b.c, -then module stores the module table in field c of -field b of global a. - - -

      -This function can receive optional options after -the module name, -where each option is a function to be applied over the module. - - -

      -To keep compatibility with old versions of Lua, -module also sets t as the new environment -of the current function. - - - -


      require (modname)

      @@ -6928,7 +7014,8 @@

      6.3 - Modules

      Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, -using the environment variable LUA_CPATH +using the environment variable LUA_CPATH_5_2 +or the environment variable LUA_CPATH or a default path defined in luaconf.h. @@ -7080,7 +7167,8 @@

      6.3 - Modules

      At start-up, Lua initializes this variable with -the value of the environment variable LUA_PATH or +the value of the environment variable LUA_PATH_5_2 or +the environment variable LUA_PATH or with a default path defined in luaconf.h, if the environment variable is not defined. Any ";;" in the value of the environment variable @@ -7136,20 +7224,6 @@

      6.3 - Modules

      -

      -


      package.seeall (module)

      - - -

      -Sets a metatable for module with -its __index field referring to the global environment, -so that this module inherits values -from the global environment. -To be used as an option to function module. - - - - @@ -7222,6 +7296,9 @@

      6.4 - String Manipulation


      string.find (s, pattern [, init [, plain]])

      + + +

      Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s @@ -7248,10 +7325,12 @@

      6.4 - String Manipulation


      string.format (formatstring, ···)

      + + +

      Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). -The format string follows the same rules as the printf family of -standard C functions. +The format string follows the same rules as the C function sprintf. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported @@ -7500,6 +7579,8 @@

      Character Class:

    • %d: represents all digits.
    • +
    • %g: represents all printable characters except space.
    • +
    • %l: represents all lowercase letters.
    • %p: represents all punctuation characters.
    • @@ -8329,7 +8410,7 @@

      6.8 - Input and Output Facilities

      -Equivalent to file:flush over the default output file. +Equivalent to io.output():flush(). @@ -8450,7 +8531,7 @@

      6.8 - Input and Output Facilities

      -Equivalent to io.input():read. +Equivalent to io.input():read(···). @@ -8485,7 +8566,7 @@

      6.8 - Input and Output Facilities

      -Equivalent to io.output():write. +Equivalent to io.output():write(···). @@ -8960,8 +9041,11 @@

      6.10 - The Debug Library

      -


      debug.getfenv (o)

      -Returns the environment of object o. +

      debug.getuservalue (u)

      + + +

      +Returns the Lua value associated to userdata u. @@ -9023,17 +9107,17 @@

      6.10 - The Debug Library

      -


      debug.getlocal ([thread,] level, local)

      +

      debug.getlocal ([thread,] f, local)

      This function returns the name and the value of the local variable -with index local of the function at level level of the stack. +with index local of the function at level f of the stack. (The first parameter or local variable has index 1, and so on, until the last active local variable.) The function returns nil if there is no local variable with the given index, -and raises an error when called with a level out of range. +and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.) @@ -9043,6 +9127,11 @@

      6.10 - The Debug Library

      (loop control variables, temporaries, and C function locals). +

      +The parameter f may also be a function. +In that case, getlocal returns only the name of function parameters. + +

      @@ -9079,12 +9168,17 @@

      6.10 - The Debug Library

      -


      debug.setfenv (object, table)

      +

      debug.setuservalue (udata, value)

      -Sets the environment of the given object to the given table. -Returns object. +Sets the given value as +the Lua value associated to the given udata. +value must be a table or nil. + + +

      +Returns udata. @@ -9259,7 +9353,8 @@

      7 - Lua Stand-alone

      Before running any argument, -the interpreter checks for an environment variable LUA_INIT. +the interpreter checks for an environment variable LUA_INIT_5_2 +(or LUA_INIT if it is not defined). If its format is @filename, then lua executes the file. Otherwise, lua executes the string itself. @@ -9417,6 +9512,12 @@

      8.1 - Changes in the Language

      8.2 - Changes in the Libraries

        +
      • +Function module is deprecated. +Modules are not expected to set global variables anymore, +and it is easy to set up a module with regular Lua code. +
      • +
      • The debug library is not loaded by default. You must explicitly require it. @@ -9428,12 +9529,6 @@

        8.2 - Changes in the Libraries

        use the variable _ENV or the new function loadin.
      • -
      • -Function ipairs is deprecated. -Use a numerical for loop instead, -or write it in Lua. -
      • -
      • Function math.log10 is deprecated. Use math.log with 10 as its second argument, instead. @@ -9481,19 +9576,21 @@

        8.3 - Changes in the API

      • -Pseudoindex LUA_ENVIRONINDEX was removed. +Pseudoindex LUA_ENVIRONINDEX +and functions lua_getfenv/lua_setfenv +were removed. C functions do not have environments any more. Use an upvalue with a shared table if you need to keep shared state among several C functions. -(You may use luaL_openlib to open a C library +(You may use luaL_setfuncs to open a C library with all functions sharing a common upvalue.) -
      • -
      • -Macros lua_getglobal, lua_setglobal, and lua_register -now operate over the function environment instead of the global -environment. -(This is more consistent with how Lua manipulates global variables.) + +

        +To manipulate the "environment" of a userdata +(which is not called "environment" anymore), +use the new functions +lua_getuservalue and lua_setuservalue.

      • @@ -9532,9 +9629,9 @@

        9 - The Complete Syntax of Lua

         
        -	chunk ::= {stat} [laststat [&lsquo;’]]
        +	chunk ::= block
         
        -	block ::= chunk
        +	block ::= {stat} [laststat [&lsquo;’]]
         
         	stat ::=  &lsquo;’ | 
         		 varlist &lsquo=’ explist | 
        @@ -9604,10 +9701,10 @@ 

        9 - The Complete Syntax of Lua


        Last update: -Mon May 17 16:24:08 BRT 2010 +Fri Jul 30 16:41:34 BRT 2010 diff --git a/doc/readme.html b/doc/readme.html index 076dd81fad..9284427dab 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -13,27 +13,12 @@ margin-left: 0px ; } -.external { - padding-right: 15px; - background: transparent url(external.png) no-repeat center right; -} - tt, kbd, code { font-size: 120% ; xcolor: black ; xpadding: 4px ; xbackground-color: #E0E0E0 ; } - -kbd { - color: black ; - background-color: #E8E8E8 ; -} - -.review { - color: red ; -} - @@ -42,14 +27,15 @@

        Lua -Welcome to Lua 5.2 +Welcome to Lua 5.2 (work4)

        - +

        +[!] This is a work version of Lua 5.2. Everything may change in the final version. -

        +

        about · installation @@ -60,10 +46,10 @@

        · reference manual
        -

        About Lua

        +

        Lua is a powerful, fast, lightweight, embeddable scripting language developed by a team @@ -73,8 +59,8 @@

        About Lua

        Lua is free software used in many products and projects around the world. -

        +

        Lua's official web site provides complete information @@ -90,36 +76,53 @@

        About Lua

        which may differ slightly from the local copy distributed in this package. -

        Installing Lua

        -Lua is distributed in source form. +

        +Lua is distributed in +source +form. You need to build it before using it. -This should be straightforward +Building Lua should be straightforward because Lua is implemented in pure ANSI C, and compiles unmodified in all known platforms that have an ANSI C compiler. Lua also compiles unmodified as C++. -

        +

        The instructions below are for Unix-like platforms. There are also instructions for other systems. See below for customization options. +

        +If you don't have the time or the inclination to compile Lua yourself, +get a binary from +LuaBinaries. +Try also +Lua for Windows, +an easy-to-use distribution of Lua that includes many useful libraries. + +

        Building Lua

        +

        In most Unix-like platforms, simply do "make" with a suitable target. Here are the details. -

        1. Open a terminal window and move to -the top-level directory, which is named lua-5.2. +the top-level directory, which is named lua-5.2.0. The Makefile there controls both the build process and the installation process.

        2. @@ -143,29 +146,31 @@

          Building Lua

          and liblua.a (the library).

        3. - If you want to check that Lua has been built correctly, do "make test" - after building Lua. This will run the interpreter on a "hello world" + To check that Lua has been built correctly, do "make test" + after building Lua. This will run the interpreter on a simple "Hello world" Lua program from the test directory. You may want to try other example programs in that directory.
        -

        Installing Lua

        +

        Once you have built Lua, you may want to install it in an official place in your system. In this case, do "make install". The official place and the way to install files are defined in Makefile. You'll probably need the right permissions to install files. -

        - If you want to build and install Lua in one step, do "make xxx install", - where xxx is your platform name.

        + To build and install Lua in one step, do "make xxx install", + where xxx is your platform name. - If you want to install Lua locally, then do "make local". +

        + To install Lua locally, then do "make local". This will create a directory install with subdirectories bin, include, lib, man, - and install Lua there as follows: -

        + and install Lua as listed below. + + To install Lua locally, but in some other directory, do + "make install INSTALL_TOP=xxx", where xxx is your chosen directory.

        @@ -186,52 +191,48 @@

        Installing Lua

        lua.1 luac.1
        - These are the only directories you need for development. -

        - - There are man pages for - lua and - luac, in both nroff and html, and a - reference manual in html in doc, some sample code in test, and some - useful stuff in etc. You don't need these directories for development. -

        - - If you want to install Lua locally, but in some other directory, do - "make install INSTALL_TOP=xxx", where xxx is your chosen directory.

        + These are the only directories you need for development. + If you only want to run Lua programs, + you only need the files in bin and man. + The files in include and lib are needed for + embedding Lua in C or C++ programs.

        Customization

        +

        Three kinds of things can be customized by editing a file:

        • Where and how to install Lua — edit Makefile.
        • How to build Lua — edit src/Makefile.
        • Lua features — edit src/luaconf.h.
        -

        +

        You don't actually need to edit the Makefiles because you may set the relevant variables in the command line when invoking make. -

        + Nevertheless, it's probably best to edit and save the Makefiles to + record the changes you need. +

        On the other hand, if you need to customize some Lua features, you'll need to edit src/luaconf.h before building and installing Lua. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. - (Further customization is possible by editing the Lua sources.) -

        + Further customization is available to experts by editing the Lua sources. - We strongly recommend that you enable dynamic loading. This is done - automatically for all platforms listed above that have this feature - and also for Windows.

        + We strongly recommend that you enable dynamic loading in src/luaconf.h. + This is done automatically for all platforms listed above that have + this feature and also for Windows.

        Building Lua on other systems

        +

        If you're not using the usual Unix tools, then the instructions for building Lua depend on the compiler you use. You'll need to create projects (or whatever your compiler uses) for building the library, the interpreter, and the compiler, as follows: -

        +

        library: @@ -239,8 +240,9 @@

        Building Lua on other systems

        lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c -lauxlib.c lbaselib.c lbitlib.c ldblib.c liolib.c lmathlib.c loslib.c -ltablib.c lstrlib.c loadlib.c linit.c +lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c +lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c +
        interpreter:
        @@ -251,14 +253,7 @@

        Building Lua on other systems

        library, luac.c print.c
        - If you use Visual Studio .NET, you can use etc/luavs.bat in its - "Command Prompt". -

        - - If all you want is to build the Lua interpreter, you may put all .c files - in a single project, except for luac.c and print.c. Or just use etc/one.c.

        - To use Lua as a library in your own programs you'll need to know how to create and use libraries with your compiler. Moreover, to dynamically load C libraries for Lua you'll need to know how to create dynamic libraries @@ -268,38 +263,31 @@

        Building Lua on other systems

        be linked statically into the host program and its symbols exported for dynamic linking; src/Makefile does this for the Lua interpreter. For Windows, we recommend that the Lua library be a DLL. -

        +

        As mentioned above, you may edit src/luaconf.h to customize some features before building Lua. -

        -

        Changes since Lua 5.1

        +

        Changes since Lua 5.2.0 (work3)

        - -Everything may change in the final version. -

        - -Here are the main changes since the previous work version:

          -
        • new _ENV proposal -
        • generational collector (very experimental) -
        • light C functions - -
        • order tag methods follow the same rules of other binary operators -
        • lua_absindex -
        • \0 in patterns -
        • empty statement -
        • options in io.lines +
        • module and luaL_register deprecated, replaced by luaL_newlib and luaL_setfuncs. +
        • new function luaL_requiref. +
        • caching of Lua closures for resue. +
        • version-specific environment variables (LUA_PATH_5_2, etc.). +
        • new class '%g' in patterns. +
        • debug.getlocal gets parameter names of inactive functions. +
        • new functions lua_tonumberx and lua_tointegerx.
        -

        -Here are the main changes in Lua since its last release. +

        Changes since Lua 5.1

        + +

        +Here are the main changes introduced in Lua 5.2. The reference manual lists the -incompatibilities that had to be introduced. -

        +incompatibilities that had to be introduced.

        Language

          @@ -358,42 +346,40 @@

          Implementation

        • handling of non-string error messages in the standalone interpreter.
        -

        License

        -[osi certified] +[osi certified] +

        Lua is free software licensed under the terms of the MIT license -reproduced below, -and -can be used for any purpose, including commercial purposes, +reproduced below; +it can be used for any purpose, including commercial purposes, at absolutely no cost without having to ask us. The only requirement is that if you do use Lua, then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. -For details and rationale, see -this. -

        +For details, see +this.

        Copyright © 1994–2010 Lua.org, PUC-Rio. -

        +

        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -

        +

        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -

        +

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -401,17 +387,15 @@

        License

        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -

        -


        Last update: -Tue May 18 13:59:06 BRT 2010 +Fri Jul 30 15:12:25 BRT 2010 diff --git a/etc/Makefile b/etc/Makefile deleted file mode 100644 index 34d8571a6c..0000000000 --- a/etc/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# makefile for Lua etc - -TOP= .. -LIB= $(TOP)/src -INC= $(TOP)/src -BIN= $(TOP)/src -SRC= $(TOP)/src -TST= $(TOP)/test - -T= test -CC= gcc -CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) -MYCFLAGS= -MYLIBS= -lm # -ldl -lreadline -lncurses -Wl,-E -RM= rm -f - - -default: - @echo 'Please choose a target: min noparser one one-lua one-lib one-luac so strict clean' - -min: min.c - $(CC) $(CFLAGS) -o $T min.c -L$(LIB) -llua $(MYLIBS) - echo 'print"Hello there!"' | ./$T - ./$T $(TST)/hello.lua - echo 'print("Hello world, from",_VERSION,"!")' | ./$T - -noparser: noparser.o - $(CC) -o $T noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) - $(BIN)/luac $(TST)/hello.lua - -./$T luac.out - -./$T -e'a=1' - -one: one-lua one-lib one-luac - -one-lua: - $(CC) $(CFLAGS) -o $T one.c $(MYLIBS) - ./$T $(TST)/hello.lua - -one-lib: - $(CC) $(CFLAGS) -DMAKE_LIB -o liblua.o -c one.c - $(CC) $(CFLAGS) -o $T min.c liblua.o $(MYLIBS) - ./$T $(TST)/hello.lua - -one-luac: - $(CC) $(CFLAGS) -o $T -DMAKE_LUAC one.c $(MYLIBS) - ./$T -l $(TST)/hello.lua - -so: - $(CC) $(CFLAGS) -shared -o dummy.so dummy.c - @#env MACOSX_DEPLOYMENT_TARGET=10.3 $(CC) $(CFLAGS) -bundle -undefined dynamic_lookup -o dummy.so dummy.c - $(BIN)/lua -v -ldummy - -strict: - -$(BIN)/lua -e 'print(a);b=2' - -$(BIN)/lua -lstrict -e 'print(a)' - -$(BIN)/lua -e 'function f() b=2 end f()' - -$(BIN)/lua -lstrict -e 'function f() b=2 end f()' - -clean: - $(RM) $T a.out core core.* *.o luac.out dummy.so - -.PHONY: default min noparser one one-lua one-lib one-luac so strict clean diff --git a/etc/README b/etc/README deleted file mode 100644 index 0eda3bd3e0..0000000000 --- a/etc/README +++ /dev/null @@ -1,30 +0,0 @@ -This directory contains some useful files and code. -Unlike the code in ../src, everything here is in the public domain. - -If any of the makes fail, you're probably not using the same libraries used -to build Lua. Set MYLIBS in Makefile or in the command line accordingly. - -dummy.c: - A minimal Lua library for testing dynamic loading. - Do "make so" for a demo. - -luavs.bat - Script to build Lua under "Visual Studio .NET Command Prompt". - Run it from the toplevel as etc\luavs.bat. - -min.c - A minimal Lua interpreter for learning and for starting your own. - Do "make min" for a demo. - -noparser.c - Linking with noparser.o avoids loading the parsing modules in lualib.a. - Do "make noparser" for a demo. - -one.c - Full Lua interpreter in a single file. Also library and compiler. - Do "make one" for a demo. - -strict.lua - Traps uses of undeclared global variables. - Do "make strict" for a demo. - diff --git a/etc/dummy.c b/etc/dummy.c deleted file mode 100644 index 1d40e8be39..0000000000 --- a/etc/dummy.c +++ /dev/null @@ -1,11 +0,0 @@ -/* -* dummy.c -- a minimal Lua library for testing dynamic loading -*/ - -#include -#include "lua.h" - -int luaopen_dummy (lua_State *L) { - puts("Hello from dummy"); - return 0; -} diff --git a/etc/luavs.bat b/etc/luavs.bat deleted file mode 100644 index 145187131c..0000000000 --- a/etc/luavs.bat +++ /dev/null @@ -1,28 +0,0 @@ -@rem Script to build Lua 5.2 under "Visual Studio .NET Command Prompt". -@rem Do not run from this directory; run it from the toplevel: etc\luavs.bat . -@rem It creates lua52.dll, lua52.lib, lua.exe, and luac.exe in src. -@rem (contributed by David Manura and Mike Pall) - -@setlocal -@set MYCOMPILE=cl /nologo /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE -@set MYLINK=link /nologo -@set MYMT=mt /nologo - -cd src -%MYCOMPILE% /DLUA_BUILD_AS_DLL l*.c -del lua.obj luac.obj -%MYLINK% /DLL /out:lua52.dll l*.obj -if exist lua52.dll.manifest^ - %MYMT% -manifest lua52.dll.manifest -outputresource:lua52.dll;2 -%MYCOMPILE% /DLUA_BUILD_AS_DLL lua.c -%MYLINK% /out:lua.exe lua.obj lua52.lib -if exist lua.exe.manifest^ - %MYMT% -manifest lua.exe.manifest -outputresource:lua.exe -%MYCOMPILE% l*.c print.c -del lua.obj linit.obj lbaselib.obj ldblib.obj liolib.obj lmathlib.obj^ - loslib.obj ltablib.obj lstrlib.obj loadlib.obj -%MYLINK% /out:luac.exe *.obj -if exist luac.exe.manifest^ - %MYMT% -manifest luac.exe.manifest -outputresource:luac.exe -del *.obj *.manifest -cd .. diff --git a/etc/min.c b/etc/min.c deleted file mode 100644 index 0b6a5c3252..0000000000 --- a/etc/min.c +++ /dev/null @@ -1,33 +0,0 @@ -/* -* min.c -- a minimal Lua interpreter -* runs one file from the command line or stdin if no file given. -* minimal error handling, no traceback, no interaction, no standard library, -* only a "print" function. -*/ - -#include - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - -static int print(lua_State *L) -{ - int n=lua_gettop(L); - int i; - for (i=1; i<=n; i++) - printf("%s ",luaL_tolstring(L,i,NULL)); - printf("\n"); - return 0; -} - -int main(int argc, char *argv[]) -{ - lua_State *L=luaL_newstate(); - luaL_openlibs(L); - lua_register(L,"print",print); - if (luaL_dofile(L,argv[1])!=0) - fprintf(stderr,"%s: %s\n",argv[0],lua_tostring(L,-1)); - lua_close(L); - return 0; -} diff --git a/etc/noparser.c b/etc/noparser.c deleted file mode 100644 index f1fd4aea6a..0000000000 --- a/etc/noparser.c +++ /dev/null @@ -1,70 +0,0 @@ -/* -* The code below can be used to make a Lua core that does not contain the -* parsing modules (lcode, llex, lparser), which represent 35% of the total core. -* You'll only be able to load binary files and strings, precompiled with luac. -* (Of course, you'll have to build luac with the original parsing modules!) -* -* To use this module, simply compile it and list its object file before the -* Lua libraries. The linker should then not load the parsing modules. -* -* If you want to avoid the dump module or the undump modules, use the -* corresponding #define below. -* -#define NOPARSER -#define NODUMP -#define NOUNDUMP -*/ - -#define NOPARSER - -#define LUA_CORE -#include "lua.h" - -/* --------------------------------------------------------------- noparser */ -#ifdef NOPARSER -#include "llex.h" -#include "lparser.h" -#include "lzio.h" - -LUAI_FUNC void luaX_init (lua_State *L) { - UNUSED(L); -} - -LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, const char *name) { - UNUSED(z); - UNUSED(buff); - UNUSED(name); - lua_pushliteral(L,"parser not available"); - lua_error(L); - return NULL; -} -#endif - -/* --------------------------------------------------------------- nodump */ -#ifdef NODUMP -#include "lundump.h" - -LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { - UNUSED(f); - UNUSED(w); - UNUSED(data); - UNUSED(strip); - lua_pushliteral(L,"dumper not available"); - lua_error(L); - return 0; -} -#endif - -/* --------------------------------------------------------------- noundump */ -#ifdef NOUNDUMP -#include "lundump.h" - -LUAI_FUNC Proto *luaU_undump (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { - UNUSED(z); - UNUSED(buff); - UNUSED(name); - lua_pushliteral(L,"binary loader not available"); - lua_error(L); - return NULL; -} -#endif diff --git a/etc/one.c b/etc/one.c deleted file mode 100644 index 372543a64b..0000000000 --- a/etc/one.c +++ /dev/null @@ -1,73 +0,0 @@ -/* -* one.c -- Lua core, libraries, and interpreter in a single file -*/ - -/* default is to build the full interpreter */ -#ifndef MAKE_LIB -#ifndef MAKE_LUAC -#ifndef MAKE_LUA -#define MAKE_LUA -#endif -#endif -#endif - -/* choose suitable platform-specific features */ -/* some of these may need extra libraries such as -ldl -lreadline -lncurses */ -#if 0 -#define LUA_USE_LINUX -#define LUA_USE_MACOSX -#define LUA_USE_POSIX -#define LUA_ANSI -#endif - -#define luaall_c - -/* core -- used by all */ -#include "lapi.c" -#include "lcode.c" -#include "lctype.c" -#include "ldebug.c" -#include "ldo.c" -#include "ldump.c" -#include "lfunc.c" -#include "lgc.c" -#include "llex.c" -#include "lmem.c" -#include "lobject.c" -#include "lopcodes.c" -#include "lparser.c" -#include "lstate.c" -#include "lstring.c" -#include "ltable.c" -#include "ltm.c" -#include "lundump.c" -#include "lvm.c" -#include "lzio.c" - -/* auxiliary library -- used by all */ -#include "lauxlib.c" - -/* standard library -- not used by luac */ -#ifndef MAKE_LUAC -#include "lbaselib.c" -#include "lbitlib.c" -#include "ldblib.c" -#include "liolib.c" -#include "lmathlib.c" -#include "loadlib.c" -#include "loslib.c" -#include "lstrlib.c" -#include "ltablib.c" -#include "linit.c" -#endif - -/* lua */ -#ifdef MAKE_LUA -#include "lua.c" -#endif - -/* luac */ -#ifdef MAKE_LUAC -#include "print.c" -#include "luac.c" -#endif diff --git a/etc/strict.lua b/etc/strict.lua deleted file mode 100644 index 5ce1aa85bf..0000000000 --- a/etc/strict.lua +++ /dev/null @@ -1,42 +0,0 @@ --- --- strict.lua --- checks uses of undeclared global variables --- All global variables must be 'declared' through a regular assignment --- (even assigning nil will do) in a main chunk before being used --- anywhere or assigned to inside a function. --- - -require"debug" -local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget - -local mt = getmetatable(_G) -if mt == nil then - mt = {} - setmetatable(_G, mt) -end - -mt.__declared = {} - -local function what () - local d = getinfo(3, "S") - return d and d.what or "C" -end - -mt.__newindex = function (t, n, v) - if not mt.__declared[n] then - local w = what() - if w ~= "main" and w ~= "C" then - error("assign to undeclared variable '"..n.."'", 2) - end - mt.__declared[n] = true - end - rawset(t, n, v) -end - -mt.__index = function (t, n) - if not mt.__declared[n] and what() ~= "C" then - error("variable '"..n.."' is not declared", 2) - end - return rawget(t, n) -end - diff --git a/src/Makefile b/src/Makefile index 83185e3484..84a21035ce 100644 --- a/src/Makefile +++ b/src/Makefile @@ -26,8 +26,8 @@ LUA_A= liblua.a CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ ltm.o lundump.o lvm.o lzio.o -LIB_O= lauxlib.o lbaselib.o lbitlib.o ldblib.o liolib.o lmathlib.o loslib.o \ - lstrlib.o ltablib.o loadlib.o linit.o +LIB_O= lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \ + lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o LUA_T= lua LUA_O= lua.o @@ -39,6 +39,7 @@ ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) ALL_A= $(LUA_A) +# Targets start here. default: $(PLAT) all: $(ALL_T) @@ -64,21 +65,21 @@ depend: @$(CC) $(CFLAGS) -MM l*.c print.c echo: - @echo "PLAT = $(PLAT)" - @echo "CC = $(CC)" - @echo "CFLAGS = $(CFLAGS)" - @echo "AR = $(AR)" - @echo "RANLIB = $(RANLIB)" - @echo "RM = $(RM)" - @echo "MYCFLAGS = $(MYCFLAGS)" - @echo "MYLDFLAGS = $(MYLDFLAGS)" - @echo "MYLIBS = $(MYLIBS)" - -# convenience targets for popular platforms + @echo "PLAT= $(PLAT)" + @echo "CC= $(CC)" + @echo "CFLAGS= $(CFLAGS)" + @echo "AR= $(AR)" + @echo "RANLIB= $(RANLIB)" + @echo "RM= $(RM)" + @echo "MYCFLAGS= $(MYCFLAGS)" + @echo "MYLDFLAGS= $(MYLDFLAGS)" + @echo "MYLIBS= $(MYLIBS)" + +# Convenience targets for popular platforms ALL= all none: - @echo "Please choose a platform:" + @echo "Please do 'make PLATFORM' where PLATFORM is one of these:" @echo " $(PLATS)" aix: @@ -119,65 +120,66 @@ solaris: # DO NOT DELETE lapi.o: lapi.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ - lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \ - lvm.h + lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \ + lvm.h lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ - lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ - lstring.h ltable.h + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ + lstring.h ltable.h +lcorolib.o: lcorolib.c lua.h luaconf.h lauxlib.h lualib.h lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h ldebug.o: ldebug.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ - ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \ - lfunc.h lstring.h lgc.h ltable.h lvm.h + ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \ + lfunc.h lstring.h lgc.h ltable.h lvm.h ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ - lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \ - lstring.h ltable.h lundump.h lvm.h + lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \ + lstring.h ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ - lzio.h lmem.h lundump.h + lzio.h lmem.h lundump.h lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \ - lstate.h ltm.h lzio.h lmem.h lopcodes.h + lstate.h ltm.h lzio.h lmem.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ - lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h + lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \ - lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h + lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lgc.h + ltm.h lzio.h lmem.h ldo.h lgc.h loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h lobject.o: lobject.c lua.h luaconf.h lctype.h llimits.h ldebug.h lstate.h \ - lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h + lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ - lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ - lfunc.h lstring.h lgc.h ltable.h + lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lfunc.h \ + lstring.h lgc.h ltable.h lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ - ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \ - ltable.h + ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \ + ltable.h lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ - ltm.h lzio.h lstring.h lgc.h + ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h + ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ - lmem.h lstring.h lgc.h ltable.h + lmem.h lstring.h lgc.h ltable.h lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ - lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ - lundump.h + lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ + lundump.h lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ - llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ - lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h + lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ - lzio.h + lzio.h print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h lopcodes.h lundump.h + ltm.h lzio.h lmem.h lopcodes.h lundump.h # (end of Makefile) diff --git a/src/lapi.c b/src/lapi.c index 8a0378f96f..2d7c336a33 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.129 2010/05/14 13:15:26 roberto Exp $ +** $Id: lapi.c,v 2.133 2010/07/25 15:18:19 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -55,7 +55,7 @@ static TValue *index2addr (lua_State *L, int idx) { return &G(L)->l_registry; else { /* upvalues */ idx = LUA_REGISTRYINDEX - idx; - api_check(L, idx <= UCHAR_MAX + 1, "upvalue index too large"); + api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); if (ttislcf(ci->func)) /* light C function? */ return cast(TValue *, luaO_nilobject); /* it has no upvalues */ else { @@ -316,27 +316,34 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { } -LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { +LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum) { TValue n; const TValue *o = index2addr(L, idx); - if (tonumber(o, &n)) + if (tonumber(o, &n)) { + if (isnum) *isnum = 1; return nvalue(o); - else + } + else { + if (isnum) *isnum = 0; return 0; + } } -LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { +LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum) { TValue n; const TValue *o = index2addr(L, idx); if (tonumber(o, &n)) { lua_Integer res; lua_Number num = nvalue(o); lua_number2integer(res, num); + if (isnum) *isnum = 1; return res; } - else + else { + if (isnum) *isnum = 0; return 0; + } } @@ -507,7 +514,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { else { Closure *cl; api_checknelems(L, n); - api_check(L, n <= UCHAR_MAX, "upvalue index too large"); + api_check(L, n <= MAXUPVAL, "upvalue index too large"); luaC_checkGC(L); cl = luaF_newCclosure(L, n); cl->c.f = fn; @@ -637,7 +644,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { } -LUA_API void lua_getenv (lua_State *L, int idx) { +LUA_API void lua_getuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); @@ -689,7 +696,7 @@ LUA_API void lua_rawset (lua_State *L, int idx) { t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); - luaC_barriert(L, hvalue(t), L->top-1); + luaC_barrierback(L, gcvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } @@ -702,7 +709,7 @@ LUA_API void lua_rawseti (lua_State *L, int idx, int n) { o = index2addr(L, idx); api_check(L, ttistable(o), "table expected"); setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1); - luaC_barriert(L, hvalue(o), L->top-1); + luaC_barrierback(L, gcvalue(o), L->top-1); L->top--; lua_unlock(L); } @@ -725,7 +732,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) - luaC_objbarriert(L, hvalue(obj), mt); + luaC_objbarrierback(L, gcvalue(obj), mt); break; } case LUA_TUSERDATA: { @@ -747,7 +754,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { } -LUA_API void lua_setenv (lua_State *L, int idx) { +LUA_API void lua_setuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); api_checknelems(L, 1); diff --git a/src/lauxlib.c b/src/lauxlib.c index 8ebc18fa7c..54f13da23e 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.212 2010/05/18 17:21:24 roberto Exp $ +** $Id: lauxlib.c,v 1.219 2010/07/28 15:51:59 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -308,8 +308,9 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { - lua_Number d = lua_tonumber(L, narg); - if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + int isnum; + lua_Number d = lua_tonumberx(L, narg, &isnum); + if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; } @@ -321,8 +322,9 @@ LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { - lua_Integer d = lua_tointeger(L, narg); - if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ + int isnum; + lua_Integer d = lua_tointegerx(L, narg, &isnum); + if (!isnum) tag_error(L, narg, LUA_TNUMBER); return d; } @@ -476,26 +478,25 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { */ typedef struct LoadF { - int first; - FILE *f; - char buff[LUAL_BUFFERSIZE]; + int n; /* number of pre-read characters */ + FILE *f; /* file being read */ + char buff[LUAL_BUFFERSIZE]; /* area for reading file */ } LoadF; static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; - if (lf->first != EOF) { - *size = 1; - lf->buff[0] = (char)lf->first; - lf->first = EOF; + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ } - else { + else { /* read a block from file */ /* 'fread' can return > 0 *and* set the EOF flag. If next call to 'getF' called 'fread', it might still wait for user input. The next check avoids this problem. */ if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ } return lf->buff; } @@ -510,6 +511,23 @@ static int errfile (lua_State *L, const char *what, int fnameindex) { } +/* +** reads the first character of file 'f' and skips its first line +** if it starts with '#'. Returns true if it skipped the first line. +** In any case, '*cp' has the first "valid" character of the file +** (after the optional first-line comment). +*/ +static int skipcomment (FILE *f, int *cp) { + int c = *cp = getc(f); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + while ((c = getc(f)) != EOF && c != '\n') ; /* skip first line */ + *cp = getc(f); /* skip end-of-line */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { LoadF lf; int status, readstatus; @@ -524,16 +542,17 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } - c = getc(lf.f); - if (c == '#') { /* Unix exec. file? */ - while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ - } - else if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ + lf.n = 0; + if (skipcomment(lf.f, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - c = getc(lf.f); /* re-read first character */ + lf.n = 0; + skipcomment(lf.f, &c); /* re-read initial portion */ } - lf.first = c; /* 'c' is the first character of the stream */ + if (c != EOF) + lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ @@ -607,9 +626,10 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { LUALIB_API int luaL_len (lua_State *L, int idx) { int l; + int isnum; lua_len(L, idx); - l = lua_tointeger(L, -1); - if (l == 0 && !lua_isnumber(L, -1)) + l = lua_tointegerx(L, -1, &isnum); + if (!isnum) luaL_error(L, "object length is not a number"); lua_pop(L, 1); /* remove object */ return l; @@ -639,6 +659,43 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { } +/* +** {====================================================== +** Compatibility with 5.1 module functions +** ======================================================= +*/ +#if defined(LUA_COMPAT_MODULE) + +static const char *luaL_findtablex (lua_State *L, int idx, + const char *fname, int szhint) { + const char *e; + if (idx) lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == NULL) e = fname + strlen(fname); + lua_pushlstring(L, fname, e - fname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, e - fname); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (*e == '.'); + return NULL; +} + + +/* +** Count number of elements in a luaL_Reg list. +*/ static int libsize (const luaL_Reg *l) { int size = 0; for (; l && l->name; l++) size++; @@ -646,37 +703,101 @@ static int libsize (const luaL_Reg *l) { } +/* +** Find or create a module table with a given name. The function +** first looks at the _LOADED table and, if that fails, try a +** global variable with that name. In any case, leaves on the stack +** the module table. +*/ +LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, + int sizehint) { + luaL_findtablex(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ + lua_getfield(L, -1, modname); /* get _LOADED[modname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + lua_pushglobaltable(L); + if (luaL_findtablex(L, 0, modname, sizehint) != NULL) + luaL_error(L, "name conflict for module " LUA_QS, modname); + lua_pushvalue(L, -1); + lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */ + } + lua_remove(L, -2); /* remove _LOADED table */ +} + + LUALIB_API void luaL_openlib (lua_State *L, const char *libname, const luaL_Reg *l, int nup) { luaL_checkversion(L); if (libname) { - /* check whether lib already exists */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); - lua_getfield(L, -1, libname); /* get _LOADED[libname] */ - if (!lua_istable(L, -1)) { /* not found? */ - lua_pop(L, 1); /* remove previous result */ - /* try global variable (and create one if it does not exist) */ - lua_pushglobaltable(L); - if (luaL_findtable(L, 0, libname, libsize(l)) != NULL) - luaL_error(L, "name conflict for module " LUA_QS, libname); - lua_pushvalue(L, -1); - lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ - } - lua_remove(L, -2); /* remove _LOADED table */ + luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ } + luaL_setfuncs(L, l, nup); +} + +#endif +/* }====================================================== */ + +/* +** set functions from list 'l' into table at top - 'nup'; each +** function gets the 'nup' elements at the top as upvalues. +** Returns with only the table at the stack. +*/ +LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup, "too many upvalues"); for (; l && l->name; l++) { /* fill the table with given functions */ int i; for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -nup); - lua_pushcclosure(L, l->func, nup); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ lua_setfield(L, -(nup + 2), l->name); } lua_pop(L, nup); /* remove upvalues */ } +/* +** ensure that stack[idx][fname] has a table and push that table +** into the stack +*/ +LUALIB_API void luaL_findtable (lua_State *L, int idx, const char *fname) { + lua_getfield(L, idx, fname); + if (lua_istable(L, -1)) return; /* table already there */ + else { + idx = lua_absindex(L, idx); + lua_pop(L, 1); /* remove previous result */ + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ + } +} + + +/* +** stripped-down 'require'. Calls 'openf' to open a module, +** registers the result in 'package.loaded' table and, if 'glb' +** is true, also registers the result in the global table. +** Leaves resulting module on the top. +*/ +LUALIB_API void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb) { + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* open module */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_pushvalue(L, -2); /* make copy of module (call result) */ + lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ + lua_pop(L, 1); /* remove _LOADED table */ + if (glb) { + lua_pushglobaltable(L); + lua_pushvalue(L, -2); /* copy of 'mod' */ + lua_setfield(L, -2, modname); /* _G[modname] = module */ + lua_pop(L, 1); /* remove _G table */ + } +} + + LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r) { const char *wild; @@ -694,33 +815,6 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, } -LUALIB_API const char *luaL_findtable (lua_State *L, int idx, - const char *fname, int szhint) { - const char *e; - if (idx) lua_pushvalue(L, idx); - do { - e = strchr(fname, '.'); - if (e == NULL) e = fname + strlen(fname); - lua_pushlstring(L, fname, e - fname); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { /* no such field? */ - lua_pop(L, 1); /* remove this nil */ - lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ - lua_pushlstring(L, fname, e - fname); - lua_pushvalue(L, -2); - lua_settable(L, -4); /* set new table into field */ - } - else if (!lua_istable(L, -1)) { /* field has a non-table value? */ - lua_pop(L, 2); /* remove table and value */ - return fname; /* return problematic part of the name */ - } - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - } while (*e == '.'); - return NULL; -} - - static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; diff --git a/src/lauxlib.h b/src/lauxlib.h index ae2e2c7571..b2034673a9 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.105 2010/05/04 17:21:08 roberto Exp $ +** $Id: lauxlib.h,v 1.108 2010/07/02 11:38:13 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -29,8 +29,6 @@ typedef struct luaL_Reg { LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); #define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) -LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, - const luaL_Reg *l, int nup); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); @@ -76,12 +74,15 @@ LUALIB_API int (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); -LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, - const char *fname, int szhint); +LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + +LUALIB_API void (luaL_findtable) (lua_State *L, int idx, const char *fname); LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, const char *msg, int level); +LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); /* ** =============================================================== @@ -89,6 +90,12 @@ LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, ** =============================================================== */ + +#define luaL_newlibtable(L,l) \ + lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) + +#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) + #define luaL_argcheck(L, cond,numarg,extramsg) \ ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) @@ -148,6 +155,12 @@ LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); /* }====================================================== */ +LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, + int sizehint); +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); + + /* compatibility with ref system */ /* pre-defined references */ diff --git a/src/lbaselib.c b/src/lbaselib.c index 946ecea5e9..1e13a183d7 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.243 2010/04/19 17:02:02 roberto Exp $ +** $Id: lbaselib.c,v 1.246 2010/07/02 11:38:13 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -210,15 +210,13 @@ static int luaB_pairs (lua_State *L) { } -#if defined(LUA_COMPAT_IPAIRS) - static int ipairsaux (lua_State *L) { int i = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TTABLE); i++; /* next value */ lua_pushinteger(L, i); lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1) && i > luaL_len(L, 1)) ? 0 : 2; + return (lua_isnil(L, -1)) ? 1 : 2; } @@ -226,14 +224,6 @@ static int luaB_ipairs (lua_State *L) { return pairsmeta(L, "__ipairs", 1, ipairsaux); } -#else - -static int luaB_ipairs (lua_State *L) { - return luaL_error(L, "'ipairs' deprecated"); -} - -#endif - static int load_aux (lua_State *L, int status) { if (status == LUA_OK) @@ -500,150 +490,13 @@ static const luaL_Reg base_funcs[] = { }; -/* -** {====================================================== -** Coroutine library -** ======================================================= -*/ - -static int auxresume (lua_State *L, lua_State *co, int narg) { - int status; - if (!lua_checkstack(co, narg)) { - lua_pushliteral(L, "too many arguments to resume"); - return -1; /* error flag */ - } - if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { - lua_pushliteral(L, "cannot resume dead coroutine"); - return -1; /* error flag */ - } - lua_xmove(L, co, narg); - status = lua_resume(co, narg); - if (status == LUA_OK || status == LUA_YIELD) { - int nres = lua_gettop(co); - if (!lua_checkstack(L, nres + 1)) { - lua_pop(co, nres); /* remove results anyway */ - lua_pushliteral(L, "too many results to resume"); - return -1; /* error flag */ - } - lua_xmove(co, L, nres); /* move yielded values */ - return nres; - } - else { - lua_xmove(co, L, 1); /* move error message */ - return -1; /* error flag */ - } -} - - -static int luaB_coresume (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - int r; - luaL_argcheck(L, co, 1, "coroutine expected"); - r = auxresume(L, co, lua_gettop(L) - 1); - if (r < 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - lua_insert(L, -(r + 1)); - return r + 1; /* return true + `resume' returns */ - } -} - - -static int luaB_auxwrap (lua_State *L) { - lua_State *co = lua_tothread(L, lua_upvalueindex(1)); - int r = auxresume(L, co, lua_gettop(L)); - if (r < 0) { - if (lua_isstring(L, -1)) { /* error object is a string? */ - luaL_where(L, 1); /* add extra info */ - lua_insert(L, -2); - lua_concat(L, 2); - } - lua_error(L); /* propagate error */ - } - return r; -} - - -static int luaB_cocreate (lua_State *L) { - lua_State *NL = lua_newthread(L); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_pushvalue(L, 1); /* move function to top */ - lua_xmove(L, NL, 1); /* move function from L to NL */ - return 1; -} - - -static int luaB_cowrap (lua_State *L) { - luaB_cocreate(L); - lua_pushcclosure(L, luaB_auxwrap, 1); - return 1; -} - - -static int luaB_yield (lua_State *L) { - return lua_yield(L, lua_gettop(L)); -} - - -static int luaB_costatus (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - if (L == co) lua_pushliteral(L, "running"); - else { - switch (lua_status(co)) { - case LUA_YIELD: - lua_pushliteral(L, "suspended"); - break; - case LUA_OK: { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ - lua_pushliteral(L, "normal"); /* it is running */ - else if (lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); /* initial state */ - break; - } - default: /* some error occurred */ - lua_pushliteral(L, "dead"); - break; - } - } - return 1; -} - - -static int luaB_corunning (lua_State *L) { - int ismain = lua_pushthread(L); - lua_pushboolean(L, ismain); - return 2; -} - - -static const luaL_Reg co_funcs[] = { - {"create", luaB_cocreate}, - {"resume", luaB_coresume}, - {"running", luaB_corunning}, - {"status", luaB_costatus}, - {"wrap", luaB_cowrap}, - {"yield", luaB_yield}, - {NULL, NULL} -}; - -/* }====================================================== */ - - -static void base_open (lua_State *L) { +LUAMOD_API int luaopen_base (lua_State *L) { /* set global _G */ lua_pushglobaltable(L); lua_pushglobaltable(L); lua_setfield(L, -2, "_G"); /* open lib into global table */ - luaL_register(L, "_G", base_funcs); + luaL_setfuncs(L, base_funcs, 0); lua_pushliteral(L, LUA_VERSION); lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ /* `newproxy' needs a weaktable as upvalue */ @@ -654,12 +507,6 @@ static void base_open (lua_State *L) { lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ -} - - -LUAMOD_API int luaopen_base (lua_State *L) { - base_open(L); - luaL_register(L, LUA_COLIBNAME, co_funcs); - return 2; + return 1; } diff --git a/src/lbitlib.c b/src/lbitlib.c index b367d0c654..1b32653dc1 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.4 2010/02/11 15:55:29 roberto Exp $ +** $Id: lbitlib.c,v 1.6 2010/07/02 12:01:53 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -23,8 +23,9 @@ typedef unsigned LUA_INT32 b_uint; static b_uint getuintarg (lua_State *L, int arg) { b_uint r; - lua_Number x = lua_tonumber(L, arg); - if (x == 0) luaL_checktype(L, arg, LUA_TNUMBER); + int isnum; + lua_Number x = lua_tonumberx(L, arg, &isnum); + if (!isnum) luaL_typeerror(L, arg, "number"); lua_number2uint(r, x); return r; } @@ -141,6 +142,6 @@ static const luaL_Reg bitlib[] = { LUAMOD_API int luaopen_bit (lua_State *L) { - luaL_register(L, LUA_BITLIBNAME, bitlib); + luaL_newlib(L, bitlib); return 1; } diff --git a/src/lcode.c b/src/lcode.c index d060b5f0d5..ea3217fae5 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.46 2010/04/17 12:46:32 roberto Exp $ +** $Id: lcode.c,v 2.49 2010/07/07 16:27:29 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -266,7 +266,7 @@ static void freereg (FuncState *fs, int reg) { static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) - freereg(fs, e->u.s.info); + freereg(fs, e->u.info); } @@ -352,7 +352,7 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ e->k = VNONRELOC; - e->u.s.info = GETARG_A(getcode(fs, e)); + e->u.info = GETARG_A(getcode(fs, e)); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), 2); @@ -368,20 +368,18 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VUPVAL: { - e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); + e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); e->k = VRELOCABLE; break; } case VINDEXED: { - freereg(fs, e->u.s.aux); - freereg(fs, e->u.s.info); - e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); - e->k = VRELOCABLE; - break; - } - case VINDEXEDUP: { - freereg(fs, e->u.s.aux); - e->u.s.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.s.info, e->u.s.aux); + OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ + freereg(fs, e->u.ind.idx); + if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ + freereg(fs, e->u.ind.t); + op = OP_GETTABLE; + } + e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); e->k = VRELOCABLE; break; } @@ -413,7 +411,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VK: { - luaK_codek(fs, reg, e->u.s.info); + luaK_codek(fs, reg, e->u.info); break; } case VKNUM: { @@ -426,8 +424,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } case VNONRELOC: { - if (reg != e->u.s.info) - luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); + if (reg != e->u.info) + luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); break; } default: { @@ -435,7 +433,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { return; /* nothing to do... */ } } - e->u.s.info = reg; + e->u.info = reg; e->k = VNONRELOC; } @@ -451,7 +449,7 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) { static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) - luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ @@ -467,7 +465,7 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; - e->u.s.info = reg; + e->u.info = reg; e->k = VNONRELOC; } @@ -483,14 +481,14 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); if (e->k == VNONRELOC) { - if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ - if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e->u.s.info); /* put value on it */ - return e->u.s.info; + if (!hasjumps(e)) return e->u.info; /* exp is already in a register */ + if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e->u.info); /* put value on it */ + return e->u.info; } } luaK_exp2nextreg(fs, e); /* default */ - return e->u.s.info; + return e->u.info; } @@ -514,21 +512,21 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { case VTRUE: case VFALSE: case VNIL: { - if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ - e->u.s.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); + if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ + e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); e->k = VK; - return RKASK(e->u.s.info); + return RKASK(e->u.info); } else break; } case VKNUM: { - e->u.s.info = luaK_numberK(fs, e->u.nval); + e->u.info = luaK_numberK(fs, e->u.nval); e->k = VK; /* go through */ } case VK: { - if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ - return RKASK(e->u.s.info); + if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ + return RKASK(e->u.info); else break; } default: break; @@ -542,22 +540,18 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); - exp2reg(fs, ex, var->u.s.info); + exp2reg(fs, ex, var->u.info); return; } case VUPVAL: { int e = luaK_exp2anyreg(fs, ex); - luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); + luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); break; } case VINDEXED: { + OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; int e = luaK_exp2RK(fs, ex); - luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); - break; - } - case VINDEXEDUP: { - int e = luaK_exp2RK(fs, ex); - luaK_codeABC(fs, OP_SETTABUP, var->u.s.info, var->u.s.aux, e); + luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } default: { @@ -574,16 +568,16 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { luaK_exp2anyreg(fs, e); freeexp(fs, e); func = fs->freereg; - luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); + luaK_codeABC(fs, OP_SELF, func, e->u.info, luaK_exp2RK(fs, key)); freeexp(fs, key); luaK_reserveregs(fs, 2); - e->u.s.info = func; + e->u.info = func; e->k = VNONRELOC; } static void invertjump (FuncState *fs, expdesc *e) { - Instruction *pc = getjumpcontrol(fs, e->u.s.info); + Instruction *pc = getjumpcontrol(fs, e->u.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); @@ -601,7 +595,7 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { } discharge2anyreg(fs, e); freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); } @@ -615,7 +609,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } case VJMP: { invertjump(fs, e); - pc = e->u.s.info; + pc = e->u.info; break; } case VFALSE: { @@ -645,7 +639,7 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) { break; } case VJMP: { - pc = e->u.s.info; + pc = e->u.info; break; } case VTRUE: { @@ -685,7 +679,7 @@ static void codenot (FuncState *fs, expdesc *e) { case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); - e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); + e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); e->k = VRELOCABLE; break; } @@ -703,8 +697,11 @@ static void codenot (FuncState *fs, expdesc *e) { void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { lua_assert(!hasjumps(t)); - t->u.s.aux = luaK_exp2RK(fs, k); - t->k = (t->k == VUPVAL) ? VINDEXEDUP : VINDEXED; + t->u.ind.t = t->u.info; + t->u.ind.idx = luaK_exp2RK(fs, k); + t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL + : check_exp(vkisinreg(t->k), VLOCAL); + t->k = VINDEXED; } @@ -734,7 +731,7 @@ static void codearith (FuncState *fs, OpCode op, freeexp(fs, e2); freeexp(fs, e1); } - e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); + e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); e1->k = VRELOCABLE; luaK_fixline(fs, line); } @@ -752,7 +749,7 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ cond = 1; } - e1->u.s.info = condjump(fs, op, cond, o1, o2); + e1->u.info = condjump(fs, op, cond, o1, o2); e1->k = VJMP; } @@ -828,10 +825,10 @@ void luaK_posfix (FuncState *fs, BinOpr op, case OPR_CONCAT: { luaK_exp2val(fs, e2); if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); + lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1->u.s.info); - e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; + SETARG_B(getcode(fs, e2), e1->u.info); + e1->k = VRELOCABLE; e1->u.info = e2->u.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ diff --git a/src/lcode.h b/src/lcode.h index d7f7dd62f0..86d2138996 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.54 2010/04/17 12:46:32 roberto Exp $ +** $Id: lcode.h,v 1.55 2010/07/02 20:42:40 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -36,7 +36,7 @@ typedef enum BinOpr { typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; -#define getcode(fs,e) ((fs)->f->code[(e)->u.s.info]) +#define getcode(fs,e) ((fs)->f->code[(e)->u.info]) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) diff --git a/src/lcorolib.c b/src/lcorolib.c new file mode 100644 index 0000000000..981ca381fd --- /dev/null +++ b/src/lcorolib.c @@ -0,0 +1,154 @@ +/* +** $Id: lcorolib.c,v 1.2 2010/07/02 11:38:13 roberto Exp $ +** Coroutine Library +** See Copyright Notice in lua.h +*/ + + +#include + + +#define lcorolib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int auxresume (lua_State *L, lua_State *co, int narg) { + int status; + if (!lua_checkstack(co, narg)) { + lua_pushliteral(L, "too many arguments to resume"); + return -1; /* error flag */ + } + if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + status = lua_resume(co, narg); + if (status == LUA_OK || status == LUA_YIELD) { + int nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) { + lua_pop(co, nres); /* remove results anyway */ + lua_pushliteral(L, "too many results to resume"); + return -1; /* error flag */ + } + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + + +static int luaB_coresume (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + int r; + luaL_argcheck(L, co, 1, "coroutine expected"); + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + `resume' returns */ + } +} + + +static int luaB_auxwrap (lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) { + if (lua_isstring(L, -1)) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + lua_error(L); /* propagate error */ + } + return r; +} + + +static int luaB_cocreate (lua_State *L) { + lua_State *NL = lua_newthread(L); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int luaB_cowrap (lua_State *L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; +} + + +static int luaB_yield (lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + + +static int luaB_costatus (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "coroutine expected"); + if (L == co) lua_pushliteral(L, "running"); + else { + switch (lua_status(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case LUA_OK: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occurred */ + lua_pushliteral(L, "dead"); + break; + } + } + return 1; +} + + +static int luaB_corunning (lua_State *L) { + int ismain = lua_pushthread(L); + lua_pushboolean(L, ismain); + return 2; +} + + +static const luaL_Reg co_funcs[] = { + {"create", luaB_cocreate}, + {"resume", luaB_coresume}, + {"running", luaB_corunning}, + {"status", luaB_costatus}, + {"wrap", luaB_cowrap}, + {"yield", luaB_yield}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_coroutine (lua_State *L) { + luaL_newlib(L, co_funcs); + return 1; +} + diff --git a/src/ldblib.c b/src/ldblib.c index 28e671dfd2..9ae6f86b16 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.121 2010/03/26 20:58:11 roberto Exp $ +** $Id: ldblib.c,v 1.124 2010/07/25 15:18:19 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -44,19 +44,19 @@ static int db_setmetatable (lua_State *L) { } -static int db_getenv (lua_State *L) { +static int db_getuservalue (lua_State *L) { luaL_checktype(L, 1, LUA_TUSERDATA); - lua_getenv(L, 1); + lua_getuservalue(L, 1); return 1; } -static int db_setenv (lua_State *L) { +static int db_setuservalue (lua_State *L) { luaL_checktype(L, 1, LUA_TUSERDATA); if (!lua_isnoneornil(L, 2)) luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); - lua_setenv(L, 1); + lua_setuservalue(L, 1); return 1; } @@ -157,19 +157,27 @@ static int db_getlocal (lua_State *L) { lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; - if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); - if (name) { - lua_xmove(L1, L, 1); - lua_pushstring(L, name); - lua_pushvalue(L, -2); - return 2; - } - else { - lua_pushnil(L); + int nvar = luaL_checkint(L, arg+2); /* local-variable index */ + if (lua_isfunction(L, arg + 1)) { /* function argument? */ + lua_pushvalue(L, arg + 1); /* push function */ + lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ return 1; } + else { /* stack-level argument */ + if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + name = lua_getlocal(L1, &ar, nvar); + if (name) { + lua_xmove(L1, L, 1); /* push local value */ + lua_pushstring(L, name); /* push name */ + lua_pushvalue(L, -2); /* re-order */ + return 2; + } + else { + lua_pushnil(L); /* no name (nor value) */ + return 1; + } + } } @@ -367,7 +375,7 @@ static int db_traceback (lua_State *L) { static const luaL_Reg dblib[] = { {"debug", db_debug}, - {"getenv", db_getenv}, + {"getuservalue", db_getuservalue}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, @@ -376,7 +384,7 @@ static const luaL_Reg dblib[] = { {"getupvalue", db_getupvalue}, {"upvaluejoin", db_upvaluejoin}, {"upvalueid", db_upvalueid}, - {"setenv", db_setenv}, + {"setuservalue", db_setuservalue}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, @@ -387,7 +395,7 @@ static const luaL_Reg dblib[] = { LUAMOD_API int luaopen_debug (lua_State *L) { - luaL_register(L, LUA_DBLIBNAME, dblib); + luaL_newlib(L, dblib); return 1; } diff --git a/src/ldebug.c b/src/ldebug.c index dcc8ca9970..5a04d5a3e6 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.70 2010/04/13 20:48:12 roberto Exp $ +** $Id: ldebug.c,v 2.72 2010/06/21 16:30:12 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -119,12 +119,21 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n, LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { - StkId pos; - const char *name = findlocal(L, ar->i_ci, n, &pos); + const char *name; lua_lock(L); - if (name) { - setobj2s(L, L->top, pos); - api_incr_top(L); + if (ar == NULL) { /* information about non-active function? */ + if (!isLfunction(L->top - 1)) /* not a Lua function? */ + name = NULL; + else /* consider live variables at function start (parameters) */ + name = luaF_getlocalname(clvalue(L->top - 1)->l.p, n, 0); + } + else { /* active function; get information through 'ar' */ + StkId pos; + name = findlocal(L, ar->i_ci, n, &pos); + if (name) { + setobj2s(L, L->top, pos); + api_incr_top(L); + } } lua_unlock(L); return name; @@ -264,7 +273,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { static void kname (Proto *p, int c, int reg, const char *what, const char **name) { - if (c == reg && *what == 'c') + if (c == reg && what && *what == 'c') return; /* index is a constant; name already correct */ else if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) *name = svalue(&p->k[INDEXK(c)]); diff --git a/src/ldo.c b/src/ldo.c index 5b0e766e95..834a054374 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.87 2010/05/05 18:49:56 roberto Exp $ +** $Id: ldo.c,v 2.88 2010/06/04 13:06:15 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -630,8 +630,7 @@ static void f_parser (lua_State *L, void *ud) { : luaY_parser(L, p->z, &p->buff, &p->varl, p->name); setptvalue2s(L, L->top, tf); incr_top(L); - cl = luaF_newLclosure(L, tf->sizeupvalues); - cl->l.p = tf; + cl = luaF_newLclosure(L, tf); setclvalue(L, L->top - 1, cl); for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ cl->l.upvals[i] = luaF_newupval(L); diff --git a/src/lfunc.c b/src/lfunc.c index e95dad017e..1a1a8bb8bd 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.24 2010/05/10 18:23:45 roberto Exp $ +** $Id: lfunc.c,v 2.27 2010/06/30 14:11:17 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -16,7 +16,6 @@ #include "lgc.h" #include "lmem.h" #include "lobject.h" -#include "lopcodes.h" #include "lstate.h" @@ -29,9 +28,11 @@ Closure *luaF_newCclosure (lua_State *L, int n) { } -Closure *luaF_newLclosure (lua_State *L, int n) { +Closure *luaF_newLclosure (lua_State *L, Proto *p) { + int n = p->sizeupvalues; Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; c->l.isC = 0; + c->l.p = p; c->l.nupvalues = cast_byte(n); while (n--) c->l.upvals[n] = NULL; return c; @@ -56,7 +57,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { lua_assert(p->v != &p->u.value); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, o)) /* is it dead? */ - changewhite(o); /* ressurrect it */ + changewhite(o); /* resurrect it */ return p; } resetoldbit(o); /* may create a newer upval after this one */ @@ -116,6 +117,7 @@ Proto *luaF_newproto (lua_State *L) { f->p = NULL; f->sizep = 0; f->code = NULL; + f->cache = NULL; f->sizecode = 0; f->lineinfo = NULL; f->sizelineinfo = 0; diff --git a/src/lfunc.h b/src/lfunc.h index d11182b0e3..da18923150 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.5 2010/03/26 20:58:11 roberto Exp $ +** $Id: lfunc.h,v 2.6 2010/06/04 13:06:15 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -20,7 +20,7 @@ LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, Proto *p); LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); diff --git a/src/lgc.c b/src/lgc.c index 276edacd7c..fcaca1b40d 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.96 2010/05/17 20:39:31 roberto Exp $ +** $Id: lgc.c,v 2.101 2010/06/30 14:11:17 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -27,7 +27,7 @@ /* how much to allocate before next GC step */ #define GCSTEPSIZE 1024 -/* maximum numer of elements to sweep in each single step */ +/* maximum number of elements to sweep in each single step */ #define GCSWEEPMAX 40 /* cost of sweeping one element */ @@ -127,7 +127,7 @@ static int iscleared (const TValue *o, int iskey) { ** barrier that moves collector forward, that is, mark the white object ** being pointed by a black object. */ -void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { +void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(isgenerational(g) || g->gcstate != GCSpause); @@ -143,18 +143,41 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { /* ** barrier that moves collector backward, that is, mark the black object -** pointing to a white object as gray again. +** pointing to a white object as gray again. (Current implementation +** only works for tables; access to 'gclist' is not uniform across +** different types.) */ -void luaC_barrierback (lua_State *L, Table *t) { +void luaC_barrierback_ (lua_State *L, GCObject *o) { global_State *g = G(L); - GCObject *o = obj2gco(t); lua_assert(isblack(o) && !isdead(g, o)); - black2gray(o); /* make table gray (again) */ - t->gclist = g->grayagain; + black2gray(o); /* make object gray (again) */ + gco2t(o)->gclist = g->grayagain; g->grayagain = o; } +/* +** barrier for prototypes. When creating first closure (cache is +** NULL), use a forward barrier; this may be the only closure of the +** prototype (if it is a "regular" function, with a single instance) +** and the prototype may be big, so it is better to avoid traversing +** it again. Otherwise, use a backward barrier, to avoid marking all +** possible instances. +*/ +LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c) { + global_State *g = G(L); + lua_assert(isblack(obj2gco(p))); + if (p->cache == NULL) { /* first time? */ + luaC_objbarrier(L, p, c); + } + else { /* use a backward barrier */ + black2gray(obj2gco(p)); /* make prototype gray (again) */ + p->gclist = g->grayagain; + g->grayagain = obj2gco(p); + } +} + + /* ** check color (and invariants) for an upvalue that was closed, ** i.e., moved into the 'allgc' list @@ -348,7 +371,7 @@ static int traverseephemeron (global_State *g, Table *h) { if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ else if (valiswhite(gval(n))) { /* value not marked yet? */ - if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ + if (iscleared(gkey(n), 1)) /* key is not marked (yet)? */ hasclears = 1; /* may have to propagate mark from key to value */ else { /* key is marked, so mark value */ marked = 1; /* value was not marked */ @@ -411,6 +434,8 @@ static int traversetable (global_State *g, Table *h) { static int traverseproto (global_State *g, Proto *f) { int i; + if (f->cache && iswhite(obj2gco(f->cache))) + f->cache = NULL; /* allow cache to be collected */ stringmark(f->source); for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); @@ -533,6 +558,7 @@ static void convergeephemerons (global_State *g) { ** ======================================================= */ + /* ** clear collected entries from all weaktables in list 'l' */ @@ -548,7 +574,7 @@ static void cleartable (GCObject *l) { } for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && /* non-empty entry? */ - (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { + (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } @@ -932,7 +958,8 @@ static void generationalcollection (lua_State *L) { g->lastmajormem = g->totalbytes; /* update control */ } else { - luaC_runtilstate(L, bitmask(GCSpause)); /* run collection */ + luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ + luaC_runtilstate(L, bitmask(GCSpause)); if (g->totalbytes > g->lastmajormem/100 * g->gcpause) g->lastmajormem = 0; /* signal for a major collection */ } diff --git a/src/lgc.h b/src/lgc.h index 18eb70fdf2..9c5b05e2dd 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.41 2010/05/10 18:23:45 roberto Exp $ +** $Id: lgc.h,v 2.44 2010/06/30 14:11:17 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -44,7 +44,7 @@ /* ** macro to tell when main invariant (white objects cannot point to black ** ones) must be kept. During a non-generational collection, the sweep -** phase may brak the invariant, as objects turned white may point to +** phase may break the invariant, as objects turned white may point to ** still-black objects. The invariant is restored when sweep ends and ** all objects are white again. During a generational collection, the ** invariant must be kept all times. @@ -112,17 +112,20 @@ #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ - luaC_barrierf(L,obj2gco(p),gcvalue(v)); } + luaC_barrier_(L,obj2gco(p),gcvalue(v)); } -#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ - luaC_barrierback(L,t); } +#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierback_(L,p); } #define luaC_objbarrier(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ - luaC_barrierf(L,obj2gco(p),obj2gco(o)); } + luaC_barrier_(L,obj2gco(p),obj2gco(o)); } -#define luaC_objbarriert(L,t,o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } +#define luaC_objbarrierback(L,p,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); } + +#define luaC_barrierproto(L,p,c) \ + { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } LUAI_FUNC void luaC_separateudata (lua_State *L, int all); LUAI_FUNC void luaC_freeallobjects (lua_State *L); @@ -131,8 +134,9 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, int offset); -LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); -LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); +LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); +LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); LUAI_FUNC void luaC_changemode (lua_State *L, int mode); diff --git a/src/linit.c b/src/linit.c index ff296cd78f..b8af9f39ad 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.24 2010/03/26 20:58:11 roberto Exp $ +** $Id: linit.c,v 1.28 2010/07/02 11:38:13 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ @@ -29,12 +29,16 @@ static const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, + {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_BITLIBNAME, luaopen_bit}, {LUA_MATHLIBNAME, luaopen_math}, +#if defined(LUA_COMPAT_DEBUGLIB) + {LUA_DBLIBNAME, luaopen_debug}, +#endif {NULL, NULL} }; @@ -50,25 +54,17 @@ static const luaL_Reg preloadedlibs[] = { LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; - /* call open functions from 'loadedlibs' */ + /* call open functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { - lua_settop(L, 0); - lua_pushstring(L, lib->name); - (lib->func)(L); + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ } /* add open functions from 'preloadedlibs' into 'package.preload' table */ - lua_pushglobaltable(L); - luaL_findtable(L, 0, "package.preload", 0); + luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); for (lib = preloadedlibs; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_setfield(L, -2, lib->name); } - lua_pop(L, 1); /* remove package.preload table */ -#if defined(LUA_COMPAT_DEBUGLIB) - lua_getglobal(L, "require"); - lua_pushliteral(L, LUA_DBLIBNAME); - lua_call(L, 1, 0); /* call 'require"debug"' */ - lua_pop(L, 1); /* remove global table */ -#endif + lua_pop(L, 1); /* remove _PRELOAD table */ } diff --git a/src/liolib.c b/src/liolib.c index c453cb956b..3ecccb11cf 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.88 2010/03/26 20:58:11 roberto Exp $ +** $Id: liolib.c,v 2.91 2010/07/28 15:51:59 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -120,7 +120,7 @@ static FILE **newprefile (lua_State *L) { static FILE **newfile (lua_State *L) { FILE **pf = newprefile(L); lua_pushvalue(L, lua_upvalueindex(1)); /* set upvalue... */ - lua_setenv(L, -2); /* ... as environment for new file */ + lua_setuservalue(L, -2); /* ... as environment for new file */ return pf; } @@ -163,7 +163,7 @@ static int io_fclose (lua_State *L) { static int aux_close (lua_State *L) { - lua_getenv(L, 1); + lua_getuservalue(L, 1); lua_getfield(L, -1, "__close"); return (lua_tocfunction(L, -1))(L); } @@ -583,7 +583,7 @@ static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, NULL, flib); /* add file methods to new metatable */ + luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ lua_pop(L, 1); /* pop new metatable */ } @@ -595,7 +595,7 @@ static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { lua_rawseti(L, 1, k); /* add it to common upvalue */ } lua_pushvalue(L, 3); /* get environment for default files */ - lua_setenv(L, -2); /* set it as environment for file */ + lua_setuservalue(L, -2); /* set it as environment for file */ lua_setfield(L, 2, fname); /* add file to module */ } @@ -615,8 +615,9 @@ LUAMOD_API int luaopen_io (lua_State *L) { createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ newenv(L, io_fclose); /* upvalue for all io functions at index 1 */ - lua_pushvalue(L, -1); /* copy to be consumed by 'openlib' */ - luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); /* new module at index 2 */ + luaL_newlibtable(L, iolib); /* new module at index 2 */ + lua_pushvalue(L, 1); /* copy of env to be consumed by 'setfuncs' */ + luaL_setfuncs(L, iolib, 1); /* create (and set) default files */ newenv(L, io_noclose); /* environment for default files at index 3 */ createstdfile(L, stdin, IO_INPUT, "stdin"); diff --git a/src/llimits.h b/src/llimits.h index 02be816eda..4b75a84e60 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.80 2010/05/07 18:44:12 roberto Exp $ +** $Id: llimits.h,v 1.82 2010/05/31 16:08:55 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -97,6 +97,11 @@ typedef LUAI_UACNUMBER l_uacNumber; #define LUAI_MAXCCALLS 200 #endif +/* +** maximum number of upvalues in a closure (both C and Lua). (Value +** must fit in an unsigned char.) +*/ +#define MAXUPVAL UCHAR_MAX /* @@ -179,7 +184,8 @@ typedef lu_int32 Instruction; #if !defined(HARDMEMTESTS) #define condchangemem(L) condmovestack(L) #else -#define condchangemem(L) luaC_fullgc(L, 0) +#define condchangemem(L) \ + ((void)(gcstopped(G(L)) || (luaC_fullgc(L, 0), 1))) #endif #endif diff --git a/src/lmathlib.c b/src/lmathlib.c index 27e6847ed8..7ba6550c1c 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.74 2009/11/24 12:05:44 roberto Exp $ +** $Id: lmathlib.c,v 1.75 2010/07/02 11:38:13 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -263,7 +263,7 @@ static const luaL_Reg mathlib[] = { ** Open math library */ LUAMOD_API int luaopen_math (lua_State *L) { - luaL_register(L, LUA_MATHLIBNAME, mathlib); + luaL_newlib(L, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, HUGE_VAL); diff --git a/src/loadlib.c b/src/loadlib.c index 793c658e86..82c00b0d60 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,11 +1,11 @@ /* -** $Id: loadlib.c,v 1.82 2010/03/19 15:02:34 roberto Exp $ +** $Id: loadlib.c,v 1.89 2010/07/28 15:51:59 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** ** This module contains an implementation of loadlib for Unix systems -** that have dlfcn, an implementation for Darwin (Mac OS X), an -** implementation for Windows, and a stub for other systems. +** that have dlfcn, an implementation for Windows, and a stub for other +** systems. */ @@ -23,17 +23,21 @@ /* -** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment +** LUA_PATH and LUA_CPATH are the names of the environment ** variables that Lua check to set its paths. */ -#if !defined(LUA_PATH_VAR) -#define LUA_PATH_VAR "LUA_PATH" +#if !defined(LUA_PATH) +#define LUA_PATH "LUA_PATH" #endif -#if !defined(LUA_CPATH_VAR) -#define LUA_CPATH_VAR "LUA_CPATH" +#if !defined(LUA_CPATH) +#define LUA_CPATH "LUA_CPATH" #endif +#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR + +#define LUA_PATHVERSION LUA_PATH LUA_PATHSUFFIX +#define LUA_CPATHVERSION LUA_CPATH LUA_PATHSUFFIX /* ** LUA_PATH_SEP is the character that separates templates in a path. @@ -145,7 +149,7 @@ static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; DWORD nsize = sizeof(buff)/sizeof(char); - DWORD n = GetModuleFileName(NULL, buff, nsize); + DWORD n = GetModuleFileNameA(NULL, buff, nsize); if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) luaL_error(L, "unable to get ModuleFileName"); else { @@ -159,7 +163,7 @@ static void setprogdir (lua_State *L) { static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; - if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buffer, sizeof(buffer), NULL)) lua_pushstring(L, buffer); else @@ -172,7 +176,7 @@ static void ll_unloadlib (void *lib) { static void *ll_load (lua_State *L, const char *path, int seeglb) { - HMODULE lib = LoadLibraryEx(path, NULL, LUA_LLE_FLAGS); + HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); (void)(seeglb); /* symbols are 'global' by default? */ if (lib == NULL) pusherror(L); return lib; @@ -188,90 +192,6 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { /* }====================================================== */ - -#elif defined(LUA_DL_DYLD) -/* -** {====================================================================== -** Old native Mac OS X - only for old versions of Mac OS (< 10.3) -** ======================================================================= -*/ - -#include - - -/* Mac appends a `_' before C function names */ -#undef POF -#define POF "_" LUA_POF - - -static void pusherror (lua_State *L) { - const char *err_str; - const char *err_file; - NSLinkEditErrors err; - int err_num; - NSLinkEditError(&err, &err_num, &err_file, &err_str); - lua_pushstring(L, err_str); -} - - -static const char *errorfromcode (NSObjectFileImageReturnCode ret) { - switch (ret) { - case NSObjectFileImageInappropriateFile: - return "file is not a bundle"; - case NSObjectFileImageArch: - return "library is for wrong CPU type"; - case NSObjectFileImageFormat: - return "bad format"; - case NSObjectFileImageAccess: - return "cannot access file"; - case NSObjectFileImageFailure: - default: - return "unable to load library"; - } -} - - -static void ll_unloadlib (void *lib) { - NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); -} - - -static void *ll_load (lua_State *L, const char *path, int seeglb) { - NSObjectFileImage img; - NSObjectFileImageReturnCode ret; - /* this would be a rare case, but prevents crashing if it happens */ - if(!_dyld_present()) { - lua_pushliteral(L, "dyld not present"); - return NULL; - } - ret = NSCreateObjectFileImageFromFile(path, &img); - if (ret == NSObjectFileImageSuccess) { - NSModule mod = NSLinkModule(img, - path, - NSLINKMODULE_OPTION_RETURN_ON_ERROR | - (seeglb ? 0 : NSLINKMODULE_OPTION_PRIVATE)); - NSDestroyObjectFileImage(img); - if (mod == NULL) pusherror(L); - return mod; - } - lua_pushstring(L, errorfromcode(ret)); - return NULL; -} - - -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { - NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); - if (nss == NULL) { - lua_pushfstring(L, "symbol " LUA_QS " not found", sym); - return NULL; - } - return (lua_CFunction)NSAddressOfSymbol(nss); -} - -/* }====================================================== */ - - - #else /* ** {====================================================== @@ -507,7 +427,7 @@ static int loader_Croot (lua_State *L) { static int loader_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); - lua_getfield(L, lua_upvalueindex(1), "preload"); + lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); @@ -575,11 +495,10 @@ static int ll_require (lua_State *L) { ** 'module' function ** ======================================================= */ - +#if defined(LUA_COMPAT_MODULE) /* -** FOR COMPATIBILITY ONLY: changes the _ENV variable of -** calling function +** changes the _ENV variable of calling function */ static void set_env (lua_State *L) { lua_Debug ar; @@ -620,18 +539,8 @@ static void modinit (lua_State *L, const char *modname) { static int ll_module (lua_State *L) { const char *modname = luaL_checkstring(L, 1); - int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ - if (!lua_istable(L, -1)) { /* not found? */ - lua_pop(L, 1); /* remove previous result */ - /* try global variable (and create one if it does not exist) */ - lua_pushglobaltable(L); - if (luaL_findtable(L, 0, modname, 1) != NULL) - return luaL_error(L, "name conflict for module " LUA_QS, modname); - lua_pushvalue(L, -1); - lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ - } + int lastarg = lua_gettop(L); /* last parameter */ + luaL_pushmodule(L, modname, 1); /* get/create module table */ /* check whether table already has a _NAME field */ lua_getfield(L, -1, "_NAME"); if (!lua_isnil(L, -1)) /* is table an initialized module? */ @@ -642,7 +551,7 @@ static int ll_module (lua_State *L) { } lua_pushvalue(L, -1); set_env(L); - dooptions(L, loaded - 1); + dooptions(L, lastarg); return 1; } @@ -660,6 +569,17 @@ static int ll_seeall (lua_State *L) { } +#else + +static int ll_seeall (lua_State *L) { + return luaL_error(L, "deprecated function"); +} + +static int ll_module (lua_State *L) { + return luaL_error(L, "deprecated function"); +} + +#endif /* }====================================================== */ @@ -667,9 +587,11 @@ static int ll_seeall (lua_State *L) { /* auxiliary mark (for internal use) */ #define AUXMARK "\1" -static void setpath (lua_State *L, const char *fieldname, const char *envname, - const char *def) { - const char *path = getenv(envname); +static void setpath (lua_State *L, const char *fieldname, const char *envname1, + const char *envname2, const char *def) { + const char *path = getenv(envname1); + if (path == NULL) /* no environment variable? */ + path = getenv(envname2); /* try alternative name */ if (path == NULL) /* no environment variable? */ lua_pushstring(L, def); /* use default */ else { @@ -710,7 +632,7 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_pushcfunction(L, gctm); lua_setfield(L, -2, "__gc"); /* create `package' table */ - luaL_register(L, LUA_LOADLIBNAME, pk_funcs); + luaL_newlib(L, pk_funcs); /* create `loaders' table */ lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0); /* fill it with pre-defined loaders */ @@ -720,21 +642,23 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ - setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); /* set field `path' */ - setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* set field `cpath' */ + /* set field 'path' */ + setpath(L, "path", LUA_PATHVERSION, LUA_PATH, LUA_PATH_DEFAULT); + /* set field 'cpath' */ + setpath(L, "cpath", LUA_CPATHVERSION, LUA_CPATH, LUA_CPATH_DEFAULT); /* store config information */ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); lua_setfield(L, -2, "config"); /* set field `loaded' */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); /* set field `preload' */ - lua_newtable(L); + luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ - luaL_openlib(L, NULL, ll_funcs, 1); /* open lib into global table */ + luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ lua_pop(L, 1); /* pop global table */ return 1; /* return 'package' table */ } diff --git a/src/lobject.h b/src/lobject.h index 736342206f..5b856f3ce6 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.40 2010/05/07 18:44:46 roberto Exp $ +** $Id: lobject.h,v 2.42 2010/07/26 15:53:23 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -56,17 +56,18 @@ typedef struct GCheader { ** Union of all Lua values */ typedef union { - GCObject *gc; - void *p; - lua_Number n; - int b; - lua_CFunction f; + GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + lua_Number n; /* numbers */ + int b; /* booleans */ + lua_CFunction f; /* light C functions */ } Value; /* -** Tagged Values +** Tagged Values. This is the basic representation of values in Lua, +** an actual value plus a tag with its type. */ #define TValuefields Value value_; int tt_ @@ -76,7 +77,7 @@ typedef struct lua_TValue { } TValue; -/* macro defining a nil value to be used in definitions */ +/* macro defining a nil value */ #define NILCONSTANT {NULL}, LUA_TNIL @@ -125,6 +126,8 @@ typedef struct lua_TValue { #define iscollectable(o) (ttype(o) >= LUA_TSTRING) + +/* Macros for internal tests */ #define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) #define checkconsistency(obj) lua_assert(!iscollectable(obj) || righttt(obj)) @@ -191,7 +194,7 @@ typedef struct lua_TValue { /* -** different types of sets, according to destination +** different types of assignments, according to destination */ /* from stack to (same) stack */ @@ -215,7 +218,7 @@ typedef TValue *StkId; /* index to stack elements */ /* -** String headers for string table +** Header for string value; string bytes follow the end of this structure */ typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ @@ -228,11 +231,16 @@ typedef union TString { } TString; +/* get the actual string (array of bytes) from a TString */ #define getstr(ts) cast(const char *, (ts) + 1) -#define svalue(o) getstr(rawtsvalue(o)) +/* get the actual string (array of bytes) from a Lua value */ +#define svalue(o) getstr(rawtsvalue(o)) +/* +** Header for userdata; memory area follows the end of this structure +*/ typedef union Udata { L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ struct { @@ -246,15 +254,26 @@ typedef union Udata { /* -** Upvalues from a function prototype +** Description of an upvalue for function prototypes */ typedef struct Upvaldesc { TString *name; /* upvalue name (for debug information) */ - lu_byte instack; + lu_byte instack; /* whether it is in stack */ lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ } Upvaldesc; +/* +** Description of a local variable for function prototypes +** (used for debug information) +*/ +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + /* ** Function Prototypes */ @@ -264,8 +283,9 @@ typedef struct Proto { Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ - struct LocVar *locvars; /* information about local variables */ + LocVar *locvars; /* information about local variables */ Upvaldesc *upvalues; /* upvalue information */ + union Closure *cache; /* last created closure with this prototype */ TString *source; int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of `k' */ @@ -276,24 +296,16 @@ typedef struct Proto { int linedefined; int lastlinedefined; GCObject *gclist; - lu_byte numparams; + lu_byte numparams; /* number of fixed parameters */ lu_byte is_vararg; - lu_byte maxstacksize; + lu_byte maxstacksize; /* maximum stack used by this function */ } Proto; -typedef struct LocVar { - TString *varname; - int startpc; /* first point where variable is active */ - int endpc; /* first point where variable is dead */ -} LocVar; - - /* -** Upvalues +** Lua Upvalues */ - typedef struct UpVal { CommonHeader; TValue *v; /* points to stack or to its own value */ @@ -317,14 +329,14 @@ typedef struct UpVal { typedef struct CClosure { ClosureHeader; lua_CFunction f; - TValue upvalue[1]; + TValue upvalue[1]; /* list of upvalues */ } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; - UpVal *upvals[1]; + UpVal *upvals[1]; /* list of upvalues */ } LClosure; @@ -338,6 +350,7 @@ typedef union Closure { #define getproto(o) (clvalue(o)->l.p) + /* ** Tables */ @@ -382,8 +395,12 @@ typedef struct Table { #define sizenode(t) (twoto((t)->lsizenode)) +/* +** (address of) a fixed nil value +*/ #define luaO_nilobject (&luaO_nilobject_) + LUAI_DDEC const TValue luaO_nilobject_; LUAI_FUNC int luaO_int2fb (unsigned int x); diff --git a/src/loslib.c b/src/loslib.c index 41592088b0..9b27ebce48 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.29 2009/12/17 13:08:51 roberto Exp $ +** $Id: loslib.c,v 1.31 2010/07/02 12:01:53 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -146,11 +146,10 @@ static int getboolfield (lua_State *L, const char *key) { static int getfield (lua_State *L, const char *key, int d) { - int res; + int res, isnum; lua_getfield(L, -1, key); - if (lua_isnumber(L, -1)) - res = (int)lua_tointeger(L, -1); - else { + res = (int)lua_tointegerx(L, -1, &isnum); + if (!isnum) { if (d < 0) return luaL_error(L, "field " LUA_QS " missing in date table", key); res = d; @@ -304,7 +303,7 @@ static const luaL_Reg syslib[] = { LUAMOD_API int luaopen_os (lua_State *L) { - luaL_register(L, LUA_OSLIBNAME, syslib); + luaL_newlib(L, syslib); return 1; } diff --git a/src/lparser.c b/src/lparser.c index 762cb4fc59..16c05d9ebc 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.86 2010/05/15 13:32:02 roberto Exp $ +** $Id: lparser.c,v 2.90 2010/07/07 16:27:29 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -138,7 +138,7 @@ static TString *str_checkname (LexState *ls) { static void init_exp (expdesc *e, expkind k, int i) { e->f = e->t = NO_JUMP; e->k = k; - e->u.s.info = i; + e->u.info = i; } @@ -221,12 +221,12 @@ static int searchupvalue (FuncState *fs, TString *name) { static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; - checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues"); + checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, - Upvaldesc, UCHAR_MAX, "upvalues"); + Upvaldesc, MAXUPVAL, "upvalues"); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; f->upvalues[fs->nups].instack = (v->k == VLOCAL); - f->upvalues[fs->nups].idx = cast_byte(v->u.s.info); + f->upvalues[fs->nups].idx = cast_byte(v->u.info); f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->L, f, name); return fs->nups++; @@ -402,8 +402,8 @@ static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; - removevars(fs, 0); luaK_ret(fs, 0, 0); /* final return */ + removevars(fs, 0); luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); @@ -518,7 +518,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { checknext(ls, '='); rkkey = luaK_exp2RK(fs, &key); expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); + luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } @@ -528,7 +528,7 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) { luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { - luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ } } @@ -538,13 +538,13 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); - luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); + luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); - luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); + luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); } } @@ -702,7 +702,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) { } } lua_assert(f->k == VNONRELOC); - base = f->u.s.info; /* base register for call */ + base = f->u.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { @@ -969,27 +969,26 @@ struct LHS_assign { ** local value in a safe place and use this safe copy in the previous ** assignment. */ -static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v, - expkind ix, OpCode op) { +static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { - if (lh->v.k == ix) { - if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ - conflict = 1; - lh->v.k = VINDEXED; - lh->v.u.s.info = extra; /* previous assignment will use safe copy */ - } - if (v->k == VLOCAL && lh->v.u.s.aux == v->u.s.info) { /* conflict? */ - conflict = 1; - lua_assert(lh->v.k == VINDEXED); - lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ - } + /* conflict in table 't'? */ + if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { + conflict = 1; + lh->v.u.ind.vt = VLOCAL; + lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ + } + /* conflict in index 'idx'? */ + if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ } } if (conflict) { - luaK_codeABC(fs, op, fs->freereg, v->u.s.info, 0); /* make copy */ + OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; + luaK_codeABC(fs, op, fs->freereg, v->u.info, 0); /* make copy */ luaK_reserveregs(fs, 1); } } @@ -997,16 +996,13 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v, static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; - check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXEDUP, - "syntax error"); + check_condition(ls, vkisvar(lh->v.k), "syntax error"); if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ struct LHS_assign nv; nv.prev = lh; primaryexp(ls, &nv.v); - if (nv.v.k == VLOCAL) - check_conflict(ls, lh, &nv.v, VINDEXED, OP_MOVE); - else if (nv.v.k == VUPVAL) - check_conflict(ls, lh, &nv.v, VINDEXEDUP, OP_GETUPVAL); + if (nv.v.k != VINDEXED) + check_conflict(ls, lh, &nv.v); checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls, "variable names"); assignment(ls, &nv, nvars+1); @@ -1108,7 +1104,7 @@ static int exp1 (LexState *ls) { expr(ls, &e); luaK_exp2nextreg(ls->fs, &e); lua_assert(e.k == VNONRELOC); - reg = e.u.s.info; + reg = e.u.info; return reg; } diff --git a/src/lparser.h b/src/lparser.h index 9e406a7b49..6055a85bf6 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.63 2010/03/12 19:14:06 roberto Exp $ +** $Id: lparser.h,v 1.65 2010/07/07 16:27:29 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -23,23 +23,30 @@ typedef enum { VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ + VNONRELOC, /* info = result register */ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in 'upvalues' */ - VINDEXED, /* info = table R/K; aux = index R/K */ - VINDEXEDUP, /* info = table upvalue; aux = R/K */ + VINDEXED, /* t = table register/upvalue; idx = index R/K */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ - VNONRELOC, /* info = result register */ VCALL, /* info = instruction pc */ VVARARG /* info = instruction pc */ } expkind; +#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) +#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) + typedef struct expdesc { expkind k; union { - struct { int info, aux; } s; - lua_Number nval; + struct { /* for indexed variables (VINDEXED) */ + short idx; /* index (R/K) */ + lu_byte t; /* table (register or upvalue) */ + lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ + } ind; + int info; /* for generic use */ + lua_Number nval; /* for VKNUM */ } u; int t; /* patch list of `exit when true' */ int f; /* patch list of `exit when false' */ diff --git a/src/lstrlib.c b/src/lstrlib.c index a5c3a2043f..558a748ec6 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.152 2010/05/04 17:20:33 roberto Exp $ +** $Id: lstrlib.c,v 1.154 2010/07/02 11:38:13 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -241,6 +241,7 @@ static int match_class (int c, int cl) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; case 's' : res = isspace(c); break; @@ -912,7 +913,7 @@ static void createmetatable (lua_State *L) { ** Open string library */ LUAMOD_API int luaopen_string (lua_State *L) { - luaL_register(L, LUA_STRLIBNAME, strlib); + luaL_newlib(L, strlib); createmetatable(L); return 1; } diff --git a/src/ltable.c b/src/ltable.c index dc6604dd9b..f93b96ccea 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.50 2010/04/18 13:22:48 roberto Exp $ +** $Id: ltable.c,v 2.52 2010/06/25 12:18:10 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -148,7 +148,7 @@ static int findindex (lua_State *L, Table *t, StkId key) { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in `next' */ - if (luaO_rawequalObj(key2tval(n), key) || + if (luaO_rawequalObj(gkey(n), key) || (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && gcvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ @@ -174,7 +174,7 @@ int luaH_next (lua_State *L, Table *t, StkId key) { } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(L, key, key2tval(gnode(t, i))); + setobj2s(L, key, gkey(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); return 1; } @@ -255,7 +255,7 @@ static int numusehash (const Table *t, int *nums, int *pnasize) { while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { - ause += countint(key2tval(n), nums); + ause += countint(gkey(n), nums); totaluse++; } } @@ -321,7 +321,7 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) - setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); + setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); } if (!isdummy(nold)) luaM_freearray(L, nold, twoto(oldhsize)); /* free old array */ @@ -406,7 +406,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { return luaH_set(L, t, key); /* re-insert key into grown table */ } lua_assert(!isdummy(n)); - othern = mainposition(t, key2tval(mp)); + othern = mainposition(t, gkey(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ @@ -423,7 +423,7 @@ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { } } setobj2t(L, gkey(mp), key); - luaC_barriert(L, t, key); + luaC_barrierback(L, obj2gco(t), key); lua_assert(ttisnil(gval(mp))); return gval(mp); } @@ -481,7 +481,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { default: { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(key2tval(n), key)) + if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); diff --git a/src/ltable.h b/src/ltable.h index 784377ac9a..c14b028323 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.13 2009/11/06 17:07:48 roberto Exp $ +** $Id: ltable.h,v 2.14 2010/06/25 12:18:10 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,8 +15,6 @@ #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) -#define key2tval(n) (&(n)->i_key.tvk) - LUAI_FUNC const TValue *luaH_getint (Table *t, int key); LUAI_FUNC TValue *luaH_setint (lua_State *L, Table *t, int key); diff --git a/src/ltablib.c b/src/ltablib.c index 2e00da29cf..b094d2f87c 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.55 2010/03/13 03:57:46 roberto Exp $ +** $Id: ltablib.c,v 1.56 2010/07/02 11:38:13 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -324,7 +324,7 @@ static const luaL_Reg tab_funcs[] = { LUAMOD_API int luaopen_table (lua_State *L) { - luaL_register(L, LUA_TABLIBNAME, tab_funcs); + luaL_newlib(L, tab_funcs); #if defined(LUA_COMPAT_UNPACK) /* _G.unpack = table.unpack */ lua_getfield(L, -1, "unpack"); diff --git a/src/lua.c b/src/lua.c index 2b1c61613d..7d23636f8f 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.190 2010/04/14 15:14:21 roberto Exp $ +** $Id: lua.c,v 1.192 2010/07/25 15:03:37 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -31,10 +31,13 @@ #define LUA_MAXINPUT 512 #endif -#if !defined(LUA_INIT_VAR) -#define LUA_INIT_VAR "LUA_INIT" +#if !defined(LUA_INIT) +#define LUA_INIT "LUA_INIT" #endif +#define LUA_INITVERSION \ + LUA_INIT "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR + /* ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that @@ -167,14 +170,14 @@ static int traceback (lua_State *L) { } -static int docall (lua_State *L, int narg, int clear) { +static int docall (lua_State *L, int narg, int nres) { int status; int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ globalL = L; /* to be available to 'laction' */ signal(SIGINT, laction); - status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); + status = lua_pcall(L, narg, nres, base); signal(SIGINT, SIG_DFL); lua_remove(L, base); /* remove traceback function */ return status; @@ -206,22 +209,31 @@ static int getargs (lua_State *L, char **argv, int n) { static int dofile (lua_State *L, const char *name) { int status = luaL_loadfile(L, name); - if (status == LUA_OK) status = docall(L, 0, 1); + if (status == LUA_OK) status = docall(L, 0, 0); return report(L, status); } static int dostring (lua_State *L, const char *s, const char *name) { int status = luaL_loadbuffer(L, s, strlen(s), name); - if (status == LUA_OK) status = docall(L, 0, 1); + if (status == LUA_OK) status = docall(L, 0, 0); return report(L, status); } static int dolibrary (lua_State *L, const char *name) { - lua_getglobal(L, "require"); + int status; + lua_pushglobaltable(L); + lua_getfield(L, -1, "require"); lua_pushstring(L, name); - return report(L, docall(L, 1, 1)); + status = docall(L, 1, 1); + if (status == LUA_OK) { + lua_setfield(L, -2, name); /* global[name] = require return */ + lua_pop(L, 1); /* remove global table */ + } + else + lua_remove(L, -2); /* remove global table (below error msg.) */ + return report(L, status); } @@ -297,7 +309,7 @@ static void dotty (lua_State *L) { const char *oldprogname = progname; progname = NULL; while ((status = loadline(L)) != -1) { - if (status == LUA_OK) status = docall(L, 0, 0); + if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); report(L, status); if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); @@ -326,7 +338,7 @@ static int handle_script (lua_State *L, char **argv, int n) { status = luaL_loadfile(L, fname); lua_insert(L, -(narg+1)); if (status == LUA_OK) - status = docall(L, narg, 0); + status = docall(L, narg, LUA_MULTRET); else lua_pop(L, narg); return report(L, status); @@ -400,12 +412,17 @@ static int runargs (lua_State *L, char **argv, int n) { static int handle_luainit (lua_State *L) { - const char *init = getenv(LUA_INIT_VAR); + const char *name = "=" LUA_INITVERSION; + const char *init = getenv(name + 1); + if (init == NULL) { + name = "=" LUA_INIT; + init = getenv(name + 1); /* try alternative name */ + } if (init == NULL) return LUA_OK; else if (init[0] == '@') return dofile(L, init+1); else - return dostring(L, init, "=" LUA_INIT_VAR); + return dostring(L, init, name); } diff --git a/src/lua.h b/src/lua.h index 09a9ab7661..d1cf33ab56 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.270 2010/05/12 14:09:20 roberto Exp $ +** $Id: lua.h,v 1.273 2010/07/25 15:18:19 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -16,8 +16,12 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.2" -#define LUA_RELEASE "Lua 5.2.0 (work3)" +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "2" +#define LUA_VERSION_RELEASE "0" " (work4)" + +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_VERSION_NUM 502 #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2010 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -153,8 +157,8 @@ LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); -LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); -LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); +LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_rawlen) (lua_State *L, int idx); @@ -213,7 +217,7 @@ LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API void (lua_getenv) (lua_State *L, int idx); +LUA_API void (lua_getuservalue) (lua_State *L, int idx); /* @@ -224,7 +228,7 @@ LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API void (lua_setenv) (lua_State *L, int idx); +LUA_API void (lua_setuservalue) (lua_State *L, int idx); /* @@ -296,6 +300,9 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); ** =============================================================== */ +#define lua_tonumber(L,i) lua_tonumberx(L,i,NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,i,NULL) + #define lua_pop(L,n) lua_settop(L, -(n)-1) #define lua_newtable(L) lua_createtable(L, 0, 0) diff --git a/src/luaconf.h b/src/luaconf.h index 0606230dae..12ec5fc1e3 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.137 2010/05/12 14:17:36 roberto Exp $ +** $Id: luaconf.h,v 1.142 2010/07/28 15:51:59 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -76,7 +76,7 @@ ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ -#if defined(_WIN32) +#if defined(_WIN32) /* { */ /* ** In Windows, any exclamation mark ('!') in the path is replaced by the ** path of the directory of the executable file of the current process. @@ -89,16 +89,18 @@ #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" -#else /* _WIN32 */ +#else /* }{ */ + +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/" #define LUA_ROOT "/usr/local/" -#define LUA_LDIR LUA_ROOT "share/lua/5.2/" -#define LUA_CDIR LUA_ROOT "lib/lua/5.2/" +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" -#endif /* _WIN32 */ +#endif /* } */ /* @@ -122,19 +124,19 @@ ** the libraries, you may want to use the following definition (define ** LUA_BUILD_AS_DLL to get it). */ -#if defined(LUA_BUILD_AS_DLL) +#if defined(LUA_BUILD_AS_DLL) /* { */ -#if defined(LUA_CORE) || defined(LUA_LIB) +#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ #define LUA_API __declspec(dllexport) -#else +#else /* }{ */ #define LUA_API __declspec(dllimport) -#endif +#endif /* } */ -#else /* LUA_BUILD_AS_DLL */ +#else /* }{ */ #define LUA_API extern -#endif /* LUA_BUILD_AS_DLL */ +#endif /* } */ /* more often than not the libs go together with the core */ @@ -156,7 +158,7 @@ ** give a warning about it. To avoid these warnings, change to the ** default definition. */ -#if defined(luaall_c) +#if defined(luaall_c) /* { */ #define LUAI_FUNC static #define LUAI_DDEC static #define LUAI_DDEF static @@ -167,11 +169,11 @@ #define LUAI_DDEC LUAI_FUNC #define LUAI_DDEF /* empty */ -#else /* luaall_c */ +#else /* }{ */ #define LUAI_FUNC extern #define LUAI_DDEC extern #define LUAI_DDEF /* empty */ -#endif /* luaall_c */ +#endif /* } */ @@ -229,10 +231,12 @@ /* @@ LUA_COMPAT_CPCALL controls the presence of macro 'lua_cpcall'. -** You can replace it with the preregistered function 'cpcall'. +** You can call your C function directly (with light C functions) */ #define lua_cpcall(L,f,u) \ - (lua_pushlightuserdata(L,(u)), luaL_cpcall(L,(f),1,0)) + (lua_pushcfunction(L, (f)), \ + lua_pushlightuserdata(L,(u)), \ + lua_pcall(L,1,0,0)) /* @@ -269,6 +273,12 @@ /* compatibility with previous wrong spelling */ #define luaL_typerror luaL_typeerror +/* +@@ LUA_COMPAT_MODULE controls compatibility with previous +** module functions 'module' (Lua) and 'luaL_register' (C). +*/ +#define LUA_COMPAT_MODULE + #endif /* LUA_COMPAT_ALL */ /* }================================================================== */ @@ -281,14 +291,14 @@ ** your machine. Probably you do not need to change this. */ /* avoid overflows in comparison */ -#if INT_MAX-20 < 32760 +#if INT_MAX-20 < 32760 /* { */ #define LUAI_BITSINT 16 -#elif INT_MAX > 2147483640L +#elif INT_MAX > 2147483640L /* }{ */ /* int has at least 32 bits */ #define LUAI_BITSINT 32 -#else +#else /* }{ */ #error "you must define LUA_BITSINT with number of bits in an integer" -#endif +#endif /* } */ /* @@ -301,16 +311,16 @@ ** good enough for your machine. Probably you do not need to change ** this. */ -#if LUAI_BITSINT >= 32 +#if LUAI_BITSINT >= 32 /* { */ #define LUA_INT32 int #define LUAI_UMEM size_t #define LUAI_MEM ptrdiff_t -#else +#else /* }{ */ /* 16-bit ints */ #define LUA_INT32 long #define LUAI_UMEM unsigned long #define LUAI_MEM long -#endif +#endif /* } */ /* @@ -436,17 +446,17 @@ /* On a Pentium, resort to a trick */ #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ - (defined(__i386) || defined (_M_IX86) || defined(__i386__)) + (defined(__i386) || defined (_M_IX86) || defined(__i386__)) /* { */ /* On a Microsoft compiler, use assembler */ -#if defined(_MSC_VER) +#if defined(_MSC_VER) /* { */ #define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} #define lua_number2integer(i,n) lua_number2int(i, n) #define lua_number2uint(i,n) \ {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} -#else /* _MSC_VER */ +#else /* }{ */ /* the next trick should work on any Pentium, but sometimes clashes with a DirectX idiosyncrasy */ @@ -456,16 +466,16 @@ union luai_Cast { double l_d; long l_l; }; #define lua_number2integer(i,n) lua_number2int(i, n) #define lua_number2uint(i,n) lua_number2int(i, n) -#endif /* _MSC_VER */ +#endif /* } */ -#else /* LUA_NUMBER_DOUBLE ... (Pentium) */ +#else /* }{ */ /* this option always works, but may be slow */ #define lua_number2int(i,n) ((i)=(int)(n)) #define lua_number2integer(i,n) ((i)=(LUA_INTEGER)(n)) #define lua_number2uint(i,n) ((i)=(unsigned LUA_INT32)(n)) -#endif /* LUA_NUMBER_DOUBLE ... (Pentium) */ +#endif /* } */ /* on several machines, coercion from unsigned to double is too slow, @@ -477,7 +487,7 @@ union luai_Cast { double l_d; long l_l; }; /* @@ luai_hashnum is a macro do hash a lua_Number value into an integer. @* The hash must be deterministic and give reasonable values for -@* both small and large values (outside the range of integers). +@* both small and large values (outside the range of integers). @* It is used only in ltable.c. */ diff --git a/src/lualib.h b/src/lualib.h index d5e4ba9d02..db2e200ef8 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.39 2009/11/24 12:05:44 roberto Exp $ +** $Id: lualib.h,v 1.40 2010/06/10 21:29:47 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -15,9 +15,11 @@ #define LUA_FILEHANDLE "FILE*" -#define LUA_COLIBNAME "coroutine" LUAMOD_API int (luaopen_base) (lua_State *L); +#define LUA_COLIBNAME "coroutine" +LUAMOD_API int (luaopen_coroutine) (lua_State *L); + #define LUA_TABLIBNAME "table" LUAMOD_API int (luaopen_table) (lua_State *L); diff --git a/src/lvm.c b/src/lvm.c index 518a16ba0a..a222049be5 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.120 2010/05/13 19:53:05 roberto Exp $ +** $Id: lvm.c,v 2.123 2010/06/30 14:11:17 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -88,7 +88,7 @@ static void callTM (lua_State *L, const TValue *f, const TValue *p1, setobj2s(L, L->top++, p1); /* 1st argument */ setobj2s(L, L->top++, p2); /* 2nd argument */ if (!hasres) /* no result? 'p3' is third argument */ - setobj2s(L, L->top++, p3); /* 3th argument */ + setobj2s(L, L->top++, p3); /* 3rd argument */ luaD_checkstack(L, 0); /* metamethod may yield only when called from Lua code */ luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); @@ -136,7 +136,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (!ttisnil(oldval) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); - luaC_barriert(L, h, val); + luaC_barrierback(L, obj2gco(h), val); return; } /* else will try the tag method */ @@ -345,6 +345,51 @@ void luaV_arith (lua_State *L, StkId ra, const TValue *rb, } +/* +** check whether cached closure in prototype 'p' may be reused, that is, +** whether there is a cached closure with the same upvalues needed by +** new closure to be created. +*/ +static Closure *getcached (Proto *p, UpVal **encup, StkId base) { + Closure *c = p->cache; + if (c != NULL) { /* is there a cached closure? */ + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ + TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; + if (c->l.upvals[i]->v != v) + return NULL; /* wrong upvalue; cannot reuse closure */ + } + } + return c; /* return cached closure (or NULL if no cached closure) */ +} + + +/* +** create a new Lua closure, push it in the stack, and initialize +** its upvalues. Note that the call to 'luaC_barrierproto' must come +** before the assignment to 'p->cache', as the function needs the +** original value of that field. +*/ +static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, + StkId ra) { + int nup = p->sizeupvalues; + Upvaldesc *uv = p->upvalues; + int i; + Closure *ncl = luaF_newLclosure(L, p); + setclvalue(L, ra, ncl); /* anchor new closure in stack */ + for (i = 0; i < nup; i++) { /* fill in its upvalues */ + if (uv[i].instack) /* upvalue refers to local variable? */ + ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx); + else /* get upvalue from enclosing function */ + ncl->l.upvals[i] = encup[uv[i].idx]; + } + luaC_barrierproto(L, p, ncl); + p->cache = ncl; /* save it on cache for reuse */ +} + + /* ** finish execution of an opcode interrupted by an yield */ @@ -721,7 +766,7 @@ void luaV_execute (lua_State *L) { for (; n > 0; n--) { TValue *val = ra+n; setobj2t(L, luaH_setint(L, h, last--), val); - luaC_barriert(L, h, val); + luaC_barrierback(L, obj2gco(h), val); } L->top = ci->top; /* correct top (in case of previous open call) */ ) @@ -729,19 +774,12 @@ void luaV_execute (lua_State *L) { luaF_close(L, ra); ) vmcase(OP_CLOSURE, - Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */ - int nup = p->sizeupvalues; - Closure *ncl = luaF_newLclosure(L, nup); - Upvaldesc *uv = p->upvalues; - int j; - ncl->l.p = p; - setclvalue(L, ra, ncl); /* anchor new closure in stack */ - for (j = 0; j < nup; j++) { /* fill in upvalues */ - if (uv[j].instack) /* upvalue refers to local variable? */ - ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx); - else /* get upvalue from enclosing function */ - ncl->l.upvals[j] = cl->upvals[uv[j].idx]; - } + Proto *p = cl->p->p[GETARG_Bx(i)]; + Closure *ncl = getcached(p, cl->upvals, base); /* cached closure */ + if (ncl == NULL) /* no match? */ + pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ + else + setclvalue(L, ra, ncl); /* push cashed closure */ checkGC(L); ) vmcase(OP_VARARG, diff --git a/src/print.c b/src/print.c index 6a5b05db92..83a1cd6852 100644 --- a/src/print.c +++ b/src/print.c @@ -1,5 +1,5 @@ /* -** $Id: print.c,v 1.60 2010/05/17 22:27:10 lhf Exp $ +** $Id: print.c,v 1.61 2010/07/31 11:34:07 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -71,6 +71,8 @@ static void PrintConstant(const Proto* f, int i) } } +#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") + static void PrintCode(const Proto* f) { const Instruction* code=f->code; @@ -116,14 +118,14 @@ static void PrintCode(const Proto* f) break; case OP_GETUPVAL: case OP_SETUPVAL: - printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); + printf("\t; %s", UPVALNAME(b)); break; case OP_GETTABUP: - printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b].name) : "-"); + printf("\t; %s", UPVALNAME(b)); if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABUP: - printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[a].name) : "-"); + printf("\t; %s", UPVALNAME(a)); if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; From d4bba06f4b8264eee00b25ee08e982d348486aaf Mon Sep 17 00:00:00 2001 From: Lua Team Date: Sat, 30 Oct 2010 12:00:00 +0000 Subject: [PATCH 52/97] Lua 5.2.0-work5 --- Makefile | 2 +- README | 6 +- doc/Makefile | 9 - doc/contents.html | 30 +-- doc/manual.html | 490 +++++++++++++++++++++++++++++++--------------- doc/readme.html | 128 ++++++------ src/Makefile | 14 +- src/lapi.c | 50 ++++- src/lauxlib.c | 75 +++++-- src/lauxlib.h | 5 +- src/lbaselib.c | 18 +- src/lbitlib.c | 82 ++++---- src/ldebug.c | 18 +- src/ldo.c | 9 +- src/ldump.c | 15 +- src/lgc.c | 6 +- src/linit.c | 4 +- src/liolib.c | 4 +- src/llex.c | 14 +- src/lmathlib.c | 4 +- src/loadlib.c | 10 +- src/lobject.c | 19 +- src/lopcodes.c | 6 +- src/lopcodes.h | 9 +- src/loslib.c | 8 +- src/lparser.c | 27 +-- src/lstate.c | 7 +- src/lstate.h | 7 +- src/lstrlib.c | 8 +- src/ltablib.c | 5 +- src/lua.c | 13 +- src/lua.h | 17 +- src/luac.c | 312 +++++++++++++++++++++++++---- src/luaconf.h | 115 ++++++++--- src/lualib.h | 6 +- src/lundump.c | 59 +++--- src/lundump.h | 15 +- src/lvm.c | 6 +- src/print.c | 229 ---------------------- test/hello.lua | 3 - 40 files changed, 1099 insertions(+), 765 deletions(-) delete mode 100644 doc/Makefile delete mode 100644 src/print.c delete mode 100644 test/hello.lua diff --git a/Makefile b/Makefile index cbc945d719..da62ab94b9 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ $(PLATS) clean: cd src && $(MAKE) $@ test: dummy - src/lua test/hello.lua + src/lua -v install: dummy cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) diff --git a/README b/README index 78c839657d..37c89345d9 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ -This is Lua 5.2 (work4), released on 30 July 2010. +This is Lua 5.2 (work5), released on 30 Oct 2010. -For information about Lua, including installation instructions and -license details, see doc/readme.html. +For installation instructions, license details, and +further information about Lua, see doc/readme.html. diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index c9e98b5506..0000000000 --- a/doc/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -R= readme -T= $R.txt -H= $R.html - -$T: $H - lynx -dump $? >$@ - -clean: - -rm -f $T diff --git a/doc/contents.html b/doc/contents.html index 397c6566af..35b51d02fc 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -126,7 +126,7 @@

        Contents

      • 6.10 – The Debug Library

      -

    • 7 – Lua Stand-alone +
    • 7 – Lua Standalone

    • 8 – Incompatibilities with the Previous Version @@ -3264,7 +3298,7 @@

      4.8 - Functions and Types

      typedef ptrdiff_t lua_Integer;

      -The type used by the Lua API to represent integral values. +The type used by the Lua API to represent signed integral values.

      @@ -3493,8 +3527,8 @@

      4.8 - Functions and Types

      -If the resulting function has upvalues, -the first upvalue is set to the value of the global environment +If the resulting function has one upvalue, +this upvalue is set to the value of the global environment stored at index LUA_RIDX_GLOBALS in the registry (see §4.5). (When loading main chunks, this upvalue will be the _ENV variable (see §2.2).) @@ -4334,7 +4368,7 @@

      4.8 - Functions and Types

      You can only call functions in threads with status LUA_OK. You can resume threads with status LUA_OK (to start a new coroutine) or LUA_YIELD -(to resume a corotine). +(to resume a coroutine). @@ -4517,6 +4551,46 @@

      4.8 - Functions and Types

      +

      lua_tounsigned

      +[-0, +0, -] +

      lua_Unsigned lua_tounsigned (lua_State *L, int index);
      + +

      +A macro equivalent to lua_tounsignedx(L, index, NULL). + + + + + +


      lua_tounsignedx

      +[-0, +0, -] +

      lua_Unsigned lua_tounsignedx (lua_State *L, int index, int *isnum);
      + +

      +Converts the Lua value at the given acceptable index +to the unsigned integral type lua_Unsigned. +The Lua value must be a number or a string convertible to a number +(see §3.4.2); +otherwise, lua_tounsignedx returns 0. + + +

      +If the number is not an integer, +it is truncated in some non-specified way. +If the number is outside the range of representable values, +it is normalized to the remainder of its division by +one more than the maximum representable value. + + +

      +If isnum is different from NULL, +its referent is assigned a boolean value that +indicates whether the operation succeeded. + + + + +


      lua_touserdata

      [-0, +0, -]

      void *lua_touserdata (lua_State *L, int index);
      @@ -4569,6 +4643,22 @@

      4.8 - Functions and Types

      +

      lua_Unsigned

      +
      typedef unsigned long lua_Unsigned;
      + +

      +The type used by the Lua API to represent unsigned integral values. +It must have at least 32 bits. + + +

      +By default it is an unsigned int or an unsigned long, +whichever can hold 32-bit values. + + + + +


      lua_version

      [-0, +0, v]

      const lua_Number *lua_version (lua_State *L);
      @@ -4681,7 +4771,7 @@

      4.8 - Functions and Types

      -

      4.9 - The Debug Interface

      +

      4.9 – The Debug Interface

      Lua has no built-in debugging facilities. @@ -5165,16 +5255,19 @@

      4.9 - The Debug Interface


      lua_upvaluejoin

      void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
      -                                              int fidx2, int n2);

      -TO BE DONE!! + int fidx2, int n2); +

      +Make the n1-th upvalue of the Lua closure at index fidx1 +refer to the n2-th upvalue of the Lua closure at index fidx2. -

      5 - The Auxiliary Library

      + +

      5 – The Auxiliary Library

      @@ -5220,7 +5313,7 @@

      5 - The Auxiliary Library

      -

      5.1 - Functions and Types

      +

      5.1 – Functions and Types

      Here we list all functions and types from the auxiliary library @@ -5591,6 +5684,18 @@

      5.1 - Functions and Types

      +

      luaL_checkunsigned

      +[-0, +0, v] +

      lua_Unsigned luaL_checkunsigned (lua_State *L, int narg);
      + +

      +Checks whether the function argument narg is a number +and returns this number cast to a lua_Unsigned. + + + + +


      luaL_checkversion

      [-0, +0, -]

      void *luaL_checkversion (lua_State *L);
      @@ -5959,7 +6064,7 @@

      5.1 - Functions and Types

      If l is not NULL, -fills the position *l with the results's length. +fills the position *l with the result's length. @@ -5997,6 +6102,23 @@

      5.1 - Functions and Types

      +

      luaL_optunsigned

      +[-0, +0, v] +

      lua_Unsigned luaL_optunsigned (lua_State *L,
      +                               int narg,
      +                               lua_Unsigned u);
      + +

      +If the function argument narg is a number, +returns this number cast to a lua_Unsigned. +If this argument is absent or is nil, +returns u. +Otherwise, raises an error. + + + + +


      luaL_prepbuffer

      [-0, +0, -]

      char *luaL_prepbuffer (luaL_Buffer *B);
      @@ -6222,7 +6344,7 @@

      5.1 - Functions and Types

      -

      6 - Standard Libraries

      +

      6 – Standard Libraries

      The standard Lua libraries provide useful functions @@ -6291,7 +6413,7 @@

      6 - Standard Libraries

      -

      6.1 - Basic Functions

      +

      6.1 – Basic Functions

      The basic library provides some core functions to Lua. @@ -6513,7 +6635,8 @@

      6.1 - Basic Functions

      This function is similar to load, but sets env as the value of the first upvalue of the created function in case of success. -(Usually this first upvalue will be _ENV (see §2.2).) +(When loading main chunks, +this upvalue will be the _ENV variable (see §2.2).) The parameters after env are similar to those of load, too. @@ -6797,7 +6920,7 @@

      6.1 - Basic Functions

      -

      6.2 - Coroutine Manipulation

      +

      6.2 – Coroutine Manipulation

      The operations related to coroutines comprise a sub-library of @@ -6907,7 +7030,7 @@

      6.2 - Coroutine Manipulation

      -

      6.3 - Modules

      +

      6.3 – Modules

      The package library provides basic @@ -6954,9 +7077,9 @@

      6.3 - Modules

      Once a loader is found, require calls the loader with a single argument, modname. -If the loader returns any value, +If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. -If the loader returns no value and +If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the @@ -6995,7 +7118,7 @@

      6.3 - Modules

      is replaced by the executable's directory. Default is '!'.
    • -
    • The fifth line is a mark to ignore all before it when bulding the +
    • The fifth line is a mark to ignore all before it when building the luaopen_ function name. Default is '-'.
    • @@ -7227,7 +7350,7 @@

      6.3 - Modules

      -

      6.4 - String Manipulation

      +

      6.4 – String Manipulation

      This library provides generic functions for string manipulation, @@ -7556,7 +7679,7 @@

      6.4 - String Manipulation

      -

      6.4.1 - Patterns

      +

      6.4.1 – Patterns

      Character Class:

      @@ -7605,7 +7728,8 @@

      Character Class:

      represents the class which is the union of all characters in set. A range of characters can be specified by -separating the end characters of the range with a '-'. +separating the end characters of the range, +in ascending order, with a '-', All classes %x described above can also be used as components in set. All other characters in set represent themselves. @@ -7699,7 +7823,7 @@

      Pattern Item:

      the next character belongs to set and the previous character does not belong to set. The set set is interpreted as previously described. -The beggining and the end of the subject are handled as if +The beginning and the end of the subject are handled as if they were the character '\0'. @@ -7750,7 +7874,7 @@

      Captures:

      -

      6.5 - Table Manipulation

      +

      6.5 – Table Manipulation

      This library provides generic functions for table manipulation. It provides all its functions inside the table table. @@ -7858,7 +7982,7 @@

      6.5 - Table Manipulation

      -

      6.6 - Mathematical Functions

      +

      6.6 – Mathematical Functions

      This library is an interface to the standard C math library. @@ -8187,22 +8311,30 @@

      6.6 - Mathematical Functions

      -

      6.7 - Bitwise operations

      +

      6.7 – Bitwise operations

      This library provides bitwise operations. -It provides all its functions inside the table bit. +It provides all its functions inside the table bit32. +It uses upper case for function names to avoid collision with +some reserved words (and, or, and not). + + +

      Unless otherwise stated, -all functions accept as arguments and return numbers -in the range [0,2^32 - 1]. -Standard Lua does not use 2-complement representation for numbers, -so in standard Lua (that is, with floating-point numbers) you -cannot use negative numbers with this library. -In particular, -1 is not the same as 0xffffffff. +all functions accept numeric arguments in the range +(-251,+251); +each argument is normalized to +the remainder of its division by 232 +and truncated to an integer (in some unspecified way), +so that its final value falls in the range [0,232 - 1]. +Similarly, all results are in the range [0,232 - 1]. +Note that bit32.NOT(0) is 0xFFFFFFFF, +which is different from -1.

      -


      bit.band (···)

      +

      bit32.AND (···)

      @@ -8212,22 +8344,22 @@

      6.7 - Bitwise operations

      -


      bit.bnot (x)

      +

      bit32.NOT (x)

      Returns the bitwise negation of x. -For any valid x, +For any integer x, the following identity holds:

      -     assert(bit.bnot(x) == 2^32 - 1 - x)
      +     assert(bit32.NOT(x) == (-1 - x) % 2^32)
       

      -


      bit.bor (···)

      +

      bit32.OR (···)

      @@ -8237,7 +8369,7 @@

      6.7 - Bitwise operations

      -


      bit.btest (···)

      +

      bit32.TEST (···)

      @@ -8248,7 +8380,7 @@

      6.7 - Bitwise operations

      -


      bit.bxor (···)

      +

      bit32.XOR (···)

      @@ -8258,36 +8390,33 @@

      6.7 - Bitwise operations

      -


      bit.lshift (x, disp)

      +

      bit32.ROL (x, disp)

      -Returns the number x shifted disp bits to the left. +Returns the number x rotated disp bits to the left. The number disp may be any representable integer. -Negative displacements shift to the right. -In any direction, vacant bits are filled with zeros. -In particular, -displacements with absolute values higher than -the total number of bits in the representation of x -result in zero (all bits are shifted out).

      -For positive displacements, -the following equality holds: +For any valid displacement, +the following identity holds:

      -     assert(bit.lshift(b, disp) == (b * 2^disp) % 2^32)
      -
      + assert(bit32.ROL(x, disp) == bit32.ROL(x, disp % 32)) +

      +In particular, +negative displacements rotate to the right. +

      -


      bit.rol (x, disp)

      +

      bit32.ROR (x, disp)

      -Returns the number x rotated disp bits to the left. +Returns the number x rotated disp bits to the right. The number disp may be any representable integer. @@ -8296,38 +8425,62 @@

      6.7 - Bitwise operations

      the following identity holds:
      -     assert(bit.rol(x, disp) == bit.rol(x, disp % 32))
      +     assert(bit32.ROR(x, disp) == bit32.ROR(x, disp % 32))
       

      In particular, -negative displacements rotate to the right. +negative displacements rotate to the left.

      -


      bit.ror (x, disp)

      +

      bit32.SAR (x, disp)

      -Returns the number x rotated disp bits to the right. +Returns the number x shifted disp bits to the right. The number disp may be any representable integer. +Negative displacements shift to the left.

      -For any valid displacement, -the following identity holds: +This shift operation is what is called arithmetic shift. +Vacant bits on the left are filled +with copies of the higher bit of x; +vacant bits on the right are filled with zeros. +In particular, +displacements with absolute values higher than 31 +result in zero or 0xFFFFFFFF (all bits are shifted out). -

      -     assert(bit.ror(x, disp) == bit.ror(x, disp % 32))
      -

      + + + +

      +


      bit32.SHL (x, disp)

      + + +

      +Returns the number x shifted disp bits to the left. +The number disp may be any representable integer. +Negative displacements shift to the right. +In any direction, vacant bits are filled with zeros. In particular, -negative displacements rotate to the left. +displacements with absolute values higher than 31 +result in zero (all bits are shifted out). +

      +For positive displacements, +the following equality holds: + +

      +     assert(bit32.SHL(b, disp) == (b * 2^disp) % 2^32)
      +
      +

      -


      bit.rshift (x, disp)

      +

      bit32.SHR (x, disp)

      @@ -8336,8 +8489,7 @@

      6.7 - Bitwise operations

      Negative displacements shift to the left. In any direction, vacant bits are filled with zeros. In particular, -displacements with absolute values higher than -the total number of bits in the representation of x +displacements with absolute values higher than 31 result in zero (all bits are shifted out). @@ -8346,13 +8498,11 @@

      6.7 - Bitwise operations

      the following equality holds:
      -     assert(bit.rshift(b, disp) == math.floor(b * 2^-disp))
      +     assert(bit32.SHR(b, disp) == math.floor(b % 2^32 / 2^disp))
       

      This shift operation is what is called logical shift. -For an arithmetic shift, -you should use the arithmetic operators. @@ -8360,7 +8510,7 @@

      6.7 - Bitwise operations

      -

      6.8 - Input and Output Facilities

      +

      6.8 – Input and Output Facilities

      The I/O library provides two different styles for file manipulation. @@ -8584,7 +8734,7 @@

      6.8 - Input and Output Facilities

      If file was created with io.popen, -a sucessful close returns the exit status of the process. +a successful close returns the exit status of the process. @@ -8768,7 +8918,7 @@

      6.8 - Input and Output Facilities

      -

      6.9 - Operating System Facilities

      +

      6.9 – Operating System Facilities

      This library is implemented through table os. @@ -8860,9 +9010,13 @@

      6.9 - Operating System Facilities

      -Calls the C function exit, -with an optional code, -to terminate the host program. +Calls the C function exit to terminate the host program. +If code is true, +the returned status is EXIT_SUCCESS; +if code is false, +the returned status is EXIT_FAILURE. +if code is a number, +the returned status is this number. The default value for code is the success code. @@ -8994,7 +9148,7 @@

      6.9 - Operating System Facilities

      -

      6.10 - The Debug Library

      +

      6.10 – The Debug Library

      This library provides @@ -9305,11 +9459,12 @@

      6.10 - The Debug Library

      -


      debug.upvaluejoin ()

      +

      debug.upvaluejoin (func1, n1, func2, n2)

      -TO BE DONE!! +Make the n1-th upvalue of the Lua closure func1 +refer to the n2-th upvalue of the Lua closure func2. @@ -9317,16 +9472,16 @@

      6.10 - The Debug Library

      -

      7 - Lua Stand-alone

      +

      7 – Lua Standalone

      Although Lua has been designed as an extension language, to be embedded in a host C program, -it is also frequently used as a stand-alone language. -An interpreter for Lua as a stand-alone language, +it is also frequently used as a standalone language. +An interpreter for Lua as a standalone language, called simply lua, is provided with the standard distribution. -The stand-alone interpreter includes +The standalone interpreter includes all standard libraries, including the debug library. Its usage is: @@ -9443,7 +9598,7 @@

      7 - Lua Stand-alone

      To allow the use of Lua as a script interpreter in Unix systems, -the stand-alone interpreter skips +the standalone interpreter skips the first line of a chunk if it starts with #. Therefore, Lua scripts can be made into executable programs by using chmod +x and the #! form, @@ -9464,7 +9619,7 @@

      7 - Lua Stand-alone

      -

      8 - Incompatibilities with the Previous Version

      +

      8 – Incompatibilities with the Previous Version

      Here we list the incompatibilities that you can find when moving a program @@ -9476,7 +9631,7 @@

      8 - Incompatibilities with the Previous Version

      -

      8.1 - Changes in the Language

      +

      8.1 – Changes in the Language

      • @@ -9500,7 +9655,7 @@

        8.1 - Changes in the Language

      • The event tail return in debug hooks was removed. Instead, tail calls generate a special new event, -tail call, so that the debuger can know there will +tail call, so that the debugger can know there will not be a corresponding return event.
      • @@ -9509,7 +9664,7 @@

        8.1 - Changes in the Language

        -

        8.2 - Changes in the Libraries

        +

        8.2 – Changes in the Libraries

        • @@ -9566,7 +9721,7 @@

          8.2 - Changes in the Libraries

          -

          8.3 - Changes in the API

          +

          8.3 – Changes in the API

          • @@ -9593,6 +9748,24 @@

            8.3 - Changes in the API

            lua_getuservalue and lua_setuservalue.
          • +
          • +Function luaL_register is deprecated. +Use luaL_setfuncs so that your module does not +create globals anymore. +(Modules are not expected to set global variables anymore.) +
          • + +
          • +Finalizers ("__gc" metamethods) for userdata are called in the +reverse order that they were marked, +not that they were created (see §2.5.1). +(Most userdata are marked immediately after they are created.) +Moreover, +if the metatable does not have a "__gc" field when set, +the finalizer will not be called, +even if it is set later. +
          • +
          • luaL_typerror was renamed luaL_typeerror, to have a correct spelling. @@ -9618,7 +9791,7 @@

            8.3 - Changes in the API

            -

            9 - The Complete Syntax of Lua

            +

            9 – The Complete Syntax of Lua

            Here is the complete syntax of Lua in extended BNF. @@ -9644,8 +9817,7 @@

            9 - The Complete Syntax of Lua

            for namelist in explist do block end | function funcname funcbody | local function Name funcbody | - local namelist [&lsquo=’ explist] | - in exp do block end + local namelist [&lsquo=’ explist] laststat ::= return [explist] | break @@ -9701,10 +9873,10 @@

            9 - The Complete Syntax of Lua


            Last update: -Fri Jul 30 16:41:34 BRT 2010 +Sat Oct 30 21:36:20 BRST 2010 diff --git a/doc/readme.html b/doc/readme.html index 9284427dab..5591999925 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -27,7 +27,7 @@

            Lua -Welcome to Lua 5.2 (work4) +Welcome to Lua 5.2 (work5)

            @@ -89,12 +89,10 @@

            Installing Lua

            Lua is implemented in pure ANSI C, and compiles unmodified in all known platforms that have an ANSI C compiler. Lua also compiles unmodified as C++. - -

            -The instructions below are for Unix-like platforms. -There are also -instructions for other systems. -See below for +The instructions given below for building Lua are for Unix-like platforms. +See also +instructions for other systems +and customization options.

            @@ -250,7 +248,7 @@

            Building Lua on other systems

            compiler:
            - library, luac.c print.c + library, luac.c

            @@ -258,7 +256,7 @@

            Building Lua on other systems

            create and use libraries with your compiler. Moreover, to dynamically load C libraries for Lua you'll need to know how to create dynamic libraries and you'll need to make sure that the Lua API functions are accessible to - those dynamic libraries — but you do not want to link the Lua library + those dynamic libraries — but don't link the Lua library into each dynamic library. For Unix, we recommend that the Lua library be linked statically into the host program and its symbols exported for dynamic linking; src/Makefile does this for the Lua interpreter. @@ -268,18 +266,6 @@

            Building Lua on other systems

            As mentioned above, you may edit src/luaconf.h to customize some features before building Lua. -

            Changes since Lua 5.2.0 (work3)

            - -
              -
            • module and luaL_register deprecated, replaced by luaL_newlib and luaL_setfuncs. -
            • new function luaL_requiref. -
            • caching of Lua closures for resue. -
            • version-specific environment variables (LUA_PATH_5_2, etc.). -
            • new class '%g' in patterns. -
            • debug.getlocal gets parameter names of inactive functions. -
            • new functions lua_tonumberx and lua_tointegerx. -
            -

            Changes since Lua 5.1

            @@ -289,61 +275,73 @@

            Changes since Lua 5.1

            lists the incompatibilities that had to be introduced. -

            Language

            +

            Main changes

              -
            • new lexical environments. -
            • no more fenv for threads. +
            • yieldable pcall and metamethods +
            • new _ENV scheme
            • ephemeron tables - (tables with weak keys only visit value when key is accessible). -
            • yieldable pcall and metamethods. -
            • tables honor the __len metamethod. -
            • max constants per function raised to 2^26. -
            • hex escapes in strings. -
            • no more verification of opcode consistency. +
            • new library for bitwise operations +
            • light C functions +
            • emergency garbage collector +
            + +Here are the other changes introduced in Lua 5.2: +

            Language

            +
              +
            • no more fenv for threads or functions +
            • tables honor the __len metamethod +
            • hex and \* escapes in strings +
            • order metamethods work for different types +
            • no more verification of opcode consistency +
            • hook event "tail return" replaced by "tail call" +
            • empty statement

            Libraries

              -
            • new library for bitwise operations. -
            • new metamethods __pairs and __ipairs. -
            • arguments for function called through xpcall. -
            • optional argument to load (to control binary x text). -
            • loadlib may load libraries with global names (RTLD_GLOBAL). -
            • new function package.searchpath. -
            • optional base in math.log. -
            • file:write returns file. -
            • closing a pipe returns exit status. -
            • os.exit may close state. -
            • new option 'isrunning' for collectgarbage and lua_gc. -
            • frontier patterns. -
            • ipairs now goes until #t. +
            • new metamethods __pairs and __ipairs +
            • arguments for function called through xpcall +
            • optional 'mode' argument to load (to control binary x text) +
            • new function loadin +
            • loadlib may load libraries with global names (RTLD_GLOBAL) +
            • new function package.searchpath +
            • optional base in math.log +
            • file:write returns file +
            • closing a pipe returns exit status +
            • os.exit may close state +
            • new option 'isrunning' for collectgarbage and lua_gc +
            • frontier patterns +
            • \0 in patterns +
            • new option *L for io.read +
            • options for io.lines

            C API

              -
            • mainthread predefined in the registry. -
            • lua_cpcall changed to a predefined function in the registry. -
            • new constants LUA_OK and LUA_ERRGCMM. -
            • new lua_compare, lua_arith, and lua_len. -
            • new lua_version and luaL_version. -
            • lua_pushstring and pushlstring return string. -
            • new luaL_testudata. -
            • new luaL_tolstring. -
            • new lua_copy. -
            • new lua_upvalueid and lua_upvaluejoin. -
            • nparams and isvarag available in debug API. +
            • main thread predefined in the registry +
            • new constants LUA_OK and LUA_ERRGCMM +
            • new lua_compare, lua_arith, and lua_len +
            • new lua_version and luaL_version +
            • lua_pushstring and pushlstring return string +
            • new luaL_testudata +
            • new luaL_tolstring +
            • new lua_copy +
            • new lua_absindex +
            • new lua_upvalueid and lua_upvaluejoin +
            • nparams and isvarag available in debug API

            Implementation

              -
            • emergency garbage collector - (core forces a full collection when allocation fails). -
            • udata with finalizers are kept in a separated list for the GC. -
            • CallInfo stack now is a linked list. -
            • internal (immutable) version of ctypes. -
            • parser uses much less C-stack space (no more auto arrays). -
            • new hash for floats. -
            • handling of non-string error messages in the standalone interpreter. +
            • max constants per function raised to 226 +
            • internal (immutable) version of ctypes +
            • simpler implementation for string buffers +
            • udata with finalizers are kept in a separated list for the GC +
            • CallInfostack now is a linked list +
            • parser uses much less C-stack space (no more auto arrays) +
            • new hash for floats +
            • handling of non-string error messages in the standalone interpreter +
            • generational mode for garbage collection (experimental)

            License

            @@ -352,7 +350,7 @@

            License

            -Lua is free software licensed under the terms of the +Lua is free software distributed under the terms of the MIT license reproduced below; it can be used for any purpose, including commercial purposes, @@ -392,10 +390,10 @@

            License


            Last update: -Fri Jul 30 15:12:25 BRT 2010 +Sat Oct 30 21:36:38 BRST 2010 diff --git a/src/Makefile b/src/Makefile index 84a21035ce..61ad180e0c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,7 +33,7 @@ LUA_T= lua LUA_O= lua.o LUAC_T= luac -LUAC_O= luac.o print.o +LUAC_O= luac.o ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) @@ -62,7 +62,7 @@ clean: $(RM) $(ALL_T) $(ALL_O) depend: - @$(CC) $(CFLAGS) -MM l*.c print.c + @$(CC) $(CFLAGS) -MM l*.c echo: @echo "PLAT= $(PLAT)" @@ -94,8 +94,7 @@ bsd: freebsd: $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline" -generic: - $(MAKE) $(ALL) MYCFLAGS= +generic: $(ALL) linux: $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -ldl -lreadline -lncurses" @@ -170,16 +169,13 @@ ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ lmem.h lstring.h lgc.h ltable.h lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h -luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ - lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ - lundump.h +luac.o: luac.c lua.h luaconf.h lauxlib.h lobject.h llimits.h lstate.h \ + ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ lzio.h -print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h lopcodes.h lundump.h # (end of Makefile) diff --git a/src/lapi.c b/src/lapi.c index 2d7c336a33..094d623be0 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.133 2010/07/25 15:18:19 roberto Exp $ +** $Id: lapi.c,v 2.139 2010/10/25 20:31:11 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -85,7 +85,7 @@ LUA_API int lua_checkstack (lua_State *L, int size) { if (L->stack_last - L->top > size) /* stack large enough? */ res = 1; /* yes; check is OK */ else { /* no; need to grow stack */ - int inuse = L->top - L->stack + EXTRA_STACK; + int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; if (inuse > LUAI_MAXSTACK - size) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ @@ -347,6 +347,23 @@ LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum) { } +LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *isnum) { + TValue n; + const TValue *o = index2addr(L, idx); + if (tonumber(o, &n)) { + lua_Unsigned res; + lua_Number num = nvalue(o); + lua_number2uint(res, num); + if (isnum) *isnum = 1; + return res; + } + else { + if (isnum) *isnum = 0; + return 0; + } +} + + LUA_API int lua_toboolean (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); return !l_isfalse(o); @@ -452,6 +469,16 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { } +LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) { + lua_Number n; + lua_lock(L); + n = lua_uint2number(u); + setnvalue(L->top, n); + api_incr_top(L); + lua_unlock(L); +} + + LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { TString *ts; lua_lock(L); @@ -799,6 +826,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); func = L->top - (nargs+1); if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ @@ -839,6 +867,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); + api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); if (errfunc == 0) func = 0; @@ -889,7 +918,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - /* set global table as 1st upvalue of 'f' (may be _ENV) */ + /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ setobj(L, f->l.upvals[0]->v, gt); luaC_barrier(L, f->l.upvals[0], gt); } @@ -974,6 +1003,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->gcpause = data; break; } + case LUA_GCSETMAJORINC: { + res = g->gcmajorinc; + g->gcmajorinc = data; + break; + } case LUA_GCSETSTEPMUL: { res = g->gcstepmul; g->gcstepmul = data; @@ -1100,11 +1134,15 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, return ""; } else { + const char *name; Proto *p = f->l.p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; if (owner) *owner = obj2gco(f->l.upvals[n - 1]); - return getstr(p->upvalues[n-1].name); + name = getstr(p->upvalues[n-1].name); + if (name == NULL) /* no debug information? */ + name = ""; + return name; } } @@ -1144,13 +1182,11 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { Closure *f; - Proto *p; StkId fi = index2addr(L, fidx); api_check(L, ttisclosure(fi), "Lua function expected"); f = clvalue(fi); api_check(L, !f->c.isC, "Lua function expected"); - p = f->l.p; - api_check(L, (1 <= n && n <= p->sizeupvalues), "invalid upvalue index"); + api_check(L, (1 <= n && n <= f->l.p->sizeupvalues), "invalid upvalue index"); if (pf) *pf = f; return &f->l.upvals[n - 1]; /* get its upvalue pointer */ } diff --git a/src/lauxlib.c b/src/lauxlib.c index 54f13da23e..807c55227e 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.219 2010/07/28 15:51:59 roberto Exp $ +** $Id: lauxlib.c,v 1.224 2010/10/29 12:52:21 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -330,11 +330,26 @@ LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { } +LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) { + int isnum; + lua_Unsigned d = lua_tounsignedx(L, narg, &isnum); + if (!isnum) + tag_error(L, narg, LUA_TNUMBER); + return d; +} + + LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer def) { return luaL_opt(L, luaL_checkinteger, narg, def); } + +LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg, + lua_Unsigned def) { + return luaL_opt(L, luaL_checkunsigned, narg, def); +} + /* }====================================================== */ @@ -434,7 +449,7 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { */ /* index of free-list header */ -#define freelist "lua-freelist" +#define freelist 0 LUALIB_API int luaL_ref (lua_State *L, int t) { @@ -444,12 +459,12 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* `nil' has a unique fixed reference */ } - lua_getfield(L, t, freelist); /* get first free element */ - ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ + lua_rawgeti(L, t, freelist); /* get first free element */ + ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ - lua_setfield(L, t, freelist); /* (t[freelist] = t[ref]) */ + lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ } else /* no free elements */ ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ @@ -461,10 +476,10 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { t = lua_absindex(L, t); - lua_getfield(L, t, freelist); + lua_rawgeti(L, t, freelist); lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ lua_pushinteger(L, ref); - lua_setfield(L, t, freelist); /* t[freelist] = ref */ + lua_rawseti(L, t, freelist); /* t[freelist] = ref */ } } @@ -511,17 +526,32 @@ static int errfile (lua_State *L, const char *what, int fnameindex) { } +static int skipBOM (LoadF *lf) { + const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */ + int c; + lf->n = 0; + do { + c = getc(lf->f); + if (c == EOF || c != *(unsigned char *)p++) return c; + lf->buff[lf->n++] = c; /* to be read by the parser */ + } while (*p != '\0'); + lf->n = 0; /* prefix matched; discard it */ + return getc(lf->f); /* return next character */ +} + + /* -** reads the first character of file 'f' and skips its first line -** if it starts with '#'. Returns true if it skipped the first line. -** In any case, '*cp' has the first "valid" character of the file -** (after the optional first-line comment). +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). */ -static int skipcomment (FILE *f, int *cp) { - int c = *cp = getc(f); +static int skipcomment (LoadF *lf, int *cp) { + int c = *cp = skipBOM(lf); if (c == '#') { /* first line is a comment (Unix exec. file)? */ - while ((c = getc(f)) != EOF && c != '\n') ; /* skip first line */ - *cp = getc(f); /* skip end-of-line */ + while ((c = getc(lf->f)) != EOF && c != '\n') ; /* skip first line */ + *cp = getc(lf->f); /* skip end-of-line */ return 1; /* there was a comment */ } else return 0; /* no comment */ @@ -542,14 +572,12 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } - lf.n = 0; - if (skipcomment(lf.f, &c)) /* read initial portion */ + if (skipcomment(&lf, &c)) /* read initial portion */ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - lf.n = 0; - skipcomment(lf.f, &c); /* re-read initial portion */ + skipcomment(&lf, &c); /* re-read initial portion */ } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ @@ -628,7 +656,7 @@ LUALIB_API int luaL_len (lua_State *L, int idx) { int l; int isnum; lua_len(L, idx); - l = lua_tointegerx(L, -1, &isnum); + l = (int)lua_tointegerx(L, -1, &isnum); if (!isnum) luaL_error(L, "object length is not a number"); lua_pop(L, 1); /* remove object */ @@ -848,5 +876,12 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) { else if (*v != ver) luaL_error(L, "version mismatch: app. needs %d, Lua core provides %f", ver, *v); + /* check conversions number -> integer types */ + lua_pushnumber(L, -(lua_Number)0x1234); + if (lua_tointeger(L, -1) != -0x1234 || + lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234) + luaL_error(L, "bad conversion number->int;" + " must recompile Lua with proper settings"); + lua_pop(L, 1); } diff --git a/src/lauxlib.h b/src/lauxlib.h index b2034673a9..504fdf586c 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.108 2010/07/02 11:38:13 roberto Exp $ +** $Id: lauxlib.h,v 1.109 2010/10/25 20:31:11 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -44,6 +44,9 @@ LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, lua_Integer def); +LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg); +LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg, + lua_Unsigned def); LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); diff --git a/src/lbaselib.c b/src/lbaselib.c index 1e13a183d7..1553c1d056 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.246 2010/07/02 11:38:13 roberto Exp $ +** $Id: lbaselib.c,v 1.251 2010/10/28 15:36:30 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -56,12 +56,15 @@ static int luaB_tonumber (lua_State *L) { const char *s1 = luaL_checkstring(L, 1); char *s2; unsigned long n; + int neg = 0; luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); + while (isspace((unsigned char)(*s1))) s1++; /* skip initial spaces */ + if (*s1 == '-') { s1++; neg = 1; } n = strtoul(s1, &s2, base); if (s1 != s2) { /* at least one valid digit? */ while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ if (*s2 == '\0') { /* no invalid trailing characters? */ - lua_pushnumber(L, (lua_Number)n); + lua_pushnumber(L, (neg) ? -(lua_Number)n : (lua_Number)n); return 1; } } @@ -142,11 +145,11 @@ static int luaB_rawset (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", "isrunning", - "gen", "inc", NULL}; + "count", "step", "setpause", "setstepmul", + "setmajorinc", "isrunning", "gen", "inc", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, - LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; + LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; int ex = luaL_optint(L, 2, 0); int res = lua_gc(L, o, ex); @@ -330,11 +333,12 @@ static int luaB_load (lua_State *L) { static int luaB_loadin (lua_State *L) { int n; - luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 1); n = luaB_load_aux(L, 2); if (n == 1) { /* success? */ lua_pushvalue(L, 1); /* environment for loaded function */ - lua_setupvalue(L, -2, 1); + if (lua_setupvalue(L, -2, 1) == NULL) + luaL_error(L, "loaded chunk does not have an upvalue"); } return n; } diff --git a/src/lbitlib.c b/src/lbitlib.c index 1b32653dc1..e93575e61a 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.6 2010/07/02 12:01:53 roberto Exp $ +** $Id: lbitlib.c,v 1.10 2010/10/28 15:17:29 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -13,22 +13,19 @@ #include "lualib.h" -/* number of bits considered when shifting/rotating (must be a power of 2) */ +/* number of bits to consider in a number */ #define NBITS 32 +#define ALLONES (~(((~(lua_Unsigned)0) << (NBITS - 1)) << 1)) -typedef LUA_INT32 b_int; -typedef unsigned LUA_INT32 b_uint; +/* mask to trim extra bits */ +#define trim(x) ((x) & ALLONES) -static b_uint getuintarg (lua_State *L, int arg) { - b_uint r; - int isnum; - lua_Number x = lua_tonumberx(L, arg, &isnum); - if (!isnum) luaL_typeerror(L, arg, "number"); - lua_number2uint(r, x); - return r; -} +typedef lua_Unsigned b_uint; + + +#define getuintarg(L,arg) luaL_checkunsigned(L,arg) static b_uint andaux (lua_State *L) { @@ -36,13 +33,13 @@ static b_uint andaux (lua_State *L) { b_uint r = ~(b_uint)0; for (i = 1; i <= n; i++) r &= getuintarg(L, i); - return r; + return trim(r); } static int b_and (lua_State *L) { b_uint r = andaux(L); - lua_pushnumber(L, lua_uint2number(r)); + lua_pushunsigned(L, r); return 1; } @@ -59,7 +56,7 @@ static int b_or (lua_State *L) { b_uint r = 0; for (i = 1; i <= n; i++) r |= getuintarg(L, i); - lua_pushnumber(L, lua_uint2number(r)); + lua_pushunsigned(L, trim(r)); return 1; } @@ -69,49 +66,66 @@ static int b_xor (lua_State *L) { b_uint r = 0; for (i = 1; i <= n; i++) r ^= getuintarg(L, i); - lua_pushnumber(L, lua_uint2number(r)); + lua_pushunsigned(L, trim(r)); return 1; } static int b_not (lua_State *L) { b_uint r = ~getuintarg(L, 1); - lua_pushnumber(L, lua_uint2number(r)); + lua_pushunsigned(L, trim(r)); return 1; } -static int b_shift (lua_State *L, int i) { - b_uint r = getuintarg(L, 1); +static int b_shift (lua_State *L, b_uint r, int i) { if (i < 0) { /* shift right? */ i = -i; + r = trim(r); if (i >= NBITS) r = 0; else r >>= i; } else { /* shift left */ if (i >= NBITS) r = 0; else r <<= i; + r = trim(r); } - lua_pushnumber(L, lua_uint2number(r)); + lua_pushunsigned(L, r); return 1; } static int b_lshift (lua_State *L) { - return b_shift(L, luaL_checkint(L, 2)); + return b_shift(L, getuintarg(L, 1), luaL_checkint(L, 2)); } static int b_rshift (lua_State *L) { - return b_shift(L, -luaL_checkint(L, 2)); + return b_shift(L, getuintarg(L, 1), -luaL_checkint(L, 2)); +} + + +static int b_arshift (lua_State *L) { + b_uint r = getuintarg(L, 1); + int i = luaL_checkint(L, 2); + if (i < 0 || !(r & (1 << (NBITS - 1)))) + return b_shift(L, r, -i); + else { /* arithmetic shift for 'negative' number */ + if (i >= NBITS) r = ALLONES; + else + r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */ + lua_pushunsigned(L, r); + return 1; + } } static int b_rot (lua_State *L, int i) { b_uint r = getuintarg(L, 1); i &= (NBITS - 1); /* i = i % NBITS */ + r = trim(r); r = (r << i) | (r >> (NBITS - i)); - lua_pushnumber(L, lua_uint2number(r)); + lua_pushunsigned(L, trim(r)); return 1; } @@ -127,21 +141,23 @@ static int b_ror (lua_State *L) { static const luaL_Reg bitlib[] = { - {"band", b_and}, - {"btest", b_test}, - {"bor", b_or}, - {"bxor", b_xor}, - {"bnot", b_not}, - {"lshift", b_lshift}, - {"rshift", b_rshift}, - {"rol", b_rol}, - {"ror", b_ror}, + {"AND", b_and}, + {"TEST", b_test}, + {"OR", b_or}, + {"XOR", b_xor}, + {"NOT", b_not}, + {"SHL", b_lshift}, + {"SAR", b_arshift}, + {"SHR", b_rshift}, + {"ROL", b_rol}, + {"ROR", b_ror}, {NULL, NULL} }; -LUAMOD_API int luaopen_bit (lua_State *L) { +LUAMOD_API int luaopen_bit32 (lua_State *L) { luaL_newlib(L, bitlib); return 1; } + diff --git a/src/ldebug.c b/src/ldebug.c index 5a04d5a3e6..a112f4da62 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.72 2010/06/21 16:30:12 roberto Exp $ +** $Id: ldebug.c,v 2.74 2010/10/11 20:24:42 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -160,9 +160,10 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { ar->what = "C"; } else { - ar->source = getstr(cl->l.p->source); - ar->linedefined = cl->l.p->linedefined; - ar->lastlinedefined = cl->l.p->lastlinedefined; + Proto *p = cl->l.p; + ar->source = p->source ? getstr(p->source) : "=?"; + ar->linedefined = p->linedefined; + ar->lastlinedefined = p->lastlinedefined; ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); @@ -315,7 +316,7 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, ? luaF_getlocalname(p, t + 1, pc) : getstr(p->upvalues[t].name); kname(p, k, a, what, name); - what = (vn && strcmp(vn, "_ENV") == 0) ? "global" : "field"; + what = (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; } break; } @@ -496,7 +497,12 @@ static void addinfo (lua_State *L, const char *msg) { if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ int line = currentline(ci); - luaO_chunkid(buff, getstr(ci_func(ci)->l.p->source), LUA_IDSIZE); + TString *src = ci_func(ci)->l.p->source; + if (src) + luaO_chunkid(buff, getstr(src), LUA_IDSIZE); + else { /* no source available; use "?" instead */ + buff[0] = '?'; buff[1] = '\0'; + } luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } } diff --git a/src/ldo.c b/src/ldo.c index 834a054374..f4f9100621 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.88 2010/06/04 13:06:15 roberto Exp $ +** $Id: ldo.c,v 2.90 2010/10/25 19:01:37 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -177,7 +177,7 @@ void luaD_growstack (lua_State *L, int n) { if (size > LUAI_MAXSTACK) /* error after extra size? */ luaD_throw(L, LUA_ERRERR); else { - int needed = L->top - L->stack + n + EXTRA_STACK; + int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; int newsize = 2 * size; if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; if (newsize < needed) newsize = needed; @@ -299,7 +299,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); - L->ci->nresults = nresults; if (ttislcf(func)) { /* light C function? */ f = fvalue(func); /* get it */ goto isCfunc; /* go to call it */ @@ -312,6 +311,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { isCfunc: /* call C function 'f' */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; ci->func = restorestack(L, funcr); ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); @@ -341,6 +341,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { else /* vararg function */ base = adjust_varargs(L, p, nargs); ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; ci->func = func; ci->u.l.base = base; ci->top = base + p->maxstacksize; @@ -368,8 +369,8 @@ int luaD_poscall (lua_State *L, StkId firstResult) { L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ } res = ci->func; /* res == final position of 1st result */ - L->ci = ci = ci->previous; /* back to caller */ wanted = ci->nresults; + L->ci = ci = ci->previous; /* back to caller */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); diff --git a/src/ldump.c b/src/ldump.c index b2c1e70992..54a7bb48bf 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $ +** $Id: ldump.c,v 1.17 2010/10/13 21:04:52 lhf Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -75,7 +75,7 @@ static void DumpString(const TString* s, DumpState* D) #define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) -static void DumpFunction(const Proto* f, const TString* p, DumpState* D); +static void DumpFunction(const Proto* f, DumpState* D); static void DumpConstants(const Proto* f, DumpState* D) { @@ -98,14 +98,11 @@ static void DumpConstants(const Proto* f, DumpState* D) case LUA_TSTRING: DumpString(rawtsvalue(o),D); break; - default: - lua_assert(0); /* cannot happen */ - break; } } n=f->sizep; DumpInt(n,D); - for (i=0; ip[i],f->source,D); + for (i=0; ip[i],D); } static void DumpUpvalues(const Proto* f, DumpState* D) @@ -122,6 +119,7 @@ static void DumpUpvalues(const Proto* f, DumpState* D) static void DumpDebug(const Proto* f, DumpState* D) { int i,n; + DumpString((D->strip) ? NULL : f->source,D); n= (D->strip) ? 0 : f->sizelineinfo; DumpVector(f->lineinfo,n,sizeof(int),D); n= (D->strip) ? 0 : f->sizelocvars; @@ -137,9 +135,8 @@ static void DumpDebug(const Proto* f, DumpState* D) for (i=0; iupvalues[i].name,D); } -static void DumpFunction(const Proto* f, const TString* p, DumpState* D) +static void DumpFunction(const Proto* f, DumpState* D) { - DumpString((f->source==p || D->strip) ? NULL : f->source,D); DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); DumpChar(f->numparams,D); @@ -170,6 +167,6 @@ int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip D.strip=strip; D.status=0; DumpHeader(&D); - DumpFunction(f,NULL,&D); + DumpFunction(f,&D); return D.status; } diff --git a/src/lgc.c b/src/lgc.c index fcaca1b40d..2286f54ed7 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.101 2010/06/30 14:11:17 roberto Exp $ +** $Id: lgc.c,v 2.103 2010/10/25 19:01:37 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -449,7 +449,7 @@ static int traverseproto (global_State *g, Proto *f) { } -static l_mem traverseclosure (global_State *g, Closure *cl) { +static int traverseclosure (global_State *g, Closure *cl) { if (cl->c.isC) { int i; for (i=0; ic.nupvalues; i++) /* mark its upvalues */ @@ -960,7 +960,7 @@ static void generationalcollection (lua_State *L) { else { luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ luaC_runtilstate(L, bitmask(GCSpause)); - if (g->totalbytes > g->lastmajormem/100 * g->gcpause) + if (g->totalbytes > g->lastmajormem/100 * g->gcmajorinc) g->lastmajormem = 0; /* signal for a major collection */ } g->GCdebt = stddebt(g); diff --git a/src/linit.c b/src/linit.c index b8af9f39ad..ecde4915ad 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.28 2010/07/02 11:38:13 roberto Exp $ +** $Id: linit.c,v 1.29 2010/10/25 14:32:36 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ @@ -34,7 +34,7 @@ static const luaL_Reg loadedlibs[] = { {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, - {LUA_BITLIBNAME, luaopen_bit}, + {LUA_BITLIBNAME, luaopen_bit32}, {LUA_MATHLIBNAME, luaopen_math}, #if defined(LUA_COMPAT_DEBUGLIB) {LUA_DBLIBNAME, luaopen_debug}, diff --git a/src/liolib.c b/src/liolib.c index 3ecccb11cf..6574e8b665 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.91 2010/07/28 15:51:59 roberto Exp $ +** $Id: liolib.c,v 2.92 2010/10/25 19:01:37 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -453,7 +453,7 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); int i; - int n = lua_tointeger(L, lua_upvalueindex(2)); + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); lua_settop(L , 1); diff --git a/src/llex.c b/src/llex.c index e380910d6b..f1f87171bb 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.37 2010/04/16 12:31:07 roberto Exp $ +** $Id: llex.c,v 2.40 2010/10/25 12:24:36 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -161,7 +161,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->linenumber = 1; ls->lastline = 1; ls->source = source; - ls->envn = luaS_new(L, "_ENV"); /* create env name */ + ls->envn = luaS_new(L, LUA_ENV); /* create env name */ luaS_fix(ls->envn); /* never collect this name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ next(ls); /* read first char */ @@ -221,11 +221,9 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { lua_assert(lisdigit(ls->current)); do { save_and_next(ls); - } while (lisdigit(ls->current) || ls->current == '.'); - if (check_next(ls, "Ee")) /* `E'? */ - check_next(ls, "+-"); /* optional exponent sign */ - while (lislalnum(ls->current)) - save_and_next(ls); + if (check_next(ls, "EePp")) /* exponent part? */ + check_next(ls, "+-"); /* optional exponent sign */ + } while (lislalnum(ls->current) || ls->current == '.'); save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ @@ -234,7 +232,7 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { /* -** skip a sequence '[=*=[' or ']=*]' and return its number of '='s or +** skip a sequence '[=*[' or ']=*]' and return its number of '='s or ** -1 if sequence is malformed */ static int skip_sep (LexState *ls) { diff --git a/src/lmathlib.c b/src/lmathlib.c index 7ba6550c1c..13aebe9e99 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.75 2010/07/02 11:38:13 roberto Exp $ +** $Id: lmathlib.c,v 1.76 2010/10/25 20:31:11 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -220,7 +220,7 @@ static int math_random (lua_State *L) { static int math_randomseed (lua_State *L) { - srand(luaL_checkint(L, 1)); + srand(luaL_checkunsigned(L, 1)); (void)rand(); /* discard first value to avoid undesirable correlations */ return 0; } diff --git a/src/loadlib.c b/src/loadlib.c index 82c00b0d60..42cfb86911 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.89 2010/07/28 15:51:59 roberto Exp $ +** $Id: loadlib.c,v 1.92 2010/10/29 14:35:09 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -177,7 +177,7 @@ static void ll_unloadlib (void *lib) { static void *ll_load (lua_State *L, const char *path, int seeglb) { HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); - (void)(seeglb); /* symbols are 'global' by default? */ + (void)(seeglb); /* symbols are 'global' by default */ if (lib == NULL) pusherror(L); return lib; } @@ -212,7 +212,7 @@ static void ll_unloadlib (void *lib) { static void *ll_load (lua_State *L, const char *path, int seeglb) { - (void)(path); /* to avoid warnings */ + (void)(path); (void)(seeglb); /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } @@ -428,8 +428,6 @@ static int loader_Croot (lua_State *L) { static int loader_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); - if (!lua_istable(L, -1)) - luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); if (lua_isnil(L, -1)) /* not found? */ lua_pushfstring(L, "\n\tno field package.preload['%s']", name); @@ -498,7 +496,7 @@ static int ll_require (lua_State *L) { #if defined(LUA_COMPAT_MODULE) /* -** changes the _ENV variable of calling function +** changes the environment variable of calling function */ static void set_env (lua_State *L) { lua_Debug ar; diff --git a/src/lobject.c b/src/lobject.c index d4fff394bd..f5fc09d7b2 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.40 2010/04/18 13:22:48 roberto Exp $ +** $Id: lobject.c,v 2.43 2010/10/29 15:54:55 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -106,14 +106,19 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { } +static int checkend (const char *s, const char *endptr) { + if (endptr == s) return 0; /* no characters converted */ + while (lisspace(cast(unsigned char, *endptr))) endptr++; + return (*endptr == '\0'); /* OK if no trailing characters */ +} + + int luaO_str2d (const char *s, lua_Number *result) { char *endptr; *result = lua_str2number(s, &endptr); - if (endptr == s) return 0; /* conversion failed */ - if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ - *result = cast_num(strtoul(s, &endptr, 16)); - while (lisspace(cast(unsigned char, *endptr))) endptr++; - return (*endptr == '\0'); /* OK if no trailing characters */ + if (checkend(s, endptr)) return 1; /* conversion OK? */ + *result = cast_num(strtoul(s, &endptr, 0)); /* try hexadecimal */ + return checkend(s, endptr); } @@ -221,7 +226,7 @@ void luaO_chunkid (char *out, const char *source, size_t bufflen) { else { /* string; format as [string "source"] */ const char *nl = strchr(source, '\n'); /* find first new line (if any) */ addstr(out, PRE, LL(PRE)); /* add prefix */ - bufflen -= LL(PRE RETS POS); /* save space for prefix+suffix */ + bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ if (l < bufflen && nl == NULL) { /* small one-line source? */ addstr(out, source, l); /* keep it */ } diff --git a/src/lopcodes.c b/src/lopcodes.c index cc1acb134e..af26722400 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.43 2010/03/12 19:14:06 roberto Exp $ +** $Id: lopcodes.c,v 1.44 2010/10/13 16:45:54 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -48,11 +48,11 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "FORLOOP", "FORPREP", "TFORCALL", + "TFORLOOP", "SETLIST", "CLOSE", "CLOSURE", "VARARG", - "TFORLOOP", "EXTRAARG", NULL }; @@ -96,11 +96,11 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ + ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ - ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ }; diff --git a/src/lopcodes.h b/src/lopcodes.h index 4140db3a74..af1dc9cd7f 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.135 2010/03/12 19:14:06 roberto Exp $ +** $Id: lopcodes.h,v 1.137 2010/10/25 12:24:55 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -17,6 +17,7 @@ `A' : 8 bits `B' : 9 bits `C' : 9 bits + 'Ax' : 26 bits ('A', 'B', and 'C' together) `Bx' : 18 bits (`B' and `C' together) `sBx' : signed Bx @@ -122,7 +123,7 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ | (cast(Instruction, bc)<=) R(A)*/ @@ -219,8 +222,6 @@ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ -OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/ - OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ } OpCode; diff --git a/src/loslib.c b/src/loslib.c index 9b27ebce48..0278eb5147 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.31 2010/07/02 12:01:53 roberto Exp $ +** $Id: loslib.c,v 1.32 2010/10/05 12:18:03 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -276,7 +276,11 @@ static int os_setlocale (lua_State *L) { static int os_exit (lua_State *L) { - int status = luaL_optint(L, 1, EXIT_SUCCESS); + int status; + if (lua_isboolean(L, 1)) + status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); + else + status = luaL_optint(L, 1, EXIT_SUCCESS); if (lua_toboolean(L, 2)) lua_close(L); exit(status); diff --git a/src/lparser.c b/src/lparser.c index 16c05d9ebc..3524b9b2e6 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.90 2010/07/07 16:27:29 roberto Exp $ +** $Id: lparser.c,v 2.92 2010/09/07 19:21:39 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -289,7 +289,7 @@ static void singlevar (LexState *ls, expdesc *var) { FuncState *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ expdesc key; - singlevaraux(fs, ls->envn, var, 1); /* get _ENV variable */ + singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ lua_assert(var->k == VLOCAL || var->k == VUPVAL); codestring(ls, &key, varname); /* key is variable name */ luaK_indexed(fs, var, &key); /* env[varname] */ @@ -352,15 +352,20 @@ static void leaveblock (FuncState *fs) { } -static void pushclosure (LexState *ls, Proto *clp, expdesc *v) { +/* +** adds prototype being created into its parent list of prototypes +** and codes instruction to create new closure +*/ +static void codeclosure (LexState *ls, Proto *clp, expdesc *v) { FuncState *fs = ls->fs->prev; Proto *f = fs->f; /* prototype of function creating new closure */ - int oldsize = f->sizep; - luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, - MAXARG_Bx, "functions"); - while (oldsize < f->sizep) f->p[oldsize++] = NULL; + if (fs->np >= f->sizep) { + int oldsize = f->sizep; + luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, + MAXARG_Bx, "functions"); + while (oldsize < f->sizep) f->p[oldsize++] = NULL; + } f->p[fs->np++] = clp; - /* initial environment for new function is current lexical environment */ luaC_objbarrier(ls->L, f, clp); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); } @@ -428,14 +433,14 @@ static void close_func (LexState *ls) { /* ** opens the main function, which is a regular vararg function with an -** upvalue named '_ENV' +** upvalue named LUA_ENV */ static void open_mainfunc (LexState *ls, FuncState *fs) { expdesc v; open_func(ls, fs); fs->f->is_vararg = 1; /* main function is always vararg */ init_exp(&v, VLOCAL, 0); - newupvalue(fs, ls->envn, &v); /* create '_ENV' upvalue */ + newupvalue(fs, ls->envn, &v); /* create environment upvalue */ } @@ -653,7 +658,7 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { chunk(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); - pushclosure(ls, new_fs.f, e); + codeclosure(ls, new_fs.f, e); close_func(ls); } diff --git a/src/lstate.c b/src/lstate.c index 6ea00b62f5..39a0ef4d43 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.85 2010/04/30 18:36:22 roberto Exp $ +** $Id: lstate.c,v 2.86 2010/09/03 14:14:01 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -29,6 +29,10 @@ #define LUAI_GCPAUSE 200 /* 200% */ #endif +#if !defined(LUAI_GCMAJOR) +#define LUAI_GCMAJOR 200 /* 200% */ +#endif + #if !defined(LUAI_GCMUL) #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ #endif @@ -254,6 +258,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->weak = g->ephemeron = g->allweak = NULL; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; + g->gcmajorinc = LUAI_GCMAJOR; g->gcstepmul = LUAI_GCMUL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { diff --git a/src/lstate.h b/src/lstate.h index e829ed4aee..bc64a4aece 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.65 2010/05/03 17:39:48 roberto Exp $ +** $Id: lstate.h,v 2.68 2010/10/29 17:52:46 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -66,13 +66,13 @@ typedef struct stringtable { /* -** informations about a call +** information about a call */ typedef struct CallInfo { StkId func; /* function index in the stack */ StkId top; /* top for this function */ struct CallInfo *previous, *next; /* dynamic call link */ - short nresults; /* expected number of results from a call */ + short nresults; /* expected number of results from this function */ lu_byte callstatus; union { struct { /* only for Lua functions */ @@ -136,6 +136,7 @@ typedef struct global_State { UpVal uvhead; /* head of double-linked list of all open upvalues */ Mbuffer buff; /* temporary buffer for string concatenation */ int gcpause; /* size of pause between successive GCs */ + int gcmajorinc; /* how much to wait for a major GC (only in gen. mode) */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ struct lua_State *mainthread; diff --git a/src/lstrlib.c b/src/lstrlib.c index 558a748ec6..f213200535 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.154 2010/07/02 11:38:13 roberto Exp $ +** $Id: lstrlib.c,v 1.156 2010/10/29 17:52:46 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -424,7 +424,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { default: goto dflt; } } - default: dflt: { /* pattern class plus optional sufix */ + default: dflt: { /* pattern class plus optional suffix */ const char *ep = classend(ms, p); /* points to what is next */ int m = s < ms->src_end && singlematch(uchar(*s), p, ep); switch (*ep) { @@ -758,9 +758,9 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { else if (*s == '\0' || iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) - sprintf(buff, "\\%d", uchar(*s)); + sprintf(buff, "\\%d", (int)uchar(*s)); else - sprintf(buff, "\\%03d", uchar(*s)); + sprintf(buff, "\\%03d", (int)uchar(*s)); luaL_addstring(b, buff); } else diff --git a/src/ltablib.c b/src/ltablib.c index b094d2f87c..17ea33bc9c 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.56 2010/07/02 11:38:13 roberto Exp $ +** $Id: ltablib.c,v 1.57 2010/10/25 19:01:37 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -16,7 +16,8 @@ #include "lualib.h" -#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), lua_rawlen(L, n)) +#define aux_getn(L,n) \ + (luaL_checktype(L, n, LUA_TTABLE), (int)lua_rawlen(L, n)) static int foreachi (lua_State *L) { diff --git a/src/lua.c b/src/lua.c index 7d23636f8f..fe2f0698b4 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.192 2010/07/25 15:03:37 roberto Exp $ +** $Id: lua.c,v 1.194 2010/10/25 19:01:37 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -369,10 +369,11 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { break; case 'e': *pe = 1; /* go through */ - case 'l': - if (argv[i][2] == '\0') { - i++; - if (argv[i] == NULL) return -(i - 1); + case 'l': /* both options need an argument */ + if (argv[i][2] == '\0') { /* no concatenated argument? */ + i++; /* try next 'argv' */ + if (argv[i] == NULL || argv[i][0] == '-') + return -(i - 1); /* no next argument or it is another option */ } break; default: /* invalid option; return its index... */ @@ -427,7 +428,7 @@ static int handle_luainit (lua_State *L) { static int pmain (lua_State *L) { - int argc = lua_tointeger(L, 1); + int argc = (int)lua_tointeger(L, 1); char **argv = (char **)lua_touserdata(L, 2); int script; int has_i = 0, has_v = 0, has_e = 0; diff --git a/src/lua.h b/src/lua.h index d1cf33ab56..9de92287b8 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.273 2010/07/25 15:18:19 roberto Exp $ +** $Id: lua.h,v 1.276 2010/10/26 19:32:19 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -18,7 +18,7 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" -#define LUA_VERSION_RELEASE "0" " (work4)" +#define LUA_VERSION_RELEASE "0" " (work5)" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE @@ -106,6 +106,9 @@ typedef LUA_NUMBER lua_Number; /* type for integer functions */ typedef LUA_INTEGER lua_Integer; +/* unsigned integer type */ +typedef LUA_UNSIGNED lua_Unsigned; + /* @@ -159,6 +162,7 @@ LUA_API const char *(lua_typename) (lua_State *L, int tp); LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); +LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_rawlen) (lua_State *L, int idx); @@ -196,6 +200,7 @@ LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n); LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l); LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, @@ -271,9 +276,10 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 -#define LUA_GCISRUNNING 8 -#define LUA_GCGEN 9 -#define LUA_GCINC 10 +#define LUA_GCSETMAJORINC 8 +#define LUA_GCISRUNNING 9 +#define LUA_GCGEN 10 +#define LUA_GCINC 11 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -302,6 +308,7 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define lua_tonumber(L,i) lua_tonumberx(L,i,NULL) #define lua_tointeger(L,i) lua_tointegerx(L,i,NULL) +#define lua_tounsigned(L,i) lua_tounsignedx(L,i,NULL) #define lua_pop(L,n) lua_settop(L, -(n)-1) diff --git a/src/luac.c b/src/luac.c index ee2026ba75..19ef916d0f 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.61 2010/05/14 11:40:22 lhf Exp $ +** $Id: luac.c,v 1.65 2010/10/26 09:07:52 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -15,14 +15,13 @@ #include "lua.h" #include "lauxlib.h" -#include "ldo.h" -#include "lfunc.h" -#include "lmem.h" #include "lobject.h" -#include "lopcodes.h" -#include "lstring.h" +#include "lstate.h" #include "lundump.h" +static void PrintFunction(const Proto* f, int full); +#define luaU_print PrintFunction + #define PROGNAME "luac" /* default program name */ #define OUTPUT PROGNAME ".out" /* default output file */ @@ -52,16 +51,16 @@ static void usage(const char* message) else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, - "usage: %s [options] [filenames]\n" - "Available options are:\n" - " -l list\n" - " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" - " -p parse only\n" - " -s strip debug information\n" - " -v show version information\n" - " -- stop handling options\n" - " - stop handling options and process stdin\n" - ,progname,Output); + "usage: %s [options] [filenames]\n" + "Available options are:\n" + " -l list\n" + " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" + " -p parse only\n" + " -s strip debug information\n" + " -v show version information\n" + " -- stop handling options\n" + " - stop handling options and process stdin\n" + ,progname,Output); exit(EXIT_FAILURE); } @@ -89,7 +88,8 @@ static int doargs(int argc, char* argv[]) else if (IS("-o")) /* output file */ { output=argv[++i]; - if (output==NULL || *output==0 || *output=='-') usage(LUA_QL("-o") " needs argument"); + if (output==NULL || *output==0 || (*output=='-' && output[1]!=0)) + usage(LUA_QL("-o") " needs argument"); if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ @@ -114,7 +114,24 @@ static int doargs(int argc, char* argv[]) return i; } -#define toproto(L,i) (clvalue(L->top+(i))->l.p) +#define FUNCTION "(function()end)();" + +static const char* reader(lua_State *L, void *ud, size_t *size) +{ + UNUSED(L); + if ((*(int*)ud)--) + { + *size=sizeof(FUNCTION)-1; + return FUNCTION; + } + else + { + *size=0; + return NULL; + } +} + +#define toproto(L,i) getproto(L->top+(i)) static const Proto* combine(lua_State* L, int n) { @@ -122,24 +139,13 @@ static const Proto* combine(lua_State* L, int n) return toproto(L,-1); else { - int i,pc; - Proto* f=luaF_newproto(L); - setptvalue2s(L,L->top,f); incr_top(L); - f->source=luaS_newliteral(L,"=(" PROGNAME ")"); - f->maxstacksize=1; - pc=2*n+1; - f->code=luaM_newvector(L,pc,Instruction); - f->sizecode=pc; - f->p=luaM_newvector(L,n,Proto*); - f->sizep=n; - pc=0; - for (i=0; ip[i]=toproto(L,i-n-1); - f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); - f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); - } - f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); + Proto* f; + int i=n; + if (lua_load(L,reader,&i,"=(" PROGNAME ")")!=LUA_OK) fatal(lua_tostring(L,-1)); + f=toproto(L,-1); + for (i=0; ip[i]=toproto(L,i-n-1); + f->sizelineinfo=0; + f->sizeupvalues=0; return f; } } @@ -152,7 +158,7 @@ static int writer(lua_State* L, const void* p, size_t size, void* u) static int pmain(lua_State* L) { - int argc=lua_tointeger(L,1); + int argc=(int)lua_tointeger(L,1); char** argv=lua_touserdata(L,2); const Proto* f; int i; @@ -160,7 +166,7 @@ static int pmain(lua_State* L) for (i=0; i1); @@ -188,7 +194,235 @@ int main(int argc, char* argv[]) lua_pushcfunction(L,&pmain); lua_pushinteger(L,argc); lua_pushlightuserdata(L,argv); - if (lua_pcall(L,2,0,0)!=0) fatal(lua_tostring(L,-1)); + if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; } + +/* +** $Id: print.c,v 1.66 2010/10/26 09:07:52 lhf Exp $ +** print bytecodes +** See Copyright Notice in lua.h +*/ + +#include +#include + +#define luac_c +#define LUA_CORE + +#include "ldebug.h" +#include "lobject.h" +#include "lopcodes.h" + +#define Sizeof(x) ((int)sizeof(x)) +#define VOID(p) ((const void*)(p)) + +static void PrintString(const TString* ts) +{ + const char* s=getstr(ts); + size_t i,n=ts->tsv.len; + printf("%c",'"'); + for (i=0; ik[i]; + switch (ttype(o)) + { + case LUA_TNIL: + printf("nil"); + break; + case LUA_TBOOLEAN: + printf(bvalue(o) ? "true" : "false"); + break; + case LUA_TNUMBER: + printf(LUA_NUMBER_FMT,nvalue(o)); + break; + case LUA_TSTRING: + PrintString(rawtsvalue(o)); + break; + default: /* cannot happen */ + printf("? type=%d",ttype(o)); + break; + } +} + +#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") + +static void PrintCode(const Proto* f) +{ + const Instruction* code=f->code; + int pc,n=f->sizecode; + for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); + printf("%-9s\t",luaP_opnames[o]); + switch (getOpMode(o)) + { + case iABC: + printf("%d",a); + if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); + break; + case iABx: + if (getBMode(o)==OpArgK) printf("%d %d",a,-bx); else printf("%d %d",a,bx); + break; + case iAsBx: + if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); + break; + case iAx: + printf("%d",-1-ax); + break; + } + switch (o) + { + case OP_LOADK: + if (bx>0) { printf("\t; "); PrintConstant(f,bx-1); } + break; + case OP_GETUPVAL: + case OP_SETUPVAL: + printf("\t; %s",UPVALNAME(b)); + break; + case OP_GETTABUP: + printf("\t; %s",UPVALNAME(b)); + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABUP: + printf("\t; %s",UPVALNAME(a)); + if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } + if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } + break; + case OP_GETTABLE: + case OP_SELF: + if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } + break; + case OP_SETTABLE: + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_POW: + case OP_EQ: + case OP_LT: + case OP_LE: + if (ISK(b) || ISK(c)) + { + printf("\t; "); + if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); + printf(" "); + if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); + } + break; + case OP_JMP: + case OP_FORLOOP: + case OP_FORPREP: + case OP_TFORLOOP: + printf("\t; to %d",sbx+pc+2); + break; + case OP_CLOSURE: + printf("\t; %p",VOID(f->p[bx])); + break; + case OP_SETLIST: + if (c==0) printf("\t; %d",(int)code[++pc]); + else printf("\t; %d",c); + break; + case OP_EXTRAARG: + printf("\t; "); PrintConstant(f,ax); + break; + default: + break; + } + printf("\n"); + } +} + +#define SS(x) ((x==1)?"":"s") +#define S(x) (int)(x),SS(x) + +static void PrintHeader(const Proto* f) +{ + const char* s=f->source ? getstr(f->source) : "=?"; + if (*s=='@' || *s=='=') + s++; + else if (*s==LUA_SIGNATURE[0]) + s="(bstring)"; + else + s="(string)"; + printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n", + (f->linedefined==0)?"main":"function",s, + f->linedefined,f->lastlinedefined, + S(f->sizecode),VOID(f)); + printf("%d%s param%s, %d slot%s, %d upvalue%s, ", + (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams), + S(f->maxstacksize),S(f->sizeupvalues)); + printf("%d local%s, %d constant%s, %d function%s\n", + S(f->sizelocvars),S(f->sizek),S(f->sizep)); +} + +static void PrintDebug(const Proto* f) +{ + int i,n; + n=f->sizek; + printf("constants (%d) for %p:\n",n,VOID(f)); + for (i=0; isizelocvars; + printf("locals (%d) for %p:\n",n,VOID(f)); + for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); + } + n=f->sizeupvalues; + printf("upvalues (%d) for %p:\n",n,VOID(f)); + for (i=0; iupvalues[i].instack,f->upvalues[i].idx); + } +} + +static void PrintFunction(const Proto* f, int full) +{ + int i,n=f->sizep; + PrintHeader(f); + PrintCode(f); + if (full) PrintDebug(f); + for (i=0; ip[i],full); +} diff --git a/src/luaconf.h b/src/luaconf.h index 12ec5fc1e3..2345e00c2c 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.142 2010/07/28 15:51:59 roberto Exp $ +** $Id: luaconf.h,v 1.148 2010/10/29 17:52:46 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -47,8 +47,8 @@ #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX -#define LUA_USE_DLOPEN -#define LUA_USE_READLINE /* needs some extra libraries */ +#define LUA_USE_DLOPEN /* does not need -ldl */ +#define LUA_USE_READLINE /* needs an extra library: -lreadline */ #endif @@ -115,6 +115,14 @@ #endif +/* +@@ LUA_ENV is the name of the variable that holds the current +@@ environment, used to access global names. +** CHANGE it if you do not like this name. +*/ +#define LUA_ENV "_ENV" + + /* @@ LUA_API is a mark for all core API functions. @@ LUALIB_API is a mark for all auxiliary library functions. @@ -430,26 +438,28 @@ */ #define LUA_INTEGER ptrdiff_t +/* +@@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned. +** It must have at least 32 bits. +*/ +#define LUA_UNSIGNED unsigned LUA_INT32 + /* @@ lua_number2int is a macro to convert lua_Number to int. @@ lua_number2integer is a macro to convert lua_Number to LUA_INTEGER. -@@ lua_number2uint is a macro to convert a lua_Number to an unsigned -@* LUA_INT32. -@@ lua_uint2number is a macro to convert an unsigned LUA_INT32 -@* to a lua_Number. -** CHANGE them if you know a faster way to convert a lua_Number to -** int (with any rounding method and without throwing errors) in your -** system. In Pentium machines, a naive typecast from double to int -** in C is extremely slow, so any alternative is worth trying. +@@ lua_number2uint is a macro to convert a lua_Number to a LUA_UNSIGNED. +@@ lua_uint2number is a macro to convert a LUA_UNSIGNED to a lua_Number. */ -/* On a Pentium, resort to a trick */ -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ - (defined(__i386) || defined (_M_IX86) || defined(__i386__)) /* { */ +#if defined(LUA_CORE) /* { */ + +#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && \ + !defined(LUA_NOIEEE754TRICK) /* { */ -/* On a Microsoft compiler, use assembler */ -#if defined(_MSC_VER) /* { */ +/* On a Microsoft compiler on a Pentium, use assembler to avoid clashes + with a DirectX idiosyncrasy */ +#if defined(_MSC_VER) && defined(M_IX86) /* { */ #define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} #define lua_number2integer(i,n) lua_number2int(i, n) @@ -457,31 +467,76 @@ {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} #else /* }{ */ -/* the next trick should work on any Pentium, but sometimes clashes - with a DirectX idiosyncrasy */ +/* the next trick should work on any machine using IEEE754 with + a 32-bit integer type */ -union luai_Cast { double l_d; long l_l; }; -#define lua_number2int(i,n) \ - { volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; (i) = u.l_l; } -#define lua_number2integer(i,n) lua_number2int(i, n) -#define lua_number2uint(i,n) lua_number2int(i, n) +union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; + +/* +@@ LUA_IEEEENDIAN is the endianness of doubles in your machine +@@ (0 for little endian, 1 for big endian); if not defined, Lua will +@@ check it dynamically. +*/ +/* check for known architectures */ +#if defined(__i386__) || defined(__i386) || defined(i386) || \ + defined (__x86_64) +#define LUA_IEEEENDIAN 0 +#elif defined(__POWERPC__) || defined(__ppc__) +#define LUA_IEEEENDIAN 1 +#endif + +#if !defined(LUA_IEEEENDIAN) /* { */ +#define LUAI_EXTRAIEEE \ + static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; +#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33) +#else +#define LUAI_EXTRAIEEE /* empty */ +#endif /* } */ + +#define lua_number2int32(i,n,t) \ + { LUAI_EXTRAIEEE \ + volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ + (i) = (t)u.l_p[LUA_IEEEENDIAN]; } + +#define lua_number2int(i,n) lua_number2int32(i, n, int) +#define lua_number2integer(i,n) lua_number2int32(i, n, LUA_INTEGER) +#define lua_number2uint(i,n) lua_number2int32(i, n, LUA_UNSIGNED) #endif /* } */ -#else /* }{ */ -/* this option always works, but may be slow */ +#endif /* } */ + + +/* the following definitions always work, but may be slow */ + +#if !defined(lua_number2int) #define lua_number2int(i,n) ((i)=(int)(n)) -#define lua_number2integer(i,n) ((i)=(LUA_INTEGER)(n)) -#define lua_number2uint(i,n) ((i)=(unsigned LUA_INT32)(n)) +#endif -#endif /* } */ +#if !defined(lua_number2integer) +#define lua_number2integer(i,n) ((i)=(LUA_INTEGER)(n)) +#endif +#if !defined(lua_number2uint) && (defined(lapi_c) || defined(luaall_c)) /* { */ +/* the following definition assures proper modulo behavior */ +#if defined(LUA_NUMBER_DOUBLE) +#include +#define lua_number2uint(i,n) \ + ((i)=(LUA_UNSIGNED)((n) - floor((n)/4294967296.0)*4294967296.0)) +#else +#define lua_number2uint(i,n) ((i)=(LUA_UNSIGNED)(n)) +#endif +#endif /* } */ -/* on several machines, coercion from unsigned to double is too slow, - so avoid that if possible */ +#if !defined(lua_uint2number) +/* on several machines, coercion from unsigned to double is slow, + so it may be worth to avoid */ #define lua_uint2number(u) \ ((LUA_INT32)(u) < 0 ? (lua_Number)(u) : (lua_Number)(LUA_INT32)(u)) +#endif + +#endif /* } */ /* diff --git a/src/lualib.h b/src/lualib.h index db2e200ef8..233a331e64 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.40 2010/06/10 21:29:47 roberto Exp $ +** $Id: lualib.h,v 1.41 2010/10/25 14:32:36 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -32,8 +32,8 @@ LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUAMOD_API int (luaopen_string) (lua_State *L); -#define LUA_BITLIBNAME "bit" -LUAMOD_API int (luaopen_bit) (lua_State *L); +#define LUA_BITLIBNAME "bit32" +LUAMOD_API int (luaopen_bit32) (lua_State *L); #define LUA_MATHLIBNAME "math" LUAMOD_API int (luaopen_math) (lua_State *L); diff --git a/src/lundump.c b/src/lundump.c index e82e195115..c875d76721 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.13 2010/03/12 19:14:06 roberto Exp $ +** $Id: lundump.c,v 1.68 2010/10/26 00:23:46 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -27,27 +27,20 @@ typedef struct { const char* name; } LoadState; -#ifdef LUAC_TRUST_BINARIES -#define IF(c,s) -#else -#define IF(c,s) if (c) error(S,s) - static void error(LoadState* S, const char* why) { - luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); + luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why); luaD_throw(S->L,LUA_ERRSYNTAX); } -#endif #define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) -#define LoadByte(S) (lu_byte)LoadChar(S) +#define LoadByte(S) (lu_byte)LoadChar(S) #define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) #define LoadVector(S,b,n,size) LoadMem(S,b,n,size) static void LoadBlock(LoadState* S, void* b, size_t size) { - size_t r=luaZ_read(S->Z,b,size); - IF (r!=0, "unexpected end"); + if (luaZ_read(S->Z,b,size)!=0) error(S,"corrupted"); } static int LoadChar(LoadState* S) @@ -61,7 +54,6 @@ static int LoadInt(LoadState* S) { int x; LoadVar(S,x); - IF (x<0, "bad integer"); return x; } @@ -94,7 +86,7 @@ static void LoadCode(LoadState* S, Proto* f) LoadVector(S,f->code,n,sizeof(Instruction)); } -static Proto* LoadFunction(LoadState* S, TString* p); +static Proto* LoadFunction(LoadState* S); static void LoadConstants(LoadState* S, Proto* f) { @@ -113,7 +105,7 @@ static void LoadConstants(LoadState* S, Proto* f) setnilvalue(o); break; case LUA_TBOOLEAN: - setbvalue(o,LoadChar(S)!=0); + setbvalue(o,LoadChar(S)); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); @@ -121,16 +113,13 @@ static void LoadConstants(LoadState* S, Proto* f) case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; - default: - IF (1, "bad constant"); - break; } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; for (i=0; ip[i]=NULL; - for (i=0; ip[i]=LoadFunction(S,f->source); + for (i=0; ip[i]=LoadFunction(S); } static void LoadUpvalues(LoadState* S, Proto* f) @@ -150,6 +139,7 @@ static void LoadUpvalues(LoadState* S, Proto* f) static void LoadDebug(LoadState* S, Proto* f) { int i,n; + f->source=LoadString(S); n=LoadInt(S); f->lineinfo=luaM_newvector(S->L,n,int); f->sizelineinfo=n; @@ -168,13 +158,10 @@ static void LoadDebug(LoadState* S, Proto* f) for (i=0; iupvalues[i].name=LoadString(S); } -static Proto* LoadFunction(LoadState* S, TString* p) +static Proto* LoadFunction(LoadState* S) { - Proto* f; - if (++G(S->L)->nCcalls > LUAI_MAXCCALLS) error(S, "function nest too deep"); - f=luaF_newproto(S->L); + Proto* f=luaF_newproto(S->L); setptvalue2s(S->L,S->L->top,f); incr_top(S->L); - f->source=LoadString(S); if (f->source==NULL) f->source=p; f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); f->numparams=LoadByte(S); @@ -185,17 +172,25 @@ static Proto* LoadFunction(LoadState* S, TString* p) LoadUpvalues(S,f); LoadDebug(S,f); S->L->top--; - G(S->L)->nCcalls--; return f; } +/* the code below must be consistent with the code in luaU_header */ +#define N0 LUAC_HEADERSIZE +#define N1 (sizeof(LUA_SIGNATURE)-1) +#define N2 N1+2 +#define N3 N2+6 + static void LoadHeader(LoadState* S) { char h[LUAC_HEADERSIZE]; char s[LUAC_HEADERSIZE]; luaU_header(h); LoadBlock(S,s,LUAC_HEADERSIZE); - IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); + if (memcmp(h,s,N0)==0) return; + if (memcmp(h,s,N1)!=0) error(S,"not a"); + if (memcmp(h,s,N2)!=0) error(S,"version mismatch in"); + if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted"); } /* @@ -214,23 +209,29 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) S.Z=Z; S.b=buff; LoadHeader(&S); - return LoadFunction(&S,luaS_newliteral(L,"=?")); + return LoadFunction(&S); } +/* data to catch conversion errors */ +#define TAIL "\x19\x93\r\n\x1a\n" + /* -* make header +* make header for precompiled chunks +* if you make any changes in the code below or in LUA_SIGNATURE in lua.h, +* be sure to update LoadHeader above and LUAC_HEADERSIZE in lundump.h */ void luaU_header (char* h) { int x=1; memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); h+=sizeof(LUA_SIGNATURE)-1; - *h++=(char)LUAC_VERSION; - *h++=(char)LUAC_FORMAT; + *h++=(char)0x52; /* Lua 5.2 */ + *h++=(char)0; /* the official format */ *h++=(char)*(char*)&x; /* endianness */ *h++=(char)sizeof(int); *h++=(char)sizeof(size_t); *h++=(char)sizeof(Instruction); *h++=(char)sizeof(lua_Number); *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ + memcpy(h,TAIL,sizeof(TAIL)-1); } diff --git a/src/lundump.h b/src/lundump.h index 5b19104fd0..e55918cf52 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.37 2005/11/16 11:55:07 roberto Exp $ +** $Id: lundump.h,v 1.43 2010/10/26 00:23:46 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -19,18 +19,7 @@ LUAI_FUNC void luaU_header (char* h); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); -#ifdef luac_c -/* print one chunk; from print.c */ -LUAI_FUNC void luaU_print (const Proto* f, int full); -#endif - -/* for header of binary files -- this is Lua 5.1 */ -#define LUAC_VERSION 0x51 - -/* for header of binary files -- this is the official format */ -#define LUAC_FORMAT 0 - /* size of header of binary files */ -#define LUAC_HEADERSIZE 12 +#define LUAC_HEADERSIZE 18 #endif diff --git a/src/lvm.c b/src/lvm.c index a222049be5..42c6c81f5f 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.123 2010/06/30 14:11:17 roberto Exp $ +** $Id: lvm.c,v 2.125 2010/10/29 17:52:46 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -301,7 +301,7 @@ void luaV_concat (lua_State *L, int total) { setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got 'n' strings to create 1 new */ - L->top -= n-1; /* poped 'n' strings and pushed one */ + L->top -= n-1; /* popped 'n' strings and pushed one */ } while (total > 1); /* repeat until only 1 result left */ } @@ -421,7 +421,7 @@ void luaV_finishOp (lua_State *L) { case OP_CONCAT: { StkId top = L->top - 1; /* top when 'call_binTM' was called */ int b = GETARG_B(inst); /* first element to concatenate */ - int total = top - 1 - (base + b); /* elements yet to concatenate */ + int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ setobj2s(L, top - 2, top); /* put TM result in proper position */ if (total > 1) { /* are there elements to concat? */ L->top = top - 1; /* top is one after last element (at top-2) */ diff --git a/src/print.c b/src/print.c deleted file mode 100644 index 83a1cd6852..0000000000 --- a/src/print.c +++ /dev/null @@ -1,229 +0,0 @@ -/* -** $Id: print.c,v 1.61 2010/07/31 11:34:07 lhf Exp $ -** print bytecodes -** See Copyright Notice in lua.h -*/ - -#include -#include - -#define luac_c -#define LUA_CORE - -#include "ldebug.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lundump.h" - -#define PrintFunction luaU_print - -#define Sizeof(x) ((int)sizeof(x)) -#define VOID(p) ((const void*)(p)) - -static void PrintString(const TString* ts) -{ - const char* s=getstr(ts); - size_t i,n=ts->tsv.len; - putchar('"'); - for (i=0; ik[i]; - switch (ttype(o)) - { - case LUA_TNIL: - printf("nil"); - break; - case LUA_TBOOLEAN: - printf(bvalue(o) ? "true" : "false"); - break; - case LUA_TNUMBER: - printf(LUA_NUMBER_FMT,nvalue(o)); - break; - case LUA_TSTRING: - PrintString(rawtsvalue(o)); - break; - default: /* cannot happen */ - printf("? type=%d",ttype(o)); - break; - } -} - -#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") - -static void PrintCode(const Proto* f) -{ - const Instruction* code=f->code; - int pc,n=f->sizecode; - for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); - printf("%-9s\t",luaP_opnames[o]); - switch (getOpMode(o)) - { - case iABC: - printf("%d",a); - if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); - if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); - break; - case iABx: - if (getBMode(o)==OpArgK) printf("%d %d",a,-bx); else printf("%d %d",a,bx); - break; - case iAsBx: - if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); - break; - case iAx: - printf("%d",ax); - break; - } - switch (o) - { - case OP_LOADK: - printf("\t; "); PrintConstant(f,bx-1); - break; - case OP_GETUPVAL: - case OP_SETUPVAL: - printf("\t; %s", UPVALNAME(b)); - break; - case OP_GETTABUP: - printf("\t; %s", UPVALNAME(b)); - if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } - break; - case OP_SETTABUP: - printf("\t; %s", UPVALNAME(a)); - if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } - if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } - break; - case OP_GETTABLE: - case OP_SELF: - if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } - break; - case OP_SETTABLE: - case OP_ADD: - case OP_SUB: - case OP_MUL: - case OP_DIV: - case OP_POW: - case OP_EQ: - case OP_LT: - case OP_LE: - if (ISK(b) || ISK(c)) - { - printf("\t; "); - if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); - printf(" "); - if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); - } - break; - case OP_JMP: - case OP_FORLOOP: - case OP_FORPREP: - printf("\t; to %d",sbx+pc+2); - break; - case OP_CLOSURE: - printf("\t; %p",VOID(f->p[bx])); - break; - case OP_SETLIST: - if (c==0) printf("\t; %d",(int)code[++pc]); - else printf("\t; %d",c); - break; - default: - break; - } - printf("\n"); - } -} - -#define SS(x) ((x==1)?"":"s") -#define S(x) x,SS(x) - -static void PrintHeader(const Proto* f) -{ - const char* s=getstr(f->source); - if (*s=='@' || *s=='=') - s++; - else if (*s==LUA_SIGNATURE[0]) - s="(bstring)"; - else - s="(string)"; - printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", - (f->linedefined==0)?"main":"function",s, - f->linedefined,f->lastlinedefined, - S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); - printf("%d%s param%s, %d slot%s, %d upvalue%s, ", - f->numparams,f->is_vararg?"+":"",SS(f->numparams), - S(f->maxstacksize),S(f->sizeupvalues)); - printf("%d local%s, %d constant%s, %d function%s\n", - S(f->sizelocvars),S(f->sizek),S(f->sizep)); -} - -static void PrintDebug(const Proto* f) -{ - int i,n; - n=f->sizek; - printf("constants (%d) for %p:\n",n,VOID(f)); - for (i=0; isizelocvars; - printf("locals (%d) for %p:\n",n,VOID(f)); - for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); - } - n=f->sizeupvalues; - printf("upvalues (%d) for %p:\n",n,VOID(f)); - if (f->upvalues==NULL) return; - for (i=0; iupvalues[i].name)); - } -} - -void PrintFunction(const Proto* f, int full) -{ - int i,n=f->sizep; - PrintHeader(f); - PrintCode(f); - if (full) PrintDebug(f); - for (i=0; ip[i],full); -} diff --git a/test/hello.lua b/test/hello.lua deleted file mode 100644 index 0925498f21..0000000000 --- a/test/hello.lua +++ /dev/null @@ -1,3 +0,0 @@ --- the first program in every language - -io.write("Hello world, from ",_VERSION,"!\n") From ccd28dfe034d5dfd130e5378a147e3e9fe7f6807 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 16 Nov 2010 12:00:00 +0000 Subject: [PATCH 53/97] Lua 5.2.0-alpha-rc1 --- README | 2 +- doc/contents.html | 14 ++--- doc/manual.html | 100 +++++++++++++----------------------- doc/readme.html | 15 +++--- src/Makefile | 4 +- src/lapi.c | 6 +-- src/lauxlib.c | 16 ++++-- src/lauxlib.h | 4 +- src/lbitlib.c | 4 +- src/ldblib.c | 13 +++-- src/linit.c | 5 +- src/liolib.c | 44 ++++++++++------ src/llimits.h | 92 ++++++++++++++++++++++++++++++++- src/lmathlib.c | 66 ++++++++++++++---------- src/loadlib.c | 18 ++----- src/lstrlib.c | 33 +++++++++--- src/ltable.c | 6 +-- src/lua.h | 2 +- src/luaconf.h | 128 +++++----------------------------------------- 19 files changed, 286 insertions(+), 286 deletions(-) diff --git a/README b/README index 37c89345d9..bc7accfee7 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Lua 5.2 (work5), released on 30 Oct 2010. +This is Lua 5.2 (alpha), released on 16 Nov 2010. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/doc/contents.html b/doc/contents.html index 35b51d02fc..199af66870 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -22,8 +22,8 @@

            [!] -This is a work version of Lua 5.2. -Everything may change in the final version. +This is an alpha version of Lua 5.2. +Some details may change in the final version.

            The reference manual is the official definition of the Lua language. @@ -52,7 +52,7 @@

            Contents

          • 2.1 – Values and Types
          • 2.2 – Environments and the Global Environment
          • 2.3 – Error Handling -
          • 2.4 – Metatables +
          • 2.4 – Metatables and Metamethods
          • 2.5 – Garbage Collection
            • 2.5.1 – Garbage-Collection Metamethods @@ -484,7 +484,6 @@

              auxiliary library

              luaL_newlib
              luaL_newmetatable
              luaL_newstate
              -luaL_setfuncs
              luaL_openlibs
              luaL_optint
              luaL_optinteger
              @@ -497,11 +496,12 @@

              auxiliary library

              luaL_pushresult
              luaL_ref
              luaL_requiref
              +luaL_setfuncs
              +luaL_setmetatable
              luaL_testudata
              luaL_tolstring
              luaL_traceback
              luaL_typename
              -luaL_typeerror
              luaL_unref
              luaL_where
              @@ -512,10 +512,10 @@

              auxiliary library


              Last update: -Sat Oct 30 21:34:44 BRST 2010 +Tue Nov 16 09:56:07 BRST 2010 diff --git a/doc/manual.html b/doc/manual.html index c97b88c1a0..db1af8c816 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -17,8 +17,8 @@

              [!] -This is a work version of Lua 5.2. -Everything may change in the final version. +This is an alpha version of Lua 5.2. +Some details may change in the final version.

              by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes @@ -38,7 +38,7 @@

              - + @@ -287,7 +287,7 @@

              2.3 – Error Handling

              -

              2.4 – Metatables

              +

              2.4 – Metatables and Metamethods

              Every value in Lua can have a metatable. @@ -305,7 +305,7 @@

              2.4 – Metatables

              We call the keys in a metatable events and the values metamethods. -In the previous example, the event is "add" +In the previous example, the event is "__add" and the metamethod is the function that performs the addition. @@ -383,7 +383,7 @@

              2.4 – Metatables

              For the unary - and # operators, -the metamethod is called repeating the first argument as a second argument. +the metamethod is called with a dummy second argument. This extra argument is only to simplify Lua's internals; it may be removed in future versions and therefore it is not present in the following code. @@ -2731,13 +2731,12 @@

              4.8 – Functions and Types

              return realloc(ptr, nsize); }

              -This code assumes +Note that ANSI C ensures that free(NULL) has no effect and that realloc(NULL, size) is equivalent to malloc(size). -ANSI C ensures both behaviors. -It also assumes that realloc does not fail when shrinking a block. -(ANSI C does not ensure this behavior, -but it seems a safe assumption.) +This code assumes that realloc does not fail when shrinking a block. +ANSI C does not ensure this behavior, +but it seems a safe assumption. @@ -5989,6 +5988,19 @@

              5.1 – Functions and Types

              +

              luaL_setmetatable

              +[-0, +0, -] +

              void luaL_setmetatable (lua_State *L, const char *tname);
              + +

              +Sets the metatable of the object at the top of the stack +as the metatable associated with name tname +in the registry (see luaL_newmetatable). + + + + +


              luaL_openlibs

              [-0, +0, e]

              void luaL_openlibs (lua_State *L);
              @@ -6280,24 +6292,6 @@

              5.1 – Functions and Types

              -

              luaL_typeerror

              -[-0, +0, v] -

              int luaL_typeerror (lua_State *L, int narg, const char *tname);
              - -

              -Generates an error with a message like the following: - -

              -     location: bad argument narg to 'func' (tname expected, got rt)
              -

              -where location is produced by luaL_where, -func is the name of the current function, -and rt is the type name of the actual argument. - - - - -


              luaL_unref

              [-0, +0, -]

              void luaL_unref (lua_State *L, int t, int ref);
              @@ -7020,8 +7014,6 @@

              6.2 – Coroutine Manipulation

              Suspends the execution of the calling coroutine. -The coroutine cannot be running a C function, -a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume. @@ -8586,20 +8578,13 @@

              6.8 – Input and Output Facilities

              -


              io.lines ([filename] [, keepNL])

              +

              io.lines ([filename] ···)

              Opens the given file name in read mode -and returns an iterator function that, -each time it is called, -returns a new line from the file. -Therefore, the construction - -

              -     for line in io.lines(filename) do body end
              -

              -will iterate over all lines of the file. +and returns an iterator function that +works like file:lines(···) over the oppened file. When the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file. @@ -8611,11 +8596,6 @@

              6.8 – Input and Output Facilities

              In this case it does not close the file when the loop ends. -

              -By default, lines removes the newline at the end of each line. -If keepNL is true, it will keep the newlines. - -

              @@ -8750,29 +8730,26 @@

              6.8 – Input and Output Facilities

              -


              file:lines ([keepNL])

              +

              file:lines (···)

              Returns an iterator function that, each time it is called, -returns a new line from the file. +reads the file according to the given formats. +When no format is given, +uses "*l" as a default. Therefore, the construction

              -     for line in file:lines() do body end
              +     for c in file:lines(1) do body end
               

              -will iterate over all lines of the file, +will iterate over all characters of the file, starting at the current position. (Unlike io.lines, this function does not close the file when the loop ends.) -

              -By default, lines removes the newline at the end of each line. -If keepNL is true, it will keep the newlines. - -

              @@ -9673,11 +9650,6 @@

              8.2 – Changes in the Libraries

              and it is easy to set up a module with regular Lua code.
            • -
            • -The debug library is not loaded by default. -You must explicitly require it. -
            • -
            • Functions setfenv and getfenv are deprecated. To set the environment of a Lua function, @@ -9767,8 +9739,8 @@

              8.3 – Changes in the API

            • -luaL_typerror was renamed luaL_typeerror, -to have a correct spelling. +luaL_typerror was deprecated. +Write your own version if you need it.
            • @@ -9873,10 +9845,10 @@

              9 – The Complete Syntax of Lua


              Last update: -Sat Oct 30 21:36:20 BRST 2010 +Tue Nov 16 09:52:41 BRST 2010 diff --git a/doc/readme.html b/doc/readme.html index 5591999925..9b0f926068 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -27,13 +27,13 @@

              Lua -Welcome to Lua 5.2 (work5) +Welcome to Lua 5.2 (alpha)

              [!] -This is a work version of Lua 5.2. -Everything may change in the final version. +This is an alpha version of Lua 5.2. +Some details may change in the final version.

              about @@ -323,12 +323,13 @@

              C API

            • new lua_compare, lua_arith, and lua_len
            • new lua_version and luaL_version
            • lua_pushstring and pushlstring return string -
            • new luaL_testudata +
            • new luaL_testudata and luaL_setmetatable
            • new luaL_tolstring
            • new lua_copy
            • new lua_absindex
            • new lua_upvalueid and lua_upvaluejoin
            • nparams and isvarag available in debug API +
            • new lua_Unsigned

            Implementation

            @@ -337,7 +338,7 @@

            Implementation

          • internal (immutable) version of ctypes
          • simpler implementation for string buffers
          • udata with finalizers are kept in a separated list for the GC -
          • CallInfostack now is a linked list +
          • CallInfo stack now is a linked list
          • parser uses much less C-stack space (no more auto arrays)
          • new hash for floats
          • handling of non-string error messages in the standalone interpreter @@ -390,10 +391,10 @@

            License


            Last update: -Sat Oct 30 21:36:38 BRST 2010 +Thu Nov 11 15:16:22 BRST 2010 diff --git a/src/Makefile b/src/Makefile index 61ad180e0c..b8cee9c6e4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,7 +7,7 @@ PLAT= none CC= gcc -CFLAGS= -O2 -Wall $(MYCFLAGS) +CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(MYCFLAGS) LIBS= -lm $(MYLIBS) AR= ar rcu @@ -97,7 +97,7 @@ freebsd: generic: $(ALL) linux: - $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -ldl -lreadline -lncurses" + $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -ldl -lreadline" macosx: $(MAKE) $(ALL) MYCFLAGS="-DLUA_USE_MACOSX" MYLIBS="-lreadline" diff --git a/src/lapi.c b/src/lapi.c index 094d623be0..074979c3c0 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.139 2010/10/25 20:31:11 roberto Exp $ +** $Id: lapi.c,v 2.140 2010/11/03 15:16:17 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -353,7 +353,7 @@ LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *isnum) { if (tonumber(o, &n)) { lua_Unsigned res; lua_Number num = nvalue(o); - lua_number2uint(res, num); + lua_number2unsigned(res, num); if (isnum) *isnum = 1; return res; } @@ -472,7 +472,7 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) { lua_Number n; lua_lock(L); - n = lua_uint2number(u); + n = lua_unsigned2number(u); setnvalue(L->top, n); api_incr_top(L); lua_unlock(L); diff --git a/src/lauxlib.c b/src/lauxlib.c index 807c55227e..cdd5a53f7e 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.224 2010/10/29 12:52:21 roberto Exp $ +** $Id: lauxlib.c,v 1.227 2010/11/10 18:05:36 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -168,7 +168,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { } -LUALIB_API int luaL_typeerror (lua_State *L, int narg, const char *tname) { +static int typeerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); @@ -176,7 +176,7 @@ LUALIB_API int luaL_typeerror (lua_State *L, int narg, const char *tname) { static void tag_error (lua_State *L, int narg, int tag) { - luaL_typeerror(L, narg, lua_typename(L, tag)); + typeerror(L, narg, lua_typename(L, tag)); } @@ -224,6 +224,12 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { } +LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + + LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); if (p != NULL) { /* value is a userdata? */ @@ -241,7 +247,7 @@ LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { void *p = luaL_testudata(L, ud, tname); - if (p == NULL) luaL_typeerror(L, ud, tname); + if (p == NULL) typeerror(L, ud, tname); return p; } @@ -377,7 +383,7 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { if (newsize - B->n < sz) /* not bit enough? */ newsize = B->n + sz; if (newsize < B->n || newsize - B->n < sz) - luaL_error(L, "string too large"); + luaL_error(L, "buffer too large"); newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */ memcpy(newbuff, B->b, B->n); /* move content to new buffer */ if (buffonstack(B)) diff --git a/src/lauxlib.h b/src/lauxlib.h index 504fdf586c..f4e31bc8b9 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.109 2010/10/25 20:31:11 roberto Exp $ +** $Id: lauxlib.h,v 1.111 2010/11/10 18:05:36 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -32,7 +32,6 @@ LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); -LUALIB_API int (luaL_typeerror) (lua_State *L, int narg, const char *tname); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); @@ -53,6 +52,7 @@ LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int narg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); diff --git a/src/lbitlib.c b/src/lbitlib.c index e93575e61a..b37344f3e6 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.10 2010/10/28 15:17:29 roberto Exp $ +** $Id: lbitlib.c,v 1.11 2010/11/08 16:31:22 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -108,7 +108,7 @@ static int b_rshift (lua_State *L) { static int b_arshift (lua_State *L) { b_uint r = getuintarg(L, 1); int i = luaL_checkint(L, 2); - if (i < 0 || !(r & (1 << (NBITS - 1)))) + if (i < 0 || !(r & ((b_uint)1 << (NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ if (i >= NBITS) r = ALLONES; diff --git a/src/ldblib.c b/src/ldblib.c index 9ae6f86b16..04213159de 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.124 2010/07/25 15:18:19 roberto Exp $ +** $Id: ldblib.c,v 1.125 2010/11/10 18:06:10 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -44,15 +44,22 @@ static int db_setmetatable (lua_State *L) { } +static void checkudata (lua_State *L, int narg) { + if (lua_type(L, narg) == LUA_TLIGHTUSERDATA) + luaL_argerror(L, narg, "full userdata expected, got light userdata"); + luaL_checktype(L, narg, LUA_TUSERDATA); +} + + static int db_getuservalue (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); + checkudata(L, 1); lua_getuservalue(L, 1); return 1; } static int db_setuservalue (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); + checkudata(L, 1); if (!lua_isnoneornil(L, 2)) luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); diff --git a/src/linit.c b/src/linit.c index ecde4915ad..fa944671c4 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,5 +1,5 @@ /* -** $Id: linit.c,v 1.29 2010/10/25 14:32:36 roberto Exp $ +** $Id: linit.c,v 1.30 2010/11/12 15:48:30 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ @@ -36,9 +36,7 @@ static const luaL_Reg loadedlibs[] = { {LUA_STRLIBNAME, luaopen_string}, {LUA_BITLIBNAME, luaopen_bit32}, {LUA_MATHLIBNAME, luaopen_math}, -#if defined(LUA_COMPAT_DEBUGLIB) {LUA_DBLIBNAME, luaopen_debug}, -#endif {NULL, NULL} }; @@ -47,7 +45,6 @@ static const luaL_Reg loadedlibs[] = { ** these libs are preloaded and must be required before used */ static const luaL_Reg preloadedlibs[] = { - {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; diff --git a/src/liolib.c b/src/liolib.c index 6574e8b665..658601ad7a 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.92 2010/10/25 19:01:37 roberto Exp $ +** $Id: liolib.c,v 2.95 2010/11/10 18:05:36 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -19,6 +19,9 @@ #include "lualib.h" +#define MAX_SIZE_T (~(size_t)0) + + /* ** lua_popen spawns a new process connected to the current one through ** the file streams. @@ -111,8 +114,7 @@ static FILE *tofile (lua_State *L) { static FILE **newprefile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ - luaL_getmetatable(L, LUA_FILEHANDLE); - lua_setmetatable(L, -2); + luaL_setmetatable(L, LUA_FILEHANDLE); return pf; } @@ -371,22 +373,32 @@ static int read_line (lua_State *L, FILE *f, int chop) { } -static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t tbr = n; /* number of chars to be read */ - size_t rlen; /* how much to read in each cycle */ - size_t nr; /* number of chars actually read in each cycle */ +static void read_all (lua_State *L, FILE *f) { + size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */ luaL_Buffer b; luaL_buffinit(L, &b); - rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ - do { - char *p = luaL_prepbuffer(&b); - if (rlen > tbr) rlen = tbr; /* cannot read more than asked */ - nr = fread(p, sizeof(char), rlen, f); + for (;;) { + char *p = luaL_prepbuffsize(&b, rlen); + size_t nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); - tbr -= nr; /* still have to read 'tbr' chars */ - } while (tbr > 0 && nr == rlen); /* until end of count or eof */ + if (nr < rlen) break; /* eof? */ + else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */ + rlen *= 2; /* double buffer size at each iteration */ + } + luaL_pushresult(&b); /* close buffer */ +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t nr; /* number of chars actually read */ + char *p; + luaL_Buffer b; + luaL_buffinit(L, &b); + p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ + nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ + luaL_addsize(&b, nr); luaL_pushresult(&b); /* close buffer */ - return (tbr < n); /* true iff read something */ + return (nr > 0); /* true iff read something */ } @@ -421,7 +433,7 @@ static int g_read (lua_State *L, FILE *f, int first) { success = read_line(L, f, 0); break; case 'a': /* file */ - read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ + read_all(L, f); /* read entire file */ success = 1; /* always success */ break; default: diff --git a/src/llimits.h b/src/llimits.h index 4b75a84e60..f8ede143d3 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.82 2010/05/31 16:08:55 roberto Exp $ +** $Id: llimits.h,v 1.84 2010/11/08 16:33:20 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -168,6 +168,96 @@ typedef lu_int32 Instruction; #define luai_userstateyield(L,n) ((void)L) #endif +/* +** lua_number2int is a macro to convert lua_Number to int. +** lua_number2integer is a macro to convert lua_Number to lua_Integer. +** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned. +** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number. +*/ + +#if defined(MS_ASMTRICK) /* { */ +/* trick with Microsoft assembler for X86 */ + +#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} +#define lua_number2integer(i,n) lua_number2int(i, n) +#define lua_number2unsigned(i,n) \ + {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} + + +#elif defined(LUA_IEEE754TRICK) /* }{ */ +/* the next trick should work on any machine using IEEE754 with + a 32-bit integer type */ + +union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; + +#if !defined(LUA_IEEEENDIAN) /* { */ +#define LUAI_EXTRAIEEE \ + static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; +#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33) +#else +#define LUAI_EXTRAIEEE /* empty */ +#endif /* } */ + +#define lua_number2int32(i,n,t) \ + { LUAI_EXTRAIEEE \ + volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ + (i) = (t)u.l_p[LUA_IEEEENDIAN]; } + +#define lua_number2int(i,n) lua_number2int32(i, n, int) +#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) +#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) + +#endif /* } */ + + +/* the following definitions always work, but may be slow */ + +#if !defined(lua_number2int) +#define lua_number2int(i,n) ((i)=(int)(n)) +#endif + +#if !defined(lua_number2integer) +#define lua_number2integer(i,n) ((i)=(lua_Integer)(n)) +#endif + +#if !defined(lua_number2unsigned) /* { */ +/* the following definition assures proper modulo behavior */ +#if defined(LUA_NUMBER_DOUBLE) +#include +#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) +#define lua_number2unsigned(i,n) \ + ((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED)) +#else +#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n)) +#endif +#endif /* } */ + + +#if !defined(lua_unsigned2number) +/* on several machines, coercion from unsigned to double is slow, + so it may be worth to avoid */ +#define lua_unsigned2number(u) \ + (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u)) +#endif + + +/* +** luai_hashnum is a macro do hash a lua_Number value into an integer. +** The hash must be deterministic and give reasonable values for +** both small and large values (outside the range of integers). +** It is used only in ltable.c. +*/ + +#if !defined(luai_hashnum) /* { */ + +#include +#include + +#define luai_hashnum(i,n) { int e; \ + n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ + lua_number2int(i, n); i += e; } + +#endif /* } */ diff --git a/src/lmathlib.c b/src/lmathlib.c index 13aebe9e99..8494d80d50 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.76 2010/10/25 20:31:11 roberto Exp $ +** $Id: lmathlib.c,v 1.78 2010/11/12 15:47:34 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -22,92 +22,101 @@ #define RADIANS_PER_DEGREE (PI/180.0) +/* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */ +#if !defined(l_tg) +#define l_tg(x) (x) +#endif + + static int math_abs (lua_State *L) { - lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { - lua_pushnumber(L, sin(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(sin)(luaL_checknumber(L, 1))); return 1; } static int math_sinh (lua_State *L) { - lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(sinh)(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { - lua_pushnumber(L, cos(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(cos)(luaL_checknumber(L, 1))); return 1; } static int math_cosh (lua_State *L) { - lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(cosh)(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { - lua_pushnumber(L, tan(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(tan)(luaL_checknumber(L, 1))); return 1; } static int math_tanh (lua_State *L) { - lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(tanh)(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { - lua_pushnumber(L, asin(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(asin)(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { - lua_pushnumber(L, acos(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(acos)(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { - lua_pushnumber(L, atan(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(atan)(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { - lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + lua_pushnumber(L, l_tg(atan2)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); return 1; } static int math_ceil (lua_State *L) { - lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(ceil)(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { - lua_pushnumber(L, floor(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(floor)(luaL_checknumber(L, 1))); return 1; } static int math_fmod (lua_State *L) { - lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + lua_pushnumber(L, l_tg(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); return 1; } static int math_modf (lua_State *L) { - double ip; - double fp = modf(luaL_checknumber(L, 1), &ip); + lua_Number ip; + lua_Number fp = l_tg(modf)(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; } static int math_sqrt (lua_State *L) { - lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(sqrt)(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { - lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + lua_pushnumber(L, l_tg(pow)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); return 1; } @@ -115,11 +124,11 @@ static int math_log (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number res; if (lua_isnoneornil(L, 2)) - res = log(x); + res = l_tg(log)(x); else { lua_Number base = luaL_checknumber(L, 2); - if (base == 10.0) res = log10(x); - else res = log(x)/log(base); + if (base == 10.0) res = l_tg(log10)(x); + else res = l_tg(log)(x)/l_tg(log)(base); } lua_pushnumber(L, res); return 1; @@ -130,12 +139,12 @@ static int math_log10 (lua_State *L) { luaL_error(L, "function " LUA_QL("log10") " is deprecated; use log(x, 10) instead"); #endif - lua_pushnumber(L, log10(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(log10)(luaL_checknumber(L, 1))); return 1; } static int math_exp (lua_State *L) { - lua_pushnumber(L, exp(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_tg(exp)(luaL_checknumber(L, 1))); return 1; } @@ -151,13 +160,14 @@ static int math_rad (lua_State *L) { static int math_frexp (lua_State *L) { int e; - lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); + lua_pushnumber(L, l_tg(frexp)(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int math_ldexp (lua_State *L) { - lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); + lua_pushnumber(L, l_tg(ldexp)(luaL_checknumber(L, 1), + luaL_checkint(L, 2))); return 1; } @@ -203,14 +213,14 @@ static int math_random (lua_State *L) { case 1: { /* only upper limit */ lua_Number u = luaL_checknumber(L, 1); luaL_argcheck(L, 1.0 <= u, 1, "interval is empty"); - lua_pushnumber(L, floor(r*u) + 1.0); /* int between 1 and `u' */ + lua_pushnumber(L, l_tg(floor)(r*u) + 1.0); /* int in [1, u] */ break; } case 2: { /* lower and upper limits */ lua_Number l = luaL_checknumber(L, 1); lua_Number u = luaL_checknumber(L, 2); luaL_argcheck(L, l <= u, 2, "interval is empty"); - lua_pushnumber(L, floor(r*(u-l+1)) + l); /* int between `l' and `u' */ + lua_pushnumber(L, l_tg(floor)(r*(u-l+1)) + l); /* int in [l, u] */ break; } default: return luaL_error(L, "wrong number of arguments"); diff --git a/src/loadlib.c b/src/loadlib.c index 42cfb86911..3e5eaecfe1 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.92 2010/10/29 14:35:09 roberto Exp $ +** $Id: loadlib.c,v 1.94 2010/11/10 20:00:04 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -239,8 +239,7 @@ static void **ll_register (lua_State *L, const char *path) { lua_pop(L, 1); /* remove result from gettable */ plib = (void **)lua_newuserdata(L, sizeof(const void *)); *plib = NULL; - luaL_getmetatable(L, "_LOADLIB"); - lua_setmetatable(L, -2); + luaL_setmetatable(L, "_LOADLIB"); lua_pushfstring(L, "%s%s", LIBPREFIX, path); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); @@ -435,21 +434,14 @@ static int loader_preload (lua_State *L) { } -static const int sentinel_ = 0; -#define sentinel ((void *)&sentinel_) - - static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); int i; lua_settop(L, 1); /* _LOADED table will be at index 2 */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); - if (lua_toboolean(L, -1)) { /* is it there? */ - if (lua_touserdata(L, -1) == sentinel) /* check loops */ - luaL_error(L, "loop or previous error loading module " LUA_QS, name); + if (lua_toboolean(L, -1)) /* is it there? */ return 1; /* package is already loaded */ - } /* else must load it; iterate over available loaders */ lua_getfield(L, lua_upvalueindex(1), "loaders"); if (!lua_istable(L, -1)) @@ -469,14 +461,12 @@ static int ll_require (lua_State *L) { else lua_pop(L, 1); } - lua_pushlightuserdata(L, sentinel); - lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ lua_pushstring(L, name); /* pass name as argument to module */ lua_call(L, 1, 1); /* run loaded module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_getfield(L, 2, name); - if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ + if (lua_isnil(L, -1)) { /* module did not set a value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ diff --git a/src/lstrlib.c b/src/lstrlib.c index f213200535..1cd37def33 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.156 2010/10/29 17:52:46 roberto Exp $ +** $Id: lstrlib.c,v 1.157 2010/11/08 17:38:37 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -722,6 +722,7 @@ static int str_gsub (lua_State *L) { ** 'string.format'; LUA_INTFRM_T is the integer type corresponding to ** the previous length */ +#if !defined(LUA_INTFRMLEN) /* { */ #if defined(LUA_USELONGLONG) #define LUA_INTFRMLEN "ll" @@ -732,6 +733,20 @@ static int str_gsub (lua_State *L) { #define LUA_INTFRMLEN "l" #define LUA_INTFRM_T long +#endif +#endif /* } */ + + +/* +** LUA_FLTFRMLEN is the length modifier for float conversions in +** 'string.format'; LUA_FLTFRM_T is the float type corresponding to +** the previous length +*/ +#if !defined(LUA_FLTFRMLEN) + +#define LUA_FLTFRMLEN "" +#define LUA_FLTFRM_T double + #endif @@ -793,14 +808,15 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { /* -** add length modifier into integer formats +** add length modifier into formats */ -static void addintlen (char *form) { +static void addlenmod (char *form, const char *lenmod) { size_t l = strlen(form); + size_t lm = strlen(lenmod); char spec = form[l - 1]; - strcpy(form + l - 1, LUA_INTFRMLEN); - form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; - form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; } @@ -834,13 +850,14 @@ static int str_format (lua_State *L) { lua_Number n = luaL_checknumber(L, arg); LUA_INTFRM_T r = (n < 0) ? (LUA_INTFRM_T)n : (LUA_INTFRM_T)(unsigned LUA_INTFRM_T)n; - addintlen(form); + addlenmod(form, LUA_INTFRMLEN); nb = sprintf(buff, form, r); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { - nb = sprintf(buff, form, (double)luaL_checknumber(L, arg)); + addlenmod(form, LUA_FLTFRMLEN); + nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg)); break; } case 'q': { diff --git a/src/ltable.c b/src/ltable.c index f93b96ccea..7ff0f89790 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.52 2010/06/25 12:18:10 roberto Exp $ +** $Id: ltable.c,v 2.53 2010/11/11 15:38:43 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -38,8 +38,8 @@ /* ** max size of array part is 2^MAXBITS */ -#if LUAI_BITSINT > 26 -#define MAXBITS 26 +#if LUAI_BITSINT >= 32 +#define MAXBITS 30 #else #define MAXBITS (LUAI_BITSINT-2) #endif diff --git a/src/lua.h b/src/lua.h index 9de92287b8..0e1f97a41c 100644 --- a/src/lua.h +++ b/src/lua.h @@ -18,7 +18,7 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" -#define LUA_VERSION_RELEASE "0" " (work5)" +#define LUA_VERSION_RELEASE "0" " (alpha)" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE diff --git a/src/luaconf.h b/src/luaconf.h index 2345e00c2c..1222dc9ce6 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.148 2010/10/29 17:52:46 roberto Exp $ +** $Id: luaconf.h,v 1.151 2010/11/12 15:48:30 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -229,7 +229,7 @@ ** You can define it to get all options, or change specific options ** to fit your specific needs. */ -#if defined(LUA_COMPAT_ALL) +#if defined(LUA_COMPAT_ALL) /* { */ /* @@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. @@ -238,8 +238,8 @@ #define LUA_COMPAT_UNPACK /* -@@ LUA_COMPAT_CPCALL controls the presence of macro 'lua_cpcall'. -** You can call your C function directly (with light C functions) +@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. +** You can call your C function directly (with light C functions). */ #define lua_cpcall(L,f,u) \ (lua_pushcfunction(L, (f)), \ @@ -258,14 +258,6 @@ */ #define LUA_COMPAT_MAXN -/* -@@ LUA_COMPAT_DEBUGLIB controls compatibility with preloading -** the debug library. -** You should add 'require"debug"' everywhere you need the debug -** library. -*/ -#define LUA_COMPAT_DEBUGLIB - /* @@ The following macros supply trivial compatibility for some ** changes in the API. The macros themselves document how to @@ -275,19 +267,16 @@ #define lua_objlen(L,i) lua_rawlen(L, (i)) -#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) #define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) -/* compatibility with previous wrong spelling */ -#define luaL_typerror luaL_typeerror - /* @@ LUA_COMPAT_MODULE controls compatibility with previous ** module functions 'module' (Lua) and 'luaL_register' (C). */ #define LUA_COMPAT_MODULE -#endif /* LUA_COMPAT_ALL */ +#endif /* } */ /* }================================================================== */ @@ -348,27 +337,13 @@ -/* -** {================================================================== -** CHANGE (to smaller values) the following definitions if your system -** has a small C stack. (Or you may want to change them to larger -** values if your system has a large C stack and these limits are -** too rigid for you.) Some of these constants control the size of -** stack-allocated arrays used by the compiler or the interpreter, while -** others limit the maximum number of recursive calls that the compiler -** or the interpreter can perform. Values too large may cause a C stack -** overflow for some forms of deep constructs. -** =================================================================== -*/ - /* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +** CHANGE it if it uses too much C-stack space. */ #define LUAL_BUFFERSIZE BUFSIZ -/* }================================================================== */ - @@ -445,32 +420,21 @@ #define LUA_UNSIGNED unsigned LUA_INT32 -/* -@@ lua_number2int is a macro to convert lua_Number to int. -@@ lua_number2integer is a macro to convert lua_Number to LUA_INTEGER. -@@ lua_number2uint is a macro to convert a lua_Number to a LUA_UNSIGNED. -@@ lua_uint2number is a macro to convert a LUA_UNSIGNED to a lua_Number. -*/ - #if defined(LUA_CORE) /* { */ -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && \ - !defined(LUA_NOIEEE754TRICK) /* { */ +#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ /* On a Microsoft compiler on a Pentium, use assembler to avoid clashes with a DirectX idiosyncrasy */ #if defined(_MSC_VER) && defined(M_IX86) /* { */ -#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} -#define lua_number2integer(i,n) lua_number2int(i, n) -#define lua_number2uint(i,n) \ - {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} +#define MS_ASMTRICK #else /* }{ */ -/* the next trick should work on any machine using IEEE754 with - a 32-bit integer type */ +/* the next definition uses a trick that should work on any machine + using IEEE754 with a 32-bit integer type */ -union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; +#define LUA_IEEE754TRICK /* @@ LUA_IEEEENDIAN is the endianness of doubles in your machine @@ -485,77 +449,11 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #define LUA_IEEEENDIAN 1 #endif -#if !defined(LUA_IEEEENDIAN) /* { */ -#define LUAI_EXTRAIEEE \ - static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; -#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33) -#else -#define LUAI_EXTRAIEEE /* empty */ -#endif /* } */ - -#define lua_number2int32(i,n,t) \ - { LUAI_EXTRAIEEE \ - volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ - (i) = (t)u.l_p[LUA_IEEEENDIAN]; } - -#define lua_number2int(i,n) lua_number2int32(i, n, int) -#define lua_number2integer(i,n) lua_number2int32(i, n, LUA_INTEGER) -#define lua_number2uint(i,n) lua_number2int32(i, n, LUA_UNSIGNED) - #endif /* } */ - #endif /* } */ - -/* the following definitions always work, but may be slow */ - -#if !defined(lua_number2int) -#define lua_number2int(i,n) ((i)=(int)(n)) -#endif - -#if !defined(lua_number2integer) -#define lua_number2integer(i,n) ((i)=(LUA_INTEGER)(n)) -#endif - -#if !defined(lua_number2uint) && (defined(lapi_c) || defined(luaall_c)) /* { */ -/* the following definition assures proper modulo behavior */ -#if defined(LUA_NUMBER_DOUBLE) -#include -#define lua_number2uint(i,n) \ - ((i)=(LUA_UNSIGNED)((n) - floor((n)/4294967296.0)*4294967296.0)) -#else -#define lua_number2uint(i,n) ((i)=(LUA_UNSIGNED)(n)) -#endif -#endif /* } */ - -#if !defined(lua_uint2number) -/* on several machines, coercion from unsigned to double is slow, - so it may be worth to avoid */ -#define lua_uint2number(u) \ - ((LUA_INT32)(u) < 0 ? (lua_Number)(u) : (lua_Number)(LUA_INT32)(u)) -#endif - -#endif /* } */ - - -/* -@@ luai_hashnum is a macro do hash a lua_Number value into an integer. -@* The hash must be deterministic and give reasonable values for -@* both small and large values (outside the range of integers). -@* It is used only in ltable.c. -*/ - -#if defined(ltable_c) || defined(luaall_c) - -#include -#include - -#define luai_hashnum(i,n) { int e; \ - n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ - lua_number2int(i, n); i += e; } - -#endif /* ltable_c */ +#endif /* } */ /* }================================================================== */ From 850a3d8f8d2ef75c2e7579f31e3b301a72c279cd Mon Sep 17 00:00:00 2001 From: Lua Team Date: Wed, 17 Nov 2010 12:00:00 +0000 Subject: [PATCH 54/97] Lua 5.2.0-alpha-rc2 --- doc/contents.html | 6 +- doc/manual.html | 266 ++++++++++++++++++++++++++++++---------------- src/lauxlib.h | 27 ++--- src/ldblib.c | 19 ++-- src/lstrlib.c | 18 +++- 5 files changed, 209 insertions(+), 127 deletions(-) diff --git a/doc/contents.html b/doc/contents.html index 199af66870..f309c1f97e 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -457,6 +457,7 @@

            auxiliary library

            luaL_argcheck
            luaL_argerror
            luaL_buffinit
            +luaL_buffinitsize
            luaL_callmeta
            luaL_checkany
            luaL_checkint
            @@ -474,6 +475,7 @@

            auxiliary library

            luaL_dofile
            luaL_dostring
            luaL_error
            +luaL_findtable
            luaL_getmetafield
            luaL_getmetatable
            luaL_gsub
            @@ -493,7 +495,9 @@

            auxiliary library

            luaL_optstring
            luaL_optunsigned
            luaL_prepbuffer
            +luaL_prepbuffsize
            luaL_pushresult
            +luaL_pushresultsize
            luaL_ref
            luaL_requiref
            luaL_setfuncs
            @@ -512,7 +516,7 @@

            auxiliary library


            Last update: -Tue Nov 16 09:56:07 BRST 2010 +Wed Nov 17 14:51:24 BRST 2010

            - + @@ -1026,7 +1026,7 @@

            3 – The Language

            [a] means an optional a. Non-terminals are shown like non-terminal, keywords are shown like kword, -and other terminal symbols are shown like &lsquo=’. +and other terminal symbols are shown like ‘=’. The complete syntax of Lua can be found in §9 at the end of this manual. @@ -1225,7 +1225,7 @@

            3.2 – Variables

            Square brackets are used to index a table:
            -	var ::= prefixexp &lsquo[’ exp &lsquo]’
            +	var ::= prefixexp ‘[’ exp ‘]

            The meaning of accesses to table fields can be changed via metatables. An access to an indexed variable t[i] is equivalent to @@ -1241,7 +1241,7 @@

            3.2 – Variables

            var["Name"]:
            -	var ::= prefixexp &lsquo.’ Name
            +	var ::= prefixexp ‘.’ Name
             

            @@ -1280,7 +1280,7 @@

            3.3.1 – Blocks

            or write two semicolons in sequence:
            -	stat ::= &lsquo;’
            +	stat ::= ‘;

            @@ -1351,9 +1351,9 @@

            3.3.3 – Assignment

            The elements in both lists are separated by commas:
            -	stat ::= varlist &lsquo=’ explist
            -	varlist ::= var {&lsquo,’ var}
            -	explist ::= exp {&lsquo,’ exp}
            +	stat ::= varlist ‘=’ explist
            +	varlist ::= var {‘,’ var}
            +	explist ::= exp {‘,’ exp}
             

            Expressions are discussed in §3.4. @@ -1454,11 +1454,11 @@

            3.3.4 – Control Structures

            The return statement is used to return values from a function or a chunk (which is just a function). -Functions and chunks can return more than one value, -and so the syntax for the return statement is +Functions can return more than one value, +so the syntax for the return statement is

            -	stat ::= return [explist] [&lsquo;’]
            +	stat ::= return [explist] [‘;’]
             

            @@ -1468,7 +1468,7 @@

            3.3.4 – Control Structures

            -	stat ::= break [&lsquo;’]
            +	stat ::= break [‘;’]
             

            A break ends the innermost enclosing loop. @@ -1502,7 +1502,7 @@

            3.3.5 – For Statement

            It has the following syntax:
            -	stat ::= for Name &lsquo=’ exp &lsquo,’ exp [&lsquo,’ exp] do block end
            +	stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
             

            The block is repeated for name starting at the value of the first exp, until it passes the second exp by steps of the @@ -1567,7 +1567,7 @@

            3.3.5 – For Statement

             	stat ::= for namelist in explist do block end
            -	namelist ::= Name {&lsquo,’ Name}
            +	namelist ::= Name {‘,’ Name}
             

            A for statement like @@ -1638,7 +1638,7 @@

            3.3.7 – Local Declarations

            The declaration can include an initial assignment:

            -	stat ::= local namelist [&lsquo=’ explist]
            +	stat ::= local namelist [‘=’ explist]
             

            If present, an initial assignment has the same semantics of a multiple assignment (see §3.3.3). @@ -1672,10 +1672,10 @@

            3.4 – Expressions

            exp ::= String exp ::= function exp ::= tableconstructor - exp ::= &lsquo...’ + exp ::= ‘...’ exp ::= exp binop exp exp ::= unop exp - prefixexp ::= var | functioncall | &lsquo(’ exp &lsquo)’ + prefixexp ::= var | functioncall | ‘(’ exp ‘)

            @@ -1957,10 +1957,10 @@

            3.4.8 – Table Constructors

            The general syntax for constructors is

            -	tableconstructor ::= &lsquo{’ [fieldlist] &lsquo}’
            +	tableconstructor ::= ‘{’ [fieldlist] ‘}’
             	fieldlist ::= field {fieldsep field} [fieldsep]
            -	field ::= &lsquo[’ exp &lsquo]’ &lsquo=’ exp | Name &lsquo=’ exp | exp
            -	fieldsep ::= &lsquo,’ | &lsquo;’
            +	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
            +	fieldsep ::= ‘,’ | ‘;

            @@ -2032,7 +2032,7 @@

            3.4.9 – Function Calls

            The form

            -	functioncall ::= prefixexp &lsquo:’ Name args
            +	functioncall ::= prefixexp ‘:’ Name args
             

            can be used to call "methods". A call v:name(args) @@ -2044,7 +2044,7 @@

            3.4.9 – Function Calls

            Arguments have the following syntax:

            -	args ::= &lsquo(’ [explist] &lsquo)’
            +	args ::= ‘(’ [explist] ‘)’
             	args ::= tableconstructor
             	args ::= String
             

            @@ -2093,7 +2093,7 @@

            3.4.10 – Function Definitions

             	function ::= function funcbody
            -	funcbody ::= &lsquo(’ [parlist] &lsquo)’ block end
            +	funcbody ::= ‘(’ [parlist] ‘)’ block end
             

            @@ -2102,7 +2102,7 @@

            3.4.10 – Function Definitions

             	stat ::= function funcname funcbody
             	stat ::= local function Name funcbody
            -	funcname ::= Name {&lsquo.’ Name} [&lsquo:’ Name]
            +	funcname ::= Name {‘.’ Name} [‘:’ Name]
             

            The statement @@ -2161,7 +2161,7 @@

            3.4.10 – Function Definitions

            initialized with the argument values:
            -	parlist ::= namelist [&lsquo,’ &lsquo...’] | &lsquo...’
            +	parlist ::= namelist [‘,’ ‘...’] | ‘...

            When a function is called, the list of arguments is adjusted to @@ -2216,6 +2216,13 @@

            3.4.10 – Function Definitions

            then the function returns with no results. +

            + +There is a system-dependent limit on the number of values +that a function may return. +This limit is guaranteed to be larger than 1000. + +

            The colon syntax is used for defining methods, @@ -5321,7 +5328,7 @@

            5.1 – Functions and Types


            luaL_addchar

            -[-0, +0, m] +[-?, +?, m]

            void luaL_addchar (luaL_Buffer *B, char c);

            @@ -5333,7 +5340,7 @@

            5.1 – Functions and Types


            luaL_addlstring

            -[-0, +0, m] +[-?, +?, m]

            void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

            @@ -5347,7 +5354,7 @@

            5.1 – Functions and Types


            luaL_addsize

            -[-0, +0, m] +[-?, +?, m]

            void luaL_addsize (luaL_Buffer *B, size_t n);

            @@ -5360,7 +5367,7 @@

            5.1 – Functions and Types


            luaL_addstring

            -[-0, +0, m] +[-?, +?, m]

            void luaL_addstring (luaL_Buffer *B, const char *s);

            @@ -5374,7 +5381,7 @@

            5.1 – Functions and Types


            luaL_addvalue

            -[-1, +0, m] +[-1, +?, m]

            void luaL_addvalue (luaL_Buffer *B);

            @@ -5462,6 +5469,27 @@

            5.1 – Functions and Types

          +

          +If you know beforehand the total size of the resulting string, +you can use the buffer like this: + +

            + +
          • First you declare a variable b of type luaL_Buffer.
          • + +
          • Then you initialize it and preallocate a space of +size sz with a call luaL_buffinitsize(L, &b, sz).
          • + +
          • Then you copy the string into that space.
          • + +
          • +You finish by calling luaL_pushresult(&b, sz), +where sz is the total size of the resulting string +copied into that space. +
          • + +
          +

          During its normal operation, a string buffer uses a variable number of stack slots. @@ -5496,6 +5524,18 @@

          5.1 – Functions and Types

          +

          luaL_buffinitsize

          +[-?, +?, m] +

          char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);
          + +

          +Equivalent to the sequence +luaL_buffinit, luaL_prepbuffsize. + + + + +


          luaL_callmeta

          [-0, +(0|1), e]

          int luaL_callmeta (lua_State *L, int obj, const char *e);
          @@ -5770,6 +5810,20 @@

          5.1 – Functions and Types

          +

          luaL_findtable

          +[-0, +1, m] +

          void luaL_findtable (lua_State *L, int idx, const char *fname);
          + +

          +Ensures that the value t[fname], +where t is the value at the valid index idx, +is a table, +and pushes that table onto the stack. + + + + +


          luaL_getmetafield

          [-0, +(0|1), m]

          int luaL_getmetafield (lua_State *L, int obj, const char *e);
          @@ -5965,42 +6019,6 @@

          5.1 – Functions and Types

          -

          luaL_setfuncs

          -[-nup, +0, e] -

          void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
          - -

          -Registers all functions in the array l -(see luaL_Reg) into the table on the top of the stack -(below optional upvalues, see next). -The pointer l may be NULL, -representing an empty list. - - -

          -When nup is not zero, -all functions are created sharing nup upvalues, -which must be previously pushed on the stack -on top of the library table. -These values are popped from the stack after the registration. - - - - - -


          luaL_setmetatable

          -[-0, +0, -] -

          void luaL_setmetatable (lua_State *L, const char *tname);
          - -

          -Sets the metatable of the object at the top of the stack -as the metatable associated with name tname -in the registry (see luaL_newmetatable). - - - - -


          luaL_openlibs

          [-0, +0, e]

          void luaL_openlibs (lua_State *L);
          @@ -6132,11 +6150,23 @@

          5.1 – Functions and Types


          luaL_prepbuffer

          -[-0, +0, -] +[-?, +?, m]

          char *luaL_prepbuffer (luaL_Buffer *B);

          -Returns an address to a space of size LUAL_BUFFERSIZE +Equivalent to luaL_prepbuffsize +with the predefined size LUAL_BUFFERSIZE. + + + + + +


          luaL_prepbuffsize

          +[-?, +?, m] +

          char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);
          + +

          +Returns an address to a space of size sz where you can copy a string to be added to buffer B (see luaL_Buffer). After copying the string into this space you must call @@ -6159,6 +6189,17 @@

          5.1 – Functions and Types

          +

          luaL_pushresultsize

          +[-?, +1, m] +

          void luaL_pushresultsize (luaL_Buffer *B, size_t sz);
          + +

          +Equivalent to the sequence luaL_addsize, luaL_pushresult. + + + + +


          luaL_ref

          [-1, +0, m]

          int luaL_ref (lua_State *L, int t);
          @@ -6229,6 +6270,42 @@

          5.1 – Functions and Types

          +

          luaL_setfuncs

          +[-nup, +0, e] +

          void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
          + +

          +Registers all functions in the array l +(see luaL_Reg) into the table on the top of the stack +(below optional upvalues, see next). +The pointer l may be NULL, +representing an empty list. + + +

          +When nup is not zero, +all functions are created sharing nup upvalues, +which must be previously pushed on the stack +on top of the library table. +These values are popped from the stack after the registration. + + + + + +


          luaL_setmetatable

          +[-0, +0, -] +

          void luaL_setmetatable (lua_State *L, const char *tname);
          + +

          +Sets the metatable of the object at the top of the stack +as the metatable associated with name tname +in the registry (see luaL_newmetatable). + + + + +


          luaL_testudata

          [-0, +0, m]

          void *luaL_testudata (lua_State *L, int narg, const char *tname);
          @@ -9176,7 +9253,9 @@

          6.10 – The Debug Library

          -Returns the Lua value associated to userdata u. +Returns the Lua value associated to u. +If u is not a userdata, +returns nil. @@ -9305,7 +9384,8 @@

          6.10 – The Debug Library

          Sets the given value as the Lua value associated to the given udata. -value must be a table or nil. +value must be a table or nil; +udata must be a full userdata.

          @@ -9776,61 +9856,61 @@

          9 – The Complete Syntax of Lua

          chunk ::= block - block ::= {stat} [laststat [&lsquo;’]] + block ::= {stat} [laststat [‘;’]] - stat ::= &lsquo;’ | - varlist &lsquo=’ explist | + stat ::= ‘;’ | + varlist ‘=’ explist | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | - for Name &lsquo=’ exp &lsquo,’ exp [&lsquo,’ exp] do block end | + for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end | for namelist in explist do block end | function funcname funcbody | local function Name funcbody | - local namelist [&lsquo=’ explist] + local namelist [‘=’ explist] laststat ::= return [explist] | break - funcname ::= Name {&lsquo.’ Name} [&lsquo:’ Name] + funcname ::= Name {‘.’ Name} [‘:’ Name] - varlist ::= var {&lsquo,’ var} + varlist ::= var {‘,’ var} - var ::= Name | prefixexp &lsquo[’ exp &lsquo]’ | prefixexp &lsquo.’ Name + var ::= Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name - namelist ::= Name {&lsquo,’ Name} + namelist ::= Name {‘,’ Name} - explist ::= {exp &lsquo,’} exp + explist ::= {exp ‘,’} exp - exp ::= nil | false | true | Number | String | &lsquo...’ | function | + exp ::= nil | false | true | Number | String | ‘...’ | function | prefixexp | tableconstructor | exp binop exp | unop exp - prefixexp ::= var | functioncall | &lsquo(’ exp &lsquo)’ + prefixexp ::= var | functioncall | ‘(’ exp ‘)’ - functioncall ::= prefixexp args | prefixexp &lsquo:’ Name args + functioncall ::= prefixexp args | prefixexp ‘:’ Name args - args ::= &lsquo(’ [explist] &lsquo)’ | tableconstructor | String + args ::= ‘(’ [explist] ‘)’ | tableconstructor | String function ::= function funcbody - funcbody ::= &lsquo(’ [parlist] &lsquo)’ block end + funcbody ::= ‘(’ [parlist] ‘)’ block end - parlist ::= namelist [&lsquo,’ &lsquo...’] | &lsquo...’ + parlist ::= namelist [‘,’ ‘...’] | ‘...’ - tableconstructor ::= &lsquo{’ [fieldlist] &lsquo}’ + tableconstructor ::= ‘{’ [fieldlist] ‘}’ fieldlist ::= field {fieldsep field} [fieldsep] - field ::= &lsquo[’ exp &lsquo]’ &lsquo=’ exp | Name &lsquo=’ exp | exp + field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp - fieldsep ::= &lsquo,’ | &lsquo;’ + fieldsep ::= ‘,’ | ‘;’ - binop ::= &lsquo+’ | &lsquo-’ | &lsquo*’ | &lsquo/’ | &lsquo^’ | &lsquo%’ | &lsquo..’ | - &lsquo<’ | &lsquo<=’ | &lsquo>’ | &lsquo>=’ | &lsquo==’ | &lsquo~=’ | + binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘^’ | ‘%’ | ‘..’ | + ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | and | or - unop ::= &lsquo-’ | not | &lsquo#’ + unop ::= ‘-’ | not | ‘#’ @@ -9845,7 +9925,7 @@

          9 – The Complete Syntax of Lua


          Last update: -Tue Nov 16 09:52:41 BRST 2010 +Wed Nov 17 14:49:08 BRST 2010

          - + @@ -53,22 +53,23 @@

          1 – Introduction

          functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. -Lua is implemented as a library, written in clean C -(that is, in the common subset of ANSI C and C++). +Lua is implemented as a library, written in clean C, +the common subset of ANSI C and C++.

          Being an extension language, Lua has no notion of a "main" program: it only works embedded in a host client, called the embedding program or simply the host. -This host program can invoke functions to execute a piece of Lua code, +The host program can invoke functions to execute a piece of Lua code, can write and read Lua variables, and can register C functions to be called by Lua code. Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. The Lua distribution includes a sample host program called lua, -which uses the Lua library to offer a complete, standalone Lua interpreter. +which uses the Lua library to offer a complete, standalone Lua interpreter, +for interactive or batch use.

          @@ -85,7 +86,7 @@

          1 – Introduction

          For a discussion of the decisions behind the design of Lua, see the technical papers available at Lua's web site. For a detailed introduction to programming in Lua, -see Roberto's book, Programming in Lua (Second Edition). +see Roberto's book, Programming in Lua (second edition). @@ -126,7 +127,7 @@

          2.1 – Values and Types

          Number represents real (double-precision floating-point) numbers. (It is easy to build Lua interpreters that use other internal representations for numbers, -such as single-precision float or long integers; +such as single-precision floats or long integers; see file luaconf.h.) String represents arrays of characters. @@ -211,7 +212,7 @@

          2.2 – Environments and the Global Environment

          As discussed in §3.2 and §3.3.3, any reference to a global name var is syntactically translated to _ENV.var. -Moreover, any chunk is compiled in the scope of an external +Moreover, every chunk is compiled in the scope of an external variable called _ENV (see §3.3.2), so _ENV itself is never a global name in a chunk. @@ -256,7 +257,7 @@

          2.2 – Environments and the Global Environment

          (through C code or the debug library), all chunks loaded after the change will get the new environment. Previously loaded chunks are not affected, however, -as each has its own copy of the environment in its _ENV variable. +as each has its own reference to the environment in its _ENV variable. Moreover, the variable _G (which is stored in the original global environment) is never updated by Lua. @@ -271,8 +272,9 @@

          2.3 – Error Handling

          Because Lua is an embedded extension language, all Lua actions start from C code in the host program calling a function from the Lua library (see lua_pcall). -Whenever an error occurs during Lua compilation or execution, -control returns to C, +Whenever an error occurs during +the compilation or execution of a Lua chunk, +control returns to the host, which can take appropriate measures (such as printing an error message). @@ -281,7 +283,7 @@

          2.3 – Error Handling

          Lua code can explicitly generate an error by calling the error function. If you need to catch errors in Lua, -you can use the pcall function. +you can use the pcall or the xpcall function. @@ -297,27 +299,26 @@

          2.4 – Metatables and Metamethods

          You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable. For instance, when a non-numeric value is the operand of an addition, -Lua checks for a function in the field "__add" in its metatable. +Lua checks for a function in the field "__add" of the value's metatable. If it finds one, Lua calls this function to perform the addition.

          -We call the keys in a metatable events -and the values metamethods. -In the previous example, the event is "__add" +The keys in a metatable are derived from the event names; +the corresponding values are called metamethods. +In the previous example, the event is "add" and the metamethod is the function that performs the addition.

          You can query the metatable of any value -through the getmetatable function. +using the getmetatable function.

          You can replace the metatable of tables -through the setmetatable -function. +using the setmetatable function. You cannot change the metatable of other types from Lua (except by using the debug library); you must use the C API for that. @@ -338,8 +339,6 @@

          2.4 – Metatables and Metamethods

          order comparisons, concatenation, length operation, and indexing. A metatable also can define a function to be called when a userdata is garbage collected. -For each of these operations Lua associates a specific key -called an event. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) @@ -353,11 +352,11 @@

          2.4 – Metatables and Metamethods

          two underscores, '__'; for instance, the key for operation "add" is the string "__add". -The semantics of these operations is better explained by a Lua function -describing how the interpreter executes the operation.

          +The semantics of these operations is better explained by a Lua function +describing how the interpreter executes the operation. The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter and it is much more efficient than this simulation. @@ -719,7 +718,7 @@

          2.5 – Garbage Collection

          the garbage-collector pause and the garbage-collector step multiplier. Both use percentage points as units -(so that a value of 100 means an internal value of 1). +(e.g., a value of 100 means an internal value of 1).

          @@ -733,14 +732,15 @@

          2.5 – Garbage Collection

          -The step multiplier +The garbage-collector step multiplier controls the relative speed of the collector relative to memory allocation. Larger values make the collector more aggressive but also increase the size of each incremental step. Values smaller than 100 make the collector too slow and can result in the collector never finishing a cycle. -The default, 200, means that the collector runs at "twice" +The default is 200, +which means that the collector runs at "twice" the speed of memory allocation. @@ -767,7 +767,7 @@

          2.5.1 – Garbage-Collection Metamethods

          Using the C API, -you can set garbage-collector metamethods for userdata (see §2.4). +you can set garbage-collector metamethods for full userdata (see §2.4). These metamethods are also called finalizers. Finalizers allow you to coordinate Lua's garbage collection with external resource management @@ -777,12 +777,12 @@

          2.5.1 – Garbage-Collection Metamethods

          For a userdata to be finalized when collected, -you must mark it first. +you must mark it for finalization. You mark a userdata for finalization when you set its metatable and the metatable has a field indexed by the string "__gc". Note that if you set a metatable without a __gc field -and later create that field, +and later create that field in the metatable, the userdata will not be marked for finalization. However, after a userdata is marked, you can freely change the __gc field of its metatable. @@ -826,7 +826,7 @@

          2.5.2 – Weak Tables

          A weak reference is ignored by the garbage collector. In other words, if the only references to an object are weak references, -then the garbage collector will collect this object. +then the garbage collector will collect that object.

          @@ -873,11 +873,11 @@

          2.5.2 – Weak Tables

          -Userdata marked for finalization has a special behavior in weak tables. +Userdata marked for finalization have a special behavior in weak tables. When a marked userdata is a value in a weak table, it is removed from the table the first time it is collected, before running its finalizer. -When it is a key, however, +However, when it is a key, it is removed from the table only when it is really freed, after running its finalizer. This behavior allows the finalizer to access values @@ -901,15 +901,16 @@

          2.6 – Coroutines

          -You create a coroutine with a call to coroutine.create. +You create a coroutine by calling coroutine.create. Its sole argument is a function that is the main function of the coroutine. The create function only creates a new coroutine and returns a handle to it (an object of type thread); -it does not start the coroutine execution. +it does not start the coroutine.

          +You execute a coroutine by calling coroutine.resume. When you first call coroutine.resume, passing as its first argument a thread returned by coroutine.create, @@ -962,7 +963,7 @@

          2.6 – Coroutines

          -As an example, +As an example of how coroutines work, consider the following code:

          @@ -3659,6 +3660,11 @@ 

          4.8 – Functions and Types

          this confuses the next call to lua_next. +

          +See function next for the caveats of modifying +the table during its traversal. + + @@ -6972,7 +6978,7 @@

          6.1 – Basic Functions


          _VERSION

          A global variable (not a function) that holds a string containing the current interpreter version. -The current contents of this variable is "Lua 5.1". +The current contents of this variable is "Lua 5.2". @@ -7665,9 +7671,9 @@

          6.4 – String Manipulation

          end) --> x="4+5 = 9" - local t = {name="lua", version="5.1"} + local t = {name="lua", version="5.2"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) - --> x="lua-5.1.tar.gz" + --> x="lua-5.2.tar.gz"
          @@ -8385,8 +8391,6 @@

          6.7 – Bitwise operations

          This library provides bitwise operations. It provides all its functions inside the table bit32. -It uses upper case for function names to avoid collision with -some reserved words (and, or, and not).

          @@ -8398,12 +8402,34 @@

          6.7 – Bitwise operations

          and truncated to an integer (in some unspecified way), so that its final value falls in the range [0,232 - 1]. Similarly, all results are in the range [0,232 - 1]. -Note that bit32.NOT(0) is 0xFFFFFFFF, +Note that bit32.bnot(0) is 0xFFFFFFFF, which is different from -1.

          -


          bit32.AND (···)

          +

          bit32.arshift (x, disp)

          + + +

          +Returns the number x shifted disp bits to the right. +The number disp may be any representable integer. +Negative displacements shift to the left. + + +

          +This shift operation is what is called arithmetic shift. +Vacant bits on the left are filled +with copies of the higher bit of x; +vacant bits on the right are filled with zeros. +In particular, +displacements with absolute values higher than 31 +result in zero or 0xFFFFFFFF (all original bits are shifted out). + + + + +

          +


          bit32.band (···)

          @@ -8413,7 +8439,7 @@

          6.7 – Bitwise operations

          -


          bit32.NOT (x)

          +

          bit32.bnot (x)

          @@ -8422,13 +8448,13 @@

          6.7 – Bitwise operations

          the following identity holds:
          -     assert(bit32.NOT(x) == (-1 - x) % 2^32)
          +     assert(bit32.bnot(x) == (-1 - x) % 2^32)
           

          -


          bit32.OR (···)

          +

          bit32.bor (···)

          @@ -8438,7 +8464,7 @@

          6.7 – Bitwise operations

          -


          bit32.TEST (···)

          +

          bit32.btest (···)

          @@ -8449,7 +8475,7 @@

          6.7 – Bitwise operations

          -


          bit32.XOR (···)

          +

          bit32.bxor (···)

          @@ -8459,7 +8485,7 @@

          6.7 – Bitwise operations

          -


          bit32.ROL (x, disp)

          +

          bit32.lrotate (x, disp)

          @@ -8472,7 +8498,7 @@

          6.7 – Bitwise operations

          the following identity holds:
          -     assert(bit32.ROL(x, disp) == bit32.ROL(x, disp % 32))
          +     assert(bit32.lrotate(x, disp) == bit32.lrotate(x, disp % 32))
           

          In particular, negative displacements rotate to the right. @@ -8481,75 +8507,53 @@

          6.7 – Bitwise operations

          -


          bit32.ROR (x, disp)

          +

          bit32.lshift (x, disp)

          -Returns the number x rotated disp bits to the right. +Returns the number x shifted disp bits to the left. The number disp may be any representable integer. +Negative displacements shift to the right. +In any direction, vacant bits are filled with zeros. +In particular, +displacements with absolute values higher than 31 +result in zero (all bits are shifted out).

          -For any valid displacement, -the following identity holds: +For positive displacements, +the following equality holds:

          -     assert(bit32.ROR(x, disp) == bit32.ROR(x, disp % 32))
          -

          -In particular, -negative displacements rotate to the left. - + assert(bit32.lshift(b, disp) == (b * 2^disp) % 2^32) +

          -


          bit32.SAR (x, disp)

          +

          bit32.rrotate (x, disp)

          -Returns the number x shifted disp bits to the right. +Returns the number x rotated disp bits to the right. The number disp may be any representable integer. -Negative displacements shift to the left. - - -

          -This shift operation is what is called arithmetic shift. -Vacant bits on the left are filled -with copies of the higher bit of x; -vacant bits on the right are filled with zeros. -In particular, -displacements with absolute values higher than 31 -result in zero or 0xFFFFFFFF (all bits are shifted out). - -

          -


          bit32.SHL (x, disp)

          - +For any valid displacement, +the following identity holds: -

          -Returns the number x shifted disp bits to the left. -The number disp may be any representable integer. -Negative displacements shift to the right. -In any direction, vacant bits are filled with zeros. +

          +     assert(bit32.rrotate(x, disp) == bit32.rrotate(x, disp % 32))
          +

          In particular, -displacements with absolute values higher than 31 -result in zero (all bits are shifted out). - - -

          -For positive displacements, -the following equality holds: +negative displacements rotate to the left. -

          -     assert(bit32.SHL(b, disp) == (b * 2^disp) % 2^32)
          -

          -


          bit32.SHR (x, disp)

          +

          bit32.rshift (x, disp)

          @@ -8567,7 +8571,7 @@

          6.7 – Bitwise operations

          the following equality holds:
          -     assert(bit32.SHR(b, disp) == math.floor(b % 2^32 / 2^disp))
          +     assert(bit32.rshift(b, disp) == math.floor(b % 2^32 / 2^disp))
           

          @@ -9925,7 +9929,7 @@

          9 – The Complete Syntax of Lua


          Last update: -Wed Nov 17 14:49:08 BRST 2010 +Mon Nov 22 16:36:19 BRST 2010 diff --git a/doc/lua.css b/doc/lua.css index b9d3cca937..d87665c9e2 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -8,6 +8,7 @@ body { } h1, h2, h3, h4 { + font-family: Verdana, sans-serif ; font-weight: normal ; font-style: italic ; } @@ -27,7 +28,7 @@ h3 { table h3 { padding-left: 0px ; - border-left: none ; + border-left: none ; } a:link { @@ -62,3 +63,21 @@ hr { padding: 8px ; border: solid #a0a0a0 2px ; } + +.footer { + color: gray ; + font-size: small ; +} + +input[type=text] { + border: solid #a0a0a0 2px ; + border-radius: 2em ; + -moz-border-radius: 2em ; + background-image: url('images/search.png') ; + background-repeat: no-repeat; + background-position: left center ; + background-position: 4px center ; + padding-left: 20px ; + height: 2em ; +} + diff --git a/doc/manual.html b/doc/manual.html index c15482124e..fdd3669b7a 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -17,14 +17,14 @@

          [!] -This is an alpha version of Lua 5.2. +This is a beta version of Lua 5.2. Some details may change in the final version.

          by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

          -Copyright © 2010 Lua.org, PUC-Rio. +Copyright © 2011 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -38,7 +38,7 @@

          - + @@ -53,7 +53,7 @@

          1 – Introduction

          functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. -Lua is implemented as a library, written in clean C, +Lua is implemented as a library, written in clean C, the common subset of ANSI C and C++. @@ -125,11 +125,14 @@

          2.1 – Values and Types

          Both nil and false make a condition false; any other value makes it true. Number represents real (double-precision floating-point) numbers. +Operations on numbers follow the same rules of +the underlying C implementation, +which, in turn, usually follows the IEEE 754 standard. (It is easy to build Lua interpreters that use other internal representations for numbers, such as single-precision floats or long integers; see file luaconf.h.) -String represents arrays of characters. +String represents immutable sequences of bytes. Lua is 8-bit clean: strings can contain any 8-bit value, @@ -167,11 +170,19 @@

          2.1 – Values and Types

          The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, -but with any value (except nil). +but with any Lua value except nil and NaN +(Not a Number, a special numeric value used to represent +undefined or unrepresentable results, such as 0/0). Tables can be heterogeneous; that is, they can contain values of all types (except nil). +Any key with value nil is not considered part of the table. +Conversely, any key that is not part of a table has +an associated value nil. + + +

          Tables are the sole data structuring mechanism in Lua; -they can be used to represent ordinary arrays, +they can be used to represent ordinary arrays, sequences, symbol tables, sets, records, graphs, trees, etc. To represent records, Lua uses the field name as an index. The language supports this representation by @@ -180,15 +191,29 @@

          2.1 – Values and Types

          (see §3.4.8). +

          +We use the term sequence to denote a table where all +integer keys comprise the set {1..n} for some integer n, +which is called the length of the sequence (see §3.4.6). + +

          Like indices, -the value of a table field can be of any type (except nil). +the value of a table field can be of any type. In particular, because functions are first-class values, table fields can contain functions. Thus tables can also carry methods (see §3.4.10). +

          +The indexing of tables follows +the definition of equality in the language. +The expressions a[i] and a[j] +denote the same table element +if and only if i == j. + +

          Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, @@ -210,7 +235,7 @@

          2.2 – Environments and the Global Environment

          As discussed in §3.2 and §3.3.3, -any reference to a global name var is syntactically translated +any reference to a global name var is syntactically translated to _ENV.var. Moreover, every chunk is compiled in the scope of an external variable called _ENV (see §3.3.2), @@ -241,13 +266,13 @@

          2.2 – Environments and the Global Environment

          When Lua compiles a chunk, -it initializes the value of its _ENV variable +it initializes the value of its _ENV variable with the global environment (see load). Therefore, by default, global variables in Lua code refer to entries in the global environment. Moreover, all standard libraries are loaded in the global environment, and several functions there operate on that environment. -You can use loadin to load a chunk with a different environment. +You can use load to load a chunk with a different environment. (In C, you have to load the chunk and then change the value of its first upvalue.) @@ -283,7 +308,32 @@

          2.3 – Error Handling

          Lua code can explicitly generate an error by calling the error function. If you need to catch errors in Lua, -you can use the pcall or the xpcall function. +you can use pcall or xpcall +to call a given function in protected mode. + + +

          +Whenever there is an error, +an error object (also called an error message) +is propagated with information about the error. +Lua itself only generates errors where the error object is a string, +but programs may generate errors with +any value for the error object. + + +

          +When you use xpcall or lua_pcall, +you may give an message handler +to be called in case of errors. +This function is called with the original error message +and returns a new error message. +It is called before the error unwonds the stack, +so that it can gather more information about the error, +for instance by inspecting the stack and creating a stack traceback. +This message handler is still protected by the protected call; +so, an error inside the message handler +will call the message handler again. +If this loop goes on, Lua breaks it and returns an appropriate message. @@ -307,7 +357,7 @@

          2.4 – Metatables and Metamethods

          The keys in a metatable are derived from the event names; the corresponding values are called metamethods. -In the previous example, the event is "add" +In the previous example, the event is "add" and the metamethod is the function that performs the addition. @@ -623,6 +673,11 @@

          2.4 – Metatables and Metamethods

        • "index": The indexing access table[key]. +Note that the metamethod is tried only +when key is not present in table. +(When table is not a table, +no key is ever present, +so the metamethod is always tried.)
          @@ -630,6 +685,7 @@ 

          2.4 – Metatables and Metamethods

          local h if type(table) == "table" then local v = rawget(table, key) + -- if key is present, return raw value if v ~= nil then return v end h = metatable(table).__index if h == nil then return nil end @@ -649,6 +705,8 @@

          2.4 – Metatables and Metamethods

        • "newindex": The indexing assignment table[key] = value. +Note that the metamethod is tried only +when key is not present in table.
          @@ -656,6 +714,7 @@ 

          2.4 – Metatables and Metamethods

          local h if type(table) == "table" then local v = rawget(table, key) + -- if key is present, do raw assignment if v ~= nil then rawset(table, key, value); return end h = metatable(table).__newindex if h == nil then rawset(table, key, value); return end @@ -758,7 +817,7 @@

          2.5 – Garbage Collection

          You can change these numbers by calling lua_gc in C or collectgarbage in Lua. -With these functions you can also control +With these functions you can also control the collector directly (e.g., stop and restart it). @@ -766,8 +825,9 @@

          2.5 – Garbage Collection

          2.5.1 – Garbage-Collection Metamethods

          -Using the C API, -you can set garbage-collector metamethods for full userdata (see §2.4). +You can set garbage-collector metamethods for tables +and, using the C API, +for full userdata (see §2.4). These metamethods are also called finalizers. Finalizers allow you to coordinate Lua's garbage collection with external resource management @@ -776,43 +836,43 @@

          2.5.1 – Garbage-Collection Metamethods

          -For a userdata to be finalized when collected, +For an object (table or userdata) to be finalized when collected, you must mark it for finalization. -You mark a userdata for finalization when you set its metatable +You mark an object for finalization when you set its metatable and the metatable has a field indexed by the string "__gc". Note that if you set a metatable without a __gc field and later create that field in the metatable, -the userdata will not be marked for finalization. +the object will not be marked for finalization. However, after a userdata is marked, you can freely change the __gc field of its metatable.

          -When a marked userdata becomes garbage, +When a marked object becomes garbage, it is not collected immediately by the garbage collector. Instead, Lua puts it in a list. After the collection, Lua does the equivalent of the following function -for each userdata in that list: +for each object in that list:

          -     function gc_event (udata)
          -       local h = metatable(udata).__gc
          +     function gc_event (obj)
          +       local h = metatable(obj).__gc
                  if type(h) == "function" then
          -         h(udata)
          +         h(obj)
                  end
                end
           

          At the end of each garbage-collection cycle, -the finalizers for userdata are called in +the finalizers for objects are called in the reverse order that they were marked for collection, among those collected in that cycle; that is, the first finalizer to be called is the one associated -with the userdata marked last in the program. -The userdata memory is freed only in the next garbage-collection cycle. +with the object marked last in the program. +The object memory is freed only in the next garbage-collection cycle. @@ -873,15 +933,13 @@

          2.5.2 – Weak Tables

          -Userdata marked for finalization have a special behavior in weak tables. -When a marked userdata is a value in a weak table, -it is removed from the table the first time it is collected, -before running its finalizer. +Objects marked for finalization have a special behavior in weak tables. +When a marked object is a value in a weak table, +it is removed from the table before running its finalizer. However, when it is a key, -it is removed from the table only when it is really freed, -after running its finalizer. -This behavior allows the finalizer to access values -associated with the userdata through weak tables. +it is removed from the table only after running its finalizer. +This behavior allows the finalizer to access properties +associated with the object through weak tables. @@ -980,7 +1038,7 @@

          2.6 – Coroutines

          print("co-body", r, s) return b, "end" end) - + print("main", coroutine.resume(co, 1, 10)) print("main", coroutine.resume(co, "r")) print("main", coroutine.resume(co, "x", "y")) @@ -1048,8 +1106,7 @@

          3.1 – Lexical Conventions

          in Lua can be any string of letters, digits, and underscores, not beginning with a digit. -This coincides with the definition of names in most languages. -Identifiers are used to name variables and table fields. +Identifiers are used to name variables, table fields, and labels.

          @@ -1058,10 +1115,10 @@

          3.1 – Lexical Conventions

          -     and       break     do        else      elseif
          -     end       false     for       function  if
          -     in        local     nil       not       or
          -     repeat    return    then      true      until     while
          +     and       break     do        else      elseif    end
          +     false     for       function  goto      if        in
          +     local     nil       not       or        repeat    return
          +     then      true      until     while
           

          @@ -1102,7 +1159,7 @@

          3.1 – Lexical Conventions

          The escape sequence '\*' skips the following span of white-space characters, including line breaks; -it is particularly useful to break and indent a long string +it is particularly useful to break and indent a long string into multiple lines without adding the newlines and spaces into the string contents. @@ -1140,9 +1197,18 @@

          3.1 – Lexical Conventions

          (carriage return, newline, carriage return followed by newline, or newline followed by carriage return) is converted to a simple newline. -You should not use long strings for non-text data; -Use instead a regular quoted literal with explicit escape sequences -for control characters. + + +

          +When parsing a from a string source, +any byte in a literal string not +explicitly affected by the previous rules represents itself. +However, Lua opens files for parsing in text mode, +and the system file functions may have problems with +some control characters. +So, it is safer to represent +non-text data as a quoted literal with +explicit escape sequences for non-text characters.

          @@ -1166,14 +1232,19 @@

          3.1 – Lexical Conventions

          -A numerical constant can be written with an optional decimal part -and an optional decimal exponent. -Lua also accepts integer hexadecimal constants, -by prefixing them with 0x. +A numerical constant can be written with an optional fractional part +and an optional decimal exponent, +marked by a letter 'e' or 'E'. +Lua also accepts hexadecimal constants, +which start with 0x or 0X. +Hexadecimal constants also accept an optional fractional part +plus an optional binary exponent, +marked by a letter 'e' or 'E'. Examples of valid numerical constants are

          -     3   3.0   3.1416   314.16e-2   0.31416E1   0xff   0x56
          +     3     3.0     3.1416     314.16e-2     0.31416E1
          +     0xff  0x0.1E  0xA23p-4   0X1.921FB54442D18P+1
           

          @@ -1194,7 +1265,6 @@

          3.2 – Variables

          Variables are places that store values. - There are three kinds of variables in Lua: global variables, local variables, and table fields. @@ -1293,7 +1363,7 @@

          3.3.1 – Blocks

          Explicit blocks are useful to control the scope of variable declarations. Explicit blocks are also sometimes used to -add a return or break statement in the middle +add a return statement in the middle of another block (see §3.3.4). @@ -1312,7 +1382,7 @@

          3.3.2 – Chunks

        • -Lua handles a chunk as the body of an anonymous function +Lua handles a chunk as the body of an anonymous function with a variable number of arguments (see §3.4.10). As such, chunks can define local variables, @@ -1452,38 +1522,60 @@

          3.3.4 – Control Structures

          -The return statement is used to return values -from a function or a chunk (which is just a function). +The goto statement transfers the program control to a label. +For syntactical reasons, +labels in Lua are considered statements too: + -Functions can return more than one value, -so the syntax for the return statement is

          -	stat ::= return [explist] [‘;’]
          +	stat ::= goto Name
          +	stat ::= label
          +	label ::= ‘@’ Name ‘:

          -The break statement is used to terminate the execution of a +A label is visible in the entire block where it is defined +(including nested blocks, but not nested functions). +A goto may jump to any visible label as long as it does not +enter into the scope of a local variable. + + +

          +Both labels and empty statements are called void statements, +as they perform no actions. + + +

          +The break statement terminates the execution of a while, repeat, or for loop, skipping to the next statement after the loop:

          -	stat ::= break [‘;’]
          +	stat ::= break
           

          A break ends the innermost enclosing loop.

          -The return and break -statements can only be written as the last statement of a block. -If it is really necessary to return or break in the -middle of a block, +The return statement is used to return values +from a function or a chunk (which is a function in disguise). + +Functions can return more than one value, +so the syntax for the return statement is + +

          +	stat ::= return [explist] [‘;’]
          +
          + +

          +The return statement can only be written +as the last statement of a block. +If it is really necessary to return in the middle of a block, then an explicit inner block can be used, -as in the idioms -do return end and do break end, -because now return and break are the last statements in -their (inner) blocks. +as in the idiom do return end, +because now return is the last statement in its (inner) block. @@ -1582,8 +1674,8 @@

          3.3.5 – For Statement

          local f, s, var = explist while true do local var_1, ···, var_n = f(s, var) + if var_1 == nil then break end var = var_1 - if var == nil then break end block end end @@ -1649,7 +1741,6 @@

          3.3.7 – Local Declarations

          A chunk is also a block (see §3.3.2), and so local variables can be declared in a chunk outside any explicit block. -The scope of such local variables extends until the end of the chunk.

          @@ -1671,7 +1762,7 @@

          3.4 – Expressions

          exp ::= nil | false | true exp ::= Number exp ::= String - exp ::= function + exp ::= functiondef exp ::= tableconstructor exp ::= ‘...’ exp ::= exp binop exp @@ -1776,7 +1867,9 @@

          3.4.2 – Coercion

          Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert -this string to a number, following the usual conversion rules. +this string to a number, following the rules of the Lua lexer. +(The string may have leading and trailing spaces, +plus an optional sign.) Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control over how numbers are converted to strings, @@ -1802,8 +1895,8 @@

          3.4.3 – Relational Operators

          Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. Tables, userdata, and threads -are compared by reference: -two objects are considered equal only if they are the same object. +are compared by reference: +two objects are considered equal only if they are the same object. Every time you create a new object (a table, userdata, or thread), this new object is different from any previously existing object. @@ -1813,13 +1906,13 @@

          3.4.3 – Relational Operators

          -You can change the way that Lua compares tables and userdata +You can change the way that Lua compares tables and userdata by using the "eq" metamethod (see §2.4).

          The conversion rules of §3.4.2 -do not apply to equality comparisons. +do not apply to equality comparisons. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table. @@ -1902,25 +1995,27 @@

          3.4.6 – The Length Operator

          -The length of a table t can be any integer index n -such that t[n] is not nil and t[n+1] is nil; -moreover, if t[1] is nil, n can be zero. -(All accesses are assumed to be raw for this description.) -For a regular array, where all non-nil values -have keys from 1 to a given n, -its length is exactly that n, -the index of its last value. -If the array has "holes" -(that is, nil values between other non-nil values), -then #t can be any of the indices that -directly precedes a nil value -(that is, it may consider any such nil value as the end of -the array). +The length of a table t is only defined if the +table is a sequence, +that is, +all its numeric keys comprise the set {1..n} for some integer n. +In that case, n is its length. +Note that a table like + +

          +     {10, 20, nil, 40}
          +

          +is not a sequence, because it has the key 4 +but does not have the key 3. +(So, there is no n such that the set {1..n} is equal +to the set of numeric keys of that table.) +Note, however, that non-numeric keys do not interfere +with whether a table is a sequence.

          A program can modify the behavior of the length operator for -any value but strings through metamethods (see §2.4). +any value but strings through the __len metamethod (see §2.4). @@ -1999,9 +2094,6 @@

          3.4.8 – Table Constructors

          and the expression is a function call or a vararg expression, then all values returned by this expression enter the list consecutively (see §3.4.9). -To avoid this, -enclose the function call or the vararg expression -in parentheses (see §3.4).

          @@ -2060,7 +2152,7 @@

          3.4.9 – Function Calls

          -A call of the form return functioncall is called +A call of the form return functioncall is called a tail call. Lua implements proper tail calls (or proper tail recursion): @@ -2093,7 +2185,7 @@

          3.4.10 – Function Definitions

          The syntax for function definition is
          -	function ::= function funcbody
          +	functiondef ::= function funcbody
           	funcbody ::= ‘(’ [parlist] ‘)’ block end
           
          @@ -2135,7 +2227,7 @@

          3.4.10 – Function Definitions

                local f; f = function () body end
           

          -not to +not to

                local f = function () body end
          @@ -2153,8 +2245,6 @@ 

          3.4.10 – Function Definitions

          the function is instantiated (or closed). This function instance (or closure) is the final value of the expression. -Different instances of the same function -can refer to different external local variables.

          @@ -2249,9 +2339,9 @@

          3.5 – Visibility Rules

          Lua is a lexically scoped language. -The scope of variables begins at the first statement after -their declaration and lasts until the end of the innermost block that -includes the declaration. +The scope of a local variable begins at the first statement after +its declaration and lasts until the last non-void statement +of the innermost block that includes the declaration. Consider the following example:

          @@ -2356,9 +2446,9 @@ 

          4.1 – The Stack

          most query operations in the API do not follow a strict stack discipline. Instead, they can refer to any element in the stack by using an index: -A positive index represents an absolute stack position +A positive index represents an absolute stack position (starting at 1); -a negative index represents an offset relative to the top of the stack. +a negative index represents an offset relative to the top of the stack. More specifically, if the stack has n elements, then index 1 represents the first element (that is, the element that was pushed onto the stack first) @@ -2594,7 +2684,7 @@

          4.7 – Handling Yields in C

          Instead, Lua calls a continuation function, which was given as an argument to the callee function. As the name implies, -the continuation function should continue the task +the continuation function should continue the task of the original function. @@ -2684,8 +2774,7 @@

          4.8 – Functions and Types

          When ptr is not NULL, -osize is the previous size of the block -pointed by ptr, +osize is the size of the block pointed by ptr, that is, the size given when it was allocated or reallocated. @@ -2705,18 +2794,14 @@

          4.8 – Functions and Types

          -When nsize is zero: -if ptr is not NULL, -the allocator should free the block pointed to by ptr. -Anyway, the allocator must return NULL. +When nsize is zero, +the allocator should behave like free +and return NULL.

          -When nsize is not zero: -if ptr is NULL, -the allocator should behave like malloc; -when ptr is not NULL, -the allocator behaves like realloc. +When nsize is not zero, +the allocator should behave like realloc. The allocator returns NULL if and only if it cannot fill the request. Lua assumes that the allocator never fails when @@ -2751,12 +2836,14 @@

          4.8 – Functions and Types


          lua_arith

          -[-2, +1, e] +[-(2/1), +1, e]

          int lua_arith (lua_State *L, int op);

          -Performs an arithmetic operation over the two values at the top -of the stack (with the value at the top being the second operand), +Performs an arithmetic operation over the two values +(or one, in the case of negation) +at the top of the stack, +with the value at the top being the second operand, pops these values, and pushes the result of the operation. The function follows the semantics of the corresponding Lua operator (that is, it may call metamethods). @@ -2824,7 +2911,7 @@

          4.8 – Functions and Types

          The function results are pushed onto the stack when the function returns. The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. -In this case, all results from the function are pushed. +In this case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), @@ -3028,10 +3115,13 @@

          4.8 – Functions and Types

          Creates a new empty table and pushes it onto the stack. -The new table has space pre-allocated -for narr array elements and nrec non-array elements. -This pre-allocation is useful when you know exactly how many elements +Parameter narr is a hint for how many elements the table +will have as a sequence; +parameter nrec is a hint for how many other elements the table will have. +Lua may use these hints to preallocate memory for the new table. +This pre-allocation is useful for performance when you know in advance +how many elements the table will have. Otherwise you can use the function lua_newtable. @@ -3147,6 +3237,11 @@

          4.8 – Functions and Types

        +

        +For more details about some options, +see collectgarbage. + + @@ -3655,7 +3750,7 @@

        4.8 – Functions and Types

        While traversing a table, do not call lua_tolstring directly on a key, unless you know that the key is actually a string. -Recall that lua_tolstring changes +Recall that lua_tolstring may change the value at the given index; this confuses the next call to lua_next. @@ -3683,7 +3778,7 @@

        4.8 – Functions and Types


        lua_pcall

        [-(nargs + 1), +(nresults|1), -] -

        int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
        +
        int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);

        Calls a function in protected mode. @@ -3704,19 +3799,20 @@

        4.8 – Functions and Types

        -If errfunc is 0, +If msgh is 0, then the error message returned on the stack is exactly the original error message. -Otherwise, errfunc is the stack index of an -error handler function. +Otherwise, msgh is the stack index of a +message handler. (In the current implementation, this index cannot be a pseudo-index.) In case of runtime errors, this function will be called with the error message -and its return value will be the message returned on the stack by lua_pcall. +and its return value will be the message +returned on the stack by lua_pcall.

        -Typically, the error handler function is used to add more debug +Typically, the message handler is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound. @@ -3737,11 +3833,11 @@

        4.8 – Functions and Types

      • LUA_ERRMEM: memory allocation error. -For such errors, Lua does not call the error handler function. +For such errors, Lua does not call the message handler.
      • LUA_ERRERR: -error while running the error handler function. +error while running the message handler.
      • LUA_ERRGCMM: @@ -3944,7 +4040,8 @@

        4.8 – Functions and Types

        Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. -The string can contain embedded zeros. +The string can contain any binary data, +including embedded zeros.

        @@ -3986,8 +4083,6 @@

        4.8 – Functions and Types

        Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. -The string should not contain embedded zeros; -it is assumed to end at the first zero.

        @@ -4249,14 +4344,11 @@

        4.8 – Functions and Types


        lua_setuservalue

        [-1, +0, -] -

        int lua_setuservalue (lua_State *L, int index);
        +
        void lua_setuservalue (lua_State *L, int index);

        Pops a table or nil from the stack and sets it as the new value associated to the userdata at the given index. -If the value at the given index is not a userdata, -lua_setuservalue returns 0. -Otherwise it returns 1. @@ -4296,7 +4388,7 @@

        4.8 – Functions and Types


        lua_setmetatable

        [-1, +0, -] -

        int lua_setmetatable (lua_State *L, int index);
        +
        void lua_setmetatable (lua_State *L, int index);

        Pops a table from the stack and @@ -4716,7 +4808,7 @@

        4.8 – Functions and Types

        void lua_xmove (lua_State *from, lua_State *to, int n);

        -Exchange values between different threads of the same global state. +Exchange values between different threads of the same global state.

        @@ -5033,17 +5125,14 @@

        4.9 – The Debug Interface

        the parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook). -The index n selects which local variable to inspect -(1 is the first parameter or active local variable, and so on, -until the last active local variable). -lua_getlocal pushes the variable's value onto the stack -and returns its name. +The index n selects which local variable to inspect; +see debug.getlocal for details about variable indices +and names.

        -Variable names starting with '(' (open parentheses) -represent internal variables -(loop control variables, temporaries, and C function locals). +lua_getlocal pushes the variable's value onto the stack +and returns its name.

        @@ -5176,7 +5265,8 @@

        4.9 – The Debug Interface

      • The return hook: is called when the interpreter returns from a function. The hook is called just before Lua leaves the function. -You have no access to the values to be returned by the function. +There is no standard way to access the values +to be returned by the function.
      • The line hook: is called when the interpreter is about to @@ -5285,7 +5375,7 @@

        5 – The Auxiliary Library

        The auxiliary library provides several convenient functions to interface C with Lua. -While the basic API provides the primitive functions for all +While the basic API provides the primitive functions for all interactions between C and Lua, the auxiliary library provides higher-level functions for some common tasks. @@ -5816,15 +5906,28 @@

        5.1 – Functions and Types

        -

        luaL_findtable

        -[-0, +1, m] -

        void luaL_findtable (lua_State *L, int idx, const char *fname);
        +

        luaL_execresult

        +[-0, +(1/3), m] +

        int luaL_execresult (lua_State *L, int stat);

        -Ensures that the value t[fname], -where t is the value at the valid index idx, -is a table, -and pushes that table onto the stack. +This function produces the return values for +process-related functions in the standard library +(os.execute and io.close). + + + + + +


        luaL_fileresult

        +[-0, +(1/3), m] +

        int luaL_fileresult (lua_State *L, int stat,
        +                                             const char *fname)
        + +

        +This function produces the return values for +file-related functions in the standard library +(io.open, os.rename, file:seek, etc.). @@ -5857,6 +5960,22 @@

        5.1 – Functions and Types

        +

        luaL_getsubtable

        +[-0, +1, m] +

        int luaL_getsubtable (lua_State *L, int idx, const char *fname);
        + +

        +Ensures that the value t[fname], +where t is the value at the valid index idx, +is a table, +and pushes that table onto the stack. +Returns true if it finds a previous table there +and false if it creates a new table. + + + + +


        luaL_gsub

        [-0, +1, m]

        const char *luaL_gsub (lua_State *L,
        @@ -5965,13 +6084,27 @@ 

        5.1 – Functions and Types

        int luaL_newlib (lua_State *L, const luaL_Reg *l);

        -Equivalent to luaL_setfuncs with no upvalues, -but first creates a new table wherein to register the functions -in list l. +Creates a new table and registers there +the functions in list l. +It is implemented as the following macro: + +

        +     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
        +
        + + + +

        luaL_newlibtable

        +[-0, +1, m] +

        int luaL_newlibtable (lua_State *L, const luaL_Reg *l);

        -Leaves the new table on the stack. +Creates a new table with a size optimized +to store all entries in the array l +(but does not actually store them). +It is intended to be used in conjunction with luaL_setfuncs +(see luaL_newlib).

        @@ -6176,7 +6309,7 @@

        5.1 – Functions and Types

        where you can copy a string to be added to buffer B (see luaL_Buffer). After copying the string into this space you must call -luaL_addsize with the size of the string to actually add +luaL_addsize with the size of the string to actually add it to the buffer. @@ -6284,8 +6417,6 @@

        5.1 – Functions and Types

        Registers all functions in the array l (see luaL_Reg) into the table on the top of the stack (below optional upvalues, see next). -The pointer l may be NULL, -representing an empty list.

        @@ -6495,7 +6626,7 @@

        6.1 – Basic Functions

        The basic library provides some core functions to Lua. If you do not include this library in your application, -you should check carefully whether you need to provide +you should check carefully whether you need to provide implementations for some of its facilities. @@ -6526,11 +6657,13 @@

        6.1 – Basic Functions

      • "stop": -stops the garbage collector. +stops automatic invocation of the garbage collector. +The collector will run only when explcitly invoked, +until a call to restart it.
      • "restart": -restarts the garbage collector. +restarts automatic invocation the garbage collector.
      • "count": @@ -6543,6 +6676,8 @@

        6.1 – Basic Functions

        k, b = collectgarbage("count") assert(k*1024 == math.floor(k)*1024 + b)

        +(The second result is useful when Lua is compiled +with a non floating-point type for numbers.)

      • "step": @@ -6658,7 +6793,7 @@

        6.1 – Basic Functions

        -


        load (ld [, source [, mode]])

        +

        load (ld [, source [, mode [, env]]])

        @@ -6666,32 +6801,35 @@

        6.1 – Basic Functions

        +If ld is a string, the chunk is this string. If ld is a function, -calls it repeatedly to get the chunk pieces. +load calls it repeatedly to get the chunk pieces. Each call to ld must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.

        -If ld is a string, the chunk is this string. +If there are no errors, +returns the compiled chunk as a function; +otherwise, returns nil plus the error message.

        -If there are no errors, -returns the compiled chunk as a function; -otherwise, returns nil plus the error message. If the resulting function has upvalues, -the first upvalue is set to the value of the global environment +the first upvalue is set to the value of the +global environment or to env, +if that parameter is given. (When loading main chunks, -this upvalue will be the _ENV variable (see §2.2).) +the first upvalue will be the _ENV variable (see §2.2).)

        source is used as the source of the chunk for error messages and debug information (see §4.9). When absent, -it defaults to "=(load)". +it defaults to ld, if ld is a string, +or to "=(load)".

        @@ -6704,21 +6842,6 @@

        6.1 – Basic Functions

        -

        -


        loadin (env, ...)

        - - -

        -This function is similar to load, -but sets env as the value of the first upvalue -of the created function in case of success. -(When loading main chunks, -this upvalue will be the _ENV variable (see §2.2).) -The parameters after env are similar to those of load, too. - - - -


        loadfile ([filename])

        @@ -6732,29 +6855,6 @@

        6.1 – Basic Functions

        -

        -


        loadstring (string [, chunkname])

        - - -

        -Similar to load, -but gets the chunk from the given string. - - -

        -To load and run a given string, use the idiom - -

        -     assert(loadstring(s))()
        -
        - -

        -When absent, -chunkname defaults to the given string. - - - -


        next (table [, index])

        @@ -6784,7 +6884,7 @@

        6.1 – Basic Functions

        -The behavior of next is undefined if, +The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. @@ -6872,6 +6972,16 @@

        6.1 – Basic Functions

        +

        +


        rawlen (v)

        +Returns the length of the object v, +which must be a table or a string, +without invoking any metamethod. +Returns an integer number. + + + +


        rawset (table, index, value)

        Sets the real value of table[index] to value, @@ -6934,9 +7044,9 @@

        6.1 – Basic Functions

        In bases above 10, the letter 'A' (in either upper or lower case) represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. -In base 10 (the default), the number can have a decimal part, -as well as an optional exponent part (see §3.1). -In other bases, only unsigned integers are accepted. +In base 10 (the default), +the numeral is converted following the coercion rules (see §3.4.2). +In other bases, only integers are accepted. @@ -6984,12 +7094,12 @@

        6.1 – Basic Functions

        -


        xpcall (f, err [, arg1, ···])

        +

        xpcall (f, msgh [, arg1, ···])

        This function is similar to pcall, -except that it sets a new error handler err. +except that it sets a new message handler msgh. @@ -7130,8 +7240,8 @@

        6.3 – Modules

        To find a loader, -require is guided by the package.loaders array. -By changing this array, +require is guided by the package.loaders sequence. +By changing this sequence, we can change how require looks for a module. The following explanation is based on the default configuration for package.loaders. @@ -7151,7 +7261,10 @@

        6.3 – Modules

        Once a loader is found, -require calls the loader with a single argument, modname. +require calls the loader with two arguments: +modname and an extra value dependent on how it got the loader. +(If the loader came from a file, +this extra value is the file name.) If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. If the loader does not return a non-nil value and @@ -7164,7 +7277,7 @@

        6.3 – Modules

        If there is any error loading or running the module, or if it cannot find any loader for the module, -then require signals an error. +then require signals an error. @@ -7255,9 +7368,13 @@

        6.3 – Modules

        with the module name (the argument given to require) as its sole parameter. The function can return another function (the module loader) +plus an extra value that will be passed to that loader, or a string explaining why it did not find that module (or nil if it has nothing to say). -Lua initializes this table with four functions. + + +

        +Lua initializes this table with four searcher functions.

        @@ -7313,6 +7430,13 @@

        6.3 – Modules

        with each submodule keeping its original open function. +

        +All searchers except the first (preload) return as the extra value +the file name where the module was found, +as returned by package.searchpath. +The first searcher returns no extra value. + +

        @@ -7384,10 +7508,16 @@

        6.3 – Modules

        (see require). +

        +This variable is only a reference to the real table; +assignments to this variable do not change the +table used by require. + +

        -


        package.searchpath (name, path)

        +

        package.searchpath (name, path [, sep])

        @@ -7400,8 +7530,15 @@

        6.3 – Modules

        For each template, the function changes each interrogation mark in the template by a copy of name -wherein all dots were replaced by the system's directory separator, +wherein all occurrences of sep +(a dot, by default) +were replaced by the system's directory separator, and then tries to open the resulting file name. +If sep is the empty string, +the replacement is not done. + + +

        For instance, if the path is the string

        @@ -7485,9 +7622,8 @@ 

        6.4 – String Manipulation

        Returns a string containing a binary representation of the given function, -so that a later loadstring on this string returns -a copy of the function. -function must be a Lua function without upvalues. +so that a later load on this string returns +a copy of the function (but with new upvalues). @@ -7552,16 +7688,19 @@

        6.4 – String Manipulation

        -The options c, d, E, e, f, -g, G, i, o, u, X, and x all -expect a number as argument, -whereas q and s expect a string. - - -

        -This function does not accept string values -containing embedded zeros, -except as arguments to the q option. +Options +A and a (when available), +E, e, f, +G, and g all expect a number as argument. +Options c, d, +i, o, u, X, and x +expect an integer as argument; +the range of that integer may be limited by +the underlying C implementation. +Option q expects a string +and s expects a string without embedded zeros. +If the argument to option s is not a string, +it is converted to one following the same rules of tostring. @@ -7577,6 +7716,8 @@

        6.4 – String Manipulation

        As an example, the following loop +will iterate over all the words from string s, +printing one per line:

              s = "hello world from Lua"
        @@ -7584,8 +7725,6 @@ 

        6.4 – String Manipulation

        print(w) end

        -will iterate over all the words from string s, -printing one per line. The next example collects all pairs key=value from the given string into a table: @@ -7667,7 +7806,7 @@

        6.4 – String Manipulation

        --> x="home = /home/roberto, user = roberto" x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) - return loadstring(s)() + return load(s)() end) --> x="4+5 = 9" @@ -7715,9 +7854,11 @@

        6.4 – String Manipulation

        -


        string.rep (s, n)

        +

        string.rep (s, n [, sep])

        Returns a string that is the concatenation of n copies of -the string s. +the string s separated by the string sep. +The default value for sep is the empty string +(that is, no separator). @@ -7867,7 +8008,7 @@

        Pattern Item:

        a single character class followed by '-', which also matches 0 or more repetitions of characters in the class. Unlike '*', -these repetition items will always match the shortest possible sequence; +these repetition items will always match the shortest possible sequence;

      • @@ -7949,41 +8090,55 @@

        Captures:

        -

        6.5 – Table Manipulation

        +

        6.5 – Table Manipulation

        + +

        This library provides generic functions for table manipulation. It provides all its functions inside the table table.

        -Most functions in the table library assume that the table -represents an array or a list. -For these functions, when we talk about the "length" of a table -we mean the result of the length operator. +Currently, all functions in the table library assume that the table +represents a list. +In particular, they all ignore non-numeric keys +in tables given as arguments. +All functions in the table library, +except table.pack, +may apply the length operator on the list. +In that case, the list must be a proper sequence +or have a __len metamethod (see §3.4.6). + + +

        +For performance reasons, +all table accesses (get/set) performed by these functions are raw. + + +

        +


        table.concat (list [, sep [, i [, j]]])

        -


        table.concat (table [, sep [, i [, j]]])

        -Given an array where all elements are strings or numbers, -returns table[i]..sep..table[i+1] ··· sep..table[j]. +Given a list where all elements are strings or numbers, +returns list[i]..sep..list[i+1] ··· sep..list[j]. The default value for sep is the empty string, the default for i is 1, -and the default for j is the length of the table. +and the default for j is #list. If i is greater than j, returns the empty string.

        -


        table.insert (table, [pos,] value)

        +

        table.insert (list, [pos,] value)

        -Inserts element value at position pos in table, +Inserts element value at position pos in list, shifting up other elements to open space, if necessary. -The default value for pos is n+1, -where n is the length of the table (see §3.4.6), +The default value for pos is #list+1, so that a call table.insert(t,x) inserts x at the end -of table t. +of list t. @@ -7993,36 +8148,38 @@

        6.5 – Table Manipulation

        -Returns a new table with all parameters stored into -keys 1, 2, etc. +Returns a new table with all parameters stored into keys 1, 2, etc. and with a field "n" with the total number of parameters. +Note that the result may not be a sequence, +if any parameter is nil.

        -


        table.remove (table [, pos])

        +

        table.remove (list [, pos])

        -Removes from table the element at position pos, +Removes from list the element at position pos, shifting down other elements to close the space, if necessary. Returns the value of the removed element. -The default value for pos is n, -where n is the length of the table, +The default value for pos is #list, so that a call table.remove(t) removes the last element -of table t. +of list t.

        -


        table.sort (table [, comp])

        -Sorts table elements in a given order, in-place, -from table[1] to table[n], -where n is the length of the table. +

        table.sort (list [, comp])

        + + +

        +Sorts list elements in a given order, in-place, +from table[1] to table[#list]. If comp is given, -then it must be a function that receives two table elements +then it must be a function that receives two list elements and returns true when the first element must come before the second in the final order (so that not comp(a[i+1],a[i]) will be true after the sort). @@ -8040,16 +8197,16 @@

        6.5 – Table Manipulation


        table.unpack (list [, i [, j]])

        + + +

        Returns the elements from the given table. This function is equivalent to

              return list[i], list[i+1], ···, list[j]
         

        -except that the above code can be written only for a fixed number -of elements. -By default, i is 1 and j is the length of the list, -as defined by the length operator (see §3.4.6). +By default, i is 1 and j is #list. @@ -8386,7 +8543,7 @@

        6.6 – Mathematical Functions

        -

        6.7 – Bitwise operations

        +

        6.7 – Bitwise Operations

        This library provides bitwise operations. @@ -8468,7 +8625,7 @@

        6.7 – Bitwise operations

        -Returns a boolean signaling +Returns a boolean signaling whether the bitwise and of its operands is different from zero. @@ -8484,6 +8641,32 @@

        6.7 – Bitwise operations

        +

        +


        bit32.extract (n, field, width)

        + + +

        +Returns the unsigned number formed by the bits +field to field + width - 1 from n. +Bits are numbered from 0 (least significant) to 31 (most significant). +All accessed bits must be in the range [0, 31]. + + + + +

        +


        bit32.replace (n, v, field, width)

        + + +

        +Returns a copy of n with +the bits field to field + width - 1 +replaced by the value v. +See bit32.extract for details about field and width. + + + +


        bit32.lrotate (x, disp)

        @@ -8722,6 +8905,11 @@

        6.8 – Input and Output Facilities


        io.popen (prog [, mode])

        +

        +This function is system dependent and is not available +on all platforms. + +

        Starts program prog in a separated process and returns a file handle that you can use to read data from this program @@ -8730,11 +8918,6 @@

        6.8 – Input and Output Facilities

        (if mode is "w"). -

        -This function is system dependent and is not available -on all platforms. - -

        @@ -8794,8 +8977,9 @@

        6.8 – Input and Output Facilities

        -If file was created with io.popen, -a successful close returns the exit status of the process. +When closing a file handle created with io.popen, +file:close returns the same values +returned by os.execute. @@ -9020,6 +9204,8 @@

        6.9 – Operating System Facilities

        wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean). +This last field may be absent +if the information is not available.

        @@ -9056,9 +9242,28 @@

        6.9 – Operating System Facilities

        This function is equivalent to the C function system. It passes command to be executed by an operating system shell. -It returns a status code, which is system-dependent. -If command is absent, then it returns nonzero if a shell is available -and zero otherwise. +It returns true +if the command terminated successfully. +Otherwise, it returns nil plus a string and a number, +as follows: + +

          + +
        • "exit": +the command terminated normally; +the following number is the exit status of the command. +
        • + +
        • "signal": +the command was terminated by a signal; +the following number is the signal that terminated the command. +
        • + +
        + +

        +When called without a command, +os.execute returns a boolean that is true if a shell is available. @@ -9072,10 +9277,10 @@

        6.9 – Operating System Facilities

        If code is true, the returned status is EXIT_SUCCESS; if code is false, -the returned status is EXIT_FAILURE. +the returned status is EXIT_FAILURE; if code is a number, the returned status is this number. -The default value for code is the success code. +The default value for code is true.

        @@ -9101,8 +9306,8 @@

        6.9 – Operating System Facilities

        -Deletes the file or directory with the given name. -Directories must be empty to be removed. +Deletes the file (or empty directory, on POSIX systems) +with the given name. If this function fails, it returns nil, plus a string describing the error. @@ -9165,7 +9370,8 @@

        6.9 – Operating System Facilities

        The returned value is a number, whose meaning depends on your system. -In POSIX, Windows, and some other systems, this number counts the number +In POSIX, Windows, and some other systems, +this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to @@ -9186,7 +9392,7 @@

        6.9 – Operating System Facilities

        -On some systems (POSIX), +On POSIX systems, this function also creates a file with that name, to avoid security risks. (Someone else might create the file with wrong permissions @@ -9327,10 +9533,16 @@

        6.10 – The Debug Library

        This function returns the name and the value of the local variable with index local of the function at level f of the stack. -(The first parameter or local variable has index 1, and so on, -until the last active local variable.) -The function returns nil if there is no local -variable with the given index, +This function accesses not only explicit local variables, +but also parameters, temporaries, etc. + + +

        +The first parameter or local variable has index 1, and so on, +until the last active variable. +Negative indices refer to vararg parameters; +-1 is the first vararg parameter. +The function returns nil if there is no variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.) @@ -9338,7 +9550,7 @@

        6.10 – The Debug Library

        Variable names starting with '(' (open parentheses) represent internal variables -(loop control variables, temporaries, and C function locals). +(loop control variables, temporaries, varargs, and C function locals).

        @@ -9454,6 +9666,11 @@

        6.10 – The Debug Library

        Otherwise, it returns the name of the local variable. +

        +See debug.getlocal for more information about +variable indices and names. + +

        @@ -9463,6 +9680,7 @@

        6.10 – The Debug Library

        Sets the metatable for the given object to the given table (which can be nil). +Returns object. @@ -9482,14 +9700,14 @@

        6.10 – The Debug Library

        -


        debug.traceback ([thread,] [message] [, level])

        +

        debug.traceback ([thread,] [message [, level]])

        -If message is present but is not a string, +If message is present but is neither a string nor nil, this function returns message without further processing. Otherwise, -returns a string with a traceback of the call stack. +it returns a string with a traceback of the call stack. An optional message string is appended at the beginning of the traceback. An optional level number tells at which level @@ -9635,6 +9853,14 @@

        7 – Lua Standalone

        the interpreter does not report the error. +

        +When finishing normally, +the interpreter closes its main Lua state +(see lua_close). +The script can avoid this step by terminating +through os.exit. + +

        If the global variable _PROMPT contains a string, then its value is used as the prompt. @@ -9671,12 +9897,12 @@

        7 – Lua Standalone

        (Of course, the location of the Lua interpreter can be different in your machine. If lua is in your PATH, -then +then
              #!/usr/bin/env lua
         

        -is a more portable solution.) +is a more portable solution.) @@ -9696,21 +9922,38 @@

        8.1 – Changes in the Language

        • -Lua identifiers cannot use locale-dependent letters. +The concept of environment changed. +Only Lua functions have environments. +To set the environment of a Lua function, +use the variable _ENV or the function load. + + +

          +C functions do not have environments any more. +Use an upvalue with a shared table if you need to keep +shared state among several C functions. +(You may use luaL_setfuncs to open a C library +with all functions sharing a common upvalue.) + + +

          +To manipulate the "environment" of a userdata +(which is now called user value), +use the new functions +lua_getuservalue and lua_setuservalue.

        • -Doing a step in the garbage collector does not restart the collector -if it has been stopped. +Lua identifiers cannot use locale-dependent letters.
        • -Weak tables with weak keys now perform like ephemeron tables. +Doing a step or a full collection in the garbage collector +does not restart the collector if it has been stopped.
        • -Threads do not have individual environments. -All threads share a single fixed environment. +Weak tables with weak keys now perform like ephemeron tables.
        • @@ -9720,6 +9963,13 @@

          8.1 – Changes in the Language

          not be a corresponding return event.
        • +
        • +Equality between function values has changed. +Now, a function definition may not create a new value; +it may reuse some previous value if there is no +observable difference to the new function. +
        • +
        @@ -9735,9 +9985,8 @@

        8.2 – Changes in the Libraries

      • -Functions setfenv and getfenv are deprecated. -To set the environment of a Lua function, -use the variable _ENV or the new function loadin. +Functions setfenv and getfenv are deprecated, +because of the changes in environments.
      • @@ -9745,11 +9994,23 @@

        8.2 – Changes in the Libraries

        Use math.log with 10 as its second argument, instead.
      • +
      • +Function loadstring is deprecated. +Use load instead; it now accepts string arguments +and are exactly equivalent to loadstring. +
      • +
      • Function table.maxn is deprecated. Write it in Lua if you really need it.
      • +
      • +Function os.execute now returns true when command +terminates successfully and nil plus error information +otherwise. +
      • +
      • Function unpack was moved into the table library and therefore must be called as table.unpack. @@ -9763,7 +10024,7 @@

        8.2 – Changes in the Libraries

      • Lua does not have bytecode verification anymore. So, all functions that load code -(load, loadfile, loadstring) +(load and loadfile) are potentially insecure when loading untrusted binary data. (Actually, those functions were already insecure because of bugs in the verification algorithm.) @@ -9789,19 +10050,8 @@

        8.3 – Changes in the API

      • Pseudoindex LUA_ENVIRONINDEX and functions lua_getfenv/lua_setfenv -were removed. -C functions do not have environments any more. -Use an upvalue with a shared table if you need to keep -shared state among several C functions. -(You may use luaL_setfuncs to open a C library -with all functions sharing a common upvalue.) - - -

        -To manipulate the "environment" of a userdata -(which is not called "environment" anymore), -use the new functions -lua_getuservalue and lua_setuservalue. +were removed, +as C functions do not have environments any more.

      • @@ -9812,12 +10062,21 @@

        8.3 – Changes in the API

      • -Finalizers ("__gc" metamethods) for userdata are called in the +The osize argument to the allocation function +may not be zero when creating a new block, +that is, when ptr is NULL +(see lua_Alloc). +Use only the test ptr == NULL to check whether +the block is new. +
      • + +
      • +Finalizers (__gc metamethods) for userdata are called in the reverse order that they were marked, not that they were created (see §2.5.1). (Most userdata are marked immediately after they are created.) Moreover, -if the metatable does not have a "__gc" field when set, +if the metatable does not have a __gc field when set, the finalizer will not be called, even if it is set later.
      • @@ -9860,11 +10119,14 @@

        9 – The Complete Syntax of Lua

        chunk ::= block - block ::= {stat} [laststat [‘;’]] + block ::= {stat} [retstat] stat ::= ‘;’ | varlist ‘=’ explist | functioncall | + label | + break | + goto Name | do block end | while exp do block end | repeat block until exp | @@ -9875,7 +10137,9 @@

        9 – The Complete Syntax of Lua

        local function Name funcbody | local namelist [‘=’ explist] - laststat ::= return [explist] | break + retstat ::= return [explist] [‘;’] + + label ::= ‘@’ Name ‘:’ funcname ::= Name {‘.’ Name} [‘:’ Name] @@ -9885,7 +10149,7 @@

        9 – The Complete Syntax of Lua

        namelist ::= Name {‘,’ Name} - explist ::= {exp ‘,’} exp + explist ::= exp {‘,’ exp} exp ::= nil | false | true | Number | String | ‘...’ | function | prefixexp | tableconstructor | exp binop exp | unop exp @@ -9896,7 +10160,7 @@

        9 – The Complete Syntax of Lua

        args ::= ‘(’ [explist] ‘)’ | tableconstructor | String - function ::= function funcbody + functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end @@ -9929,10 +10193,10 @@

        9 – The Complete Syntax of Lua


        Last update: -Mon Nov 22 16:36:19 BRST 2010 +Mon Jun 13 14:56:14 BRT 2011 diff --git a/doc/readme.html b/doc/readme.html index 411d7605e8..a437ea17bb 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -27,12 +27,12 @@

        Lua -Welcome to Lua 5.2 (alpha) +Welcome to Lua 5.2 (beta)

        [!] -This is an alpha version of Lua 5.2. +This is a beta version of Lua 5.2. Some details may change in the final version.

        @@ -278,11 +278,13 @@

        Changes since Lua 5.1

        Main changes

        • yieldable pcall and metamethods -
        • new _ENV scheme +
        • new lexical scheme for globals
        • ephemeron tables
        • new library for bitwise operations
        • light C functions
        • emergency garbage collector +
        • goto statement +
        • finalizers for tables
        Here are the other changes introduced in Lua 5.2: @@ -291,29 +293,34 @@

        Language

      • no more fenv for threads or functions
      • tables honor the __len metamethod
      • hex and \* escapes in strings +
      • support for hexadecimal floats
      • order metamethods work for different types
      • no more verification of opcode consistency
      • hook event "tail return" replaced by "tail call"
      • empty statement +
      • break statement may appear in the middle of a block

      Libraries

        -
      • new metamethods __pairs and __ipairs
      • arguments for function called through xpcall
      • optional 'mode' argument to load (to control binary x text) -
      • new function loadin +
      • optional 'env' argument to load (environment for loaded chunk)
      • loadlib may load libraries with global names (RTLD_GLOBAL)
      • new function package.searchpath +
      • modules receive their paths when loaded
      • optional base in math.log +
      • optional separator in string.rep
      • file:write returns file
      • closing a pipe returns exit status
      • os.exit may close state +
      • new metamethods __pairs and __ipairs
      • new option 'isrunning' for collectgarbage and lua_gc
      • frontier patterns
      • \0 in patterns
      • new option *L for io.read
      • options for io.lines +
      • debug.getlocal can access function varargs

      C API

      @@ -321,7 +328,7 @@

      C API

    • main thread predefined in the registry
    • new constants LUA_OK and LUA_ERRGCMM
    • new lua_compare, lua_arith, and lua_len -
    • new lua_version and luaL_version +
    • new lua_version and luaL_checkversion
    • lua_pushstring and pushlstring return string
    • new luaL_testudata and luaL_setmetatable
    • new luaL_tolstring @@ -364,7 +371,7 @@

      License

      this.
      -Copyright © 1994–2010 Lua.org, PUC-Rio. +Copyright © 1994–2011 Lua.org, PUC-Rio.

      Permission is hereby granted, free of charge, to any person obtaining a copy @@ -391,10 +398,10 @@

      License


      Last update: -Sat Nov 20 19:23:14 BRST 2010 +Mon Jun 13 15:07:49 BRT 2011 diff --git a/src/Makefile b/src/Makefile index b8cee9c6e4..9d3d97c824 100644 --- a/src/Makefile +++ b/src/Makefile @@ -126,7 +126,7 @@ lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ - lstring.h ltable.h + lstring.h ltable.h lvm.h lcorolib.o: lcorolib.c lua.h luaconf.h lauxlib.h lualib.h lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h @@ -164,7 +164,7 @@ lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h + ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ lmem.h lstring.h lgc.h ltable.h diff --git a/src/lapi.c b/src/lapi.c index 074979c3c0..7761419e8a 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.140 2010/11/03 15:16:17 roberto Exp $ +** $Id: lapi.c,v 2.149 2011/06/13 14:13:06 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -59,9 +59,9 @@ static TValue *index2addr (lua_State *L, int idx) { if (ttislcf(ci->func)) /* light C function? */ return cast(TValue *, luaO_nilobject); /* it has no upvalues */ else { - Closure *func = clvalue(ci->func); - return (idx <= func->c.nupvalues) - ? &func->c.upvalue[idx-1] + CClosure *func = clCvalue(ci->func); + return (idx <= func->nupvalues) + ? &func->upvalue[idx-1] : cast(TValue *, luaO_nilobject); } } @@ -195,10 +195,8 @@ static void moveto (lua_State *L, TValue *fr, int idx) { TValue *to = index2addr(L, idx); api_checkvalidindex(L, to); setobj(L, to, fr); - if (idx < LUA_REGISTRYINDEX) { /* function upvalue? */ - lua_assert(ttisclosure(L->ci->func)); - luaC_barrier(L, clvalue(L->ci->func), fr); - } + if (idx < LUA_REGISTRYINDEX) /* function upvalue? */ + luaC_barrier(L, clCvalue(L->ci->func), fr); /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ } @@ -251,7 +249,7 @@ LUA_API const char *lua_typename (lua_State *L, int t) { LUA_API int lua_iscfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (ttislcf(o) || (ttisclosure(o) && clvalue(o)->c.isC)); + return (ttislcf(o) || (ttisCclosure(o))); } @@ -278,20 +276,28 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = index2addr(L, index1); StkId o2 = index2addr(L, index2); return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaO_rawequalObj(o1, o2); + : luaV_rawequalobj(o1, o2); } LUA_API void lua_arith (lua_State *L, int op) { + StkId o1; /* 1st operand */ + StkId o2; /* 2nd operand */ lua_lock(L); - api_checknelems(L, 2); - if (ttisnumber(L->top - 2) && ttisnumber(L->top - 1)) { - changenvalue(L->top - 2, - luaO_arith(op, nvalue(L->top - 2), nvalue(L->top - 1))); + if (op != LUA_OPUNM) /* all other operations expect two operands */ + api_checknelems(L, 2); + else { /* for unary minus, add fake 2nd operand */ + api_checknelems(L, 1); + setobjs2s(L, L->top, L->top - 1); + L->top++; + } + o1 = L->top - 2; + o2 = L->top - 1; + if (ttisnumber(o1) && ttisnumber(o2)) { + changenvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); } else - luaV_arith(L, L->top - 2, L->top - 2, L->top - 1, - cast(TMS, op - LUA_OPADD + TM_ADD)); + luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); L->top--; lua_unlock(L); } @@ -390,7 +396,7 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { LUA_API size_t lua_rawlen (lua_State *L, int idx) { StkId o = index2addr(L, idx); - switch (ttype(o)) { + switch (ttypenv(o)) { case LUA_TSTRING: return tsvalue(o)->len; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); @@ -402,15 +408,15 @@ LUA_API size_t lua_rawlen (lua_State *L, int idx) { LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); if (ttislcf(o)) return fvalue(o); - else if (ttisclosure(o) && clvalue(o)->c.isC) - return clvalue(o)->c.f; + else if (ttisCclosure(o)) + return clCvalue(o)->f; else return NULL; /* not a C function */ } LUA_API void *lua_touserdata (lua_State *L, int idx) { StkId o = index2addr(L, idx); - switch (ttype(o)) { + switch (ttypenv(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; @@ -428,7 +434,8 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) { StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); - case LUA_TFUNCTION: return clvalue(o); + case LUA_TLCL: return clLvalue(o); + case LUA_TCCL: return clCvalue(o); case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: @@ -456,6 +463,8 @@ LUA_API void lua_pushnil (lua_State *L) { LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { lua_lock(L); setnvalue(L->top, n); + luai_checknum(L, L->top, + luaG_runerror(L, "C API - attempt to push a signaling NaN")); api_incr_top(L); lua_unlock(L); } @@ -548,7 +557,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { L->top -= n; while (n--) setobj2n(L, &cl->c.upvalue[n], L->top + n); - setclvalue(L, L->top, cl); + setclCvalue(L, L->top, cl); } api_incr_top(L); lua_unlock(L); @@ -648,7 +657,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { int res; lua_lock(L); obj = index2addr(L, objindex); - switch (ttype(obj)) { + switch (ttypenv(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; @@ -755,18 +764,19 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { api_check(L, ttistable(L->top - 1), "table expected"); mt = hvalue(L->top - 1); } - switch (ttype(obj)) { + switch (ttypenv(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) luaC_objbarrierback(L, gcvalue(obj), mt); + luaC_checkfinalizer(L, gcvalue(obj), mt); break; } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; if (mt) { luaC_objbarrier(L, rawuvalue(obj), mt); - luaC_checkfinalizer(L, rawuvalue(obj)); + luaC_checkfinalizer(L, gcvalue(obj), mt); } break; } @@ -912,15 +922,14 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname); if (status == LUA_OK) { /* no errors? */ - Closure *f = clvalue(L->top - 1); /* get newly created function */ - lua_assert(!f->c.isC); - if (f->l.nupvalues == 1) { /* does it have one upvalue? */ + LClosure *f = clLvalue(L->top - 1); /* get newly created function */ + if (f->nupvalues == 1) { /* does it have one upvalue? */ /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ - setobj(L, f->l.upvals[0]->v, gt); - luaC_barrier(L, f->l.upvals[0], gt); + setobj(L, f->upvals[0]->v, gt); + luaC_barrier(L, f->upvals[0], gt); } } lua_unlock(L); @@ -959,11 +968,12 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g = G(L); switch (what) { case LUA_GCSTOP: { - stopgc(g); + g->gcrunning = 0; break; } case LUA_GCRESTART: { - g->GCdebt = 0; + luaE_setdebt(g, 0); + g->gcrunning = 1; break; } case LUA_GCCOLLECT: { @@ -972,30 +982,27 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ - res = cast_int(g->totalbytes >> 10); + res = cast_int(gettotalbytes(g) >> 10); break; } case LUA_GCCOUNTB: { - res = cast_int(g->totalbytes & 0x3ff); + res = cast_int(gettotalbytes(g) & 0x3ff); break; } case LUA_GCSTEP: { - int stopped = gcstopped(g); if (g->gckind == KGC_GEN) { /* generational mode? */ res = (g->lastmajormem == 0); /* 1 if will do major collection */ - luaC_step(L); /* do a single step */ + luaC_forcestep(L); /* do a single step */ } else { while (data-- >= 0) { - luaC_step(L); + luaC_forcestep(L); if (g->gcstate == GCSpause) { /* end of cycle? */ res = 1; /* signal it */ break; } } } - if (stopped) /* collector was stopped? */ - stopgc(g); /* keep it that way */ break; } case LUA_GCSETPAUSE: { @@ -1014,7 +1021,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCISRUNNING: { - res = !gcstopped(g); + res = g->gcrunning; break; } case LUA_GCGEN: { /* change collector to generational mode */ @@ -1124,25 +1131,27 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { static const char *aux_upvalue (StkId fi, int n, TValue **val, GCObject **owner) { - Closure *f; - if (!ttisclosure(fi)) return NULL; - f = clvalue(fi); - if (f->c.isC) { - if (!(1 <= n && n <= f->c.nupvalues)) return NULL; - *val = &f->c.upvalue[n-1]; - if (owner) *owner = obj2gco(f); - return ""; - } - else { - const char *name; - Proto *p = f->l.p; - if (!(1 <= n && n <= p->sizeupvalues)) return NULL; - *val = f->l.upvals[n-1]->v; - if (owner) *owner = obj2gco(f->l.upvals[n - 1]); - name = getstr(p->upvalues[n-1].name); - if (name == NULL) /* no debug information? */ - name = ""; - return name; + switch (ttype(fi)) { + case LUA_TCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + if (!(1 <= n && n <= f->nupvalues)) return NULL; + *val = &f->upvalue[n-1]; + if (owner) *owner = obj2gco(f); + return ""; + } + case LUA_TLCL: { /* Lua closure */ + LClosure *f = clLvalue(fi); + const char *name; + Proto *p = f->p; + if (!(1 <= n && n <= p->sizeupvalues)) return NULL; + *val = f->upvals[n-1]->v; + if (owner) *owner = obj2gco(f->upvals[n - 1]); + name = getstr(p->upvalues[n-1].name); + if (name == NULL) /* no debug information? */ + name = ""; + return name; + } + default: return NULL; /* not a closure */ } } @@ -1180,34 +1189,39 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { } -static UpVal **getupvalref (lua_State *L, int fidx, int n, Closure **pf) { - Closure *f; +static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { + LClosure *f; StkId fi = index2addr(L, fidx); - api_check(L, ttisclosure(fi), "Lua function expected"); - f = clvalue(fi); - api_check(L, !f->c.isC, "Lua function expected"); - api_check(L, (1 <= n && n <= f->l.p->sizeupvalues), "invalid upvalue index"); + api_check(L, ttisLclosure(fi), "Lua function expected"); + f = clLvalue(fi); + api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); if (pf) *pf = f; - return &f->l.upvals[n - 1]; /* get its upvalue pointer */ + return &f->upvals[n - 1]; /* get its upvalue pointer */ } LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { - Closure *f; StkId fi = index2addr(L, fidx); - api_check(L, ttisclosure(fi), "function expected"); - f = clvalue(fi); - if (f->c.isC) { - api_check(L, 1 <= n && n <= f->c.nupvalues, "invalid upvalue index"); - return &f->c.upvalue[n - 1]; + switch (ttype(fi)) { + case LUA_TLCL: { /* lua closure */ + return *getupvalref(L, fidx, n, NULL); + } + case LUA_TCCL: { /* C closure */ + CClosure *f = clCvalue(fi); + api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); + return &f->upvalue[n - 1]; + } + default: { + api_check(L, 0, "closure expected"); + return NULL; + } } - else return *getupvalref(L, fidx, n, NULL); } LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, int fidx2, int n2) { - Closure *f1; + LClosure *f1; UpVal **up1 = getupvalref(L, fidx1, n1, &f1); UpVal **up2 = getupvalref(L, fidx2, n2, NULL); *up1 = *up2; diff --git a/src/lauxlib.c b/src/lauxlib.c index cdd5a53f7e..fc08023022 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.227 2010/11/10 18:05:36 roberto Exp $ +** $Id: lauxlib.c,v 1.232 2011/05/03 16:01:57 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -203,6 +203,64 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { return lua_error(L); } + +LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { + int en = errno; /* calls to Lua API may change this value */ + if (stat) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (fname) + lua_pushfstring(L, "%s: %s", fname, strerror(en)); + else + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + + +#if !defined(inspectstat) /* { */ + +#if defined(LUA_USE_POSIX) + +#include + +/* +** use appropriate macros to interpret 'pclose' return status +*/ +#define inspectstat(stat,what) \ + if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ + else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } + +#else + +#define inspectstat(stat,what) /* no op */ + +#endif + +#endif /* } */ + + +LUALIB_API int luaL_execresult (lua_State *L, int stat) { + const char *what = "exit"; /* type of termination */ + if (stat == -1) /* error? */ + return luaL_fileresult(L, 0, NULL); + else { + inspectstat(stat, what); /* interpret result */ + if (*what == 'e' && stat == 0) /* successful termination? */ + return luaL_fileresult(L, 1, NULL); + else { /* return nil,what,code */ + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; + } + } +} + /* }====================================================== */ @@ -384,8 +442,10 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { newsize = B->n + sz; if (newsize < B->n || newsize - B->n < sz) luaL_error(L, "buffer too large"); - newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */ - memcpy(newbuff, B->b, B->n); /* move content to new buffer */ + /* create larger buffer */ + newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char)); + /* move content to new buffer */ + memcpy(newbuff, B->b, B->n * sizeof(char)); if (buffonstack(B)) lua_remove(L, -2); /* remove old buffer */ B->b = newbuff; @@ -397,7 +457,7 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { char *b = luaL_prepbuffsize(B, l); - memcpy(b, s, l); + memcpy(b, s, l * sizeof(char)); luaL_addsize(B, l); } @@ -700,8 +760,8 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { */ #if defined(LUA_COMPAT_MODULE) -static const char *luaL_findtablex (lua_State *L, int idx, - const char *fname, int szhint) { +static const char *luaL_findtable (lua_State *L, int idx, + const char *fname, int szhint) { const char *e; if (idx) lua_pushvalue(L, idx); do { @@ -745,13 +805,13 @@ static int libsize (const luaL_Reg *l) { */ LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, int sizehint) { - luaL_findtablex(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ lua_getfield(L, -1, modname); /* get _LOADED[modname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ lua_pushglobaltable(L); - if (luaL_findtablex(L, 0, modname, sizehint) != NULL) + if (luaL_findtable(L, 0, modname, sizehint) != NULL) luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */ @@ -767,7 +827,10 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ } - luaL_setfuncs(L, l, nup); + if (l) + luaL_setfuncs(L, l, nup); + else + lua_pop(L, nup); /* remove upvalues */ } #endif @@ -780,7 +843,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, */ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup, "too many upvalues"); - for (; l && l->name; l++) { /* fill the table with given functions */ + for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -nup); @@ -795,15 +858,16 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { ** ensure that stack[idx][fname] has a table and push that table ** into the stack */ -LUALIB_API void luaL_findtable (lua_State *L, int idx, const char *fname) { +LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { lua_getfield(L, idx, fname); - if (lua_istable(L, -1)) return; /* table already there */ + if (lua_istable(L, -1)) return 1; /* table already there */ else { idx = lua_absindex(L, idx); lua_pop(L, 1); /* remove previous result */ lua_newtable(L); lua_pushvalue(L, -1); /* copy to be left at top */ lua_setfield(L, idx, fname); /* assign new table to field */ + return 0; /* false, because did not find table there */ } } @@ -819,7 +883,7 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_pushcfunction(L, openf); lua_pushstring(L, modname); /* argument to open function */ lua_call(L, 1, 1); /* open module */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_pushvalue(L, -2); /* make copy of module (call result) */ lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ lua_pop(L, 1); /* remove _LOADED table */ diff --git a/src/lauxlib.h b/src/lauxlib.h index 39506456e1..8b85ebe539 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.113 2010/11/16 19:20:01 roberto Exp $ +** $Id: lauxlib.h,v 1.116 2011/04/08 19:17:36 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -62,6 +62,9 @@ LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, const char *const lst[]); +LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); +LUALIB_API int (luaL_execresult) (lua_State *L, int stat); + /* pre-defined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) @@ -83,7 +86,7 @@ LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); -LUALIB_API void (luaL_findtable) (lua_State *L, int idx, const char *fname); +LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, const char *msg, int level); diff --git a/src/lbaselib.c b/src/lbaselib.c index 1553c1d056..82c8c1fe10 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.251 2010/10/28 15:36:30 roberto Exp $ +** $Id: lbaselib.c,v 1.261 2011/05/26 16:09:40 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -32,44 +32,54 @@ static int luaB_print (lua_State *L) { lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) - return luaL_error(L, LUA_QL("tostring") " must return a string to " - LUA_QL("print")); + return luaL_error(L, + LUA_QL("tostring") " must return a string to " LUA_QL("print")); if (i>1) luai_writestring("\t", 1); luai_writestring(s, l); lua_pop(L, 1); /* pop result */ } - luai_writestring("\n", 1); + luai_writeline(); return 0; } +#define SPACECHARS " \f\n\r\t\v" + static int luaB_tonumber (lua_State *L) { int base = luaL_optint(L, 2, 10); + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); if (base == 10) { /* standard conversion */ luaL_checkany(L, 1); if (lua_isnumber(L, 1)) { lua_pushnumber(L, lua_tonumber(L, 1)); return 1; - } + } /* else not a number */ } else { - const char *s1 = luaL_checkstring(L, 1); - char *s2; - unsigned long n; + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + const char *e = s + l; /* end point for 's' */ int neg = 0; - luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - while (isspace((unsigned char)(*s1))) s1++; /* skip initial spaces */ - if (*s1 == '-') { s1++; neg = 1; } - n = strtoul(s1, &s2, base); - if (s1 != s2) { /* at least one valid digit? */ - while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ - if (*s2 == '\0') { /* no invalid trailing characters? */ - lua_pushnumber(L, (neg) ? -(lua_Number)n : (lua_Number)n); + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') { s++; neg = 1; } /* handle signal */ + else if (*s == '+') s++; + if (isalnum((unsigned char)*s)) { + lua_Number n = 0; + do { + int digit = (isdigit((unsigned char)*s)) ? *s - '0' + : toupper((unsigned char)*s) - 'A' + 10; + if (digit >= base) break; /* invalid numeral; force a fail */ + n = n * (lua_Number)base + (lua_Number)digit; + s++; + } while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + if (s == e) { /* no invalid trailing characters? */ + lua_pushnumber(L, (neg) ? -n : n); return 1; - } - } + } /* else not a number */ + } /* else not a number */ } - lua_pushnil(L); /* else not a number */ + lua_pushnil(L); /* not a number */ return 1; } @@ -110,12 +120,10 @@ static int luaB_setmetatable (lua_State *L) { } -static int luaB_getfenv (lua_State *L) { - return luaL_error(L, "getfenv/setfenv deprecated"); +static int luaB_deprecated (lua_State *L) { + return luaL_error(L, "deprecated function"); } -#define luaB_setfenv luaB_getfenv - static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); @@ -125,6 +133,15 @@ static int luaB_rawequal (lua_State *L) { } +static int luaB_rawlen (lua_State *L) { + int t = lua_type(L, 1); + luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, + "table or string expected"); + lua_pushinteger(L, lua_rawlen(L, 1)); + return 1; +} + + static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); @@ -251,6 +268,11 @@ static int luaB_loadfile (lua_State *L) { ** ======================================================= */ +/* +** check whether a chunk (prefix in 's') satisfies given 'mode' +** ('t' for text, 'b' for binary). Returns error message (also +** pushed on the stack) in case of errors. +*/ static const char *checkrights (lua_State *L, const char *mode, const char *s) { if (strchr(mode, 'b') == NULL && *s == LUA_SIGNATURE[0]) return lua_pushstring(L, "attempt to load a binary chunk"); @@ -261,10 +283,11 @@ static const char *checkrights (lua_State *L, const char *mode, const char *s) { /* -** reserves a slot, above all arguments, to hold a copy of the returned -** string to avoid it being collected while parsed +** reserved slot, above all arguments, to hold a copy of the returned +** string to avoid it being collected while parsed. 'load' has four +** optional arguments (chunk, source name, mode, and environment). */ -#define RESERVEDSLOT 4 +#define RESERVEDSLOT 5 /* @@ -273,25 +296,20 @@ static const char *checkrights (lua_State *L, const char *mode, const char *s) { ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ -typedef struct { /* reader state */ - int f; /* position of reader function on stack */ - const char *mode; /* allowed modes (binary/text) */ -} Readstat; - static const char *generic_reader (lua_State *L, void *ud, size_t *size) { const char *s; - Readstat *stat = (Readstat *)ud; + const char **mode = (const char **)ud; luaL_checkstack(L, 2, "too many nested functions"); - lua_pushvalue(L, stat->f); /* get function */ + lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { *size = 0; return NULL; } else if ((s = lua_tostring(L, -1)) != NULL) { - if (stat->mode != NULL) { /* first time? */ - s = checkrights(L, stat->mode, s); /* check mode */ - stat->mode = NULL; /* to avoid further checks */ + if (*mode != NULL) { /* first time? */ + s = checkrights(L, *mode, s); /* check mode */ + *mode = NULL; /* to avoid further checks */ if (s) luaL_error(L, s); } lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ @@ -304,52 +322,38 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { } -static int luaB_load_aux (lua_State *L, int farg) { +static int luaB_load (lua_State *L) { int status; - Readstat stat; size_t l; - const char *s = lua_tolstring(L, farg, &l); - stat.mode = luaL_optstring(L, farg + 2, "bt"); + int top = lua_gettop(L); + const char *s = lua_tolstring(L, 1, &l); + const char *mode = luaL_optstring(L, 3, "bt"); if (s != NULL) { /* loading a string? */ - const char *chunkname = luaL_optstring(L, farg + 1, s); - status = (checkrights(L, stat.mode, s) != NULL) + const char *chunkname = luaL_optstring(L, 2, s); + status = (checkrights(L, mode, s) != NULL) || luaL_loadbuffer(L, s, l, chunkname); } else { /* loading from a reader function */ - const char *chunkname = luaL_optstring(L, farg + 1, "=(load)"); - luaL_checktype(L, farg, LUA_TFUNCTION); - stat.f = farg; + const char *chunkname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); lua_settop(L, RESERVEDSLOT); /* create reserved slot */ - status = lua_load(L, generic_reader, &stat, chunkname); + status = lua_load(L, generic_reader, &mode, chunkname); + } + if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */ + lua_pushvalue(L, 4); /* environment for loaded function */ + lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */ } return load_aux(L, status); } -static int luaB_load (lua_State *L) { - return luaB_load_aux(L, 1); -} - - -static int luaB_loadin (lua_State *L) { - int n; - luaL_checkany(L, 1); - n = luaB_load_aux(L, 2); - if (n == 1) { /* success? */ - lua_pushvalue(L, 1); /* environment for loaded function */ - if (lua_setupvalue(L, -2, 1) == NULL) - luaL_error(L, "loaded chunk does not have an upvalue"); - } - return n; -} +#if defined(LUA_COMPAT_LOADSTRING) +#define luaB_loadstring luaB_load +#else +#define luaB_loadstring luaB_deprecated +#endif -static int luaB_loadstring (lua_State *L) { - lua_settop(L, 2); - lua_pushliteral(L, "tb"); - return luaB_load(L); /* dostring(s, n) == load(s, n, "tb") */ - -} /* }====================================================== */ @@ -391,7 +395,7 @@ static int luaB_select (lua_State *L) { static int pcallcont (lua_State *L) { - int errfunc; /* call has an error function in bottom of the stack */ + int errfunc = 0; /* =0 to avoid warnings */ int status = lua_getctx(L, &errfunc); lua_assert(status != LUA_OK); lua_pushboolean(L, (status == LUA_YIELD)); /* first result (status) */ @@ -436,55 +440,27 @@ static int luaB_tostring (lua_State *L) { } -static int luaB_newproxy (lua_State *L) { - lua_settop(L, 1); - lua_newuserdata(L, 0); /* create proxy */ - if (lua_toboolean(L, 1) == 0) - return 1; /* no metatable */ - else if (lua_isboolean(L, 1)) { - lua_createtable(L, 0, 1); /* create a new metatable `m' ... */ - lua_pushboolean(L, 1); - lua_setfield(L, -2, "__gc"); /* ... m.__gc = false (HACK!!)... */ - lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ - lua_pushboolean(L, 1); - lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ - } - else { - int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ - if (lua_getmetatable(L, 1)) { - lua_rawget(L, lua_upvalueindex(1)); - validproxy = lua_toboolean(L, -1); - lua_pop(L, 1); /* remove value */ - } - luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); - lua_getmetatable(L, 1); /* metatable is valid; get it */ - } - lua_setmetatable(L, 2); - return 1; -} - - static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, - {"getfenv", luaB_getfenv}, + {"getfenv", luaB_deprecated}, {"getmetatable", luaB_getmetatable}, {"ipairs", luaB_ipairs}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, - {"loadin", luaB_loadin}, {"loadstring", luaB_loadstring}, {"next", luaB_next}, {"pairs", luaB_pairs}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"rawequal", luaB_rawequal}, + {"rawlen", luaB_rawlen}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, {"select", luaB_select}, - {"setfenv", luaB_setfenv}, + {"setfenv", luaB_deprecated}, {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, @@ -503,14 +479,6 @@ LUAMOD_API int luaopen_base (lua_State *L) { luaL_setfuncs(L, base_funcs, 0); lua_pushliteral(L, LUA_VERSION); lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ - /* `newproxy' needs a weaktable as upvalue */ - lua_createtable(L, 0, 1); /* new table `w' */ - lua_pushvalue(L, -1); /* `w' will be its own metatable */ - lua_setmetatable(L, -2); - lua_pushliteral(L, "kv"); - lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ - lua_pushcclosure(L, luaB_newproxy, 1); - lua_setfield(L, -2, "newproxy"); /* set global `newproxy' */ return 1; } diff --git a/src/lbitlib.c b/src/lbitlib.c index 35879000f8..dcc0ac16ec 100644 --- a/src/lbitlib.c +++ b/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.13 2010/11/22 18:06:33 roberto Exp $ +** $Id: lbitlib.c,v 1.15 2010/12/17 13:26:38 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -14,25 +14,30 @@ /* number of bits to consider in a number */ -#define NBITS 32 +#if !defined(LUA_NBITS) +#define LUA_NBITS 32 +#endif -#define ALLONES (~(((~(lua_Unsigned)0) << (NBITS - 1)) << 1)) -/* mask to trim extra bits */ +#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + +/* macro to trim extra bits */ #define trim(x) ((x) & ALLONES) -typedef lua_Unsigned b_uint; +/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ +#define mask(n) (~((ALLONES << 1) << ((n) - 1))) + +typedef lua_Unsigned b_uint; -#define getuintarg(L,arg) luaL_checkunsigned(L,arg) static b_uint andaux (lua_State *L) { int i, n = lua_gettop(L); b_uint r = ~(b_uint)0; for (i = 1; i <= n; i++) - r &= getuintarg(L, i); + r &= luaL_checkunsigned(L, i); return trim(r); } @@ -55,7 +60,7 @@ static int b_or (lua_State *L) { int i, n = lua_gettop(L); b_uint r = 0; for (i = 1; i <= n; i++) - r |= getuintarg(L, i); + r |= luaL_checkunsigned(L, i); lua_pushunsigned(L, trim(r)); return 1; } @@ -65,14 +70,14 @@ static int b_xor (lua_State *L) { int i, n = lua_gettop(L); b_uint r = 0; for (i = 1; i <= n; i++) - r ^= getuintarg(L, i); + r ^= luaL_checkunsigned(L, i); lua_pushunsigned(L, trim(r)); return 1; } static int b_not (lua_State *L) { - b_uint r = ~getuintarg(L, 1); + b_uint r = ~luaL_checkunsigned(L, 1); lua_pushunsigned(L, trim(r)); return 1; } @@ -82,11 +87,11 @@ static int b_shift (lua_State *L, b_uint r, int i) { if (i < 0) { /* shift right? */ i = -i; r = trim(r); - if (i >= NBITS) r = 0; + if (i >= LUA_NBITS) r = 0; else r >>= i; } else { /* shift left */ - if (i >= NBITS) r = 0; + if (i >= LUA_NBITS) r = 0; else r <<= i; r = trim(r); } @@ -96,22 +101,22 @@ static int b_shift (lua_State *L, b_uint r, int i) { static int b_lshift (lua_State *L) { - return b_shift(L, getuintarg(L, 1), luaL_checkint(L, 2)); + return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2)); } static int b_rshift (lua_State *L) { - return b_shift(L, getuintarg(L, 1), -luaL_checkint(L, 2)); + return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2)); } static int b_arshift (lua_State *L) { - b_uint r = getuintarg(L, 1); + b_uint r = luaL_checkunsigned(L, 1); int i = luaL_checkint(L, 2); - if (i < 0 || !(r & ((b_uint)1 << (NBITS - 1)))) + if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ - if (i >= NBITS) r = ALLONES; + if (i >= LUA_NBITS) r = ALLONES; else r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */ lua_pushunsigned(L, r); @@ -121,10 +126,10 @@ static int b_arshift (lua_State *L) { static int b_rot (lua_State *L, int i) { - b_uint r = getuintarg(L, 1); - i &= (NBITS - 1); /* i = i % NBITS */ + b_uint r = luaL_checkunsigned(L, 1); + i &= (LUA_NBITS - 1); /* i = i % NBITS */ r = trim(r); - r = (r << i) | (r >> (NBITS - i)); + r = (r << i) | (r >> (LUA_NBITS - i)); lua_pushunsigned(L, trim(r)); return 1; } @@ -140,17 +145,58 @@ static int b_rrot (lua_State *L) { } +/* +** get field and width arguments for field-manipulation functions, +** checking whether they are valid +*/ +static int fieldargs (lua_State *L, int farg, int *width) { + int f = luaL_checkint(L, farg); + int w = luaL_optint(L, farg + 1, 1); + luaL_argcheck(L, 0 <= f, farg, "field cannot be netative"); + luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); + if (f + w > LUA_NBITS) + luaL_error(L, "trying to access non-existent bits"); + *width = w; + return f; +} + + +static int b_extract (lua_State *L) { + int w; + b_uint r = luaL_checkunsigned(L, 1); + int f = fieldargs(L, 2, &w); + r = (r >> f) & mask(w); + lua_pushunsigned(L, r); + return 1; +} + + +static int b_replace (lua_State *L) { + int w; + b_uint r = luaL_checkunsigned(L, 1); + b_uint v = luaL_checkunsigned(L, 2); + int f = fieldargs(L, 3, &w); + int m = mask(w); + v &= m; /* erase bits outside given width */ + r = (r & ~(m << f)) | (v << f); + lua_pushunsigned(L, r); + return 1; +} + + static const luaL_Reg bitlib[] = { {"arshift", b_arshift}, {"band", b_and}, {"bnot", b_not}, {"bor", b_or}, {"bxor", b_xor}, + {"btest", b_test}, + {"extract", b_extract}, {"lrotate", b_lrot}, {"lshift", b_lshift}, + {"replace", b_replace}, {"rrotate", b_rrot}, {"rshift", b_rshift}, - {"btest", b_test}, {NULL, NULL} }; diff --git a/src/lcode.c b/src/lcode.c index ea3217fae5..00966a1269 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.49 2010/07/07 16:27:29 roberto Exp $ +** $Id: lcode.c,v 2.56 2011/05/31 18:27:56 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -23,6 +23,7 @@ #include "lparser.h" #include "lstring.h" #include "ltable.h" +#include "lvm.h" #define hasjumps(e) ((e)->t != (e)->f) @@ -35,19 +36,23 @@ static int isnumeral(expdesc *e) { void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; + int l = from + n - 1; /* last register to set nil */ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ previous = &fs->f->code[fs->pc-1]; if (GET_OPCODE(*previous) == OP_LOADNIL) { int pfrom = GETARG_A(*previous); - int pto = GETARG_B(*previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(*previous, from+n-1); + int pl = pfrom + GETARG_B(*previous); + if ((pfrom <= from && from <= pl + 1) || + (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ + if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) l = pl; /* l = max(l, pl) */ + SETARG_A(*previous, from); + SETARG_B(*previous, l - from); return; } - } + } /* else go through */ } - luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ + luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ } @@ -171,6 +176,19 @@ void luaK_patchlist (FuncState *fs, int list, int target) { } +LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) { + level++; /* argument is +1 to reserve 0 as non-op */ + while (list != NO_JUMP) { + int next = getjump(fs, list); + lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && + (GETARG_A(fs->f->code[list]) == 0 || + GETARG_A(fs->f->code[list]) >= level)); + SETARG_A(fs->f->code[list], level); + list = next; + } +} + + void luaK_patchtohere (FuncState *fs, int list) { luaK_getlabel(fs); luaK_concat(fs, &fs->jpc, list); @@ -229,11 +247,11 @@ static int codeextraarg (FuncState *fs, int a) { } -int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k) { - if (k < MAXARG_Bx) - return luaK_codeABx(fs, o, reg, k + 1); +int luaK_codek (FuncState *fs, int reg, int k) { + if (k <= MAXARG_Bx) + return luaK_codeABx(fs, OP_LOADK, reg, k); else { - int p = luaK_codeABx(fs, o, reg, 0); + int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); codeextraarg(fs, k); return p; } @@ -278,7 +296,7 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { if (ttisnumber(idx)) { lua_Number n = nvalue(idx); lua_number2int(k, n); - if (luaO_rawequalObj(&f->k[k], v)) + if (luaV_rawequalobj(&f->k[k], v)) return k; /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); go through and create a new entry for this value */ @@ -564,15 +582,15 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { - int func; + int ereg; luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' was placed */ freeexp(fs, e); - func = fs->freereg; - luaK_codeABC(fs, OP_SELF, func, e->u.info, luaK_exp2RK(fs, key)); - freeexp(fs, key); - luaK_reserveregs(fs, 2); - e->u.info = func; + e->u.info = fs->freereg; /* base register for op_self */ e->k = VNONRELOC; + luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ + luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); + freeexp(fs, key); } @@ -603,21 +621,14 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { - case VK: case VKNUM: case VTRUE: { - pc = NO_JUMP; /* always true; do nothing */ - break; - } case VJMP: { invertjump(fs, e); pc = e->u.info; break; } - case VFALSE: { - if (!hasjumps(e)) { - pc = luaK_jump(fs); /* always jump */ - break; - } - /* else go through */ + case VK: case VKNUM: case VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; } default: { pc = jumponcond(fs, e, 0); @@ -634,20 +645,13 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { - case VNIL: case VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ - break; - } case VJMP: { pc = e->u.info; break; } - case VTRUE: { - if (!hasjumps(e)) { - pc = luaK_jump(fs); /* always jump */ - break; - } - /* else go through */ + case VNIL: case VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; } default: { pc = jumponcond(fs, e, 1); diff --git a/src/lcode.h b/src/lcode.h index 86d2138996..26a5daafcc 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.55 2010/07/02 20:42:40 roberto Exp $ +** $Id: lcode.h,v 1.57 2011/04/07 18:14:12 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -44,11 +44,9 @@ typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) -#define luaK_codek(fs,reg,k) luaK_codeABxX(fs, OP_LOADK, reg, k) - LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); -LUAI_FUNC int luaK_codeABxX (FuncState *fs, OpCode o, int reg, int k); +LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); @@ -71,6 +69,7 @@ LUAI_FUNC int luaK_jump (FuncState *fs); LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); +LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); diff --git a/src/ldblib.c b/src/ldblib.c index d631dcba69..78f6cc0613 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.126 2010/11/16 18:01:28 roberto Exp $ +** $Id: ldblib.c,v 1.130 2011/04/08 19:17:36 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -18,6 +18,9 @@ #include "lualib.h" +#define HOOKKEY "_HKEY" + + static int db_getregistry (lua_State *L) { lua_pushvalue(L, LUA_REGISTRYINDEX); @@ -39,8 +42,8 @@ static int db_setmetatable (lua_State *L) { luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); lua_settop(L, 2); - lua_pushboolean(L, lua_setmetatable(L, 1)); - return 1; + lua_setmetatable(L, 1); + return 1; /* return 1st argument */ } @@ -250,14 +253,13 @@ static int db_upvaluejoin (lua_State *L) { } -static const char KEY_HOOK = 'h'; +#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY); static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail call"}; - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); + gethooktable(L); lua_pushlightuserdata(L, L); lua_rawget(L, -2); if (lua_isfunction(L, -1)) { @@ -291,19 +293,6 @@ static char *unmakemask (int mask, char *smask) { } -static void gethooktable (lua_State *L) { - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - lua_createtable(L, 0, 1); - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); - } -} - - static int db_sethook (lua_State *L) { int arg, mask, count; lua_Hook func; diff --git a/src/ldebug.c b/src/ldebug.c index a112f4da62..a2565cf592 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.74 2010/10/11 20:24:42 roberto Exp $ +** $Id: ldebug.c,v 2.82 2011/06/02 19:31:40 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -35,12 +35,12 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); static int currentpc (CallInfo *ci) { lua_assert(isLua(ci)); - return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); + return pcRel(ci->u.l.savedpc, ci_func(ci)->p); } static int currentline (CallInfo *ci) { - return getfuncline(ci_func(ci)->l.p, currentpc(ci)); + return getfuncline(ci_func(ci)->p, currentpc(ci)); } @@ -94,13 +94,28 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { } +static const char *findvararg (CallInfo *ci, int n, StkId *pos) { + int nparams = clLvalue(ci->func)->p->numparams; + if (n >= ci->u.l.base - ci->func - nparams) + return NULL; /* no such vararg */ + else { + *pos = ci->func + nparams + n; + return "(*vararg)"; /* generic name for any vararg */ + } +} + + static const char *findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *name = NULL; StkId base; if (isLua(ci)) { - base = ci->u.l.base; - name = luaF_getlocalname(ci_func(ci)->l.p, n, currentpc(ci)); + if (n < 0) /* access to vararg values? */ + return findvararg(ci, -n, pos); + else { + base = ci->u.l.base; + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); + } } else base = ci->func + 1; @@ -108,10 +123,8 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n, StkId limit = (ci == L->ci) ? L->top : ci->next->func; if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ name = "(*temporary)"; /* generic name for any valid slot */ - else { - *pos = base; /* to avoid warnings */ + else return NULL; /* no name */ - } } *pos = base + (n - 1); return name; @@ -125,10 +138,10 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { if (!isLfunction(L->top - 1)) /* not a Lua function? */ name = NULL; else /* consider live variables at function start (parameters) */ - name = luaF_getlocalname(clvalue(L->top - 1)->l.p, n, 0); + name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); } else { /* active function; get information through 'ar' */ - StkId pos; + StkId pos = 0; /* to avoid warnings */ name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobj2s(L, L->top, pos); @@ -141,11 +154,11 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - StkId pos; + StkId pos = 0; /* to avoid warnings */ const char *name = findlocal(L, ar->i_ci, n, &pos); lua_lock(L); if (name) - setobjs2s(L, pos, L->top - 1); + setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ lua_unlock(L); return name; @@ -243,7 +256,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { if (*what == '>') { ci = NULL; func = L->top - 1; - luai_apicheck(L, ttisfunction(func)); + api_check(L, ttisfunction(func), "function expected"); what++; /* skip the '>' */ L->top--; /* pop function */ } @@ -271,21 +284,38 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { ** ======================================================= */ +static const char *getobjname (lua_State *L, CallInfo *ci, int reg, + const char **name); -static void kname (Proto *p, int c, int reg, const char *what, - const char **name) { - if (c == reg && what && *what == 'c') - return; /* index is a constant; name already correct */ - else if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) - *name = svalue(&p->k[INDEXK(c)]); - else - *name = "?"; + +/* +** find a "name" for the RK value 'c' +*/ +static void kname (lua_State *L, CallInfo *ci, int c, int oreg, + const char *what, const char **name) { + if (ISK(c)) { /* is 'c' a constant? */ + TValue *kvalue = &ci_func(ci)->p->k[INDEXK(c)]; + if (ttisstring(kvalue)) { /* literal constant? */ + *name = svalue(kvalue); /* it is its own name */ + return; + } + /* else no reasonable name found */ + } + else { /* 'c' is a register */ + if (c != oreg) /* not the original register? */ + what = getobjname(L, ci, c, name); /* search for 'c' */ + if (what && *what == 'c') { /* found a constant name? */ + return; /* 'name' already filled */ + } + /* else no reasonable name found */ + } + *name = "?"; /* no reasonable name found */ } static const char *getobjname (lua_State *L, CallInfo *ci, int reg, const char **name) { - Proto *p = ci_func(ci)->l.p; + Proto *p = ci_func(ci)->p; const char *what = NULL; int lastpc = currentpc(ci); int pc; @@ -312,10 +342,10 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, if (reg == a) { int k = GETARG_C(i); /* key index */ int t = GETARG_B(i); - const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ + const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ ? luaF_getlocalname(p, t + 1, pc) : getstr(p->upvalues[t].name); - kname(p, k, a, what, name); + kname(L, ci, k, a, what, name); what = (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; } break; @@ -329,10 +359,11 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, } break; } - case OP_LOADK: { + case OP_LOADK: + case OP_LOADKX: { if (reg == a) { - int b = GETARG_Bx(i); - b = (b > 0) ? b - 1 : GETARG_Ax(p->code[pc + 1]); + int b = (op == OP_LOADK) ? GETARG_Bx(i) + : GETARG_Ax(p->code[pc + 1]); if (ttisstring(&p->k[b])) { what = "constant"; *name = svalue(&p->k[b]); @@ -341,15 +372,15 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, break; } case OP_LOADNIL: { - int b = GETARG_B(i); /* move from 'b' to 'a' */ - if (a <= reg && reg <= b) /* set registers from 'a' to 'b' */ + int b = GETARG_B(i); + if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ what = NULL; break; } case OP_SELF: { if (reg == a) { int k = GETARG_C(i); /* key index */ - kname(p, k, a, what, name); + kname(L, ci, k, a, what, name); what = "method"; } break; @@ -371,6 +402,10 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, pc += b; /* do the jump */ break; } + case OP_TEST: { + if (reg == a) what = NULL; /* jumped code can change 'a' */ + break; + } default: if (testAMode(op) && reg == a) what = NULL; break; @@ -386,9 +421,9 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous)) return NULL; /* calling function is not Lua (or is unknown) */ ci = ci->previous; /* calling function */ - i = ci_func(ci)->l.p->code[currentpc(ci)]; + i = ci_func(ci)->p->code[currentpc(ci)]; if (GET_OPCODE(i) == OP_EXTRAARG) /* extra argument? */ - i = ci_func(ci)->l.p->code[currentpc(ci) - 1]; /* get 'real' instruction */ + i = ci_func(ci)->p->code[currentpc(ci) - 1]; /* get 'real' instruction */ switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: @@ -425,7 +460,10 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { -/* only ANSI way to check whether a pointer points to an array */ +/* +** only ANSI way to check whether a pointer points to an array +** (used only for error messages, so efficiency is not a big concern) +*/ static int isinstack (CallInfo *ci, const TValue *o) { StkId p; for (p = ci->u.l.base; p < ci->top; p++) @@ -436,7 +474,7 @@ static int isinstack (CallInfo *ci, const TValue *o) { static const char *getupvalname (CallInfo *ci, const TValue *o, const char **name) { - LClosure *c = &ci_func(ci)->l; + LClosure *c = ci_func(ci); int i; for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v == o) { @@ -455,7 +493,7 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ - if (!kind && isinstack(ci, o)) /* no? try a register */ + if (!kind && isinstack(ci, o)) /* no? try a register */ kind = getobjname(L, ci, cast_int(o - ci->u.l.base), &name); } if (kind) @@ -497,7 +535,7 @@ static void addinfo (lua_State *L, const char *msg) { if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ int line = currentline(ci); - TString *src = ci_func(ci)->l.p->source; + TString *src = ci_func(ci)->p->source; if (src) luaO_chunkid(buff, getstr(src), LUA_IDSIZE); else { /* no source available; use "?" instead */ diff --git a/src/ldebug.h b/src/ldebug.h index 545fa345ed..6590c56bba 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.5 2009/06/10 16:57:53 roberto Exp $ +** $Id: ldebug.h,v 2.6 2011/06/02 19:31:40 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -17,6 +17,9 @@ #define resethookcount(L) (L->hookcount = L->basehookcount) +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue((ci)->func)) + LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, const char *opname); diff --git a/src/ldo.c b/src/ldo.c index f4f9100621..c3d86affd4 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.90 2010/10/25 19:01:37 roberto Exp $ +** $Id: ldo.c,v 2.95 2011/06/02 19:31:40 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -293,65 +293,59 @@ static StkId tryfuncTM (lua_State *L, StkId func) { ** returns true if function has been executed (C function) */ int luaD_precall (lua_State *L, StkId func, int nresults) { - Closure *cl; lua_CFunction f; - ptrdiff_t funcr; - if (!ttisfunction(func)) /* `func' is not a function? */ - func = tryfuncTM(L, func); /* check the `function' tag method */ - funcr = savestack(L, func); - if (ttislcf(func)) { /* light C function? */ - f = fvalue(func); /* get it */ - goto isCfunc; /* go to call it */ - } - cl = clvalue(func); - if (cl->c.isC) { /* C closure? */ - CallInfo *ci; - int n; - f = cl->c.f; - isCfunc: /* call C function 'f' */ - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = next_ci(L); /* now 'enter' new function */ - ci->nresults = nresults; - ci->func = restorestack(L, funcr); - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); - ci->callstatus = 0; - if (L->hookmask & LUA_MASKCALL) - luaD_hook(L, LUA_HOOKCALL, -1); - lua_unlock(L); - n = (*f)(L); /* do the actual call */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, L->top - n); - return 1; - } - else { /* Lua function: prepare its call */ - CallInfo *ci; - int nparams, nargs; - StkId base; - Proto *p = cl->l.p; - luaD_checkstack(L, p->maxstacksize); - func = restorestack(L, funcr); - nargs = cast_int(L->top - func) - 1; /* number of real arguments */ - nparams = p->numparams; /* number of expected parameters */ - for (; nargs < nparams; nargs++) - setnilvalue(L->top++); /* complete missing arguments */ - if (!p->is_vararg) /* no varargs? */ - base = func + 1; - else /* vararg function */ - base = adjust_varargs(L, p, nargs); - ci = next_ci(L); /* now 'enter' new function */ - ci->nresults = nresults; - ci->func = func; - ci->u.l.base = base; - ci->top = base + p->maxstacksize; - lua_assert(ci->top <= L->stack_last); - ci->u.l.savedpc = p->code; /* starting point */ - ci->callstatus = CIST_LUA; - L->top = ci->top; - if (L->hookmask & LUA_MASKCALL) - callhook(L, ci); - return 0; + CallInfo *ci; + int n; /* number of arguments (Lua) or returns (C) */ + ptrdiff_t funcr = savestack(L, func); + switch (ttype(func)) { + case LUA_TLCF: /* light C function */ + f = fvalue(func); + goto Cfunc; + case LUA_TCCL: { /* C closure */ + f = clCvalue(func)->f; + Cfunc: + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = restorestack(L, funcr); + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->callstatus = 0; + if (L->hookmask & LUA_MASKCALL) + luaD_hook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, L->top - n); + return 1; + } + case LUA_TLCL: { /* Lua function: prepare its call */ + StkId base; + Proto *p = clLvalue(func)->p; + luaD_checkstack(L, p->maxstacksize); + func = restorestack(L, funcr); + n = cast_int(L->top - func) - 1; /* number of real arguments */ + for (; n < p->numparams; n++) + setnilvalue(L->top++); /* complete missing arguments */ + base = (!p->is_vararg) ? func + 1 : adjust_varargs(L, p, n); + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->u.l.base = base; + ci->top = base + p->maxstacksize; + lua_assert(ci->top <= L->stack_last); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_LUA; + L->top = ci->top; + if (L->hookmask & LUA_MASKCALL) + callhook(L, ci); + return 0; + } + default: { /* not a function */ + func = tryfuncTM(L, func); /* retry with 'function' tag method */ + return luaD_precall(L, func, nresults); + } } } @@ -615,8 +609,8 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, */ struct SParser { /* data to `f_parser' */ ZIO *z; - Mbuffer buff; /* buffer to be used by the scanner */ - Varlist varl; /* list of local variables (to be used by the parser) */ + Mbuffer buff; /* dynamic structure used by the scanner */ + Dyndata dyd; /* dynamic structures used by the parser */ const char *name; }; @@ -625,14 +619,14 @@ static void f_parser (lua_State *L, void *ud) { Proto *tf; Closure *cl; struct SParser *p = cast(struct SParser *, ud); - int c = luaZ_lookahead(p->z); + int c = zgetc(p->z); /* read first character */ tf = (c == LUA_SIGNATURE[0]) ? luaU_undump(L, p->z, &p->buff, p->name) - : luaY_parser(L, p->z, &p->buff, &p->varl, p->name); + : luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); setptvalue2s(L, L->top, tf); incr_top(L); cl = luaF_newLclosure(L, tf); - setclvalue(L, L->top - 1, cl); + setclLvalue(L, L->top - 1, cl); for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ cl->l.upvals[i] = luaF_newupval(L); } @@ -643,11 +637,15 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { int status; L->nny++; /* cannot yield during parsing */ p.z = z; p.name = name; - p.varl.actvar = NULL; p.varl.nactvar = p.varl.actvarsize = 0; + p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; + p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; + p.dyd.label.arr = NULL; p.dyd.label.size = 0; luaZ_initbuffer(L, &p.buff); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); - luaM_freearray(L, p.varl.actvar, p.varl.actvarsize); + luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); + luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); + luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); L->nny--; return status; } diff --git a/src/ldump.c b/src/ldump.c index 54a7bb48bf..77b578d777 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.17 2010/10/13 21:04:52 lhf Exp $ +** $Id: ldump.c,v 1.18 2011/05/06 13:35:17 lhf Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -69,7 +69,7 @@ static void DumpString(const TString* s, DumpState* D) { size_t size=s->tsv.len+1; /* include trailing '\0' */ DumpVar(size,D); - DumpBlock(getstr(s),size,D); + DumpBlock(getstr(s),size*sizeof(char),D); } } @@ -150,7 +150,7 @@ static void DumpFunction(const Proto* f, DumpState* D) static void DumpHeader(DumpState* D) { - char h[LUAC_HEADERSIZE]; + lu_byte h[LUAC_HEADERSIZE]; luaU_header(h); DumpBlock(h,LUAC_HEADERSIZE,D); } diff --git a/src/lgc.c b/src/lgc.c index 2286f54ed7..598cc71c7e 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.103 2010/10/25 19:01:37 roberto Exp $ +** $Id: lgc.c,v 2.109 2011/05/05 19:42:25 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -51,7 +51,7 @@ ** standard negative debt for GC; a reasonable "time" to wait before ** starting a new cycle */ -#define stddebt(g) (-cast(l_mem, g->totalbytes/100) * g->gcpause) +#define stddebt(g) (-cast(l_mem, gettotalbytes(g)/100) * g->gcpause) /* @@ -68,11 +68,15 @@ #define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS))) -#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) +#define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT) #define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) +#define checkconsistency(obj) \ + lua_longassert(!iscollectable(obj) || righttt(obj)) + + #define markvalue(g,o) { checkconsistency(o); \ if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } @@ -114,12 +118,11 @@ static void removeentry (Node *n) { */ static int iscleared (const TValue *o, int iskey) { if (!iscollectable(o)) return 0; - if (ttisstring(o)) { + else if (ttisstring(o)) { stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ return 0; } - return iswhite(gcvalue(o)) || - (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); + else return iswhite(gcvalue(o)) || (!iskey && isfinalized(gcvalue(o))); } @@ -319,8 +322,7 @@ static void remarkupvals (global_State *g) { ** mark root set and reset all gray lists, to start a new ** incremental (or full) collection */ -static void markroot (lua_State *L) { - global_State *g = G(L); +static void markroot (global_State *g) { g->gray = g->grayagain = NULL; g->weak = g->allweak = g->ephemeron = NULL; markobject(g, g->mainthread); @@ -635,6 +637,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { int ow = otherwhite(g); int toclear, toset; /* bits to clear and to set in all live objects */ int tostop; /* stop sweep when this is true */ + l_mem debt = g->GCdebt; /* current debt */ if (isgenerational(g)) { /* generational mode? */ toclear = ~0; /* clear nothing */ toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ @@ -657,13 +660,15 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ if (testbits(marked, tostop)) { static GCObject *nullp = NULL; - return &nullp; /* stop sweeping this list */ + p = &nullp; /* stop sweeping this list */ + break; } /* update marks */ gch(curr)->marked = cast_byte((marked & toclear) | toset); p = &gch(curr)->next; /* go to next element */ } } + luaE_setdebt(g, debt); /* sweeping should not change debt */ return p; } @@ -687,19 +692,17 @@ static void checkSizes (lua_State *L) { } -static Udata *udata2finalize (global_State *g) { +static GCObject *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ - Udata *u = rawgco2u(o); - lua_assert(isfinalized(&u->uv)); - lua_assert(!isold(o)); - g->tobefnz = u->uv.next; /* remove it from 'tobefnz' list */ - u->uv.next = g->allgc; /* return it to 'allgc' list */ + lua_assert(isfinalized(o)); + g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ + gch(o)->next = g->allgc; /* return it to 'allgc' list */ g->allgc = o; - resetbit(u->uv.marked, SEPARATED); /* mark that it is not in 'tobefnz' */ - resetoldbit(o); /* see MOVE OLD rule */ + resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */ + lua_assert(!isold(o)); /* see MOVE OLD rule */ if (!keepinvariant(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ - return u; + return o; } @@ -711,20 +714,22 @@ static void dothecall (lua_State *L, void *ud) { static void GCTM (lua_State *L, int propagateerrors) { global_State *g = G(L); - Udata *udata = udata2finalize(g); - const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC); + const TValue *tm; + TValue v; + setgcovalue(L, &v, udata2finalize(g)); + tm = luaT_gettmbyobj(L, &v, TM_GC); if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ int status; lu_byte oldah = L->allowhook; - lu_mem oldd = g->GCdebt; + int running = g->gcrunning; L->allowhook = 0; /* stop debug hooks during GC tag method */ - stopgc(g); /* avoid GC steps */ + g->gcrunning = 0; /* avoid GC steps */ setobj2s(L, L->top, tm); /* push finalizer... */ - setuvalue(L, L->top+1, udata); /* ... and its argument */ + setobj2s(L, L->top + 1, &v); /* ... and its argument */ L->top += 2; /* and (next line) call the finalizer */ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ - g->GCdebt = oldd; /* restore threshold */ + g->gcrunning = running; /* restore state */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status == LUA_ERRRUN) { /* is there an error msg.? */ luaO_pushfstring(L, "error in __gc tag method (%s)", @@ -738,25 +743,25 @@ static void GCTM (lua_State *L, int propagateerrors) { /* -** move all unreachable udata that need finalization from list 'udgc' to -** list 'tobefnz' +** move all unreachable objects that need finalization from list 'finobj' +** to list 'tobefnz' */ void luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); - GCObject **p = &g->udgc; + GCObject **p = &g->finobj; GCObject *curr; GCObject **lastnext = &g->tobefnz; /* find last 'next' field in 'tobefnz' list (to add elements in its end) */ while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; while ((curr = *p) != NULL) { /* traverse all finalizable objects */ - lua_assert(gch(curr)->tt == LUA_TUSERDATA && !isfinalized(gco2u(curr))); + lua_assert(!isfinalized(curr)); lua_assert(testbit(gch(curr)->marked, SEPARATED)); if (!(all || iswhite(curr))) /* not being collected? */ p = &gch(curr)->next; /* don't bother with it */ else { l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ - *p = gch(curr)->next; /* remove 'curr' from 'udgc' list */ + *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */ gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; lastnext = &gch(curr)->next; @@ -766,23 +771,23 @@ void luaC_separateudata (lua_State *L, int all) { /* -** if userdata 'u' has a finalizer, remove it from 'allgc' list (must -** search the list to find it) and link it in 'udgc' list. +** if object 'o' has a finalizer, remove it from 'allgc' list (must +** search the list to find it) and link it in 'finobj' list. */ -void luaC_checkfinalizer (lua_State *L, Udata *u) { +void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); - if (testbit(u->uv.marked, SEPARATED) || /* udata is already separated... */ - isfinalized(&u->uv) || /* ... or is finalized... */ - gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalizer? */ + if (testbit(gch(o)->marked, SEPARATED) || /* obj. is already separated... */ + isfinalized(o) || /* ... or is finalized... */ + gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ return; /* nothing to be done */ - else { /* move 'u' to 'udgc' list */ + else { /* move 'o' to 'finobj' list */ GCObject **p; - for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ; - *p = u->uv.next; /* remove 'u' from root list */ - u->uv.next = g->udgc; /* link it in list 'udgc' */ - g->udgc = obj2gco(u); - l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ - resetoldbit(obj2gco(u)); /* see MOVE OLD rule */ + for (p = &g->allgc; *p != o; p = &gch(*p)->next) ; + *p = gch(o)->next; /* remove 'o' from root list */ + gch(o)->next = g->finobj; /* link it in list 'finobj' */ + g->finobj = o; + l_setbit(gch(o)->marked, SEPARATED); /* mark it as such */ + resetoldbit(o); /* see MOVE OLD rule */ } } @@ -808,7 +813,7 @@ void luaC_changemode (lua_State *L, int mode) { if (mode == KGC_GEN) { /* change to generational mode */ /* make sure gray lists are consistent */ luaC_runtilstate(L, bitmask(GCSpropagate)); - g->lastmajormem = g->totalbytes; + g->lastmajormem = gettotalbytes(g); g->gckind = KGC_GEN; } else { /* change to incremental mode */ @@ -823,10 +828,14 @@ void luaC_changemode (lua_State *L, int mode) { /* -** call all pending finalizers */ +** call all pending finalizers +*/ static void callallpendingfinalizers (lua_State *L, int propagateerrors) { global_State *g = G(L); - while (g->tobefnz) GCTM(L, propagateerrors); + while (g->tobefnz) { + resetoldbit(g->tobefnz); + GCTM(L, propagateerrors); + } } @@ -837,8 +846,8 @@ void luaC_freeallobjects (lua_State *L) { /* following "white" makes all objects look dead */ g->currentwhite = WHITEBITS; g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->udgc); - lua_assert(g->udgc == NULL); + sweepwholelist(L, &g->finobj); + lua_assert(g->finobj == NULL); sweepwholelist(L, &g->allgc); lua_assert(g->allgc == NULL); for (i = 0; i < g->strt.size; i++) /* free all string lists */ @@ -883,7 +892,7 @@ static l_mem singlestep (lua_State *L) { switch (g->gcstate) { case GCSpause: { if (!isgenerational(g)) - markroot(L); /* start a new collection */ + markroot(g); /* start a new collection */ /* in any case, root must be marked */ lua_assert(!iswhite(obj2gco(g->mainthread)) && !iswhite(gcvalue(&g->l_registry))); @@ -905,7 +914,7 @@ static l_mem singlestep (lua_State *L) { return GCSWEEPCOST; } else { /* no more strings to sweep */ - g->sweepgc = &g->udgc; /* prepare to sweep userdata */ + g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */ g->gcstate = GCSsweepudata; return 0; } @@ -955,15 +964,15 @@ static void generationalcollection (lua_State *L) { global_State *g = G(L); if (g->lastmajormem == 0) { /* signal for another major collection? */ luaC_fullgc(L, 0); /* perform a full regular collection */ - g->lastmajormem = g->totalbytes; /* update control */ + g->lastmajormem = gettotalbytes(g); /* update control */ } else { luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ luaC_runtilstate(L, bitmask(GCSpause)); - if (g->totalbytes > g->lastmajormem/100 * g->gcmajorinc) + if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc) g->lastmajormem = 0; /* signal for a major collection */ } - g->GCdebt = stddebt(g); + luaE_setdebt(g, stddebt(g)); } @@ -974,21 +983,33 @@ static void step (lua_State *L) { lim -= singlestep(L); } while (lim > 0 && g->gcstate != GCSpause); if (g->gcstate != GCSpause) - g->GCdebt -= GCSTEPSIZE; + luaE_setdebt(g, g->GCdebt - GCSTEPSIZE); else - g->GCdebt = stddebt(g); + luaE_setdebt(g, stddebt(g)); } -void luaC_step (lua_State *L) { +/* +** performs a basic GC step even if the collector is stopped +*/ +void luaC_forcestep (lua_State *L) { + global_State *g = G(L); int i; - if (isgenerational(G(L))) generationalcollection(L); + if (isgenerational(g)) generationalcollection(L); else step(L); - for (i = 0; i < GCFINALIZENUM && G(L)->tobefnz; i++) + for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++) GCTM(L, 1); /* Call a few pending finalizers */ } +/* +** performs a basic GC step only if collector is running +*/ +void luaC_step (lua_State *L) { + if (G(L)->gcrunning) luaC_forcestep(L); +} + + /* ** performs a full GC cycle; if "isemergency", does not call ** finalizers (which could change stack positions) @@ -1016,7 +1037,7 @@ void luaC_fullgc (lua_State *L, int isemergency) { luaC_runtilstate(L, bitmask(GCSpropagate)); } g->gckind = origkind; - g->GCdebt = stddebt(g); + luaE_setdebt(g, stddebt(g)); if (!isemergency) /* do not run finalizers during emergency GC */ callallpendingfinalizers(L, 1); } diff --git a/src/lgc.h b/src/lgc.h index 9c5b05e2dd..0fae4dd292 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.44 2010/06/30 14:11:17 roberto Exp $ +** $Id: lgc.h,v 2.50 2011/01/26 16:30:02 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -52,10 +52,6 @@ #define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) -#define gcstopped(g) ((g)->GCdebt == MIN_LMEM) -#define stopgc(g) ((g)->GCdebt = MIN_LMEM) - - /* ** some useful bit tricks */ @@ -76,8 +72,8 @@ #define WHITE0BIT 0 /* object is white (type 0) */ #define WHITE1BIT 1 /* object is white (type 1) */ #define BLACKBIT 2 /* object is black */ -#define FINALIZEDBIT 3 /* for userdata: has been finalized */ -#define SEPARATED 4 /* " ": it's in 'udgc' list or in 'tobefnz' */ +#define FINALIZEDBIT 3 /* object has been separated for finalization */ +#define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */ #define FIXEDBIT 5 /* object is fixed (should not be collected) */ #define OLDBIT 6 /* object is old (only in generational mode) */ /* bit 7 is currently used by tests (luaL_checkmemory) */ @@ -108,7 +104,9 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_checkGC(L) {condchangemem(L); if (G(L)->GCdebt > 0) luaC_step(L);} +#define luaC_condGC(L,c) \ + {if (G(L)->GCdebt > 0) {c;}; condchangemem(L);} +#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);) #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ @@ -130,6 +128,7 @@ LUAI_FUNC void luaC_separateudata (lua_State *L, int all); LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_forcestep (lua_State *L); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, @@ -137,7 +136,7 @@ LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); -LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); +LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); LUAI_FUNC void luaC_changemode (lua_State *L, int mode); diff --git a/src/linit.c b/src/linit.c index fa944671c4..8d3aa6576f 100644 --- a/src/linit.c +++ b/src/linit.c @@ -1,16 +1,16 @@ /* -** $Id: linit.c,v 1.30 2010/11/12 15:48:30 roberto Exp $ -** Initialization of libraries for lua.c and other clients +** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $ +** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ -/* +/* ** If you embed Lua in your program and need to open the standard ** libraries, call luaL_openlibs in your program. If you need a ** different set of libraries, copy this file to your project and edit ** it to suit your needs. -*/ +*/ #define linit_c @@ -57,7 +57,7 @@ LUALIB_API void luaL_openlibs (lua_State *L) { lua_pop(L, 1); /* remove lib */ } /* add open functions from 'preloadedlibs' into 'package.preload' table */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); for (lib = preloadedlibs; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_setfield(L, -2, lib->name); diff --git a/src/liolib.c b/src/liolib.c index 658601ad7a..ab1f131109 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.95 2010/11/10 18:05:36 roberto Exp $ +** $Id: liolib.c,v 2.99 2011/03/03 16:34:46 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -26,28 +26,29 @@ ** lua_popen spawns a new process connected to the current one through ** the file streams. */ -#if !defined(lua_popen) +#if !defined(lua_popen) /* { */ -#if defined(LUA_USE_POPEN) +#if defined(LUA_USE_POPEN) /* { */ -#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) -#define lua_pclose(L,file) ((void)L, pclose(file)) +#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) +#define lua_pclose(L,file) ((void)L, pclose(file)) -#elif defined(LUA_WIN) +#elif defined(LUA_WIN) /* }{ */ -#define lua_popen(L,c,m) ((void)L, _popen(c,m)) -#define lua_pclose(L,file) ((void)L, _pclose(file)) +#define lua_popen(L,c,m) ((void)L, _popen(c,m)) +#define lua_pclose(L,file) ((void)L, _pclose(file)) -#else -#define lua_popen(L,c,m) ((void)((void)c, m), \ - luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) -#define lua_pclose(L,file) ((void)((void)L, file), -1) +#else /* }{ */ -#endif +#define lua_popen(L,c,m) ((void)((void)c, m), \ + luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) +#define lua_pclose(L,file) ((void)((void)L, file), -1) -#endif +#endif /* } */ + +#endif /* } */ #define IO_INPUT 1 @@ -57,24 +58,6 @@ static const char *const fnames[] = {"input", "output"}; -static int pushresult (lua_State *L, int i, const char *filename) { - int en = errno; /* calls to Lua API may change this value */ - if (i) { - lua_pushboolean(L, 1); - return 1; - } - else { - lua_pushnil(L); - if (filename) - lua_pushfstring(L, "%s: %s", filename, strerror(en)); - else - lua_pushfstring(L, "%s", strerror(en)); - lua_pushinteger(L, en); - return 3; - } -} - - static void fileerror (lua_State *L, int arg, const char *filename) { lua_pushfstring(L, "%s: %s", filename, strerror(errno)); luaL_argerror(L, arg, lua_tostring(L, -1)); @@ -143,13 +126,8 @@ static int io_noclose (lua_State *L) { static int io_pclose (lua_State *L) { FILE **p = tofilep(L); int stat = lua_pclose(L, *p); - *p = NULL; - if (stat == -1) /* error? */ - return pushresult(L, 0, NULL); - else { - lua_pushinteger(L, stat); - return 1; /* return status */ - } + *p = NULL; /* mark stream as closed (for GC) */ + return luaL_execresult(L, stat); } @@ -159,8 +137,8 @@ static int io_pclose (lua_State *L) { static int io_fclose (lua_State *L) { FILE **p = tofilep(L); int ok = (fclose(*p) == 0); - *p = NULL; - return pushresult(L, ok, NULL); + *p = NULL; /* mark stream as closed (for GC) */ + return luaL_fileresult(L, ok, NULL); } @@ -181,8 +159,7 @@ static int io_close (lua_State *L) { static int io_gc (lua_State *L) { FILE *f = *tofilep(L); - /* ignore closed files */ - if (f != NULL) + if (f != NULL) /* ignore closed files */ aux_close(L); return 0; } @@ -205,14 +182,14 @@ static int io_open (lua_State *L) { int i = 0; /* check whether 'mode' matches '[rwa]%+?b?' */ if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL && - (mode[i] != '+' || ++i) && /* skip if char is '+' */ - (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ + (mode[i] != '+' || ++i) && /* skip if char is '+' */ + (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ (mode[i] == '\0'))) luaL_error(L, "invalid mode " LUA_QL("%s") " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); pf = newfile(L); *pf = fopen(filename, mode); - return (*pf == NULL) ? pushresult(L, 0, filename) : 1; + return (*pf == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -225,14 +202,14 @@ static int io_popen (lua_State *L) { const char *mode = luaL_optstring(L, 2, "r"); FILE **pf = newfile(L); *pf = lua_popen(L, filename, mode); - return (*pf == NULL) ? pushresult(L, 0, filename) : 1; + return (*pf == NULL) ? luaL_fileresult(L, 0, filename) : 1; } static int io_tmpfile (lua_State *L) { FILE **pf = newfile(L); *pf = tmpfile(); - return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; + return (*pf == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } @@ -305,7 +282,7 @@ static int io_lines (lua_State *L) { if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ if (lua_isnil(L, 1)) { /* no file name? */ lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); /* get default input */ - lua_replace(L, 1); /* put it at index 1 */ + lua_replace(L, 1); /* put it at index 1 */ tofile(L); /* check that it's a valid file handle */ toclose = 0; /* do not close it after iteration */ } @@ -315,7 +292,7 @@ static int io_lines (lua_State *L) { *pf = fopen(filename, "r"); if (*pf == NULL) fileerror(L, 1, filename); - lua_replace(L, 1); /* put file at index 1 */ + lua_replace(L, 1); /* put file at index 1 */ toclose = 1; /* close it after iteration */ } aux_lines(L, toclose); @@ -443,7 +420,7 @@ static int g_read (lua_State *L, FILE *f, int first) { } } if (ferror(f)) - return pushresult(L, 0, NULL); + return luaL_fileresult(L, 0, NULL); if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ @@ -507,7 +484,7 @@ static int g_write (lua_State *L, FILE *f, int arg) { } } if (status) return 1; /* file handle already on stack top */ - else return pushresult(L, status, NULL); + else return luaL_fileresult(L, status, NULL); } @@ -517,7 +494,7 @@ static int io_write (lua_State *L) { static int f_write (lua_State *L) { - FILE * f = tofile(L); + FILE * f = tofile(L); lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ return g_write(L, f, 2); } @@ -531,7 +508,7 @@ static int f_seek (lua_State *L) { long offset = luaL_optlong(L, 3, 0); op = fseek(f, offset, mode[op]); if (op) - return pushresult(L, 0, NULL); /* error */ + return luaL_fileresult(L, 0, NULL); /* error */ else { lua_pushinteger(L, ftell(f)); return 1; @@ -546,18 +523,18 @@ static int f_setvbuf (lua_State *L) { int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); int res = setvbuf(f, NULL, mode[op], sz); - return pushresult(L, res == 0, NULL); + return luaL_fileresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { - return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } static int f_flush (lua_State *L) { - return pushresult(L, fflush(tofile(L)) == 0, NULL); + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); } diff --git a/src/llex.c b/src/llex.c index 9980af7166..7d034b0af1 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.41 2010/11/18 18:38:44 roberto Exp $ +** $Id: llex.c,v 2.47 2011/05/03 15:51:16 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -35,7 +35,7 @@ /* ORDER RESERVED */ static const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "if", + "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "..", "...", "==", ">=", "<=", "~=", "", @@ -67,7 +67,6 @@ void luaX_init (lua_State *L) { for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ } } @@ -127,7 +126,7 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TValue *o; /* entry for `str' */ TString *ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_setstr(L, ls->fs->h, ts); + o = luaH_setstr(L, ls->fs->h, ts); if (ttisnil(o)) { setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); @@ -152,9 +151,11 @@ static void inclinenumber (LexState *ls) { } -void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { +void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, + int firstchar) { ls->decpoint = '.'; ls->L = L; + ls->current = firstchar; ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->z = z; ls->fs = NULL; @@ -164,7 +165,6 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->envn = luaS_new(L, LUA_ENV); /* create env name */ luaS_fix(ls->envn); /* never collect this name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ - next(ls); /* read first char */ } @@ -185,7 +185,7 @@ static int check_next (LexState *ls, const char *set) { } -/* +/* ** change all characters 'from' in buffer to 'to' */ static void buffreplace (LexState *ls, char from, char to) { @@ -200,6 +200,9 @@ static void buffreplace (LexState *ls, char from, char to) { #define getlocaledecpoint() (localeconv()->decimal_point[0]) #endif + +#define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e) + /* ** in case of format error, try to change decimal point separator to ** the one defined in the current locale and check again @@ -208,7 +211,7 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) { char old = ls->decpoint; ls->decpoint = getlocaledecpoint(); buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ - if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { + if (!buff2d(ls->buff, &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ lexerror(ls, "malformed number", TK_NUMBER); @@ -226,7 +229,7 @@ static void read_numeral (LexState *ls, SemInfo *seminfo) { } while (lislalnum(ls->current) || ls->current == '.'); save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ - if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ + if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ trydecpoint(ls, seminfo); /* try to update decimal point separator */ } @@ -283,13 +286,6 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } -static int hexavalue (int c) { - if (lisdigit(c)) return c - '0'; - else if (lisupper(c)) return c - 'A' + 10; - else return c - 'a' + 10; -} - - static int readhexaesc (LexState *ls) { int c1, c2 = EOZ; if (!lisxdigit(c1 = next(ls)) || !lisxdigit(c2 = next(ls))) { @@ -299,7 +295,7 @@ static int readhexaesc (LexState *ls) { if (c2 != EOZ) save(ls, c2); lexerror(ls, "hexadecimal digit expected", TK_STRING); } - return (hexavalue(c1) << 4) + hexavalue(c2); + return (luaO_hexavalue(c1) << 4) + luaO_hexavalue(c2); } diff --git a/src/llex.h b/src/llex.h index 1a811dce5c..5edbbc1d9a 100644 --- a/src/llex.h +++ b/src/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.65 2010/04/05 16:35:37 roberto Exp $ +** $Id: llex.h,v 1.70 2011/05/03 15:51:16 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -13,8 +13,6 @@ #define FIRST_RESERVED 257 -/* maximum length of a reserved word */ -#define TOKEN_LEN (sizeof("function")/sizeof(char)) /* @@ -25,7 +23,7 @@ enum RESERVED { /* terminal symbols denoted by reserved words */ TK_AND = FIRST_RESERVED, TK_BREAK, TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, - TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_EOS, @@ -48,17 +46,19 @@ typedef struct Token { } Token; +/* state of the lexer plus state of the parser when shared by all + functions */ typedef struct LexState { int current; /* current character (charint) */ int linenumber; /* input line counter */ int lastline; /* line of last token `consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ - struct FuncState *fs; /* `FuncState' is private to the parser */ + struct FuncState *fs; /* current function (parser) */ struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ - struct Varlist *varl; /* list of all active local variables */ + struct Dyndata *dyd; /* dynamic structures used by the parser */ TString *source; /* current source name */ TString *envn; /* environment variable name */ char decpoint; /* locale decimal point */ @@ -67,7 +67,7 @@ typedef struct LexState { LUAI_FUNC void luaX_init (lua_State *L); LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, - TString *source); + TString *source, int firstchar); LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); LUAI_FUNC int luaX_lookahead (LexState *ls); diff --git a/src/llimits.h b/src/llimits.h index f8ede143d3..b571441393 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.84 2010/11/08 16:33:20 roberto Exp $ +** $Id: llimits.h,v 1.89 2011/05/05 19:43:14 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -59,9 +59,12 @@ typedef LUAI_UACNUMBER l_uacNumber; /* internal assertions for in-house debugging */ #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) +/* to avoid problems with conditions too long */ +#define lua_longassert(c) { if (!(c)) lua_assert(0); } #else #define lua_assert(c) /* empty */ #define check_exp(c,e) (e) +#define lua_longassert(c) /* empty */ #endif /* @@ -87,6 +90,7 @@ typedef LUAI_UACNUMBER l_uacNumber; #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) +#define cast_uchar(i) cast(unsigned char, (i)) /* @@ -173,6 +177,9 @@ typedef lu_int32 Instruction; ** lua_number2integer is a macro to convert lua_Number to lua_Integer. ** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned. ** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number. +** luai_hashnum is a macro to hash a lua_Number value into an integer. +** The hash must be deterministic and give reasonable values for +** both small and large values (outside the range of integers). */ #if defined(MS_ASMTRICK) /* { */ @@ -203,6 +210,10 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ (i) = (t)u.l_p[LUA_IEEEENDIAN]; } +#define luai_hashnum(i,n) \ + { volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \ + (i) = u.l_p[0] + u.l_p[1]; } /* add double bits for his hash */ + #define lua_number2int(i,n) lua_number2int32(i, n, int) #define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) #define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) @@ -241,14 +252,8 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #endif -/* -** luai_hashnum is a macro do hash a lua_Number value into an integer. -** The hash must be deterministic and give reasonable values for -** both small and large values (outside the range of integers). -** It is used only in ltable.c. -*/ -#if !defined(luai_hashnum) /* { */ +#if (defined(ltable_c) || defined(luaall_c)) && !defined(luai_hashnum) #include #include @@ -257,7 +262,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ lua_number2int(i, n); i += e; } -#endif /* } */ +#endif @@ -275,7 +280,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #define condchangemem(L) condmovestack(L) #else #define condchangemem(L) \ - ((void)(gcstopped(G(L)) || (luaC_fullgc(L, 0), 1))) + ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1))) #endif #endif diff --git a/src/lmem.c b/src/lmem.c index 0f3178a279..c3775dfb31 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.79 2010/05/05 18:49:56 roberto Exp $ +** $Id: lmem.c,v 1.81 2010/12/20 19:40:07 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -79,14 +79,14 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { size_t realosize = (block) ? osize : 0; lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) - if (nsize > realosize && !gcstopped(g)) + if (nsize > realosize && g->gcrunning) luaC_fullgc(L, 1); /* force a GC whenever possible */ #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { api_check(L, nsize > realosize, "realloc cannot fail when shrinking a block"); - if (!gcstopped(g)) { + if (g->gcrunning) { luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } @@ -94,9 +94,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { luaD_throw(L, LUA_ERRMEM); } lua_assert((nsize == 0) == (newblock == NULL)); - g->totalbytes = (g->totalbytes - realosize) + nsize; - if (!gcstopped(g)) - g->GCdebt += nsize; /* give some credit to garbage collector */ + g->GCdebt = (g->GCdebt + nsize) - realosize; #if defined(TRACEMEM) { /* auxiliary patch to monitor garbage collection. ** To plot, gnuplot with following command: @@ -108,9 +106,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { if ((total % 200) == 0) { if (f == NULL) f = fopen(TRACEMEM, "w"); fprintf(f, "%lu %u %d %d\n", total, - g->totalbytes, - gcstopped(g) ? 0 : g->GCdebt, - g->gcstate * 1000); + g->totalbytes, g->GCdebt, g->gcstate * 1000); } } #endif diff --git a/src/loadlib.c b/src/loadlib.c index 3e5eaecfe1..ce3c2e6e40 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.94 2010/11/10 20:00:04 roberto Exp $ +** $Id: loadlib.c,v 1.98 2011/04/08 19:17:36 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -164,7 +164,7 @@ static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, buffer, sizeof(buffer), NULL)) + NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) lua_pushstring(L, buffer); else lua_pushfstring(L, "system error %d\n", error); @@ -321,8 +321,10 @@ static const char *pushnexttemplate (lua_State *L, const char *path) { static const char *searchpath (lua_State *L, const char *name, - const char *path) { - name = luaL_gsub(L, name, ".", LUA_DIRSEP); + const char *path, + const char *sep) { + if (*sep != '\0') /* non-empty separator? */ + name = luaL_gsub(L, name, sep, LUA_DIRSEP); /* replace it by proper one */ lua_pushliteral(L, ""); /* error accumulator */ while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename = luaL_gsub(L, lua_tostring(L, -1), @@ -339,7 +341,9 @@ static const char *searchpath (lua_State *L, const char *name, static int ll_searchpath (lua_State *L) { - const char *f = searchpath(L, luaL_checkstring(L, 1), luaL_checkstring(L, 2)); + const char *f = searchpath(L, luaL_checkstring(L, 1), + luaL_checkstring(L, 2), + luaL_optstring(L, 3, ".")); if (f != NULL) return 1; else { /* error message is on top of the stack */ lua_pushnil(L); @@ -356,13 +360,19 @@ static const char *findfile (lua_State *L, const char *name, path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); - return searchpath(L, name, path); + return searchpath(L, name, path, "."); } -static void loaderror (lua_State *L, const char *filename) { - luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", - lua_tostring(L, 1), filename, lua_tostring(L, -1)); +static int checkload (lua_State *L, int stat, const char *filename) { + if (stat) { /* module loaded successfully? */ + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; /* return open function and file name */ + } + else + return luaL_error(L, "error loading module " LUA_QS + " from file " LUA_QS ":\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); } @@ -370,10 +380,8 @@ static int loader_Lua (lua_State *L) { const char *filename; const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path"); - if (filename == NULL) return 1; /* library not found in this path */ - if (luaL_loadfile(L, filename) != LUA_OK) - loaderror(L, filename); - return 1; /* library loaded successfully */ + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); } @@ -398,10 +406,8 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) { static int loader_C (lua_State *L) { const char *name = luaL_checkstring(L, 1); const char *filename = findfile(L, name, "cpath"); - if (filename == NULL) return 1; /* library not found in this path */ - if (loadfunc(L, filename, name) != 0) - loaderror(L, filename); - return 1; /* library loaded successfully */ + if (filename == NULL) return 1; /* module not found in this path */ + return checkload(L, (loadfunc(L, filename, name) == 0), filename); } @@ -415,12 +421,16 @@ static int loader_Croot (lua_State *L) { filename = findfile(L, lua_tostring(L, -1), "cpath"); if (filename == NULL) return 1; /* root not found */ if ((stat = loadfunc(L, filename, name)) != 0) { - if (stat != ERRFUNC) loaderror(L, filename); /* real error */ - lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, - name, filename); - return 1; /* function not found */ + if (stat != ERRFUNC) + return checkload(L, 0, filename); /* real error */ + else { /* open function not found */ + lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, + name, filename); + return 1; + } } - return 1; + lua_pushstring(L, filename); /* will be 2nd argument to module */ + return 2; } @@ -453,16 +463,19 @@ static int ll_require (lua_State *L) { luaL_error(L, "module " LUA_QS " not found:%s", name, lua_tostring(L, -2)); lua_pushstring(L, name); - lua_call(L, 1, 1); /* call it */ - if (lua_isfunction(L, -1)) /* did it find module? */ + lua_call(L, 1, 2); /* call it */ + if (lua_isfunction(L, -2)) /* did it find module? */ break; /* module loaded successfully */ - else if (lua_isstring(L, -1)) /* loader returned error message? */ - lua_concat(L, 2); /* accumulate it */ + else if (lua_isstring(L, -2)) { /* loader returned error message? */ + lua_pop(L, 1); /* remove extra return */ + lua_concat(L, 2); /* accumulate error message */ + } else - lua_pop(L, 1); + lua_pop(L, 2); /* remove both returns */ } lua_pushstring(L, name); /* pass name as argument to module */ - lua_call(L, 1, 1); /* run loaded module */ + lua_insert(L, -2); /* name is 1st argument (before search data) */ + lua_call(L, 2, 1); /* run loaded module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_getfield(L, 2, name); @@ -639,10 +652,10 @@ LUAMOD_API int luaopen_package (lua_State *L) { LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); lua_setfield(L, -2, "config"); /* set field `loaded' */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED"); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); /* set field `preload' */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ diff --git a/src/lobject.c b/src/lobject.c index f5fc09d7b2..dcc487cad2 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.43 2010/10/29 15:54:55 roberto Exp $ +** $Id: lobject.c,v 2.49 2011/05/31 18:24:36 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -70,28 +70,6 @@ int luaO_ceillog2 (unsigned int x) { } -int luaO_rawequalObj (const TValue *t1, const TValue *t2) { - if (ttype(t1) != ttype(t2)) return 0; - else switch (ttype(t1)) { - case LUA_TNIL: - return 1; - case LUA_TNUMBER: - return luai_numeq(nvalue(t1), nvalue(t2)); - case LUA_TBOOLEAN: - return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ - case LUA_TLIGHTUSERDATA: - return pvalue(t1) == pvalue(t2); - case LUA_TSTRING: - return rawtsvalue(t1) == rawtsvalue(t2); - case LUA_TLCF: - return fvalue(t1) == fvalue(t2); - default: - lua_assert(iscollectable(t1)); - return gcvalue(t1) == gcvalue(t2); - } -} - - lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { switch (op) { case LUA_OPADD: return luai_numadd(NULL, v1, v2); @@ -106,19 +84,87 @@ lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { } -static int checkend (const char *s, const char *endptr) { - if (endptr == s) return 0; /* no characters converted */ - while (lisspace(cast(unsigned char, *endptr))) endptr++; - return (*endptr == '\0'); /* OK if no trailing characters */ +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else if (lisupper(c)) return c - 'A' + 10; + else return c - 'a' + 10; +} + + +#if !defined(lua_strx2number) + +#include + + +static int isneg (const char **s) { + if (**s == '-') { (*s)++; return 1; } + else if (**s == '+') (*s)++; + return 0; } -int luaO_str2d (const char *s, lua_Number *result) { +static lua_Number readhexa (const char **s, lua_Number r, int *count) { + while (lisxdigit(cast_uchar(**s))) { /* read integer part */ + r = (r * 16.0) + (double)luaO_hexavalue(*(*s)++); + (*count)++; + } + return r; +} + + +/* +** convert an hexadecimal numeric string to a number, following +** C99 specification for 'strtod' +*/ +static lua_Number lua_strx2number (const char *s, char **endptr) { + lua_Number r = 0.0; + int e = 0, i = 0; + int neg = 0; /* 1 if number is negative */ + *endptr = cast(char *, s); /* nothing is valid yet */ + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); /* check signal */ + if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ + return 0.0; /* invalid format (no '0x') */ + s += 2; /* skip '0x' */ + r = readhexa(&s, r, &i); /* read integer part */ + if (*s == '.') { + s++; /* skip dot */ + r = readhexa(&s, r, &e); /* read fractional part */ + } + if (i == 0 && e == 0) + return 0.0; /* invalid format (no digit) */ + e *= -4; /* each fractional digit divides value by 2^-4 */ + *endptr = cast(char *, s); /* valid up to here */ + if (*s == 'p' || *s == 'P') { /* exponent part? */ + int exp1 = 0; + int neg1; + s++; /* skip 'p' */ + neg1 = isneg(&s); /* signal */ + if (!lisdigit(cast_uchar(*s))) + goto ret; /* must have at least one digit */ + while (lisdigit(cast_uchar(*s))) /* read exponent */ + exp1 = exp1 * 10 + *(s++) - '0'; + if (neg1) exp1 = -exp1; + e += exp1; + } + *endptr = cast(char *, s); /* valid up to here */ + ret: + if (neg) r = -r; + return ldexp(r, e); +} + +#endif + + +int luaO_str2d (const char *s, size_t len, lua_Number *result) { char *endptr; - *result = lua_str2number(s, &endptr); - if (checkend(s, endptr)) return 1; /* conversion OK? */ - *result = cast_num(strtoul(s, &endptr, 0)); /* try hexadecimal */ - return checkend(s, endptr); + if (strpbrk(s, "xX")) /* hexa? */ + *result = lua_strx2number(s, &endptr); + else + *result = lua_str2number(s, &endptr); + if (endptr == s) return 0; /* nothing recognized */ + while (lisspace(cast_uchar(*endptr))) endptr++; + return (endptr == s + len); /* OK if no trailing characters */ } @@ -196,19 +242,20 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { } +/* number of chars of a literal string without the ending \0 */ +#define LL(x) (sizeof(x)/sizeof(char) - 1) -#define LL(x) (sizeof(x) - 1) #define RETS "..." #define PRE "[string \"" #define POS "\"]" -#define addstr(a,b,l) ( memcpy(a,b,l), a += (l) ) +#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) void luaO_chunkid (char *out, const char *source, size_t bufflen) { size_t l = strlen(source); if (*source == '=') { /* 'literal' source */ if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l); + memcpy(out, source + 1, l * sizeof(char)); else { /* truncate it */ addstr(out, source + 1, bufflen - 1); *out = '\0'; @@ -216,11 +263,11 @@ void luaO_chunkid (char *out, const char *source, size_t bufflen) { } else if (*source == '@') { /* file name */ if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l); + memcpy(out, source + 1, l * sizeof(char)); else { /* add '...' before rest of name */ addstr(out, RETS, LL(RETS)); bufflen -= LL(RETS); - memcpy(out, source + 1 + l - bufflen, bufflen); + memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); } } else { /* string; format as [string "source"] */ @@ -236,6 +283,7 @@ void luaO_chunkid (char *out, const char *source, size_t bufflen) { addstr(out, source, l); addstr(out, RETS, LL(RETS)); } - memcpy(out, POS, LL(POS) + 1); + memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); } } + diff --git a/src/lobject.h b/src/lobject.h index 5b856f3ce6..7f7a68307a 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.42 2010/07/26 15:53:23 roberto Exp $ +** $Id: lobject.h,v 2.60 2011/06/13 14:13:06 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -23,12 +23,38 @@ #define LUA_TUPVAL (LUA_NUMTAGS+1) #define LUA_TDEADKEY (LUA_NUMTAGS+2) +/* +** number of all possible tags (including LUA_TNONE but excluding DEADKEY) +*/ +#define LUA_TOTALTAGS (LUA_TUPVAL+2) + + +/* +** tags for Tagged Values have the following use of bits: +** bits 0-3: actual tag (a LUA_T* value) +** bits 4-5: variant bits +** bit 6: whether value is collectable +*/ /* -** Variant tag for light C functions (negative to be considered -** non collectable by 'iscollectable') +** LUA_TFUNCTION variants: +** 0 - Lua function +** 1 - light C function +** 2 - regular C function (closure) */ -#define LUA_TLCF (~0x0F | LUA_TFUNCTION) + +/* Variant tags for functions */ +#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */ +#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */ +#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ + + +/* Bit mark for collectable types */ +#define BIT_ISCOLLECTABLE (1 << 6) + +/* mark a tag as collectable */ +#define ctb(t) ((t) | BIT_ISCOLLECTABLE) + /* ** Union of all collectable objects @@ -55,13 +81,10 @@ typedef struct GCheader { /* ** Union of all Lua values */ -typedef union { - GCObject *gc; /* collectable objects */ - void *p; /* light userdata */ - lua_Number n; /* numbers */ - int b; /* booleans */ - lua_CFunction f; /* light C functions */ -} Value; +typedef union Value Value; + + +#define numfield lua_Number n; /* numbers */ @@ -72,125 +95,143 @@ typedef union { #define TValuefields Value value_; int tt_ -typedef struct lua_TValue { - TValuefields; -} TValue; +typedef struct lua_TValue TValue; /* macro defining a nil value */ -#define NILCONSTANT {NULL}, LUA_TNIL +#define NILCONSTANT {NULL}, LUA_TNIL -/* -** type tag of a TValue -*/ -#define ttype(o) ((o)->tt_) +#define val_(o) ((o)->value_) +#define num_(o) (val_(o).n) -/* -** type tag of a TValue with no variants -*/ -#define ttypenv(o) (ttype(o) & 0x0F) +/* raw type tag of a TValue */ +#define rttype(o) ((o)->tt_) + +/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ +#define ttype(o) (rttype(o) & 0x3F) + + +/* type tag of a TValue with no variants (bits 0-3) */ +#define ttypenv(o) (rttype(o) & 0x0F) /* Macros to test type */ -#define ttisnil(o) (ttype(o) == LUA_TNIL) -#define ttisnumber(o) (ttype(o) == LUA_TNUMBER) -#define ttisstring(o) (ttype(o) == LUA_TSTRING) -#define ttistable(o) (ttype(o) == LUA_TTABLE) -#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION) -#define ttisclosure(o) (ttype(o) == LUA_TFUNCTION) -#define ttislcf(o) (ttype(o) == LUA_TLCF) -#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) -#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) -#define ttisthread(o) (ttype(o) == LUA_TTHREAD) -#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) -#define ttisdeadkey(o) (ttype(o) == LUA_TDEADKEY) +#define checktag(o,t) (rttype(o) == (t)) +#define ttisnumber(o) checktag((o), LUA_TNUMBER) +#define ttisnil(o) checktag((o), LUA_TNIL) +#define ttisboolean(o) checktag((o), LUA_TBOOLEAN) +#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) +#define ttisstring(o) checktag((o), ctb(LUA_TSTRING)) +#define ttistable(o) checktag((o), ctb(LUA_TTABLE)) +#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION) +#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION) +#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) +#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) +#define ttislcf(o) checktag((o), LUA_TLCF) +#define ttisuserdata(o) checktag((o), ctb(LUA_TUSERDATA)) +#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) +#define ttisdeadkey(o) checktag((o), ctb(LUA_TDEADKEY)) + +#define ttisequal(o1,o2) (rttype(o1) == rttype(o2)) /* Macros to access values */ -#define gcvalue(o) check_exp(iscollectable(o), (o)->value_.gc) -#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value_.p) -#define nvalue(o) check_exp(ttisnumber(o), (o)->value_.n) -#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value_.gc->ts) +#define nvalue(o) check_exp(ttisnumber(o), num_(o)) +#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) +#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) +#define rawtsvalue(o) check_exp(ttisstring(o), &val_(o).gc->ts) #define tsvalue(o) (&rawtsvalue(o)->tsv) -#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value_.gc->u) +#define rawuvalue(o) check_exp(ttisuserdata(o), &val_(o).gc->u) #define uvalue(o) (&rawuvalue(o)->uv) -#define clvalue(o) check_exp(ttisclosure(o), &(o)->value_.gc->cl) -#define fvalue(o) check_exp(ttislcf(o), (o)->value_.f) -#define hvalue(o) check_exp(ttistable(o), &(o)->value_.gc->h) -#define bvalue(o) check_exp(ttisboolean(o), (o)->value_.b) -#define thvalue(o) check_exp(ttisthread(o), &(o)->value_.gc->th) +#define clvalue(o) check_exp(ttisclosure(o), &val_(o).gc->cl) +#define clLvalue(o) check_exp(ttisLclosure(o), &val_(o).gc->cl.l) +#define clCvalue(o) check_exp(ttisCclosure(o), &val_(o).gc->cl.c) +#define fvalue(o) check_exp(ttislcf(o), val_(o).f) +#define hvalue(o) check_exp(ttistable(o), &val_(o).gc->h) +#define bvalue(o) check_exp(ttisboolean(o), val_(o).b) +#define thvalue(o) check_exp(ttisthread(o), &val_(o).gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) -#define iscollectable(o) (ttype(o) >= LUA_TSTRING) +#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) /* Macros for internal tests */ -#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) - -#define checkconsistency(obj) lua_assert(!iscollectable(obj) || righttt(obj)) +#define righttt(obj) (ttypenv(obj) == gcvalue(obj)->gch.tt) #define checkliveness(g,obj) \ - lua_assert(!iscollectable(obj) || (righttt(obj) && !isdead(g,gcvalue(obj)))) + lua_longassert(!iscollectable(obj) || \ + (righttt(obj) && !isdead(g,gcvalue(obj)))) /* Macros to set values */ -#define setnilvalue(obj) ((obj)->tt_=LUA_TNIL) +#define settt_(o,t) ((o)->tt_=(t)) #define setnvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value_.n=(x); i_o->tt_=LUA_TNUMBER; } + { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); } -#define setfvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value_.f=(x); i_o->tt_=LUA_TLCF; } +#define changenvalue(o,x) check_exp(ttisnumber(o), num_(o)=(x)) -#define changenvalue(o,x) check_exp((o)->tt_==LUA_TNUMBER, (o)->value_.n=(x)) +#define setnilvalue(obj) settt_(obj, LUA_TNIL) + +#define setfvalue(obj,x) \ + { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); } #define setpvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value_.p=(x); i_o->tt_=LUA_TLIGHTUSERDATA; } + { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } #define setbvalue(obj,x) \ - { TValue *i_o=(obj); i_o->value_.b=(x); i_o->tt_=LUA_TBOOLEAN; } + { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } + +#define setgcovalue(L,obj,x) \ + { TValue *io=(obj); GCObject *i_g=(x); \ + val_(io).gc=i_g; settt_(io, ctb(gch(i_g)->tt)); } #define setsvalue(L,obj,x) \ - { TValue *i_o=(obj); \ - i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TSTRING; \ - checkliveness(G(L),i_o); } + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TSTRING)); \ + checkliveness(G(L),io); } #define setuvalue(L,obj,x) \ - { TValue *i_o=(obj); \ - i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TUSERDATA; \ - checkliveness(G(L),i_o); } + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \ + checkliveness(G(L),io); } #define setthvalue(L,obj,x) \ - { TValue *i_o=(obj); \ - i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTHREAD; \ - checkliveness(G(L),i_o); } + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTHREAD)); \ + checkliveness(G(L),io); } + +#define setclLvalue(L,obj,x) \ + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \ + checkliveness(G(L),io); } -#define setclvalue(L,obj,x) \ - { TValue *i_o=(obj); \ - i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TFUNCTION; \ - checkliveness(G(L),i_o); } +#define setclCvalue(L,obj,x) \ + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \ + checkliveness(G(L),io); } #define sethvalue(L,obj,x) \ - { TValue *i_o=(obj); \ - i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TTABLE; \ - checkliveness(G(L),i_o); } + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ + checkliveness(G(L),io); } #define setptvalue(L,obj,x) \ - { TValue *i_o=(obj); \ - i_o->value_.gc=cast(GCObject *, (x)); i_o->tt_=LUA_TPROTO; \ - checkliveness(G(L),i_o); } + { TValue *io=(obj); \ + val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \ + checkliveness(G(L),io); } -#define setdeadvalue(obj) ((obj)->tt_=LUA_TDEADKEY) +#define setdeadvalue(obj) settt_(obj, ctb(LUA_TDEADKEY)) #define setobj(L,obj1,obj2) \ - { const TValue *o2=(obj2); TValue *o1=(obj1); \ - o1->value_ = o2->value_; o1->tt_=o2->tt_; \ - checkliveness(G(L),o1); } + { const TValue *io2=(obj2); TValue *io1=(obj1); \ + io1->value_ = io2->value_; io1->tt_ = io2->tt_; \ + checkliveness(G(L),io1); } /* @@ -214,9 +255,121 @@ typedef struct lua_TValue { + +/* +** {====================================================== +** NaN Trick +** ======================================================= +*/ + +#if defined(LUA_NANTRICKLE) || defined(LUA_NANTRICKBE) + +/* +** numbers are represented in the 'd_' field. All other values have the +** value (NNMARK | tag) in 'tt_'. A number with such pattern would be +** a "signaled NaN", which is never generated by regular operations by +** the CPU (nor by 'strtod') +*/ +#if !defined(NNMARK) +#define NNMARK 0x7FF7A500 +#endif + +#undef TValuefields +#if defined(LUA_NANTRICKLE) +/* little endian */ +#define TValuefields \ + union { struct { Value v_; int tt_; } i; double d_; } u +#else +/* big endian */ +#define TValuefields \ + union { struct { int tt_; Value v_; } i; double d_; } u +#endif + +#undef numfield +#define numfield /* no such field; numbers are the entire struct */ + +/* basic check to distinguish numbers from non-numbers */ +#undef ttisnumber +#define ttisnumber(o) (((o)->u.i.tt_ & 0x7fffff00) != NNMARK) + +#define tag2tt(t) (NNMARK | (t)) + +#undef NILCONSTANT +#define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}} + +#undef val_ +#define val_(o) ((o)->u.i.v_) +#undef num_ +#define num_(o) ((o)->u.d_) + +#undef rttype +#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : (o)->u.i.tt_ & 0xff) + +#undef settt_ +#define settt_(o,t) ((o)->u.i.tt_=tag2tt(t)) + +#undef setnvalue +#define setnvalue(obj,x) \ + { TValue *io_=(obj); num_(io_)=(x); lua_assert(ttisnumber(io_)); } + +#undef setobj +#define setobj(L,obj1,obj2) \ + { const TValue *o2_=(obj2); TValue *o1_=(obj1); \ + o1_->u = o2_->u; \ + checkliveness(G(L),o1_); } + + +/* +** these redefinitions are not mandatory, but these forms are more efficient +*/ + +#undef checktag +#define checktag(o,t) ((o)->u.i.tt_ == tag2tt(t)) + +#undef ttisequal +#define ttisequal(o1,o2) \ + (ttisnumber(o1) ? ttisnumber(o2) : ((o1)->u.i.tt_ == (o2)->u.i.tt_)) + + + +#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } + + +#else + +#define luai_checknum(L,o,c) { /* empty */ } + +#endif +/* }====================================================== */ + + + +/* +** {====================================================== +** types and prototypes +** ======================================================= +*/ + + +union Value { + GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + int b; /* booleans */ + lua_CFunction f; /* light C functions */ + numfield /* numbers */ +}; + + +struct lua_TValue { + TValuefields; +}; + + typedef TValue *StkId; /* index to stack elements */ + + /* ** Header for string value; string bytes follow the end of this structure */ @@ -226,7 +379,7 @@ typedef union TString { CommonHeader; lu_byte reserved; unsigned int hash; - size_t len; + size_t len; /* number of characters in string */ } tsv; } TString; @@ -247,7 +400,7 @@ typedef union Udata { CommonHeader; struct Table *metatable; struct Table *env; - size_t len; + size_t len; /* number of bytes */ } uv; } Udata; @@ -346,9 +499,9 @@ typedef union Closure { } Closure; -#define isLfunction(o) (ttisclosure(o) && !clvalue(o)->c.isC) +#define isLfunction(o) ttisLclosure(o) -#define getproto(o) (clvalue(o)->l.p) +#define getproto(o) (clLvalue(o)->p) /* @@ -403,12 +556,13 @@ typedef struct Table { LUAI_DDEC const TValue luaO_nilobject_; + LUAI_FUNC int luaO_int2fb (unsigned int x); LUAI_FUNC int luaO_fb2int (int x); -LUAI_FUNC int luaO_ceillog2 (lu_int32 x); +LUAI_FUNC int luaO_ceillog2 (unsigned int x); LUAI_FUNC lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2); -LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); -LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); +LUAI_FUNC int luaO_str2d (const char *s, size_t len, lua_Number *result); +LUAI_FUNC int luaO_hexavalue (int c); LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); diff --git a/src/lopcodes.c b/src/lopcodes.c index af26722400..2e34676687 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.44 2010/10/13 16:45:54 roberto Exp $ +** $Id: lopcodes.c,v 1.48 2011/04/19 16:22:13 roberto Exp $ ** See Copyright Notice in lua.h */ @@ -16,6 +16,7 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", + "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", @@ -50,7 +51,6 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "TFORCALL", "TFORLOOP", "SETLIST", - "CLOSE", "CLOSURE", "VARARG", "EXTRAARG", @@ -64,8 +64,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { /* T A B C mode opcode */ opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ @@ -88,7 +89,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ - ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ + ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ @@ -98,7 +99,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ - ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ diff --git a/src/lopcodes.h b/src/lopcodes.h index af1dc9cd7f..01c69bdb27 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.137 2010/10/25 12:24:55 roberto Exp $ +** $Id: lopcodes.h,v 1.141 2011/04/19 16:22:13 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -167,9 +167,10 @@ typedef enum { name args description ------------------------------------------------------------------------*/ OP_MOVE,/* A B R(A) := R(B) */ -OP_LOADK,/* A Bx R(A) := Kst(Bx - 1) */ +OP_LOADK,/* A Bx R(A) := Kst(Bx) */ +OP_LOADKX,/* A R(A) := Kst(extra arg) */ OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ -OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ +OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */ OP_GETUPVAL,/* A B R(A) := UpValue[B] */ OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */ @@ -195,8 +196,7 @@ OP_LEN,/* A B R(A) := length of R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ -OP_JMP,/* sBx pc+=sBx */ - +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ @@ -217,7 +217,6 @@ OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/ OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ -OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ @@ -244,7 +243,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next 'instruction' is EXTRAARG(real C). - (*) In OP_LOADK, if (Bx == 0) then next 'instruction' is EXTRAARG(real Bx). + (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. (*) For comparisons, A specifies what condition the test should accept (true or false). diff --git a/src/loslib.c b/src/loslib.c index 0278eb5147..2ce9902f45 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.32 2010/10/05 12:18:03 roberto Exp $ +** $Id: loslib.c,v 1.34 2011/03/03 16:34:46 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -59,37 +59,28 @@ -static int os_pushresult (lua_State *L, int i, const char *filename) { - int en = errno; /* calls to Lua API may change this value */ - if (i) { - lua_pushboolean(L, 1); - return 1; - } +static int os_execute (lua_State *L) { + const char *cmd = luaL_optstring(L, 1, NULL); + int stat = system(cmd); + if (cmd != NULL) + return luaL_execresult(L, stat); else { - lua_pushnil(L); - lua_pushfstring(L, "%s: %s", filename, strerror(en)); - lua_pushinteger(L, en); - return 3; + lua_pushboolean(L, stat); /* true if there is a shell */ + return 1; } } -static int os_execute (lua_State *L) { - lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); - return 1; -} - - static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); - return os_pushresult(L, remove(filename) == 0, filename); + return luaL_fileresult(L, remove(filename) == 0, filename); } static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); - return os_pushresult(L, rename(fromname, toname) == 0, fromname); + return luaL_fileresult(L, rename(fromname, toname) == 0, fromname); } @@ -182,7 +173,7 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) { return conv; /* to avoid warnings */ } - + static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); diff --git a/src/lparser.c b/src/lparser.c index 3524b9b2e6..225e022eba 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.92 2010/09/07 19:21:39 roberto Exp $ +** $Id: lparser.c,v 2.109 2011/05/02 17:33:01 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -41,10 +41,11 @@ */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ - int breaklist; /* list of jumps out of this loop */ - lu_byte nactvar; /* # active locals outside the breakable structure */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ + lu_byte nactvar; /* # active locals outside the block */ lu_byte upval; /* true if some variable in the block is an upvalue */ - lu_byte isbreakable; /* true if `block' is a loop */ + lu_byte isloop; /* true if `block' is a loop */ } BlockCnt; @@ -52,7 +53,7 @@ typedef struct BlockCnt { /* ** prototypes for recursive non-terminal functions */ -static void chunk (LexState *ls); +static void statement (LexState *ls); static void expr (LexState *ls, expdesc *v); @@ -66,6 +67,13 @@ static void anchor_token (LexState *ls) { } +/* semantic error */ +static void semerror (LexState *ls, const char *msg) { + ls->t.token = 0; /* remove 'near to' from final message */ + luaX_syntaxerror(ls, msg); +} + + static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); @@ -103,6 +111,7 @@ static void check (LexState *ls, int c) { error_expected(ls, c); } + static void checknext (LexState *ls, int c) { check(ls, c); luaX_next(ls); @@ -167,13 +176,13 @@ static int registerlocalvar (LexState *ls, TString *varname) { static void new_localvar (LexState *ls, TString *name) { FuncState *fs = ls->fs; - Varlist *vl = ls->varl; + Dyndata *dyd = ls->dyd; int reg = registerlocalvar(ls, name); - checklimit(fs, vl->nactvar + 1 - fs->firstlocal, + checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, MAXVARS, "local variables"); - luaM_growvector(ls->L, vl->actvar, vl->nactvar + 1, - vl->actvarsize, vardesc, MAX_INT, "local variables"); - vl->actvar[vl->nactvar++].idx = cast(unsigned short, reg); + luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, + dyd->actvar.size, Vardesc, MAX_INT, "local variables"); + dyd->actvar.arr[dyd->actvar.n++].idx = cast(unsigned short, reg); } @@ -186,7 +195,7 @@ static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { static LocVar *getlocvar (FuncState *fs, int i) { - int idx = fs->ls->varl->actvar[fs->firstlocal + i].idx; + int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; lua_assert(idx < fs->nlocvars); return &fs->f->locvars[idx]; } @@ -202,7 +211,7 @@ static void adjustlocalvars (LexState *ls, int nvars) { static void removevars (FuncState *fs, int tolevel) { - fs->ls->varl->nactvar -= (fs->nactvar - tolevel); + fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); while (fs->nactvar > tolevel) getlocvar(fs, --fs->nactvar)->endpc = fs->pc; } @@ -245,12 +254,12 @@ static int searchvar (FuncState *fs, TString *n) { /* Mark block where variable at given level was defined - (to emit OP_CLOSE later). + (to emit close instructions later). */ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; - while (bl && bl->nactvar > level) bl = bl->previous; - if (bl) bl->upval = 1; + while (bl->nactvar > level) bl = bl->previous; + bl->upval = 1; } @@ -327,10 +336,107 @@ static void enterlevel (LexState *ls) { #define leavelevel(ls) (G((ls)->L)->nCcalls--) -static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { - bl->breaklist = NO_JUMP; - bl->isbreakable = isbreakable; +static void closegoto (LexState *ls, int g, Labeldesc *label) { + int i; + FuncState *fs = ls->fs; + Labellist *gl = &ls->dyd->gt; + Labeldesc *gt = &gl->arr[g]; + lua_assert(eqstr(gt->name, label->name)); + if (gt->nactvar < label->nactvar) { + const char *msg = luaO_pushfstring(ls->L, + " at line %d jumps into the scope of local " LUA_QS, + getstr(gt->name), gt->line, getstr(getlocvar(fs, gt->nactvar)->varname)); + semerror(ls, msg); + } + luaK_patchlist(fs, gt->pc, label->pc); + /* remove goto from pending list */ + for (i = g; i < gl->n - 1; i++) + gl->arr[i] = gl->arr[i + 1]; + gl->n--; +} + + +/* +** try to close a goto with existing labels; this solves backward jumps +*/ +static int findlabel (LexState *ls, int g) { + int i; + BlockCnt *bl = ls->fs->bl; + Dyndata *dyd = ls->dyd; + Labeldesc *gt = &dyd->gt.arr[g]; + /* check labels in current block for a match */ + for (i = bl->firstlabel; i < dyd->label.n; i++) { + Labeldesc *lb = &dyd->label.arr[i]; + if (eqstr(lb->name, gt->name)) { /* correct label? */ + if (gt->nactvar > lb->nactvar && + (bl->upval || dyd->label.n > bl->firstlabel)) + luaK_patchclose(ls->fs, gt->pc, lb->nactvar); + closegoto(ls, g, lb); /* close it */ + return 1; + } + } + return 0; /* label not found; cannot close goto */ +} + + +static int newlabelentry (LexState *ls, Labellist *l, TString *name, + int line, int pc) { + int n = l->n; + luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, MAX_INT, "labels"); + l->arr[n].name = name; + l->arr[n].line = line; + l->arr[n].nactvar = ls->fs->nactvar; + l->arr[n].pc = pc; + l->n++; + return n; +} + + +/* +** check whether new label 'lb' matches any pending gotos in current +** block; solves forward jumps +*/ +static void findgotos (LexState *ls, Labeldesc *lb) { + Labellist *gl = &ls->dyd->gt; + int i = ls->fs->bl->firstgoto; + while (i < gl->n) { + if (eqstr(gl->arr[i].name, lb->name)) + closegoto(ls, i, lb); + else + i++; + } +} + + +/* +** "export" pending gotos to outer level, to check them against +** outer labels; if the block being exited has upvalues, and +** the goto exists the scope of any variable (which can be the +** upvalue), close those variables being exited. +*/ +static void movegotosout (FuncState *fs, BlockCnt *bl) { + int i = bl->firstgoto; + Labellist *gl = &fs->ls->dyd->gt; + /* correct pending gotos to current block and try to close it + with visible labels */ + while (i < gl->n) { + Labeldesc *gt = &gl->arr[i]; + if (gt->nactvar > bl->nactvar) { + if (bl->upval) + luaK_patchclose(fs, gt->pc, bl->nactvar); + gt->nactvar = bl->nactvar; + } + if (!findlabel(fs->ls, i)) + i++; /* move to next one */ + } +} + + +static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { + bl->isloop = isloop; bl->nactvar = fs->nactvar; + bl->firstlabel = fs->ls->dyd->label.n; + bl->firstgoto = fs->ls->dyd->gt.n; bl->upval = 0; bl->previous = fs->bl; fs->bl = bl; @@ -338,17 +444,48 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { } +/* +** create a label named "break" to resolve break statements +*/ +static void breaklabel (LexState *ls) { + TString *n = luaS_new(ls->L, "break"); + int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); + findgotos(ls, &ls->dyd->label.arr[l]); +} + +/* +** generates an error for an undefined 'goto'; choose appropriate +** message when label name is a reserved word (which can only be 'break') +*/ +static void undefgoto (LexState *ls, Labeldesc *gt) { + const char *msg = (gt->name->tsv.reserved > 0) + ? "<%s> at line %d not inside a loop" + : "label " LUA_QS " ( at line %d) undefined"; + msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); + semerror(ls, msg); +} + + static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; + LexState *ls = fs->ls; + if (bl->previous && bl->upval) { + /* create a 'jump to here' to close upvalues */ + int j = luaK_jump(fs); + luaK_patchclose(fs, j, bl->nactvar); + luaK_patchtohere(fs, j); + } + if (bl->isloop) + breaklabel(ls); /* close pending breaks */ fs->bl = bl->previous; removevars(fs, bl->nactvar); - if (bl->upval) - luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); - /* a block either controls scope or breaks (never both) */ - lua_assert(!bl->isbreakable || !bl->upval); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ - luaK_patchtohere(fs, bl->breaklist); + ls->dyd->label.n = bl->firstlabel; /* remove local labels */ + if (bl->previous) /* inner block? */ + movegotosout(fs, bl); /* update pending gotos to outer block */ + else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ + undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ } @@ -368,10 +505,11 @@ static void codeclosure (LexState *ls, Proto *clp, expdesc *v) { f->p[fs->np++] = clp; luaC_objbarrier(ls->L, f, clp); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); + luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */ } -static void open_func (LexState *ls, FuncState *fs) { +static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { lua_State *L = ls->L; Proto *f; fs->prev = ls->fs; /* linked list of funcstates */ @@ -387,7 +525,7 @@ static void open_func (LexState *ls, FuncState *fs) { fs->nups = 0; fs->nlocvars = 0; fs->nactvar = 0; - fs->firstlocal = ls->varl->nactvar; + fs->firstlocal = ls->dyd->actvar.n; fs->bl = NULL; f = luaF_newproto(L); fs->f = f; @@ -400,6 +538,7 @@ static void open_func (LexState *ls, FuncState *fs) { /* anchor table of constants (to avoid being collected) */ sethvalue2s(L, L->top, fs->h); incr_top(L); + enterblock(fs, bl, 0); } @@ -408,7 +547,7 @@ static void close_func (LexState *ls) { FuncState *fs = ls->fs; Proto *f = fs->f; luaK_ret(fs, 0, 0); /* final return */ - removevars(fs, 0); + leaveblock(fs); luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); @@ -435,42 +574,49 @@ static void close_func (LexState *ls) { ** opens the main function, which is a regular vararg function with an ** upvalue named LUA_ENV */ -static void open_mainfunc (LexState *ls, FuncState *fs) { +static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) { expdesc v; - open_func(ls, fs); + open_func(ls, fs, bl); fs->f->is_vararg = 1; /* main function is always vararg */ init_exp(&v, VLOCAL, 0); newupvalue(fs, ls->envn, &v); /* create environment upvalue */ } -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl, - const char *name) { - LexState lexstate; - FuncState funcstate; - TString *tname = luaS_new(L, name); - setsvalue2s(L, L->top, tname); /* push name to protect it */ - incr_top(L); - lexstate.buff = buff; - lexstate.varl = varl; - luaX_setinput(L, &lexstate, z, tname); - open_mainfunc(&lexstate, &funcstate); - luaX_next(&lexstate); /* read first token */ - chunk(&lexstate); /* read main chunk */ - check(&lexstate, TK_EOS); - close_func(&lexstate); - L->top--; /* pop name */ - lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); - return funcstate.f; -} - - /*============================================================*/ /* GRAMMAR RULES */ /*============================================================*/ +/* +** check whether current token is in the follow set of a block. +** 'until' closes syntactical blocks, but do not close scope, +** so it handled in separate. +*/ +static int block_follow (LexState *ls, int withuntil) { + switch (ls->t.token) { + case TK_ELSE: case TK_ELSEIF: + case TK_END: case TK_EOS: + return 1; + case TK_UNTIL: return withuntil; + default: return 0; + } +} + + +static void statlist (LexState *ls) { + /* statlist -> { stat [`;'] } */ + while (!block_follow(ls, 1)) { + if (ls->t.token == TK_RETURN) { + statement(ls); + return; /* 'return' must be last statement */ + } + statement(ls); + } +} + + static void fieldsel (LexState *ls, expdesc *v) { /* fieldsel -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; @@ -586,7 +732,7 @@ static void field (LexState *ls, struct ConsControl *cc) { static void constructor (LexState *ls, expdesc *t) { - /* constructor -> '{' [ field { sep field } [sep] ] '}' + /* constructor -> '{' [ field { sep field } [sep] ] '}' sep -> ',' | ';' */ FuncState *fs = ls->fs; int line = ls->linenumber; @@ -596,7 +742,7 @@ static void constructor (LexState *ls, expdesc *t) { cc.t = t; init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ - luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ + luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); @@ -643,19 +789,20 @@ static void parlist (LexState *ls) { } -static void body (LexState *ls, expdesc *e, int needself, int line) { - /* body -> `(' parlist `)' chunk END */ +static void body (LexState *ls, expdesc *e, int ismethod, int line) { + /* body -> `(' parlist `)' block END */ FuncState new_fs; - open_func(ls, &new_fs); + BlockCnt bl; + open_func(ls, &new_fs, &bl); new_fs.f->linedefined = line; checknext(ls, '('); - if (needself) { - new_localvarliteral(ls, "self"); + if (ismethod) { + new_localvarliteral(ls, "self"); /* create 'self' parameter */ adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); - chunk(ls); + statlist(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); codeclosure(ls, new_fs.f, e); @@ -663,8 +810,8 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { } -static int explist1 (LexState *ls, expdesc *v) { - /* explist1 -> expr { `,' expr } */ +static int explist (LexState *ls, expdesc *v) { + /* explist -> expr { `,' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { @@ -681,12 +828,12 @@ static void funcargs (LexState *ls, expdesc *f, int line) { expdesc args; int base, nparams; switch (ls->t.token) { - case '(': { /* funcargs -> `(' [ explist1 ] `)' */ + case '(': { /* funcargs -> `(' [ explist ] `)' */ luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { - explist1(ls, &args); + explist(ls, &args); luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); @@ -937,23 +1084,12 @@ static void expr (LexState *ls, expdesc *v) { */ -static int block_follow (int token) { - switch (token) { - case TK_ELSE: case TK_ELSEIF: case TK_END: - case TK_UNTIL: case TK_EOS: - return 1; - default: return 0; - } -} - - static void block (LexState *ls) { - /* block -> chunk */ + /* block -> statlist */ FuncState *fs = ls->fs; BlockCnt bl; enterblock(fs, &bl, 0); - chunk(ls); - lua_assert(bl.breaklist == NO_JUMP); + statlist(ls); leaveblock(fs); } @@ -1012,10 +1148,10 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { "variable names"); assignment(ls, &nv, nvars+1); } - else { /* assignment -> `=' explist1 */ + else { /* assignment -> `=' explist */ int nexps; checknext(ls, '='); - nexps = explist1(ls, &e); + nexps = explist(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); if (nexps > nvars) @@ -1042,19 +1178,38 @@ static int cond (LexState *ls) { } -static void breakstat (LexState *ls) { +static void gotostat (LexState *ls, TString *label, int line) { + /* create new entry for this goto */ + int g = newlabelentry(ls, &ls->dyd->gt, label, line, luaK_jump(ls->fs)); + findlabel(ls, g); +} + + +static void labelstat (LexState *ls, TString *label, int line) { + /* label -> '@' NAME ':' */ FuncState *fs = ls->fs; - BlockCnt *bl = fs->bl; - int upval = 0; - while (bl && !bl->isbreakable) { - upval |= bl->upval; - bl = bl->previous; + Labellist *ll = &ls->dyd->label; + int l, i; /* index of new label being created */ + /* check for repeated labels on the same block */ + for (i = ls->fs->bl->firstlabel; i < ll->n; i++) { + if (eqstr(label, ll->arr[i].name)) { + const char *msg = luaO_pushfstring(ls->L, + "label " LUA_QS " already defined on line %d", + getstr(label), ll->arr[i].line); + semerror(ls, msg); + } } - if (!bl) - luaX_syntaxerror(ls, "no loop to break"); - if (upval) - luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); - luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); + checknext(ls, ':'); /* skip colon */ + /* create new entry for this label */ + l = newlabelentry(ls, ll, label, line, fs->pc); + /* skip other no-op statements */ + while (ls->t.token == ';' || ls->t.token == '@') + statement(ls); + if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ + /* assume that locals are already out of scope */ + ll->arr[l].nactvar = fs->bl->nactvar; + } + findgotos(ls, &ll->arr[l]); } @@ -1086,19 +1241,13 @@ static void repeatstat (LexState *ls, int line) { enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ - chunk(ls); + statlist(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ - if (!bl2.upval) { /* no upvalues? */ - leaveblock(fs); /* finish scope */ - luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ - } - else { /* complete semantics when there are upvalues */ - breakstat(ls); /* if condition then break */ - luaK_patchtohere(ls->fs, condexit); /* else... */ - leaveblock(fs); /* finish scope... */ - luaK_jumpto(fs, repeat_init); /* and repeat */ - } + if (bl2.upval) /* upvalues? */ + luaK_patchclose(fs, condexit, bl2.nactvar); + leaveblock(fs); /* finish scope */ + luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ leaveblock(fs); /* finish loop */ } @@ -1163,7 +1312,7 @@ static void fornum (LexState *ls, TString *varname, int line) { static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist1 forbody */ + /* forlist -> NAME {,NAME} IN explist forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 4; /* gen, state, control, plus at least one declared var */ @@ -1181,7 +1330,7 @@ static void forlist (LexState *ls, TString *indexname) { } checknext(ls, TK_IN); line = ls->linenumber; - adjust_assign(ls, 3, explist1(ls, &e), &e); + adjust_assign(ls, 3, explist(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 3, 0); } @@ -1241,19 +1390,20 @@ static void ifstat (LexState *ls, int line) { static void localfunc (LexState *ls) { - expdesc v, b; + expdesc b; FuncState *fs = ls->fs; - new_localvar(ls, str_checkname(ls)); - init_exp(&v, VLOCAL, fs->freereg); - luaK_reserveregs(fs, 1); - adjustlocalvars(ls, 1); - body(ls, &b, 0, ls->linenumber); - luaK_storevar(fs, &v, &b); + int varidx = fs->nactvar; /* index of new local variable */ + new_localvar(ls, str_checkname(ls)); /* new local variable */ + adjustlocalvars(ls, 1); /* enter its scope */ + body(ls, &b, 0, ls->linenumber); /* function created in next register */ + lua_assert(b.k == VNONRELOC && b.u.ind.idx == varidx); + /* debug information will only see the variable after this point! */ + getlocvar(fs, varidx)->startpc = fs->pc; } static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ + /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ int nvars = 0; int nexps; expdesc e; @@ -1262,7 +1412,7 @@ static void localstat (LexState *ls) { nvars++; } while (testnext(ls, ',')); if (testnext(ls, '=')) - nexps = explist1(ls, &e); + nexps = explist(ls, &e); else { e.k = VVOID; nexps = 0; @@ -1274,25 +1424,25 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {fieldsel} [`:' NAME] */ - int needself = 0; + int ismethod = 0; singlevar(ls, v); while (ls->t.token == '.') fieldsel(ls, v); if (ls->t.token == ':') { - needself = 1; + ismethod = 1; fieldsel(ls, v); } - return needself; + return ismethod; } static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ - int needself; + int ismethod; expdesc v, b; luaX_next(ls); /* skip FUNCTION */ - needself = funcname(ls, &v); - body(ls, &b, needself, line); + ismethod = funcname(ls, &v); + body(ls, &b, ismethod, line); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ } @@ -1313,14 +1463,14 @@ static void exprstat (LexState *ls) { static void retstat (LexState *ls) { - /* stat -> RETURN explist */ + /* stat -> RETURN [explist] [';'] */ FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ - if (block_follow(ls->t.token) || ls->t.token == ';') + if (block_follow(ls, 1) || ls->t.token == ';') first = nret = 0; /* return no values */ else { - nret = explist1(ls, &e); /* optional return values */ + nret = explist(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ @@ -1341,41 +1491,43 @@ static void retstat (LexState *ls) { } } luaK_ret(fs, first, nret); + testnext(ls, ';'); /* skip optional semicolon */ } -static int statement (LexState *ls) { +static void statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ + enterlevel(ls); switch (ls->t.token) { case ';': { /* stat -> ';' (empty statement) */ luaX_next(ls); /* skip ';' */ - return 0; + break; } case TK_IF: { /* stat -> ifstat */ ifstat(ls, line); - return 0; + break; } case TK_WHILE: { /* stat -> whilestat */ whilestat(ls, line); - return 0; + break; } case TK_DO: { /* stat -> DO block END */ luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); - return 0; + break; } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); - return 0; + break; } case TK_REPEAT: { /* stat -> repeatstat */ repeatstat(ls, line); - return 0; + break; } case TK_FUNCTION: { /* stat -> funcstat */ funcstat(ls, line); - return 0; + break; } case TK_LOCAL: { /* stat -> localstat */ luaX_next(ls); /* skip LOCAL */ @@ -1383,39 +1535,62 @@ static int statement (LexState *ls) { localfunc(ls); else localstat(ls); - return 0; + break; + } + case '@': { /* stat -> label */ + luaX_next(ls); /* skip '@' */ + labelstat(ls, str_checkname(ls), line); + break; } case TK_RETURN: { /* stat -> retstat */ luaX_next(ls); /* skip RETURN */ retstat(ls); - return 1; /* must be last statement */ + break; } case TK_BREAK: { /* stat -> breakstat */ luaX_next(ls); /* skip BREAK */ - breakstat(ls); - return 1; /* must be last statement */ + /* code it as "goto 'break'" */ + gotostat(ls, luaS_new(ls->L, "break"), line); + break; + } + case TK_GOTO: { /* stat -> 'goto' NAME */ + luaX_next(ls); /* skip GOTO */ + gotostat(ls, str_checkname(ls), line); + break; } default: { /* stat -> func | assignment */ exprstat(ls); - return 0; + break; } } + lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + ls->fs->freereg >= ls->fs->nactvar); + ls->fs->freereg = ls->fs->nactvar; /* free registers */ + leavelevel(ls); } +/* }====================================================================== */ -static void chunk (LexState *ls) { - /* chunk -> { stat [`;'] } */ - int islast = 0; - enterlevel(ls); - while (!islast && !block_follow(ls->t.token)) { - islast = statement(ls); - if (islast) - testnext(ls, ';'); - lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && - ls->fs->freereg >= ls->fs->nactvar); - ls->fs->freereg = ls->fs->nactvar; /* free registers */ - } - leavelevel(ls); + +Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { + LexState lexstate; + FuncState funcstate; + BlockCnt bl; + TString *tname = luaS_new(L, name); + setsvalue2s(L, L->top, tname); /* push name to protect it */ + incr_top(L); + lexstate.buff = buff; + lexstate.dyd = dyd; + dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; + luaX_setinput(L, &lexstate, z, tname, firstchar); + open_mainfunc(&lexstate, &funcstate, &bl); + luaX_next(&lexstate); /* read first token */ + statlist(&lexstate); /* main body */ + check(&lexstate, TK_EOS); + close_func(&lexstate); + L->top--; /* pop name */ + lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); + return funcstate.f; } -/* }====================================================================== */ diff --git a/src/lparser.h b/src/lparser.h index 6055a85bf6..4e7e06fc52 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.65 2010/07/07 16:27:29 roberto Exp $ +** $Id: lparser.h,v 1.68 2011/02/23 13:13:10 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -53,19 +53,42 @@ typedef struct expdesc { } expdesc; -typedef struct vardesc { - unsigned short idx; -} vardesc; +/* description of active local variable */ +typedef struct Vardesc { + unsigned short idx; /* variable index in stack */ +} Vardesc; -/* list of all active local variables */ -typedef struct Varlist { - vardesc *actvar; - int nactvar; - int actvarsize; -} Varlist; +/* description of pending goto statements and label statements */ +typedef struct Labeldesc { + TString *name; /* label identifier */ + int pc; /* position in code */ + int line; /* line where it appeared */ + lu_byte nactvar; /* local level where it appears in current block */ +} Labeldesc; +/* list of labels or gotos */ +typedef struct Labellist { + Labeldesc *arr; /* array */ + int n; /* number of entries in use */ + int size; /* array size */ +} Labellist; + + +/* dynamic structures used by the parser */ +typedef struct Dyndata { + struct { /* list of active local variables */ + Vardesc *arr; + int n; + int size; + } actvar; + Labellist gt; /* list of pending gotos */ + Labellist label; /* list of active labels */ +} Dyndata; + + +/* control of blocks */ struct BlockCnt; /* defined in lparser.c */ @@ -91,7 +114,7 @@ typedef struct FuncState { LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Varlist *varl, const char *name); + Dyndata *dyd, const char *name, int firstchar); #endif diff --git a/src/lstate.c b/src/lstate.c index 39a0ef4d43..45dac3c590 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.86 2010/09/03 14:14:01 roberto Exp $ +** $Id: lstate.c,v 2.89 2010/12/20 19:40:07 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -65,11 +65,14 @@ typedef struct LG { #define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) - /* -** maximum number of nested calls made by error-handling function +** set GCdebt to a new value keeping the value (totalbytes + GCdebt) +** invariant */ -#define LUAI_EXTRACALLS 10 +void luaE_setdebt (global_State *g, l_mem debt) { + g->totalbytes -= (debt - g->GCdebt); + g->GCdebt = debt; +} CallInfo *luaE_extendCI (lua_State *L) { @@ -154,7 +157,7 @@ static void f_luaopen (lua_State *L, void *ud) { /* pre-create memory-error message */ g->memerrmsg = luaS_newliteral(L, MEMERRMSG); luaS_fix(g->memerrmsg); /* it should never be collected */ - g->GCdebt = 0; + g->gcrunning = 1; /* allow gc */ } @@ -187,7 +190,7 @@ static void close_state (lua_State *L) { luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); luaZ_freebuffer(L, &g->buff); freestack(L); - lua_assert(g->totalbytes == sizeof(LG)); + lua_assert(gettotalbytes(g) == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); } @@ -241,7 +244,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->mainthread = L; g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; - stopgc(g); /* no GC while building state */ + g->gcrunning = 0; /* no GC while building state */ g->lastmajormem = 0; g->strt.size = 0; g->strt.nuse = 0; @@ -252,11 +255,12 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->version = lua_version(NULL); g->gcstate = GCSpause; g->allgc = NULL; - g->udgc = NULL; + g->finobj = NULL; g->tobefnz = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; g->totalbytes = sizeof(LG); + g->GCdebt = 0; g->gcpause = LUAI_GCPAUSE; g->gcmajorinc = LUAI_GCMAJOR; g->gcstepmul = LUAI_GCMUL; diff --git a/src/lstate.h b/src/lstate.h index bc64a4aece..9d21e7e8fe 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.68 2010/10/29 17:52:46 roberto Exp $ +** $Id: lstate.h,v 2.72 2011/06/02 19:31:40 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -32,9 +32,9 @@ ** when traversing the respective threads, but the thread may already be ** dead, while the upvalue is still accessible through closures.) ** -** Userdata with finalizers are kept in the list g->udgc. +** Objects with finalizers are kept in the list g->finobj. ** -** The list g->tobefnz links all userdata being finalized. +** The list g->tobefnz links all objects being finalized. */ @@ -104,7 +104,6 @@ typedef struct CallInfo { #define CIST_TAIL (1<<6) /* call was tail called */ -#define ci_func(ci) (clvalue((ci)->func)) #define isLua(ci) ((ci)->callstatus & CIST_LUA) @@ -114,8 +113,8 @@ typedef struct CallInfo { typedef struct global_State { lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ - lu_mem totalbytes; /* number of bytes currently allocated */ - l_mem GCdebt; /* when positive, run a GC step */ + lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ lu_mem lastmajormem; /* memory in use after last major collection */ stringtable strt; /* hash table for strings */ TValue l_registry; @@ -123,9 +122,10 @@ typedef struct global_State { lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ + lu_byte gcrunning; /* true if GC is running */ int sweepstrgc; /* position of sweep in `strt' */ GCObject *allgc; /* list of all collectable objects */ - GCObject *udgc; /* list of collectable userdata with finalizers */ + GCObject *finobj; /* list of collectable objects with finalizers */ GCObject **sweepgc; /* current position of sweep */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ @@ -209,6 +209,10 @@ union GCObject { #define obj2gco(v) (cast(GCObject *, (v))) +/* actual number of total bytes allocated */ +#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt) + +LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC void luaE_freeCI (lua_State *L); diff --git a/src/lstring.c b/src/lstring.c index 145621b697..adec415e78 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.18 2010/05/10 18:23:45 roberto Exp $ +** $Id: lstring.c,v 2.19 2011/05/03 16:01:57 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -84,8 +84,9 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { o != NULL; o = gch(o)->next) { TString *ts = rawgco2ts(o); - if (h == ts->tsv.hash && ts->tsv.len == l && - (memcmp(str, getstr(ts), l) == 0)) { + if (h == ts->tsv.hash && + ts->tsv.len == l && + (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ changewhite(o); /* resurrect it */ return ts; diff --git a/src/lstrlib.c b/src/lstrlib.c index 2491bbb4c4..369054fdcb 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.159 2010/11/19 16:25:51 roberto Exp $ +** $Id: lstrlib.c,v 1.168 2011/06/09 18:22:47 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -45,7 +45,7 @@ static int str_len (lua_State *L) { /* translate a relative string position: negative means back from end */ static size_t posrelat (ptrdiff_t pos, size_t len) { if (pos >= 0) return (size_t)pos; - else if (pos == -pos || (size_t)-pos > len) return 0; + else if (-(size_t)pos > len) return 0; else return len - ((size_t)-pos) + 1; } @@ -101,15 +101,29 @@ static int str_upper (lua_State *L) { return 1; } + +/* reasonable limit to avoid arithmetic overflow */ +#define MAXSIZE ((~(size_t)0) >> 1) + static int str_rep (lua_State *L) { - size_t l; - luaL_Buffer b; + size_t l, lsep; const char *s = luaL_checklstring(L, 1, &l); int n = luaL_checkint(L, 2); - luaL_buffinit(L, &b); - while (n-- > 0) - luaL_addlstring(&b, s, l); - luaL_pushresult(&b); + const char *sep = luaL_optlstring(L, 3, "", &lsep); + if (n <= 0) lua_pushliteral(L, ""); + else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */ + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = n * l + (n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + memcpy(p, sep, lsep * sizeof(char)); p += lsep; + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } return 1; } @@ -125,7 +139,7 @@ static int str_byte (lua_State *L) { if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); if (posi + n <= pose) /* overflow? */ - luaL_error(L, "string slice too long"); + return luaL_error(L, "string slice too long"); luaL_checkstack(L, n, "string slice too long"); for (i=0; i= sizeof(FLAGS)) + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ @@ -806,7 +820,7 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; - memcpy(form, strfrmt, p - strfrmt + 1); + memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); form += p - strfrmt + 1; *form = '\0'; return p; @@ -861,6 +875,9 @@ static int str_format (lua_State *L) { break; } case 'e': case 'E': case 'f': +#if defined(LUA_USE_AFORMAT) + case 'a': case 'A': +#endif case 'g': case 'G': { addlenmod(form, LUA_FLTFRMLEN); nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg)); @@ -872,16 +889,16 @@ static int str_format (lua_State *L) { } case 's': { size_t l; - const char *s = luaL_checklstring(L, arg, &l); + const char *s = luaL_tolstring(L, arg, &l); if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ - lua_pushvalue(L, arg); luaL_addvalue(&b); break; } else { nb = sprintf(buff, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ break; } } @@ -900,6 +917,15 @@ static int str_format (lua_State *L) { /* }====================================================== */ +static int noindex (lua_State *L) { + const char *f = lua_tostring(L, 2); + if (f) + return luaL_error(L, "no field '%s' in strings", f); + else + return luaL_error(L, "no such field in strings"); +} + + static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, @@ -915,19 +941,22 @@ static const luaL_Reg strlib[] = { {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, + {"__index", noindex}, {NULL, NULL} }; static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* create metatable for strings */ + /* setmetatable("", {__index = string}) */ lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); - lua_setmetatable(L, -2); /* set string metatable */ + lua_createtable(L, 0, 1); /* create metatable for strings */ + lua_pushvalue(L, -3); /* set the string library... */ + lua_setfield(L, -2, "__index"); /* ...as the __index metamethod */ + lua_setmetatable(L, -2); /* set metatable for strings */ lua_pop(L, 1); /* pop dummy string */ - lua_pushvalue(L, -2); /* string library... */ - lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ - lua_pop(L, 1); /* pop metatable */ + /* setmetatable(string, string) */ + lua_pushvalue(L, -1); /* push string library */ + lua_setmetatable(L, -2); /* set it as its own metatable */ } diff --git a/src/ltable.c b/src/ltable.c index 7ff0f89790..155c271681 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.53 2010/11/11 15:38:43 roberto Exp $ +** $Id: ltable.c,v 2.59 2011/06/09 18:23:27 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -33,6 +33,7 @@ #include "lstate.h" #include "lstring.h" #include "ltable.h" +#include "lvm.h" /* @@ -87,8 +88,9 @@ static Node *hashnum (const Table *t, lua_Number n) { int i; luai_hashnum(i, n); if (i < 0) { - i = -i; /* must be a positive value */ - if (i < 0) i = 0; /* handle INT_MIN */ + if ((unsigned int)i == -(unsigned int)i) + i = 0; /* handle INT_MIN */ + i = -i; /* must be a positive value */ } return hashmod(t, i); } @@ -148,8 +150,8 @@ static int findindex (lua_State *L, Table *t, StkId key) { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in `next' */ - if (luaO_rawequalObj(gkey(n), key) || - (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && + if (luaV_rawequalobj(gkey(n), key) || + (ttisdeadkey(gkey(n)) && iscollectable(key) && gcvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ @@ -336,7 +338,7 @@ void luaH_resizearray (lua_State *L, Table *t, int nasize) { static void rehash (lua_State *L, Table *t, const TValue *ek) { int nasize, na; - int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ + int nums[MAXBITS+1]; /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */ int i; int totaluse; for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ @@ -467,7 +469,7 @@ const TValue *luaH_getstr (Table *t, TString *key) { ** main search function */ const TValue *luaH_get (Table *t, const TValue *key) { - switch (ttype(key)) { + switch (ttypenv(key)) { case LUA_TNIL: return luaO_nilobject; case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { @@ -481,7 +483,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { default: { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(gkey(n), key)) + if (luaV_rawequalobj(gkey(n), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); diff --git a/src/ltablib.c b/src/ltablib.c index faabfe534d..0d69fc906c 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.58 2010/11/23 17:21:14 roberto Exp $ +** $Id: ltablib.c,v 1.59 2010/12/17 12:15:34 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -17,7 +17,7 @@ #define aux_getn(L,n) \ - (luaL_checktype(L, n, LUA_TTABLE), (int)lua_rawlen(L, n)) + (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) static int deprecatedfunc (lua_State *L) { @@ -104,7 +104,7 @@ static int tconcat (lua_State *L) { const char *sep = luaL_optlstring(L, 2, "", &lsep); luaL_checktype(L, 1, LUA_TTABLE); i = luaL_optint(L, 3, 1); - last = luaL_opt(L, luaL_checkint, 4, (int)lua_rawlen(L, 1)); + last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1)); luaL_buffinit(L, &b); for (; i < last; i++) { addfield(L, &b, i); @@ -143,7 +143,7 @@ static int unpack (lua_State *L) { int i, e, n; luaL_checktype(L, 1, LUA_TTABLE); i = luaL_optint(L, 2, 1); - e = luaL_opt(L, luaL_checkint, 3, (int)lua_rawlen(L, 1)); + e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ n = e - i + 1; /* number of elements */ if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ diff --git a/src/ltm.c b/src/ltm.c index faa8f57d2b..e70006dd7f 100644 --- a/src/ltm.c +++ b/src/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.12 2010/04/13 20:48:12 roberto Exp $ +** $Id: ltm.c,v 2.14 2011/06/02 19:31:40 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -21,11 +21,11 @@ static const char udatatypename[] = "userdata"; -LUAI_DDEF const char *const luaT_typenames_[] = { +LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "string", "table", "function", udatatypename, "thread", - "proto", "upval" + "proto", "upval" /* these last two cases are used for tests only */ }; @@ -62,7 +62,7 @@ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { Table *mt; - switch (ttype(o)) { + switch (ttypenv(o)) { case LUA_TTABLE: mt = hvalue(o)->metatable; break; diff --git a/src/ltm.h b/src/ltm.h index 05abc40bd2..89bdc19a1e 100644 --- a/src/ltm.h +++ b/src/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.10 2010/04/13 20:48:12 roberto Exp $ +** $Id: ltm.h,v 2.11 2011/02/28 17:32:10 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -46,7 +46,7 @@ typedef enum { #define ttypename(x) luaT_typenames_[(x) + 1] #define objtypename(x) ttypename(ttypenv(x)) -LUAI_DDEC const char *const luaT_typenames_[]; +LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); diff --git a/src/lua.c b/src/lua.c index fe2f0698b4..4d098b97da 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.194 2010/10/25 19:01:37 roberto Exp $ +** $Id: lua.c,v 1.199 2011/05/26 16:09:40 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -106,13 +106,11 @@ static void laction (int i) { static void print_usage (const char *badoption) { - if (badoption[1] == 'e' || badoption[1] == 'l') { - luai_writestringerror("%s: ", progname); + luai_writestringerror("%s: ", progname); + if (badoption[1] == 'e' || badoption[1] == 'l') luai_writestringerror("'%s' needs argument\n", badoption); - } else { - luai_writestringerror("%s: ", progname); + else luai_writestringerror("unrecognized option '%s'\n", badoption); - } luai_writestringerror( "usage: %s [options] [script [args]]\n" "Available options are:\n" @@ -185,7 +183,8 @@ static int docall (lua_State *L, int narg, int nres) { static void print_version (void) { - printf("%s\n", LUA_COPYRIGHT); + luai_writestring(LUA_COPYRIGHT, sizeof(LUA_COPYRIGHT)); + luai_writeline(); } @@ -247,14 +246,14 @@ static const char *get_prompt (lua_State *L, int firstline) { } /* mark in error messages for incomplete statements */ -#define mark "" -#define marklen (sizeof(mark) - 1) +#define EOFMARK "" +#define marklen (sizeof(EOFMARK)/sizeof(char) - 1) static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); - if (lmsg >= marklen && strcmp(msg + lmsg - marklen, mark) == 0) { + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { lua_pop(L, 1); return 1; } @@ -322,7 +321,7 @@ static void dotty (lua_State *L) { } } lua_settop(L, 0); /* clear stack */ - luai_writestring("\n", 1); + luai_writeline(); progname = oldprogname; } diff --git a/src/lua.h b/src/lua.h index 0e1f97a41c..05d0d565c6 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.276 2010/10/26 19:32:19 roberto Exp $ +** $Id: lua.h,v 1.277 2011/04/18 14:15:48 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -18,12 +18,12 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" -#define LUA_VERSION_RELEASE "0" " (alpha)" +#define LUA_VERSION_RELEASE "0" " (beta)" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_VERSION_NUM 502 -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2010 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2011 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -415,7 +415,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2010 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2011 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/luac.c b/src/luac.c index 19ef916d0f..1b28c79951 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.65 2010/10/26 09:07:52 lhf Exp $ +** $Id: luac.c,v 1.66 2011/05/10 01:08:57 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -143,9 +143,12 @@ static const Proto* combine(lua_State* L, int n) int i=n; if (lua_load(L,reader,&i,"=(" PROGNAME ")")!=LUA_OK) fatal(lua_tostring(L,-1)); f=toproto(L,-1); - for (i=0; ip[i]=toproto(L,i-n-1); + for (i=0; ip[i]=toproto(L,i-n-1); + if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; + } f->sizelineinfo=0; - f->sizeupvalues=0; return f; } } @@ -200,7 +203,7 @@ int main(int argc, char* argv[]) } /* -** $Id: print.c,v 1.66 2010/10/26 09:07:52 lhf Exp $ +** $Id: print.c,v 1.67 2011/05/06 13:37:15 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -270,6 +273,7 @@ static void PrintConstant(const Proto* f, int i) } #define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-") +#define MYK(x) (-1-(x)) static void PrintCode(const Proto* f) { @@ -293,23 +297,25 @@ static void PrintCode(const Proto* f) { case iABC: printf("%d",a); - if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); - if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); + if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b); + if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c); break; case iABx: - if (getBMode(o)==OpArgK) printf("%d %d",a,-bx); else printf("%d %d",a,bx); + printf("%d",a); + if (getBMode(o)==OpArgK) printf(" %d",MYK(bx)); + if (getBMode(o)==OpArgU) printf(" %d",bx); break; case iAsBx: - if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); + printf("%d %d",a,sbx); break; case iAx: - printf("%d",-1-ax); + printf("%d",MYK(ax)); break; } switch (o) { case OP_LOADK: - if (bx>0) { printf("\t; "); PrintConstant(f,bx-1); } + printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: @@ -355,8 +361,7 @@ static void PrintCode(const Proto* f) printf("\t; %p",VOID(f->p[bx])); break; case OP_SETLIST: - if (c==0) printf("\t; %d",(int)code[++pc]); - else printf("\t; %d",c); + if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c); break; case OP_EXTRAARG: printf("\t; "); PrintConstant(f,ax); diff --git a/src/luaconf.h b/src/luaconf.h index 1222dc9ce6..72a1689a28 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.151 2010/11/12 15:48:30 roberto Exp $ +** $Id: luaconf.h,v 1.159 2011/06/13 14:13:06 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -35,6 +35,7 @@ #if defined(LUA_WIN) #define LUA_DL_DLL +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #endif @@ -43,12 +44,18 @@ #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ +#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ +#define LUA_USE_LONGLONG /* assume support for long long */ #endif #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* does not need -ldl */ #define LUA_USE_READLINE /* needs an extra library: -lreadline */ +#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ +#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ +#define LUA_USE_LONGLONG /* assume support for long long */ #endif @@ -202,10 +209,11 @@ /* -@@ luai_writestring defines how 'print' prints its results. +@@ luai_writestring/luai_writeline define how 'print' prints its results. */ #include #define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#define luai_writeline() (luai_writestring("\n", 1), fflush(stdout)) /* @@ luai_writestringerror defines how to print error messages. @@ -253,6 +261,12 @@ */ #define LUA_COMPAT_LOG10 +/* +@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base +** library. You can rewrite 'loadstring(s)' as 'load(s)'. +*/ +#define LUA_COMPAT_LOADSTRING + /* @@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. */ @@ -371,14 +385,27 @@ @@ LUA_NUMBER_FMT is the format for writing numbers. @@ lua_number2str converts a number to a string. @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. -@@ lua_str2number converts a string to a number. */ #define LUA_NUMBER_SCAN "%lf" #define LUA_NUMBER_FMT "%.14g" #define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ + + +/* +@@ lua_str2number converts a decimal numeric string to a number. +@@ lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' do both conversions. C89, however, has no function +** to convert floating hexadecimal strings to numbers. For these +** systems, you can leave 'lua_strx2number' undefined and Lua will +** provide its own implementation. +*/ #define lua_str2number(s,p) strtod((s), (p)) +#if defined(LUA_USE_STRTODHEX) +#define lua_strx2number(s,p) strtod((s), (p)) +#endif + /* @@ The luai_num* macros define the primitive operations over numbers. @@ -438,11 +465,11 @@ /* @@ LUA_IEEEENDIAN is the endianness of doubles in your machine -@@ (0 for little endian, 1 for big endian); if not defined, Lua will -@@ check it dynamically. +** (0 for little endian, 1 for big endian); if not defined, Lua will +** check it dynamically. */ /* check for known architectures */ -#if defined(__i386__) || defined(__i386) || defined(i386) || \ +#if defined(__i386__) || defined(__i386) || defined(__X86__) || \ defined (__x86_64) #define LUA_IEEEENDIAN 0 #elif defined(__POWERPC__) || defined(__ppc__) @@ -458,6 +485,30 @@ /* }================================================================== */ +/* +@@ LUA_NANTRICKLE/LUA_NANTRICKBE controls the use of a trick to pack all +** types into a single double value, using NaN values to represent +** non-number values. The trick only works on 32-bit machines (ints and +** pointers are 32-bit values) with numbers represented as IEEE 754-2008 +** doubles with conventional endianess (12345678 or 87654321), in CPUs +** that do not produce signaling NaN values (all NaNs are quiet). +*/ +#if defined(LUA_CORE) /* { */ + +#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ + +/* little-endian architectures that satisfy those conditions */ +#if defined(__i386__) || defined(__i386) || defined(__X86__) + +#define LUA_NANTRICKLE + +#endif + +#endif /* } */ + +#endif /* } */ + + /* =================================================================== */ diff --git a/src/lualib.h b/src/lualib.h index 233a331e64..8132da6c09 100644 --- a/src/lualib.h +++ b/src/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.41 2010/10/25 14:32:36 roberto Exp $ +** $Id: lualib.h,v 1.42 2011/05/25 14:12:28 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -50,7 +50,7 @@ LUALIB_API void (luaL_openlibs) (lua_State *L); -#ifndef lua_assert +#if !defined(lua_assert) #define lua_assert(x) ((void)0) #endif diff --git a/src/lundump.c b/src/lundump.c index c875d76721..ba1a3dc37e 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.68 2010/10/26 00:23:46 lhf Exp $ +** $Id: lundump.c,v 1.69 2011/05/06 13:35:17 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -38,6 +38,10 @@ static void error(LoadState* S, const char* why) #define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) #define LoadVector(S,b,n,size) LoadMem(S,b,n,size) +#if !defined(luai_verifycode) +#define luai_verifycode(L,b,f) (f) +#endif + static void LoadBlock(LoadState* S, void* b, size_t size) { if (luaZ_read(S->Z,b,size)!=0) error(S,"corrupted"); @@ -54,6 +58,7 @@ static int LoadInt(LoadState* S) { int x; LoadVar(S,x); + if (x<0) error(S,"corrupted"); return x; } @@ -73,7 +78,7 @@ static TString* LoadString(LoadState* S) else { char* s=luaZ_openspace(S->L,S->b,size); - LoadBlock(S,s,size); + LoadBlock(S,s,size*sizeof(char)); return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ } } @@ -177,16 +182,17 @@ static Proto* LoadFunction(LoadState* S) /* the code below must be consistent with the code in luaU_header */ #define N0 LUAC_HEADERSIZE -#define N1 (sizeof(LUA_SIGNATURE)-1) +#define N1 (sizeof(LUA_SIGNATURE)-sizeof(char)) #define N2 N1+2 #define N3 N2+6 static void LoadHeader(LoadState* S) { - char h[LUAC_HEADERSIZE]; - char s[LUAC_HEADERSIZE]; + lu_byte h[LUAC_HEADERSIZE]; + lu_byte s[LUAC_HEADERSIZE]; luaU_header(h); - LoadBlock(S,s,LUAC_HEADERSIZE); + memcpy(s,h,sizeof(char)); /* first char already read */ + LoadBlock(S,s+sizeof(char),LUAC_HEADERSIZE-sizeof(char)); if (memcmp(h,s,N0)==0) return; if (memcmp(h,s,N1)!=0) error(S,"not a"); if (memcmp(h,s,N2)!=0) error(S,"version mismatch in"); @@ -209,29 +215,30 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) S.Z=Z; S.b=buff; LoadHeader(&S); - return LoadFunction(&S); + return luai_verifycode(L,buff,LoadFunction(&S)); } -/* data to catch conversion errors */ -#define TAIL "\x19\x93\r\n\x1a\n" +#define MYINT(s) (s[0]-'0') +#define VERSION MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR) +#define FORMAT 0 /* this is the official format */ /* * make header for precompiled chunks -* if you make any changes in the code below or in LUA_SIGNATURE in lua.h, -* be sure to update LoadHeader above and LUAC_HEADERSIZE in lundump.h +* if you change the code below be sure to update LoadHeader and FORMAT above +* and LUAC_HEADERSIZE in lundump.h */ -void luaU_header (char* h) +void luaU_header (lu_byte* h) { int x=1; - memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); - h+=sizeof(LUA_SIGNATURE)-1; - *h++=(char)0x52; /* Lua 5.2 */ - *h++=(char)0; /* the official format */ - *h++=(char)*(char*)&x; /* endianness */ - *h++=(char)sizeof(int); - *h++=(char)sizeof(size_t); - *h++=(char)sizeof(Instruction); - *h++=(char)sizeof(lua_Number); - *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ - memcpy(h,TAIL,sizeof(TAIL)-1); + memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-sizeof(char)); + h+=sizeof(LUA_SIGNATURE)-sizeof(char); + *h++=cast_byte(VERSION); + *h++=cast_byte(FORMAT); + *h++=cast_byte(*(char*)&x); /* endianness */ + *h++=cast_byte(sizeof(int)); + *h++=cast_byte(sizeof(size_t)); + *h++=cast_byte(sizeof(Instruction)); + *h++=cast_byte(sizeof(lua_Number)); + *h++=cast_byte(((lua_Number)0.5)==0); /* is lua_Number integral? */ + memcpy(h,LUAC_TAIL,sizeof(LUAC_TAIL)-sizeof(char)); } diff --git a/src/lundump.h b/src/lundump.h index e55918cf52..b63993ffe5 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.43 2010/10/26 00:23:46 lhf Exp $ +** $Id: lundump.h,v 1.44 2011/05/06 13:35:17 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -14,12 +14,15 @@ LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); /* make header; from lundump.c */ -LUAI_FUNC void luaU_header (char* h); +LUAI_FUNC void luaU_header (lu_byte* h); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); -/* size of header of binary files */ -#define LUAC_HEADERSIZE 18 +/* data to catch conversion errors */ +#define LUAC_TAIL "\x19\x93\r\n\x1a\n" + +/* size in bytes of header of binary files */ +#define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char)) #endif diff --git a/src/lvm.c b/src/lvm.c index 42c6c81f5f..e4f90af40a 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.125 2010/10/29 17:52:46 roberto Exp $ +** $Id: lvm.c,v 2.141 2011/06/09 18:24:22 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -35,7 +35,7 @@ const TValue *luaV_tonumber (const TValue *obj, TValue *n) { lua_Number num; if (ttisnumber(obj)) return obj; - if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { + if (ttisstring(obj) && luaO_str2d(svalue(obj), tsvalue(obj)->len, &num)) { setnvalue(n, num); return n; } @@ -65,7 +65,7 @@ static void traceexec (lua_State *L) { luaD_hook(L, LUA_HOOKCOUNT, -1); } if (mask & LUA_MASKLINE) { - Proto *p = ci_func(ci)->l.p; + Proto *p = ci_func(ci)->p; int npc = pcRel(ci->u.l.savedpc, p); int newline = getfuncline(p, npc); if (npc == 0 || /* call linehook when enter a new function, */ @@ -161,7 +161,6 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; - if (event == TM_UNM) p2 = luaO_nilobject; callTM(L, tm, p1, p2, res, 1); return 1; } @@ -175,7 +174,7 @@ static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2, if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); if (tm2 == NULL) return NULL; /* no metamethod */ - if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ + if (luaV_rawequalobj(tm1, tm2)) /* same metamethods? */ return tm1; return NULL; } @@ -238,9 +237,12 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { } -int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) { +/* +** equality of Lua values. L == NULL means raw equality (no metamethods) +*/ +int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; - lua_assert(ttype(t1) == ttype(t2)); + lua_assert(ttisequal(t1, t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); @@ -250,15 +252,19 @@ int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) { case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; + else if (L == NULL) return 0; tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; + else if (L == NULL) return 0; tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } - default: return gcvalue(t1) == gcvalue(t2); + default: + lua_assert(iscollectable(t1)); + return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ callTM(L, tm, t1, t2, L->top, 1); /* call TM */ @@ -286,18 +292,20 @@ void luaV_concat (lua_State *L, int total) { char *buffer; int i; /* collect total length */ - for (n = 1; n < total && tostring(L, top-n-1); n++) { - size_t l = tsvalue(top-n-1)->len; - if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); + for (i = 1; i < total && tostring(L, top-i-1); i++) { + size_t l = tsvalue(top-i-1)->len; + if (l >= (MAX_SIZET/sizeof(char)) - tl) + luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; - for (i=n; i>0; i--) { /* concat all strings */ + n = i; + do { /* concat all strings */ size_t l = tsvalue(top-i)->len; - memcpy(buffer+tl, svalue(top-i), l); + memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); tl += l; - } + } while (--i > 0); setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got 'n' strings to create 1 new */ @@ -308,7 +316,7 @@ void luaV_concat (lua_State *L, int total) { void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; - switch (ttype(rb)) { + switch (ttypenv(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); @@ -327,7 +335,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { break; } } - callTM(L, tm, rb, luaO_nilobject, ra, 1); + callTM(L, tm, rb, rb, ra, 1); } @@ -378,7 +386,7 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, Upvaldesc *uv = p->upvalues; int i; Closure *ncl = luaF_newLclosure(L, p); - setclvalue(L, ra, ncl); /* anchor new closure in stack */ + setclLvalue(L, ra, ncl); /* anchor new closure in stack */ for (i = 0; i < nup; i++) { /* fill in its upvalues */ if (uv[i].instack) /* upvalue refers to local variable? */ ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx); @@ -454,6 +462,11 @@ void luaV_finishOp (lua_State *L) { ** some macros for common tasks in `luaV_execute' */ +#if !defined luai_runtimecheck +#define luai_runtimecheck(L, c) /* void */ +#endif + + #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) @@ -466,12 +479,19 @@ void luaV_finishOp (lua_State *L) { (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) -#define dojump(i) (ci->u.l.savedpc += (i)) +/* execute a jump instruction */ +#define dojump(ci,i,e) \ + { int a = GETARG_A(i); \ + if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \ + ci->u.l.savedpc += GETARG_sBx(i) + e; } + +/* for test instructions, execute the jump instruction that follows it */ +#define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); } #define Protect(x) { {x;}; base = ci->u.l.base; } -#define checkGC(L) Protect(luaC_checkGC(L); luai_threadyield(L);) +#define checkGC(L,c) Protect(luaC_condGC(L, c); luai_threadyield(L);) #define arith_op(op,tm) { \ @@ -493,9 +513,8 @@ void luaV_execute (lua_State *L) { TValue *k; StkId base; newframe: /* reentry point when frame changes (call/return) */ - lua_assert(isLua(ci)); lua_assert(ci == L->ci); - cl = &clvalue(ci->func)->l; + cl = clLvalue(ci->func); k = cl->p->k; base = ci->u.l.base; /* main loop of interpreter */ @@ -515,7 +534,13 @@ void luaV_execute (lua_State *L) { setobjs2s(L, ra, RB(i)); ) vmcase(OP_LOADK, - TValue *rb = KBx(i); + TValue *rb = k + GETARG_Bx(i); + setobj2s(L, ra, rb); + ) + vmcase(OP_LOADKX, + TValue *rb; + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); + rb = k + GETARG_Ax(*ci->u.l.savedpc++); setobj2s(L, ra, rb); ) vmcase(OP_LOADBOOL, @@ -523,10 +548,10 @@ void luaV_execute (lua_State *L) { if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ ) vmcase(OP_LOADNIL, - TValue *rb = RB(i); + int b = GETARG_B(i); do { - setnilvalue(rb--); - } while (rb >= ra); + setnilvalue(ra++); + } while (b--); ) vmcase(OP_GETUPVAL, int b = GETARG_B(i); @@ -558,7 +583,11 @@ void luaV_execute (lua_State *L) { sethvalue(L, ra, t); if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - checkGC(L); + checkGC(L, + L->top = ra + 1; /* limit of live values */ + luaC_step(L); + L->top = ci->top; /* restore top */ + ) ) vmcase(OP_SELF, StkId rb = RB(i); @@ -594,7 +623,8 @@ void luaV_execute (lua_State *L) { } ) vmcase(OP_NOT, - int res = l_isfalse(RB(i)); /* next assignment may change this value */ + TValue *rb = RB(i); + int res = l_isfalse(rb); /* next assignment may change this value */ setbvalue(ra, res); ) vmcase(OP_LEN, @@ -603,49 +633,61 @@ void luaV_execute (lua_State *L) { vmcase(OP_CONCAT, int b = GETARG_B(i); int c = GETARG_C(i); + StkId rb; L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c-b+1); checkGC(L);) + Protect(luaV_concat(L, c - b + 1)); + ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */ + rb = b + base; + setobjs2s(L, ra, rb); + checkGC(L, + L->top = (ra >= rb ? ra + 1 : rb); /* limit of live values */ + luaC_step(L); + ) L->top = ci->top; /* restore top */ - setobjs2s(L, RA(i), base+b); ) vmcase(OP_JMP, - dojump(GETARG_sBx(i)); + dojump(ci, i, 0); ) vmcase(OP_EQ, TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( - if (equalobj(L, rb, rc) == GETARG_A(i)) - dojump(GETARG_sBx(*ci->u.l.savedpc)); + if (equalobj(L, rb, rc) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); ) - ci->u.l.savedpc++; ) vmcase(OP_LT, Protect( - if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) - dojump(GETARG_sBx(*ci->u.l.savedpc)); + if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); ) - ci->u.l.savedpc++; ) vmcase(OP_LE, Protect( - if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) - dojump(GETARG_sBx(*ci->u.l.savedpc)); + if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) + ci->u.l.savedpc++; + else + donextjump(ci); ) - ci->u.l.savedpc++; ) vmcase(OP_TEST, - if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra)) - dojump(GETARG_sBx(*ci->u.l.savedpc)); - ci->u.l.savedpc++; + if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) + ci->u.l.savedpc++; + else + donextjump(ci); ) vmcase(OP_TESTSET, TValue *rb = RB(i); - if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) { + if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) + ci->u.l.savedpc++; + else { setobjs2s(L, ra, rb); - dojump(GETARG_sBx(*ci->u.l.savedpc)); + donextjump(ci); } - ci->u.l.savedpc++; ) vmcase(OP_CALL, int b = GETARG_B(i); @@ -711,7 +753,7 @@ void luaV_execute (lua_State *L) { lua_Number limit = nvalue(ra+1); if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit) : luai_numle(L, limit, idx)) { - dojump(GETARG_sBx(i)); /* jump back */ + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } @@ -727,7 +769,7 @@ void luaV_execute (lua_State *L) { else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); - dojump(GETARG_sBx(i)); + ci->u.l.savedpc += GETARG_sBx(i); ) vmcase(OP_TFORCALL, StkId cb = ra + 3; /* call base */ @@ -746,7 +788,7 @@ void luaV_execute (lua_State *L) { l_tforloop: if (!ttisnil(ra + 1)) { /* continue loop? */ setobjs2s(L, ra, ra + 1); /* save control variable */ - dojump(GETARG_sBx(i)); /* jump back */ + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ } ) vmcase(OP_SETLIST, @@ -759,6 +801,7 @@ void luaV_execute (lua_State *L) { lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); c = GETARG_Ax(*ci->u.l.savedpc++); } + luai_runtimecheck(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ @@ -770,17 +813,18 @@ void luaV_execute (lua_State *L) { } L->top = ci->top; /* correct top (in case of previous open call) */ ) - vmcase(OP_CLOSE, - luaF_close(L, ra); - ) vmcase(OP_CLOSURE, Proto *p = cl->p->p[GETARG_Bx(i)]; Closure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) /* no match? */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ else - setclvalue(L, ra, ncl); /* push cashed closure */ - checkGC(L); + setclLvalue(L, ra, ncl); /* push cashed closure */ + checkGC(L, + L->top = ra + 1; /* limit of live values */ + luaC_step(L); + L->top = ci->top; /* restore top */ + ) ) vmcase(OP_VARARG, int b = GETARG_B(i) - 1; diff --git a/src/lvm.h b/src/lvm.h index 8e91da5925..ec35822406 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.14 2009/12/17 16:20:01 roberto Exp $ +** $Id: lvm.h,v 2.17 2011/05/31 18:27:56 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -17,12 +17,15 @@ #define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL)) -#define equalobj(L,o1,o2) \ - (ttype(o1) == ttype(o2) && luaV_equalval_(L, o1, o2)) +#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2)) + +#define luaV_rawequalobj(t1,t2) \ + (ttisequal(t1,t2) && luaV_equalobj_(NULL,t1,t2)) /* not to called directly */ -LUAI_FUNC int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2); +LUAI_FUNC int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2); + LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); diff --git a/src/lzio.c b/src/lzio.c index 5121ada846..7d2677bd6a 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ +** $Id: lzio.c,v 1.33 2011/02/23 13:13:10 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -25,26 +25,14 @@ int luaZ_fill (ZIO *z) { lua_unlock(L); buff = z->reader(L, z->data, &size); lua_lock(L); - if (buff == NULL || size == 0) return EOZ; - z->n = size - 1; + if (buff == NULL || size == 0) + return EOZ; + z->n = size - 1; /* discount char being returned */ z->p = buff; return char2int(*(z->p++)); } -int luaZ_lookahead (ZIO *z) { - if (z->n == 0) { - if (luaZ_fill(z) == EOZ) - return EOZ; - else { - z->n++; /* luaZ_fill removed first byte; put back it */ - z->p--; - } - } - return char2int(*z->p); -} - - void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { z->L = L; z->reader = reader; @@ -58,8 +46,14 @@ void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; - if (luaZ_lookahead(z) == EOZ) - return n; /* return number of missing bytes */ + if (z->n == 0) { /* no bytes in buffer? */ + if (luaZ_fill(z) == EOZ) /* try to read more */ + return n; /* no more input; return number of missing bytes */ + else { + z->n++; /* luaZ_fill consumed first byte; put it back */ + z->p--; + } + } m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; diff --git a/src/lzio.h b/src/lzio.h index 53eb91efe3..4174986d4b 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.22 2009/05/18 17:26:25 roberto Exp $ +** $Id: lzio.h,v 1.24 2011/02/23 13:13:10 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -50,7 +50,6 @@ LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data); LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ -LUAI_FUNC int luaZ_lookahead (ZIO *z); @@ -59,7 +58,7 @@ LUAI_FUNC int luaZ_lookahead (ZIO *z); struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ - lua_Reader reader; + lua_Reader reader; /* reader function */ void* data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; From 16559ecd52698cfead11eca834903b686bf62d65 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Tue, 21 Jun 2011 12:00:00 +0000 Subject: [PATCH 58/97] Lua 5.2.0-beta-rc2 --- doc/contents.html | 8 +- doc/lua.css | 3 +- doc/manual.html | 92 ++++++++-------- doc/readme.html | 7 +- src/Makefile | 48 +++++---- src/lauxlib.c | 13 ++- src/lauxlib.h | 5 +- src/lbaselib.c | 21 ++-- src/lbitlib.c | 4 +- src/lctype.c | 45 -------- src/lctype.h | 50 --------- src/ldo.c | 27 ++++- src/liolib.c | 267 ++++++++++++++++++++++------------------------ src/llex.c | 102 ++++++++---------- src/llex.h | 4 +- src/lobject.c | 22 ++-- src/loslib.c | 4 +- src/lparser.c | 47 +++++--- src/lparser.h | 5 +- src/lstrlib.c | 4 +- src/ltable.c | 4 +- src/lua.c | 4 +- src/luac.c | 6 +- src/lundump.c | 4 +- 24 files changed, 364 insertions(+), 432 deletions(-) delete mode 100644 src/lctype.c delete mode 100644 src/lctype.h diff --git a/doc/contents.html b/doc/contents.html index 5e94ebd131..13b33b0828 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -40,7 +40,7 @@

      Copyright © 2011 Lua.org, PUC-Rio. Freely available under the terms of the -Lua license. +Lua license.

      Contents

      @@ -146,6 +146,8 @@

      Lua functions

      _G
      _VERSION
      + +

      assert
      collectgarbage
      dofile
      @@ -518,9 +520,9 @@

      auxiliary library


    - + Last update: -Mon Jun 13 15:09:33 BRT 2011 +Mon Jun 20 08:55:58 BRT 2011

    - + @@ -54,7 +54,7 @@

    1 – Introduction

    Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. Lua is implemented as a library, written in clean C, -the common subset of ANSI C and C++. +the common subset of Standard C and C++.

    @@ -192,8 +192,9 @@

    2.1 – Values and Types

    -We use the term sequence to denote a table where all -integer keys comprise the set {1..n} for some integer n, +We use the term sequence to denote a table where +the set of all positive numeric keys is equal to {1..n} +for some integer n, which is called the length of the sequence (see §3.4.6). @@ -234,7 +235,7 @@

    2.1 – Values and Types

    2.2 – Environments and the Global Environment

    -As discussed in §3.2 and §3.3.3, +As will be discussed in §3.2 and §3.3.3, any reference to a global name var is syntactically translated to _ENV.var. Moreover, every chunk is compiled in the scope of an external @@ -1136,7 +1137,7 @@

    3.1 – Lexical Conventions

          +     -     *     /     %     ^     #
          ==    ~=    <=    >=    <     >     =
    -     (     )     {     }     [     ]
    +     (     )     {     }     [     ]     ::
          ;     :     ,     .     ..    ...
     
    @@ -1239,7 +1240,7 @@

    3.1 – Lexical Conventions

    which start with 0x or 0X. Hexadecimal constants also accept an optional fractional part plus an optional binary exponent, -marked by a letter 'e' or 'E'. +marked by a letter 'p' or 'P'. Examples of valid numerical constants are
    @@ -1531,12 +1532,13 @@ 

    3.3.4 – Control Structures

     	stat ::= goto Name
     	stat ::= label
    -	label ::= ‘@’ Name ‘:’
    +	label ::= ‘::’ Name ‘::

    A label is visible in the entire block where it is defined (including nested blocks, but not nested functions). +A function cannot have more than one label with a given name. A goto may jump to any visible label as long as it does not enter into the scope of a local variable. @@ -1995,10 +1997,17 @@

    3.4.6 – The Length Operator

    -The length of a table t is only defined if the +A program can modify the behavior of the length operator for +any value but strings through the __len metamethod (see §2.4). + + +

    +Unless a __len metamethod is given, +the length of a table t is only defined if the table is a sequence, that is, -all its numeric keys comprise the set {1..n} for some integer n. +the set of its positive numeric keys is equal to {1..n} +for some integer n. In that case, n is its length. Note that a table like @@ -2008,16 +2017,11 @@

    3.4.6 – The Length Operator

    is not a sequence, because it has the key 4 but does not have the key 3. (So, there is no n such that the set {1..n} is equal -to the set of numeric keys of that table.) +to the set of positive numeric keys of that table.) Note, however, that non-numeric keys do not interfere with whether a table is a sequence. -

    -A program can modify the behavior of the length operator for -any value but strings through the __len metamethod (see §2.4). - - @@ -2824,11 +2828,11 @@

    4.8 – Functions and Types

    return realloc(ptr, nsize); }

    -Note that ANSI C ensures +Note that Standard C ensures that free(NULL) has no effect and that realloc(NULL, size) is equivalent to malloc(size). This code assumes that realloc does not fail when shrinking a block. -ANSI C does not ensure this behavior, +Standard C does not ensure this behavior, but it seems a safe assumption. @@ -2864,11 +2868,6 @@

    4.8 – Functions and Types

    -

    -When the operation is LUA_OPUNM, -the caller must push a nil value for the second operand. - - @@ -5907,7 +5906,7 @@

    5.1 – Functions and Types


    luaL_execresult

    -[-0, +(1/3), m] +[-0, +3, m]

    int luaL_execresult (lua_State *L, int stat);

    @@ -6097,7 +6096,7 @@

    5.1 – Functions and Types


    luaL_newlibtable

    [-0, +1, m] -

    int luaL_newlibtable (lua_State *L, const luaL_Reg *l);
    +
    int luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

    Creates a new table with a size optimized @@ -7471,7 +7470,7 @@

    6.3 – Modules

    -This function is not supported by ANSI C. +This function is not supported by Standard C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard). @@ -8098,15 +8097,13 @@

    6.5 – Table Manipulation

    -Currently, all functions in the table library assume that the table -represents a list. -In particular, they all ignore non-numeric keys -in tables given as arguments. -All functions in the table library, +Currently, all functions in the table library, except table.pack, -may apply the length operator on the list. -In that case, the list must be a proper sequence -or have a __len metamethod (see §3.4.6). +work on lists. +A list here means a proper sequence +or a table with a __len metamethod (see §3.4.6). +In particular, all functions ignore non-numeric keys +in lists given as arguments.

    @@ -8135,7 +8132,8 @@

    6.5 – Table Manipulation

    Inserts element value at position pos in list, -shifting up other elements to open space, if necessary. +shifting up the elements +list[pos], list[pos+1], ···, list[#list]. The default value for pos is #list+1, so that a call table.insert(t,x) inserts x at the end of list t. @@ -8162,7 +8160,9 @@

    6.5 – Table Manipulation

    Removes from list the element at position pos, -shifting down other elements to close the space, if necessary. +shifting down the elements +list[pos+1], list[pos+2], ···, list[#list] +and erasing element list[#list]. Returns the value of the removed element. The default value for pos is #list, so that a call table.remove(t) removes the last element @@ -8177,12 +8177,12 @@

    6.5 – Table Manipulation

    Sorts list elements in a given order, in-place, -from table[1] to table[#list]. +from list[1] to list[#list]. If comp is given, then it must be a function that receives two list elements and returns true when the first element must come before the second in the final order -(so that not comp(a[i+1],a[i]) will be true after the sort). +(so that not comp(list[i+1],list[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead. @@ -8459,7 +8459,7 @@

    6.6 – Mathematical Functions

    This function is an interface to the simple -pseudo-random generator function rand provided by ANSI C. +pseudo-random generator function rand provided by Standard C. (No guarantees can be given for its statistical properties.) @@ -9242,9 +9242,11 @@

    6.9 – Operating System Facilities

    This function is equivalent to the C function system. It passes command to be executed by an operating system shell. -It returns true -if the command terminated successfully. -Otherwise, it returns nil plus a string and a number, +Its first result is true +if the command terminated successfully, +or nil otherwise. +After this first result +the function returns a string and a number, as follows:

      @@ -10139,7 +10141,7 @@

      9 – The Complete Syntax of Lua

      retstat ::= return [explist] [‘;’] - label ::= ‘@’ Name ‘:’ + label ::= ‘::’ Name ‘::’ funcname ::= Name {‘.’ Name} [‘:’ Name] @@ -10191,9 +10193,9 @@

      9 – The Complete Syntax of Lua


      - + Last update: -Mon Jun 13 14:56:14 BRT 2011 +Tue Jun 21 19:09:27 BRT 2011

      - + @@ -209,10 +209,11 @@

      2.1 – Values and Types

      The indexing of tables follows -the definition of equality in the language. +the definition of raw equality in the language. The expressions a[i] and a[j] denote the same table element -if and only if i == j. +if and only if i and j are raw equal +(that is, equal without metamethods).

      @@ -328,7 +329,7 @@

      2.3 – Error Handling

      to be called in case of errors. This function is called with the original error message and returns a new error message. -It is called before the error unwonds the stack, +It is called before the error unwinds the stack, so that it can gather more information about the error, for instance by inspecting the stack and creating a stack traceback. This message handler is still protected by the protected call; @@ -443,7 +444,7 @@

      2.4 – Metatables and Metamethods

    -

  • "sub": +
  • "sub": the - operation. Behavior similar to the "add" operation.
  • -
  • "mul": +
  • "mul": the * operation. Behavior similar to the "add" operation.
  • -
  • "div": +
  • "div": the / operation. Behavior similar to the "add" operation.
  • -
  • "mod": +
  • "mod": the % operation. Behavior similar to the "add" operation, @@ -507,7 +508,7 @@

    2.4 – Metatables and Metamethods

    o1 - floor(o1/o2)*o2 as the primitive operation.
  • -
  • "pow": +
  • "pow": the ^ (exponentiation) operation. Behavior similar to the "add" operation, @@ -515,7 +516,7 @@

    2.4 – Metatables and Metamethods

    as the primitive operation.
  • -
  • "unm": +
  • "unm": the unary - operation. @@ -538,7 +539,7 @@

    2.4 – Metatables and Metamethods

  • -
  • "concat": +
  • "concat": the .. (concatenation) operation. @@ -559,7 +560,7 @@

    2.4 – Metatables and Metamethods

  • -
  • "len": +
  • "len": the # operation. @@ -582,7 +583,7 @@

    2.4 – Metatables and Metamethods

    See §3.4.6 for a description of the length of a table.
  • -
  • "eq": +
  • "eq": the == operation. The function getequalhandler defines how Lua chooses a metamethod @@ -620,7 +621,7 @@

    2.4 – Metatables and Metamethods

  • -
  • "lt": +
  • "lt": the < operation. @@ -642,7 +643,7 @@

    2.4 – Metatables and Metamethods

  • -
  • "le": +
  • "le": the <= operation. @@ -672,7 +673,7 @@

    2.4 – Metatables and Metamethods

    equivalent to not (b < a).
  • -
  • "index": +
  • "index": The indexing access table[key]. Note that the metamethod is tried only when key is not present in table. @@ -704,7 +705,7 @@

    2.4 – Metatables and Metamethods

  • -
  • "newindex": +
  • "newindex": The indexing assignment table[key] = value. Note that the metamethod is tried only when key is not present in table. @@ -733,7 +734,7 @@

    2.4 – Metatables and Metamethods

  • -
  • "call": +
  • "call": called when Lua calls a value. @@ -845,7 +846,7 @@

    2.5.1 – Garbage-Collection Metamethods

    Note that if you set a metatable without a __gc field and later create that field in the metatable, the object will not be marked for finalization. -However, after a userdata is marked, +However, after an object is marked, you can freely change the __gc field of its metatable. @@ -873,7 +874,16 @@

    2.5.1 – Garbage-Collection Metamethods

    among those collected in that cycle; that is, the first finalizer to be called is the one associated with the object marked last in the program. -The object memory is freed only in the next garbage-collection cycle. +The execution of each finalizer may occur at any point during +the execution of the regular code. + + +

    +Because the object being collected must still be used by the finalizer +and even resurrectedresurrection +(e.g., stored by the finalizer in a global variable), +the object memory is freed only when it becomes completely inaccessible +(that is, in the next garbage-collection cycle unless it was resurrected). @@ -1536,9 +1546,10 @@

    3.3.4 – Control Structures

    -A label is visible in the entire block where it is defined -(including nested blocks, but not nested functions). -A function cannot have more than one label with a given name. +A label is visible in the entire block where it is defined, +except +inside nested blocks where a label with the same name is defined and +inside nested functions. A goto may jump to any visible label as long as it does not enter into the scope of a local variable. @@ -2592,12 +2603,12 @@

    4.5 – Registry

    The following constants are defined:
      -
    • LUA_RIDX_MAINTHREAD: At this index the registry has +
    • LUA_RIDX_MAINTHREAD: At this index the registry has the main thread of the state. (The main thread is the one created together with the state.)
    • -
    • LUA_RIDX_GLOBALS: At this index the registry has +
    • LUA_RIDX_GLOBALS: At this index the registry has the global environment. This is the C equivalent to the _G global variable.
    • @@ -2840,7 +2851,7 @@

      4.8 – Functions and Types


      lua_arith

      -[-(2/1), +1, e] +[-(2|1), +1, e]

      int lua_arith (lua_State *L, int op);

      @@ -2858,13 +2869,13 @@

      4.8 – Functions and Types

      @@ -3068,9 +3079,9 @@

      4.8 – Functions and Types

      @@ -3186,28 +3197,28 @@

      4.8 – Functions and Types

        -
      • LUA_GCSTOP: +
      • LUA_GCSTOP: stops the garbage collector.
      • -
      • LUA_GCRESTART: +
      • LUA_GCRESTART: restarts the garbage collector.
      • -
      • LUA_GCCOLLECT: +
      • LUA_GCCOLLECT: performs a full garbage-collection cycle.
      • -
      • LUA_GCCOUNT: +
      • LUA_GCCOUNT: returns the current amount of memory (in Kbytes) in use by Lua.
      • -
      • LUA_GCCOUNTB: +
      • LUA_GCCOUNTB: returns the remainder of dividing the current amount of bytes of memory in use by Lua by 1024.
      • -
      • LUA_GCSTEP: +
      • LUA_GCSTEP: performs an incremental step of garbage collection. The step "size" is controlled by data (larger values mean more steps) in a non-specified way. @@ -3217,19 +3228,19 @@

        4.8 – Functions and Types

        garbage-collection cycle.
      • -
      • LUA_GCSETPAUSE: +
      • LUA_GCSETPAUSE: sets data as the new value for the pause of the collector (see §2.5). The function returns the previous value of the pause.
      • -
      • LUA_GCSETSTEPMUL: +
      • LUA_GCSETSTEPMUL: sets data as the new value for the step multiplier of the collector (see §2.5). The function returns the previous value of the step multiplier.
      • -
      • LUA_GCISRUNNING: +
      • LUA_GCISRUNNING: returns a boolean that tells whether the collector is running (i.e., not stopped).
      • @@ -3293,19 +3304,6 @@

        4.8 – Functions and Types

        -

        lua_getuservalue

        -[-0, +1, -] -

        void lua_getuservalue (lua_State *L, int index);
        - -

        -Pushes onto the stack the Lua value associated with the userdata -at the given index. -This Lua value must be a table or nil. - - - - -


        lua_getfield

        [-0, +1, e]

        void lua_getfield (lua_State *L, int index, const char *k);
        @@ -3381,6 +3379,19 @@

        4.8 – Functions and Types

        +

        lua_getuservalue

        +[-0, +1, -] +

        void lua_getuservalue (lua_State *L, int index);
        + +

        +Pushes onto the stack the Lua value associated with the userdata +at the given index. +This Lua value must be a table or nil. + + + + +


        lua_insert

        [-1, +1, -]

        void lua_insert (lua_State *L, int index);
        @@ -3590,15 +3601,15 @@

        4.8 – Functions and Types

          -
        • LUA_OK (0): no errors;
        • +
        • LUA_OK (0): no errors;
        • -
        • LUA_ERRSYNTAX: +
        • LUA_ERRSYNTAX: syntax error during pre-compilation;
        • -
        • LUA_ERRMEM: +
        • LUA_ERRMEM: memory allocation error.
        • -
        • LUA_ERRGCMM: +
        • LUA_ERRGCMM: error while running a __gc metamethod. (This error has no relation with the chunk being loaded. It is generated by the garbage collector.) @@ -3707,13 +3718,6 @@

          4.8 – Functions and Types

          A full userdata is only equal to itself (under raw equality). -

          -When Lua collects a full userdata with a gc metamethod, -Lua calls the metamethod and marks the userdata as finalized. -When this userdata is collected again then -Lua frees its corresponding memory. - - @@ -3823,23 +3827,23 @@

          4.8 – Functions and Types

            -
          • LUA_OK (0): +
          • LUA_OK (0): success.
          • -
          • LUA_ERRRUN: +
          • LUA_ERRRUN: a runtime error.
          • -
          • LUA_ERRMEM: +
          • LUA_ERRMEM: memory allocation error. For such errors, Lua does not call the message handler.
          • -
          • LUA_ERRERR: +
          • LUA_ERRERR: error while running the message handler.
          • -
          • LUA_ERRGCMM: +
          • LUA_ERRGCMM: error while running a __gc metamethod. (This error typically has no relation with the function being called. It is generated by the garbage collector.) @@ -4018,7 +4022,7 @@

            4.8 – Functions and Types


            lua_pushliteral

            [-0, +1, m] -

            void lua_pushliteral (lua_State *L, const char *s);
            +
            const char *lua_pushliteral (lua_State *L, const char *s);

            This macro is equivalent to lua_pushlstring, @@ -4341,18 +4345,6 @@

            4.8 – Functions and Types

            -

            lua_setuservalue

            -[-1, +0, -] -

            void lua_setuservalue (lua_State *L, int index);
            - -

            -Pops a table or nil from the stack and sets it as -the new value associated to the userdata at the given index. - - - - -


            lua_setfield

            [-1, +0, e]

            void lua_setfield (lua_State *L, int index, const char *k);
            @@ -4433,6 +4425,18 @@

            4.8 – Functions and Types

            +

            lua_setuservalue

            +[-1, +0, -] +

            void lua_setuservalue (lua_State *L, int index);
            + +

            +Pops a table or nil from the stack and sets it as +the new value associated to the userdata at the given index. + + + + +


            lua_State

            typedef struct lua_State lua_State;
            @@ -4919,7 +4923,7 @@

            4.9 – The Debug Interface

              -
            • source: +
            • source: the source of the chunk that created the function. If source starts with a '@', it means that the function was defined in a file where @@ -4931,31 +4935,31 @@

              4.9 – The Debug Interface

              source is that string.
            • -
            • short_src: +
            • short_src: a "printable" version of source, to be used in error messages.
            • -
            • linedefined: +
            • linedefined: the line number where the definition of the function starts.
            • -
            • lastlinedefined: +
            • lastlinedefined: the line number where the definition of the function ends.
            • -
            • what: +
            • what: the string "Lua" if the function is a Lua function, "C" if it is a C function, "main" if it is the main part of a chunk.
            • -
            • currentline: +
            • currentline: the current line where the given function is executing. When no line information is available, currentline is set to -1.
            • -
            • name: +
            • name: a reasonable name for the given function. Because functions in Lua are first-class values, they do not have a fixed name: @@ -4967,7 +4971,7 @@

              4.9 – The Debug Interface

              then name is set to NULL.
            • -
            • namewhat: +
            • namewhat: explains the name field. The value of namewhat can be "global", "local", "method", @@ -4976,21 +4980,21 @@

              4.9 – The Debug Interface

              (Lua uses the empty string when no other option seems to apply.)
            • -
            • istailcall: +
            • istailcall: true if this function invocation was called by a tail call. In this case, the caller of this level is not in the stack.
            • -
            • nups: +
            • nups: the number of upvalues of the function.
            • -
            • nparams: +
            • nparams: the number of fixed parameters of the function (always 0 for C functions).
            • -
            • isvararg: +
            • isvararg: whether the function is a vararg function (always true for C functions).
            • @@ -5070,29 +5074,30 @@

              4.9 – The Debug Interface

                -
              • 'n': fills in the field name and namewhat; +
              • 'n': fills in the field name and namewhat;
              • -
              • 'S': +
              • 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
              • -
              • 'l': fills in the field currentline; +
              • 'l': fills in the field currentline;
              • -
              • 't': fills in the field istailcall; +
              • 't': fills in the field istailcall;
              • -
              • 'u': fills in the field nups; +
              • 'u': fills in the fields +nups, nparams, and isvararg;
              • -
              • 'f': +
              • 'f': pushes onto the stack the function that is running at the given level;
              • -
              • 'L': +
              • 'L': pushes onto the stack a table whose indices are the numbers of the lines that are valid on the function. (A valid line is a line with some associated code, @@ -5164,7 +5169,8 @@

                4.9 – The Debug Interface

                an identification of the activation record of the function executing at a given level. Level 0 is the current running function, -whereas level n+1 is the function that has called level n. +whereas level n+1 is the function that has called level n +(except for tail calls, which do not count on the stack). When there are no errors, lua_getstack returns 1; when called with a level greater than the stack depth, it returns 0. @@ -5257,24 +5263,24 @@

                4.9 – The Debug Interface

                  -
                • The call hook: is called when the interpreter calls a function. +
                • The call hook: is called when the interpreter calls a function. The hook is called just after Lua enters the new function, before the function gets its arguments.
                • -
                • The return hook: is called when the interpreter returns from a function. +
                • The return hook: is called when the interpreter returns from a function. The hook is called just before Lua leaves the function. There is no standard way to access the values to be returned by the function.
                • -
                • The line hook: is called when the interpreter is about to +
                • The line hook: is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.)
                • -
                • The count hook: is called after the interpreter executes every +
                • The count hook: is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.)
                • @@ -5333,7 +5339,7 @@

                  4.9 – The Debug Interface


                  lua_upvalueid

                  [-0, +0, -] -

                  void *(lua_upvalueid) (lua_State *L, int funcindex, int n);
                  +
                  void *lua_upvalueid (lua_State *L, int funcindex, int n);

                  Returns an unique identifier for the upvalue numbered n @@ -5832,7 +5838,7 @@

                  5.1 – Functions and Types


                  luaL_checkversion

                  [-0, +0, -] -

                  void *luaL_checkversion (lua_State *L);
                  +
                  void luaL_checkversion (lua_State *L);

                  Checks whether the core running the call, @@ -5919,9 +5925,9 @@

                  5.1 – Functions and Types


                  luaL_fileresult

                  -[-0, +(1/3), m] +[-0, +(1|3), m]

                  int luaL_fileresult (lua_State *L, int stat,
                  -                                             const char *fname)
                  + const char *fname);

                  This function produces the return values for @@ -6650,22 +6656,22 @@

                  6.1 – Basic Functions

                    -
                  • "collect": +
                  • "collect": performs a full garbage-collection cycle. This is the default option.
                  • -
                  • "stop": +
                  • "stop": stops automatic invocation of the garbage collector. The collector will run only when explcitly invoked, until a call to restart it.
                  • -
                  • "restart": +
                  • "restart": restarts automatic invocation the garbage collector.
                  • -
                  • "count": +
                  • "count": returns the total memory in use by Lua (in Kbytes) and a second value with the total memory in bytes modulo 1024. The first value has a fractional part, @@ -6679,7 +6685,7 @@

                    6.1 – Basic Functions

                    with a non floating-point type for numbers.)
                  • -
                  • "step": +
                  • "step": performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. @@ -6688,19 +6694,19 @@

                    6.1 – Basic Functions

                    Returns true if the step finished a collection cycle.
                  • -
                  • "setpause": +
                  • "setpause": sets arg as the new value for the pause of the collector (see §2.5). Returns the previous value for pause.
                  • -
                  • "setstepmul": +
                  • "setstepmul": sets arg as the new value for the step multiplier of the collector (see §2.5). Returns the previous value for step.
                  • -
                  • "isrunning": +
                  • "isrunning": returns a boolean that tells whether the collector is running (i.e., not stopped).
                  • @@ -7757,9 +7763,9 @@

                    6.4 – String Manipulation

                    If repl is a string, then its value is used for replacement. The character % works as an escape character: -any sequence in repl of the form %n, -with n between 1 and 9, -stands for the value of the n-th captured substring (see below). +any sequence in repl of the form %d, +with d between 1 and 9, +stands for the value of the d-th captured substring (see below). The sequence %0 stands for the whole match. The sequence %% stands for a single %. @@ -7903,35 +7909,35 @@

                    Character Class:

                      -
                    • x: +
                    • x: (where x is not one of the magic characters ^$()%.[]*+-?) represents the character x itself.
                    • -
                    • .: (a dot) represents all characters.
                    • +
                    • .: (a dot) represents all characters.
                    • -
                    • %a: represents all letters.
                    • +
                    • %a: represents all letters.
                    • -
                    • %c: represents all control characters.
                    • +
                    • %c: represents all control characters.
                    • -
                    • %d: represents all digits.
                    • +
                    • %d: represents all digits.
                    • -
                    • %g: represents all printable characters except space.
                    • +
                    • %g: represents all printable characters except space.
                    • -
                    • %l: represents all lowercase letters.
                    • +
                    • %l: represents all lowercase letters.
                    • -
                    • %p: represents all punctuation characters.
                    • +
                    • %p: represents all punctuation characters.
                    • -
                    • %s: represents all space characters.
                    • +
                    • %s: represents all space characters.
                    • -
                    • %u: represents all uppercase letters.
                    • +
                    • %u: represents all uppercase letters.
                    • -
                    • %w: represents all alphanumeric characters.
                    • +
                    • %w: represents all alphanumeric characters.
                    • -
                    • %x: represents all hexadecimal digits.
                    • +
                    • %x: represents all hexadecimal digits.
                    • -
                    • %x: (where x is any non-alphanumeric character) +
                    • %x: (where x is any non-alphanumeric character) represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic) @@ -7939,7 +7945,7 @@

                      Character Class:

                      when used to represent itself in a pattern.

                    • -
                    • [set]: +
                    • [set]: represents the class which is the union of all characters in set. A range of characters can be specified by @@ -7961,7 +7967,7 @@

                      Character Class:

                      have no meaning.

                    • -
                    • [^set]: +
                    • [^set]: represents the complement of set, where set is interpreted as above.
                    • @@ -8097,13 +8103,11 @@

                      6.5 – Table Manipulation

                      -Currently, all functions in the table library, -except table.pack, -work on lists. -A list here means a proper sequence -or a table with a __len metamethod (see §3.4.6). -In particular, all functions ignore non-numeric keys -in lists given as arguments. +Remember that, whenever an operation needs the length of a table, +the table should be a proper sequence +or have a __len metamethod (see §3.4.6). +All functions ignore non-numeric keys +in tables given as arguments.

                      @@ -8642,7 +8646,7 @@

                      6.7 – Bitwise Operations

                      -


                      bit32.extract (n, field, width)

                      +

                      bit32.extract (n, field [, width])

                      @@ -8652,10 +8656,14 @@

                      6.7 – Bitwise Operations

                      All accessed bits must be in the range [0, 31]. +

                      +The default for width is 1. + +

                      -


                      bit32.replace (n, v, field, width)

                      +

                      bit32.replace (n, v, field [, width])

                      @@ -8848,7 +8856,7 @@

                      6.8 – Input and Output Facilities

                      Opens the given file name in read mode and returns an iterator function that -works like file:lines(···) over the oppened file. +works like file:lines(···) over the opened file. When the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file. @@ -8877,12 +8885,12 @@

                      6.8 – Input and Output Facilities

                      The mode string can be any of the following:
                        -
                      • "r": read mode (the default);
                      • -
                      • "w": write mode;
                      • -
                      • "a": append mode;
                      • -
                      • "r+": update mode, all previous data is preserved;
                      • -
                      • "w+": update mode, all previous data is erased;
                      • -
                      • "a+": append update mode, previous data is preserved, +
                      • "r": read mode (the default);
                      • +
                      • "w": write mode;
                      • +
                      • "a": append mode;
                      • +
                      • "r+": update mode, all previous data is preserved;
                      • +
                      • "w+": update mode, all previous data is erased;
                      • +
                      • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

                      The mode string can also have a 'b' at the end, @@ -9037,28 +9045,28 @@

                      6.8 – Input and Output Facilities

                        -
                      • "*n": +
                      • "*n": reads a number; this is the only format that returns a number instead of a string.
                      • -
                      • "*a": +
                      • "*a": reads the whole file, starting at the current position. On end of file, it returns the empty string.
                      • -
                      • "*l": +
                      • "*l": reads the next line skipping the end of line, returning nil on end of file. This is the default format.
                      • -
                      • "*L": +
                      • "*L": reads the next line keeping the end of line (if present), returning nil on end of file.
                      • -
                      • number: +
                      • number: reads a string with up to this number of characters, returning nil on end of file. If number is zero, @@ -9081,9 +9089,9 @@

                        6.8 – Input and Output Facilities

                        specified by the string whence, as follows:
                          -
                        • "set": base is position 0 (beginning of the file);
                        • -
                        • "cur": base is current position;
                        • -
                        • "end": base is end of file;
                        • +
                        • "set": base is position 0 (beginning of the file);
                        • +
                        • "cur": base is current position;
                        • +
                        • "end": base is end of file;

                        In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. @@ -9114,17 +9122,17 @@

                        6.8 – Input and Output Facilities

                          -
                        • "no": +
                        • "no": no buffering; the result of any output operation appears immediately.
                        • -
                        • "full": +
                        • "full": full buffering; output operation is performed only when the buffer is full (or when you explicitly flush the file (see io.flush)).
                        • -
                        • "line": +
                        • "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device). @@ -9251,12 +9259,12 @@

                          6.9 – Operating System Facilities

                            -
                          • "exit": +
                          • "exit": the command terminated normally; the following number is the exit status of the command.
                          • -
                          • "signal": +
                          • "signal": the command was terminated by a signal; the following number is the signal that terminated the command.
                          • @@ -9460,18 +9468,6 @@

                            6.10 – The Debug Library

                            -

                            -


                            debug.getuservalue (u)

                            - - -

                            -Returns the Lua value associated to u. -If u is not a userdata, -returns nil. - - - -


                            debug.gethook ([thread])

                            @@ -9596,18 +9592,13 @@

                            6.10 – The Debug Library

                            -


                            debug.setuservalue (udata, value)

                            - - -

                            -Sets the given value as -the Lua value associated to the given udata. -value must be a table or nil; -udata must be a full userdata. +


                            debug.getuservalue (u)

                            -Returns udata. +Returns the Lua value associated to u. +If u is not a userdata, +returns nil. @@ -9624,9 +9615,9 @@

                            6.10 – The Debug Library

                            with the given meaning:
                              -
                            • "c": the hook is called every time Lua calls a function;
                            • -
                            • "r": the hook is called every time Lua returns from a function;
                            • -
                            • "l": the hook is called every time Lua enters a new line of code.
                            • +
                            • "c": the hook is called every time Lua calls a function;
                            • +
                            • "r": the hook is called every time Lua returns from a function;
                            • +
                            • "l": the hook is called every time Lua enters a new line of code.

                            With a count different from zero, the hook is called after every count instructions. @@ -9701,6 +9692,23 @@

                            6.10 – The Debug Library

                            +

                            +


                            debug.setuservalue (udata, value)

                            + + +

                            +Sets the given value as +the Lua value associated to the given udata. +value must be a table or nil; +udata must be a full userdata. + + +

                            +Returns udata. + + + +


                            debug.traceback ([thread,] [message [, level]])

                            @@ -9772,12 +9780,12 @@

                            7 – Lua Standalone

                            The options are:
                              -
                            • -e stat: executes string stat;
                            • -
                            • -l mod: "requires" mod;
                            • -
                            • -i: enters interactive mode after running script;
                            • -
                            • -v: prints version information;
                            • -
                            • --: stops handling options;
                            • -
                            • -: executes stdin as a file and stops handling options.
                            • +
                            • -e stat: executes string stat;
                            • +
                            • -l mod: "requires" mod;
                            • +
                            • -i: enters interactive mode after running script;
                            • +
                            • -v: prints version information;
                            • +
                            • --: stops handling options;
                            • +
                            • -: executes stdin as a file and stops handling options.

                            After handling its options, lua runs the given script, passing to it the given args as string arguments. @@ -10195,7 +10203,7 @@

                            9 – The Complete Syntax of Lua


                            Last update: -Tue Jun 21 19:09:27 BRT 2011 +Mon Jun 27 15:48:15 BRT 2011

                            - + @@ -880,7 +880,7 @@

                            2.5.1 – Garbage-Collection Metamethods

                            Because the object being collected must still be used by the finalizer -and even resurrectedresurrection +and even resurrected (e.g., stored by the finalizer in a global variable), the object memory is freed only when it becomes completely inaccessible (that is, in the next garbage-collection cycle unless it was resurrected). @@ -7245,11 +7245,11 @@

                            6.3 – Modules

                            To find a loader, -require is guided by the package.loaders sequence. +require is guided by the package.searchers sequence. By changing this sequence, we can change how require looks for a module. The following explanation is based on the default configuration -for package.loaders. +for package.searchers.

                            @@ -7261,7 +7261,7 @@

                            6.3 – Modules

                            If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, -it tries an all-in-one loader (see package.loaders). +it tries an all-in-one loader (see package.searchers).

                            @@ -7359,7 +7359,84 @@

                            6.3 – Modules

                            -


                            package.loaders

                            +

                            package.loadlib (libname, funcname)

                            + + +

                            +Dynamically links the host program with the C library libname. + + +

                            +If funcname is "*", +then it only links with the library, +making the symbols exported by the library +available to other dynamically linked libraries. +Otherwise, +it looks for a function funcname inside the library +and returns this function as a C function. +(So, funcname must follow the protocol (see lua_CFunction)). + + +

                            +This is a low-level function. +It completely bypasses the package and module system. +Unlike require, +it does not perform any path searching and +does not automatically adds extensions. +libname must be the complete file name of the C library, +including if necessary a path and an extension. +funcname must be the exact name exported by the C library +(which may depend on the C compiler and linker used). + + +

                            +This function is not supported by Standard C. +As such, it is only available on some platforms +(Windows, Linux, Mac OS X, Solaris, BSD, +plus other Unix systems that support the dlfcn standard). + + + + +

                            +


                            package.path

                            + + +

                            +The path used by require to search for a Lua loader. + + +

                            +At start-up, Lua initializes this variable with +the value of the environment variable LUA_PATH_5_2 or +the environment variable LUA_PATH or +with a default path defined in luaconf.h, +if the environment variable is not defined. +Any ";;" in the value of the environment variable +is replaced by the default path. + + + + +

                            +


                            package.preload

                            + + +

                            +A table to store loaders for specific modules +(see require). + + +

                            +This variable is only a reference to the real table; +assignments to this variable do not change the +table used by require. + + + + +

                            +


                            package.searchers

                            @@ -7444,83 +7521,6 @@

                            6.3 – Modules

                            -

                            -


                            package.loadlib (libname, funcname)

                            - - -

                            -Dynamically links the host program with the C library libname. - - -

                            -If funcname is "*", -then it only links with the library, -making the symbols exported by the library -available to other dynamically linked libraries. -Otherwise, -it looks for a function funcname inside the library -and returns this function as a C function. -(So, funcname must follow the protocol (see lua_CFunction)). - - -

                            -This is a low-level function. -It completely bypasses the package and module system. -Unlike require, -it does not perform any path searching and -does not automatically adds extensions. -libname must be the complete file name of the C library, -including if necessary a path and an extension. -funcname must be the exact name exported by the C library -(which may depend on the C compiler and linker used). - - -

                            -This function is not supported by Standard C. -As such, it is only available on some platforms -(Windows, Linux, Mac OS X, Solaris, BSD, -plus other Unix systems that support the dlfcn standard). - - - - -

                            -


                            package.path

                            - - -

                            -The path used by require to search for a Lua loader. - - -

                            -At start-up, Lua initializes this variable with -the value of the environment variable LUA_PATH_5_2 or -the environment variable LUA_PATH or -with a default path defined in luaconf.h, -if the environment variable is not defined. -Any ";;" in the value of the environment variable -is replaced by the default path. - - - - -

                            -


                            package.preload

                            - - -

                            -A table to store loaders for specific modules -(see require). - - -

                            -This variable is only a reference to the real table; -assignments to this variable do not change the -table used by require. - - - -


                            package.searchpath (name, path [, sep])

                            @@ -10031,6 +10031,10 @@

                            8.2 – Changes in the Libraries

                            as now patterns may contain '\0' as a regular character. +
                          • +The table package.loaders was renamed package.searchers. +
                          • +
                          • Lua does not have bytecode verification anymore. So, all functions that load code @@ -10203,7 +10207,7 @@

                            9 – The Complete Syntax of Lua


                            Last update: -Mon Jun 27 15:48:15 BRT 2011 +Tue Jun 28 14:51:18 BRT 2011

                            - + @@ -8152,8 +8152,8 @@

                            6.5 – Table Manipulation

                            Returns a new table with all parameters stored into keys 1, 2, etc. and with a field "n" with the total number of parameters. -Note that the result may not be a sequence, -if any parameter is nil. +Also returns, as a second result, the total number of parameters. +Note that the resulting table may not be a sequence. @@ -9995,7 +9995,7 @@

                            8.2 – Changes in the Libraries

                          • -Functions setfenv and getfenv are deprecated, +Functions setfenv and getfenv were removed, because of the changes in environments.
                          • @@ -10096,7 +10096,7 @@

                            8.3 – Changes in the API

                          • -luaL_typerror was deprecated. +luaL_typerror was removed. Write your own version if you need it.
                          • @@ -10207,7 +10207,7 @@

                            9 – The Complete Syntax of Lua


                            Last update: -Tue Jun 28 14:51:18 BRT 2011 +Mon Jul 4 16:21:50 BRT 2011

                            - + @@ -1167,7 +1167,7 @@

                            3.1 – Lexical Conventions

                            and '\'' (apostrophe [single quote]). A backslash followed by a real newline results in a newline in the string. -The escape sequence '\*' skips the following span +The escape sequence '\z' skips the following span of white-space characters, including line breaks; it is particularly useful to break and indent a long string @@ -2603,12 +2603,12 @@

                            4.5 – Registry

                            The following constants are defined:
                              -
                            • LUA_RIDX_MAINTHREAD: At this index the registry has +
                            • LUA_RIDX_MAINTHREAD: At this index the registry has the main thread of the state. (The main thread is the one created together with the state.)
                            • -
                            • LUA_RIDX_GLOBALS: At this index the registry has +
                            • LUA_RIDX_GLOBALS: At this index the registry has the global environment. This is the C equivalent to the _G global variable.
                            • @@ -6656,22 +6656,22 @@

                              6.1 – Basic Functions

                                -
                              • "collect": +
                              • "collect": performs a full garbage-collection cycle. This is the default option.
                              • -
                              • "stop": +
                              • "stop": stops automatic invocation of the garbage collector. The collector will run only when explcitly invoked, until a call to restart it.
                              • -
                              • "restart": +
                              • "restart": restarts automatic invocation the garbage collector.
                              • -
                              • "count": +
                              • "count": returns the total memory in use by Lua (in Kbytes) and a second value with the total memory in bytes modulo 1024. The first value has a fractional part, @@ -6685,7 +6685,7 @@

                                6.1 – Basic Functions

                                with a non floating-point type for numbers.)
                              • -
                              • "step": +
                              • "step": performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. @@ -6694,19 +6694,19 @@

                                6.1 – Basic Functions

                                Returns true if the step finished a collection cycle.
                              • -
                              • "setpause": +
                              • "setpause": sets arg as the new value for the pause of the collector (see §2.5). Returns the previous value for pause.
                              • -
                              • "setstepmul": +
                              • "setstepmul": sets arg as the new value for the step multiplier of the collector (see §2.5). Returns the previous value for step.
                              • -
                              • "isrunning": +
                              • "isrunning": returns a boolean that tells whether the collector is running (i.e., not stopped).
                              • @@ -7649,7 +7649,7 @@

                                6.4 – String Manipulation

                                A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, -with no characters in pattern being considered "magic". +with no characters in pattern being considered magic. Note that if plain is given, then init must be given as well. @@ -7671,21 +7671,18 @@

                                6.4 – String Manipulation

                                following the description given in its first argument (which must be a string). The format string follows the same rules as the C function sprintf. The only differences are that the options/modifiers -*, l, L, n, p, -and h are not supported +*, h, L, l, n, +and p are not supported and that there is an extra option, q. -The q option formats a string in a form suitable to be safely read -back by the Lua interpreter: -the string is written between double quotes, -and all double quotes, newlines, embedded zeros, -and backslashes in the string -are correctly escaped when written. +The q option formats a string between double quotes, +using escape sequences when necessary to ensure that +it can safely be read back by the Lua interpreter. For instance, the call
                                      string.format('%q', 'a string with "quotes" and \n new line')
                                 

                                -will produce the string: +may produce the string:

                                      "a string with \"quotes\" and \
                                @@ -7702,8 +7699,8 @@ 

                                6.4 – String Manipulation

                                expect an integer as argument; the range of that integer may be limited by the underlying C implementation. -Option q expects a string -and s expects a string without embedded zeros. +Option q expects a string; +option s expects a string without embedded zeros. If the argument to option s is not a string, it is converted to one following the same rules of tostring. @@ -8885,12 +8882,12 @@

                                6.8 – Input and Output Facilities

                                The mode string can be any of the following:
                                  -
                                • "r": read mode (the default);
                                • -
                                • "w": write mode;
                                • -
                                • "a": append mode;
                                • -
                                • "r+": update mode, all previous data is preserved;
                                • -
                                • "w+": update mode, all previous data is erased;
                                • -
                                • "a+": append update mode, previous data is preserved, +
                                • "r": read mode (the default);
                                • +
                                • "w": write mode;
                                • +
                                • "a": append mode;
                                • +
                                • "r+": update mode, all previous data is preserved;
                                • +
                                • "w+": update mode, all previous data is erased;
                                • +
                                • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

                                The mode string can also have a 'b' at the end, @@ -9045,23 +9042,23 @@

                                6.8 – Input and Output Facilities

                                  -
                                • "*n": +
                                • "*n": reads a number; this is the only format that returns a number instead of a string.
                                • -
                                • "*a": +
                                • "*a": reads the whole file, starting at the current position. On end of file, it returns the empty string.
                                • -
                                • "*l": +
                                • "*l": reads the next line skipping the end of line, returning nil on end of file. This is the default format.
                                • -
                                • "*L": +
                                • "*L": reads the next line keeping the end of line (if present), returning nil on end of file.
                                • @@ -9089,9 +9086,9 @@

                                  6.8 – Input and Output Facilities

                                  specified by the string whence, as follows:
                                    -
                                  • "set": base is position 0 (beginning of the file);
                                  • -
                                  • "cur": base is current position;
                                  • -
                                  • "end": base is end of file;
                                  • +
                                  • "set": base is position 0 (beginning of the file);
                                  • +
                                  • "cur": base is current position;
                                  • +
                                  • "end": base is end of file;

                                  In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. @@ -9122,17 +9119,17 @@

                                  6.8 – Input and Output Facilities

                                    -
                                  • "no": +
                                  • "no": no buffering; the result of any output operation appears immediately.
                                  • -
                                  • "full": +
                                  • "full": full buffering; output operation is performed only when the buffer is full (or when you explicitly flush the file (see io.flush)).
                                  • -
                                  • "line": +
                                  • "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device). @@ -9615,9 +9612,9 @@

                                    6.10 – The Debug Library

                                    with the given meaning:
                                      -
                                    • "c": the hook is called every time Lua calls a function;
                                    • -
                                    • "r": the hook is called every time Lua returns from a function;
                                    • -
                                    • "l": the hook is called every time Lua enters a new line of code.
                                    • +
                                    • 'c': the hook is called every time Lua calls a function;
                                    • +
                                    • 'r': the hook is called every time Lua returns from a function;
                                    • +
                                    • 'l': the hook is called every time Lua enters a new line of code.

                                    With a count different from zero, the hook is called after every count instructions. @@ -10207,7 +10204,7 @@

                                    9 – The Complete Syntax of Lua


                                    Last update: -Mon Jul 4 16:21:50 BRT 2011 +Tue Jul 5 19:16:15 BRT 2011

                                    - + @@ -2962,8 +2962,8 @@

                                    4.8 – Functions and Types


                                    lua_callk

                                    [-(nargs + 1), +nresults, e] -

                                    void lua_callk (lua_State *L, int nargs, int nresults,
                                    -                          int ctx, lua_CFunction k);
                                    +
                                    void lua_callk (lua_State *L, int nargs, int nresults, int ctx,
                                    +                lua_CFunction k);

                                    This function behaves exactly like lua_call, @@ -3857,7 +3857,7 @@

                                    4.8 – Functions and Types


                                    lua_pcallk

                                    [-(nargs + 1), +(nresults|1), -]

                                    int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
                                    -                          int ctx, lua_CFunction k);
                                    + int ctx, lua_CFunction k);

                                This function behaves exactly like lua_pcall, @@ -4839,8 +4839,7 @@

                                4.8 – Functions and Types


                                lua_yieldk

                                [-?, +?, -] -

                                int lua_yieldk  (lua_State *L, int nresults, int ctx,
                                -                           lua_CFunction k);
                                +
                                int lua_yieldk  (lua_State *L, int nresults, int ctx, lua_CFunction k);

                                Yields a coroutine. @@ -5362,7 +5361,7 @@

                                4.9 – The Debug Interface


                                lua_upvaluejoin

                                void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
                                -                                              int fidx2, int n2);
                                + int fidx2, int n2);

                                Make the n1-th upvalue of the Lua closure at index fidx1 @@ -5926,8 +5925,7 @@

                                5.1 – Functions and Types


                                luaL_fileresult

                                [-0, +(1|3), m] -

                                int luaL_fileresult (lua_State *L, int stat,
                                -                                             const char *fname);
                                +
                                int luaL_fileresult (lua_State *L, int stat, const char *fname);

                                This function produces the return values for @@ -6394,7 +6392,7 @@

                                5.1 – Functions and Types


                                luaL_requiref

                                [-0, +1, e]

                                void luaL_requiref (lua_State *L, const char *modname,
                                -                              lua_CFunction openf, int glb);
                                + lua_CFunction openf, int glb);

                                Calls function openf with string modname as an argument @@ -6486,8 +6484,8 @@

                                5.1 – Functions and Types


                                luaL_traceback

                                [-0, +1, m] -

                                void luaL_traceback (lua_State *L, lua_State *L1,
                                -                               const char *msg, int level);
                                +
                                void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                                +                     int level);

                                Creates and pushes a traceback of the stack L1. @@ -10204,7 +10202,7 @@

                                9 – The Complete Syntax of Lua


                                Last update: -Tue Jul 5 19:16:15 BRT 2011 +Fri Jul 8 17:11:02 BRT 2011 diff --git a/doc/lua.1 b/doc/lua.1 new file mode 100644 index 0000000000..1dbf04366c --- /dev/null +++ b/doc/lua.1 @@ -0,0 +1,116 @@ +.\" $Id: lua.man,v 1.13 2011/11/16 17:16:53 lhf Exp $ +.TH LUA 1 "$Date: 2011/11/16 17:16:53 $" +.SH NAME +lua \- Lua interpreter +.SH SYNOPSIS +.B lua +[ +.I options +] +[ +.I script +[ +.I args +] +] +.SH DESCRIPTION +.B lua +is the standalone Lua interpreter. +It loads and executes Lua programs, +either in textual source form or +in precompiled binary form. +(Precompiled binaries are output by +.BR luac , +the Lua compiler.) +.B lua +can be used as a batch interpreter and also interactively. +.LP +The given +.I options +are handled in order and then +the Lua program in file +.I script +is loaded and executed. +The given +.I args +are available to +.I script +as strings in a global table named +.BR arg . +If no options or arguments are given, +then +.B "\-v \-i" +is assumed when the standard input is a terminal; +otherwise, +.B "\-" +is assumed. +.LP +In interactive mode, +.B lua +prompts the user, +reads lines from the standard input, +and executes them as they are read. +If a line does not contain a complete statement, +then a secondary prompt is displayed and +lines are read until a complete statement is formed or +a syntax error is found. +If a line starts with +.BR '=' , +then +.B lua +evaluates and displays +the values of the expressions in the remainder of the line. +.LP +At the very start, +before even handling the command line, +.B lua +checks the contents of the environment variables +.B LUA_INIT_5_2 +or +.BR LUA_INIT , +in that order. +If the contents is of the form +.RI '@ filename ', +then +.I filename +is executed. +Otherwise, the string is assumed to be a Lua statement and is executed. +.SH OPTIONS +.TP +.BI \-e " stat" +execute statement +.IR stat . +.TP +.B \-i +enter interactive mode after executing +.IR script . +.TP +.BI \-l " name" +execute the equivalent of +.IB name =require(' name ') +before executing +.IR script . +.TP +.B \-v +show version information. +.TP +.B \-E +ignore environment variables. +.TP +.B \-\- +stop handling options. +.TP +.B \- +stop handling options and execute the standard input as a file. +.SH "SEE ALSO" +.BR luac (1) +.br +The documentation at lua.org, +especially section 7 of the reference manual. +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +R. Ierusalimschy, +L. H. de Figueiredo, +W. Celes +.\" EOF diff --git a/doc/lua.css b/doc/lua.css index fb462d9b9a..54708f823d 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -1,7 +1,6 @@ body { color: #000000 ; background-color: #FFFFFF ; - font-family: sans-serif ; font-family: Helvetica, Arial, sans-serif ; text-align: justify ; margin-right: 20px ; @@ -18,12 +17,13 @@ h2 { padding-top: 0.4em ; padding-bottom: 0.4em ; padding-left: 20px ; + padding-right: 20px ; margin-left: -20px ; background-color: #E0E0FF ; } h3 { - padding-left: 8px ; + padding-left: 0.5em ; border-left: solid #E0E0FF 1em ; } @@ -76,7 +76,6 @@ input[type=text] { -moz-border-radius: 2em ; background-image: url('images/search.png') ; background-repeat: no-repeat; - background-position: left center ; background-position: 4px center ; padding-left: 20px ; height: 2em ; diff --git a/doc/luac.1 b/doc/luac.1 new file mode 100644 index 0000000000..33a4ed00ac --- /dev/null +++ b/doc/luac.1 @@ -0,0 +1,118 @@ +.\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $ +.TH LUAC 1 "$Date: 2011/11/16 13:53:40 $" +.SH NAME +luac \- Lua compiler +.SH SYNOPSIS +.B luac +[ +.I options +] [ +.I filenames +] +.SH DESCRIPTION +.B luac +is the Lua compiler. +It translates programs written in the Lua programming language +into binary files containing precompiled chunks +that can be later loaded and executed. +.LP +The main advantages of precompiling chunks are: +faster loading, +protecting source code from accidental user changes, +and +off-line syntax checking. +Precompiling does not imply faster execution +because in Lua chunks are always compiled into bytecodes before being executed. +.B luac +simply allows those bytecodes to be saved in a file for later execution. +Precompiled chunks are not necessarily smaller than the corresponding source. +The main goal in precompiling is faster loading. +.LP +In the command line, +you can mix +text files containing Lua source and +binary files containing precompiled chunks. +.B luac +produces a single output file containing the combined bytecodes +for all files given. +Executing the combined file is equivalent to executing the given files. +By default, +the output file is named +.BR luac.out , +but you can change this with the +.B \-o +option. +.LP +Precompiled chunks are +.I not +portable across different architectures. +Moreover, +the internal format of precompiled chunks +is likely to change when a new version of Lua is released. +Make sure you save the source files of all Lua programs that you precompile. +.LP +.SH OPTIONS +.TP +.B \-l +produce a listing of the compiled bytecode for Lua's virtual machine. +Listing bytecodes is useful to learn about Lua's virtual machine. +If no files are given, then +.B luac +loads +.B luac.out +and lists its contents. +Use +.B \-l \-l +for a full listing. +.TP +.BI \-o " file" +output to +.IR file , +instead of the default +.BR luac.out . +(You can use +.B "'\-'" +for standard output, +but not on platforms that open standard output in text mode.) +The output file may be one of the given files because +all files are loaded before the output file is written. +Be careful not to overwrite precious files. +.TP +.B \-p +load files but do not generate any output file. +Used mainly for syntax checking and for testing precompiled chunks: +corrupted files will probably generate errors when loaded. +If no files are given, then +.B luac +loads +.B luac.out +and tests its contents. +No messages are displayed if the file loads without errors. +.TP +.B \-s +strip debug information before writing the output file. +This saves some space in very large chunks, +but if errors occur when running a stripped chunk, +then the error messages may not contain the full information they usually do. +In particular, +line numbers and names of local variables are lost. +.TP +.B \-v +show version information. +.TP +.B \-\- +stop handling options. +.TP +.B \- +stop handling options and process standard input. +.SH "SEE ALSO" +.BR lua (1) +.br +The documentation at lua.org. +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH AUTHORS +R. Ierusalimschy, +L. H. de Figueiredo, +W. Celes +.\" EOF diff --git a/doc/manual.css b/doc/manual.css index 6d5a3f09b5..b158aea36f 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -2,13 +2,16 @@ h3 code { font-family: inherit ; } -pre { - font-size: 105% ; +pre, code { + font-size: 12pt ; } span.apii { float: right ; font-family: inherit ; + font-style: normal ; + font-size: small ; + color: gray ; } p+h1, ul+h1 { diff --git a/doc/manual.html b/doc/manual.html index 72155652c4..9e16e6b0e8 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -16,11 +16,6 @@

                                Lua 5.2 Reference Manual

                                -[!] -This is a beta version of Lua 5.2. -Some details may change in the final version. -

                                - by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

                                @@ -38,7 +33,7 @@

                                - + @@ -51,8 +46,8 @@

                                1 – Introduction

                                facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. -Lua is intended to be used as a powerful, light-weight -scripting language for any program that needs one. +Lua is intended to be used as a powerful, lightweight, +embeddable scripting language for any program that needs one. Lua is implemented as a library, written in clean C, the common subset of Standard C and C++. @@ -86,14 +81,14 @@

                                1 – Introduction

                                For a discussion of the decisions behind the design of Lua, see the technical papers available at Lua's web site. For a detailed introduction to programming in Lua, -see Roberto's book, Programming in Lua (second edition). +see Roberto's book, Programming in Lua.

                                2 – Basic Concepts

                                -This section describes some basic concepts of the language. +This section describes the basic concepts of the language. @@ -148,11 +143,14 @@

                                2.1 – Values and Types

                                The type userdata is provided to allow arbitrary C data to be stored in Lua variables. -This type corresponds to a block of raw memory -and has no pre-defined operations in Lua, +A userdata value is a pointer to a block of raw memory. +There are two kinds of userdata: +full userdata, where the block of memory is managed by Lua, +and light userdata, where the block of memory is managed by the host. +Userdata has no predefined operations in Lua, except assignment and identity test. -However, by using metatables, -the programmer can define operations for userdata values +By using metatables, +the programmer can define operations for full userdata values (see §2.4). Userdata values cannot be created or modified in Lua, only through the C API. @@ -200,7 +198,7 @@

                                2.1 – Values and Types

                                Like indices, -the value of a table field can be of any type. +the values of table fields can be of any type. In particular, because functions are first-class values, table fields can contain functions. @@ -227,7 +225,7 @@

                                2.1 – Values and Types

                                The library function type returns a string describing the type -of a given value. +of a given value (see §6.1). @@ -239,8 +237,8 @@

                                2.2 – Environments and the Global Environment

                                As will be discussed in §3.2 and §3.3.3, any reference to a global name var is syntactically translated to _ENV.var. -Moreover, every chunk is compiled in the scope of an external -variable called _ENV (see §3.3.2), +Moreover, every chunk is compiled in the scope of +an external local variable called _ENV (see §3.3.2), so _ENV itself is never a global name in a chunk. @@ -252,12 +250,11 @@

                                2.2 – Environments and the Global Environment

                                you can define new variables and parameters with that name. Each reference to a global name uses the _ENV that is visible at that point in the program, -following the usual visibility rules of Lua. +following the usual visibility rules of Lua (see §3.5).

                                -Any table used as the value of _ENV is usually called -an environment. +Any table used as the value of _ENV is called an environment.

                                @@ -268,13 +265,14 @@

                                2.2 – Environments and the Global Environment

                                When Lua compiles a chunk, -it initializes the value of its _ENV variable +it initializes the value of its _ENV upvalue with the global environment (see load). Therefore, by default, global variables in Lua code refer to entries in the global environment. -Moreover, all standard libraries are loaded in the global environment, +Moreover, all standard libraries are loaded in the global environment and several functions there operate on that environment. -You can use load to load a chunk with a different environment. +You can use load (or loadfile) +to load a chunk with a different environment. (In C, you have to load the chunk and then change the value of its first upvalue.) @@ -325,7 +323,7 @@

                                2.3 – Error Handling

                                When you use xpcall or lua_pcall, -you may give an message handler +you may give a message handler to be called in case of errors. This function is called with the original error message and returns a new error message. @@ -389,8 +387,8 @@

                                2.4 – Metatables and Metamethods

                                A metatable controls how an object behaves in arithmetic operations, order comparisons, concatenation, length operation, and indexing. -A metatable also can define a function to be called when a userdata -is garbage collected. +A metatable also can define a function to be called +when a userdata or a table is garbage collected. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) @@ -427,8 +425,8 @@

                                2.4 – Metatables and Metamethods

                                rawget(getmetatable(obj) or {}, event)

                                -That is, the access to a metamethod does not invoke other metamethods, -and the access to objects with no metatables does not fail +This means that the access to a metamethod does not invoke other metamethods, +and access to objects with no metatables does not fail (it simply results in nil). @@ -590,13 +588,17 @@

                                2.4 – Metatables and Metamethods

                                for equality. A metamethod is selected only when both values being compared have the same type -and the same metamethod for the selected operation. +and the same metamethod for the selected operation, +and the values are either tables or full userdata.
                                -     function getequalhandler (op1, op2, event)
                                -       if type(op1) ~= type(op2) then return nil end
                                -       local mm1 = metatable(op1)[event]
                                -       local mm2 = metatable(op2)[event]
                                +     function getequalhandler (op1, op2)
                                +       if type(op1) ~= type(op2) or
                                +          (type(op1) ~= "table" and type(op1) ~= "userdata") then
                                +         return nil     -- different values
                                +       end
                                +       local mm1 = metatable(op1).__eq
                                +       local mm2 = metatable(op2).__eq
                                        if mm1 == mm2 then return mm1 else return nil end
                                      end
                                 

                                @@ -604,21 +606,19 @@

                                2.4 – Metatables and Metamethods

                                      function eq_event (op1, op2)
                                -       if type(op1) ~= type(op2) then  -- different types?
                                -         return false   -- different values
                                -       end
                                        if op1 == op2 then   -- primitive equal?
                                          return true   -- values are equal
                                        end
                                        -- try metamethod
                                -       local h = getequalhandler(op1, op2, "__eq")
                                +       local h = getequalhandler(op1, op2)
                                        if h then
                                -         return (h(op1, op2))
                                +         return not not h(op1, op2)
                                        else
                                          return false
                                        end
                                      end
                                 

                                +Note that the result is always a boolean.

                              • "lt": @@ -634,13 +634,14 @@

                                2.4 – Metatables and Metamethods

                                else local h = getbinhandler(op1, op2, "__lt") if h then - return (h(op1, op2)) + return not not h(op1, op2) else error(···) end end end

                                +Note that the result is always a boolean.

                              • "le": @@ -656,7 +657,7 @@

                                2.4 – Metatables and Metamethods

                                else local h = getbinhandler(op1, op2, "__le") if h then - return (h(op1, op2)) + return not not h(op1, op2) else h = getbinhandler(op1, op2, "__lt") if h then @@ -671,6 +672,11 @@

                                2.4 – Metatables and Metamethods

                                Note that, in the absence of a "le" metamethod, Lua tries the "lt", assuming that a <= b is equivalent to not (b < a). + + +

                                +As with the other comparison operators, +the result is always a boolean.

                              • "index": @@ -770,7 +776,7 @@

                                2.5 – Garbage Collection

                                a garbage collector to collect all dead objects (that is, objects that are no longer accessible from Lua). All memory used by Lua is subject to automatic management: -tables, userdata, functions, threads, strings, etc. +strings, tables, userdata, functions, threads, internal structures, etc.

                                @@ -819,10 +825,25 @@

                                2.5 – Garbage Collection

                                You can change these numbers by calling lua_gc in C or collectgarbage in Lua. -With these functions you can also control +You can also use these functions to control the collector directly (e.g., stop and restart it). +

                                +As an experimental feature in Lua 5.2, +you can change the collector's operation mode +from incremental to generational. +A generational collector assumes that most objects die young, +and therefore it traverses only young (recently created) objects. +This behavior can reduce the time used by the collector, +but also increases memory usage (as old dead objects may accumulate). +To mitigate this second problem, +from time to time the generational collector performs a full collection. +Remember that this is an experimental feature; +you are welcome to try it, +but check your gains. + +

                                2.5.1 – Garbage-Collection Metamethods

                                @@ -879,11 +900,17 @@

                                2.5.1 – Garbage-Collection Metamethods

                                -Because the object being collected must still be used by the finalizer -and even resurrected -(e.g., stored by the finalizer in a global variable), -the object memory is freed only when it becomes completely inaccessible -(that is, in the next garbage-collection cycle unless it was resurrected). +Because the object being collected must still be used by the finalizer, +it (and other objects accessible only through it) +must be resurrected by Lua. +Usually, this resurrection is transient, +and the object memory is freed in the next garbage-collection cycle. +However, if the finalizer stores the object in some global place +(e.g., a global variable), +then there is a permanent resurrection. +In any case, +the object memory is freed only when it becomes completely inaccessible; +its finalizer will never be called twice. @@ -927,32 +954,42 @@

                                2.5.2 – Weak Tables

                                -After you use a table as a metatable, -you should not change the value of its __mode field. -Otherwise, the weak behavior of the tables controlled by this -metatable is undefined. +Any change in the weakness of a table may take effect only +at the next collect cycle. +In particular, if you change the weakness to a stronger mode, +Lua may still collect some items from that table +before the change takes effect.

                                Only objects that have an explicit construction -can be removed from weak tables. -Values, such as numbers and booleans, +are removed from weak tables. +Values, such as numbers and light C functions, are not subject to garbage collection, and therefore are not removed from weak tables (unless its associated value is collected). -Lua treats strings and light C functions as non-object values. +Although strings are subject to garbage collection, +they do not have an explicit construction, +and therefore are not removed from weak tables.

                                -Objects marked for finalization have a special behavior in weak tables. -When a marked object is a value in a weak table, -it is removed from the table before running its finalizer. -However, when it is a key, -it is removed from the table only after running its finalizer. +Resurrected objects +(that is, objects being finalized +and objects accessible only through objects being finalized) +have a special behavior in weak tables. +They are removed from weak values before running their finalizers, +but are removed from weak keys only in the next collection +after running their finalizers, when such objects are actually freed. This behavior allows the finalizer to access properties associated with the object through weak tables. +

                                +If a weak table is among the resurrected objects in a collection cycle, +it may not be properly cleared until the next cycle. + + @@ -1060,7 +1097,6 @@

                                2.6 – Coroutines

                                      co-body 1       10
                                      foo     2
                                -     
                                      main    true    4
                                      co-body r
                                      main    true    11      -9
                                @@ -1090,7 +1126,7 @@ 

                                3 – The Language

                                -The language constructs will be explained using the usual extended BNF notation, +Language constructs will be explained using the usual extended BNF notation, in which {a} means 0 or more a's, and [a] means an optional a. @@ -1176,7 +1212,7 @@

                                3.1 – Lexical Conventions

                                -A character in a literal string can also be specified by its numerical value. +A byte in a literal string can also be specified by its numerical value. This can be done with the escape sequence \xXX, where XX is a sequence of exactly two hexadecimal digits, or with the escape sequence \ddd, @@ -1407,13 +1443,13 @@

                                3.3.2 – Chunks

                                A chunk can be stored in a file or in a string inside the host program. To execute a chunk, -Lua first pre-compiles the chunk into instructions for a virtual machine, +Lua first precompiles the chunk into instructions for a virtual machine, and then it executes the compiled code with an interpreter for the virtual machine.

                                -Chunks can also be pre-compiled into binary form; +Chunks can also be precompiled into binary form; see program luac for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly. @@ -1555,7 +1591,7 @@

                                3.3.4 – Control Structures

                                -Both labels and empty statements are called void statements, +Labels and empty statements are called void statements, as they perform no actions. @@ -1806,14 +1842,13 @@

                                3.4 – Expressions

                                Both function calls and vararg expressions can result in multiple values. -If an expression is used as a statement -(only possible for function calls (see §3.3.6)), +If a function call is used as a statement (see §3.3.6), then its return list is adjusted to zero elements, thus discarding all returned values. If an expression is used as the last (or the only) element of a list of expressions, then no adjustment is made -(unless the call is enclosed in parentheses). +(unless the expression is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, discarding all values except the first one. @@ -1881,8 +1916,7 @@

                                3.4.2 – Coercion

                                string and number values at run time. Any arithmetic operation applied to a string tries to convert this string to a number, following the rules of the Lua lexer. -(The string may have leading and trailing spaces, -plus an optional sign.) +(The string may have leading and trailing spaces and a sign.) Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control over how numbers are converted to strings, @@ -2254,8 +2288,8 @@

                                3.4.10 – Function Definitions

                                A function definition is an executable expression, whose value has type function. -When Lua pre-compiles a chunk, -all its function bodies are pre-compiled too. +When Lua precompiles a chunk, +all its function bodies are precompiled too. Then, whenever Lua executes the function definition, the function is instantiated (or closed). This function instance (or closure) @@ -2272,9 +2306,9 @@

                                3.4.10 – Function Definitions

                                When a function is called, the list of arguments is adjusted to the length of the list of parameters, -unless the function is a variadic or vararg function, -which is -indicated by three dots ('...') at the end of its parameter list. +unless the function is a vararg function, +which is indicated by three dots ('...') +at the end of its parameter list. A vararg function does not adjust its argument list; instead, it collects all extra arguments and supplies them to the function through a vararg expression, @@ -2425,7 +2459,8 @@

                                4 – The Application Program Interface

                                Even when we use the term "function", any facility in the API may be provided as a macro instead. -All such macros use each of their arguments exactly once +Except where stated otherwise, +all such macros use each of their arguments exactly once (except for the first argument, which is always a Lua state), and so do not generate any hidden side-effects. @@ -2434,8 +2469,7 @@

                                4 – The Application Program Interface

                                As in most C libraries, the Lua API functions do not check their arguments for validity or consistency. However, you can change this behavior by compiling Lua -with a proper definition for the macro luai_apicheck, -in file luaconf.h. +with the macro LUA_USE_APICHECK defined. @@ -2472,10 +2506,6 @@

                                4.1 – The Stack

                                index -1 also represents the last element (that is, the element at the top) and index -n represents the first element. -We say that an index is valid -if it lies between 1 and the stack top -(that is, if 1 ≤ abs(index) ≤ top). - @@ -2494,7 +2524,7 @@

                                4.2 – Stack Size

                                Whenever Lua calls C, -it ensures that at least LUA_MINSTACK stack positions are available. +it ensures that the stack has at least LUA_MINSTACK extra slots. LUA_MINSTACK is defined as 20, so that usually you do not have to worry about stack space unless your code has loops pushing elements onto the stack. @@ -2509,33 +2539,66 @@

                                4.2 – Stack Size

                                you should use lua_checkstack. + + + +

                                4.3 – Valid and Acceptable Indices

                                +

                                -Most query functions accept as indices any value inside the -available stack space, that is, indices up to the maximum stack size -that you have set through lua_checkstack. -Such indices are called acceptable indices. -More formally, we define an acceptable index +Any function in the API that receives stack indices +works only with valid indices or acceptable indices. + + +

                                +A valid index is an index that refers to a +valid position within the stack, that is, +it lies between 1 and the stack top +(1 ≤ abs(index) ≤ top). + +Usually, functions that need a specific stack position +(e.g., lua_remove) require valid indices. + + +

                                +Functions that do not need a specific stack position, +but only a value in the stack (e.g., query functions), +can be called with acceptable indices. +An acceptable index refers to a position within +the space allocated for the stack, +that is, indices up to the stack size. +More formally, we define an acceptable index as follows:

                                      (index < 0 && abs(index) <= top) ||
                                -     (index > 0 && index <= stackspace)
                                +     (index > 0 && index <= stack size)
                                 

                                -Note that 0 is never an acceptable index. +(Note that 0 is never an acceptable index.) +When a function is called, +its stack size is top + LUA_MINSTACK. +You can change its stack size through function lua_checkstack. +

                                +Acceptable indices serve to avoid extra tests +against the stack top when querying the stack. +For instance, a C function can query its third argument +without the need to first check whether there is a third argument, +that is, without the need to check whether 3 is a valid index. +

                                +For functions that can be called with acceptable indices, +any non-valid index is treated as if it +contains a value of a virtual type LUA_TNONE. -

                                4.3 – Pseudo-Indices

                                Unless otherwise noted, any function that accepts valid indices also accepts pseudo-indices, which represent some Lua values that are accessible to C code but which are not in the stack. -Pseudo-indices are used to access -the registry +Pseudo-indices are used to access the registry and the upvalues of a C function (see §4.4). @@ -2547,10 +2610,10 @@

                                4.4 – C Closures

                                When a C function is created, it is possible to associate some values with it, -thus creating a C closure; +thus creating a C closure +(see lua_pushcclosure); these values are called upvalues and are -accessible to the function whenever it is called -(see lua_pushcclosure). +accessible to the function whenever it is called.

                                @@ -2573,12 +2636,13 @@

                                4.5 – Registry

                                Lua provides a registry, -a pre-defined table that can be used by any C code to -store whatever Lua value it needs to store. -This table is always located at pseudo-index +a predefined table that can be used by any C code to +store whatever Lua values it needs to store. +The registry table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, -but it should take care to choose keys different from those used +but it should take care to choose keys +that are different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name, or a light userdata with the address of a C object in your code, @@ -2610,7 +2674,6 @@

                                4.5 – Registry

                              • LUA_RIDX_GLOBALS: At this index the registry has the global environment. -This is the C equivalent to the _G global variable.
                              @@ -2629,8 +2692,8 @@

                              4.6 – Error Handling in C

                              it raises an error; that is, it does a long jump. A protected environment uses setjmp -to set a recover point; -any error jumps to the most recent active recover point. +to set a recovery point; +any error jumps to the most recent active recovery point.

                              @@ -2639,7 +2702,8 @@

                              4.6 – Error Handling in C

                              and then calls abort, thus exiting the host application. Your panic function can avoid this exit by -never returning (e.g., doing a long jump). +never returning +(e.g., doing a long jump to your own recovery point outside Lua).

                              @@ -2677,8 +2741,7 @@

                              4.7 – Handling Yields in C

                              -To explain continuations, -let us set some terminology. +We need to set some terminology to explain continuations. We have a C function called from Lua which we will call the original function. This original function then calls one of those three functions in the C API, @@ -2704,7 +2767,7 @@

                              4.7 – Handling Yields in C

                              -Lua treats the continuation function as if it was the original function. +Lua treats the continuation function as if it were the original function. The continuation function receives the same Lua stack from the original function, in the same state it would be if the callee function had returned. @@ -2712,7 +2775,7 @@

                              4.7 – Handling Yields in C

                              after a lua_callk the function and its arguments are removed from the stack and replaced by the results from the call.) It also has the same upvalues. -Whatever it returns is handled by Lua as if it was the return +Whatever it returns is handled by Lua as if it were the return of the original function. @@ -2749,15 +2812,14 @@

                              4.8 – Functions and Types

                              The third field, x, tells whether the function may throw errors: '-' means the function never throws any error; -'m' means the function may throw an error -only due to not enough memory; +'m' means the function may throw only memory allocation errors; 'e' means the function may throw other kinds of errors; 'v' means the function may throw an error on purpose.

                              lua_absindex

                              -[-0, +0, -] +[-0, +0, –]

                              int lua_absindex (lua_State *L, int idx);

                              @@ -2795,7 +2857,7 @@

                              4.8 – Functions and Types

                              When ptr is NULL, -osize codes the kind of object that Lua is allocating. +osize encodes the kind of object that Lua is allocating. osize is any of LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, or LUA_TTHREAD when (and only when) @@ -2818,7 +2880,7 @@

                              4.8 – Functions and Types

                              When nsize is not zero, the allocator should behave like realloc. The allocator returns NULL -if and only if it cannot fill the request. +if and only if it cannot fulfill the request. Lua assumes that the allocator never fails when osize >= nsize. @@ -2843,8 +2905,8 @@

                              4.8 – Functions and Types

                              that free(NULL) has no effect and that realloc(NULL, size) is equivalent to malloc(size). This code assumes that realloc does not fail when shrinking a block. -Standard C does not ensure this behavior, -but it seems a safe assumption. +(Although Standard C does not ensure this behavior, +it seems to be a safe assumption.) @@ -2883,7 +2945,7 @@

                              4.8 – Functions and Types


                              lua_atpanic

                              -[-0, +0, -] +[-0, +0, –]

                              lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

                              @@ -2901,7 +2963,7 @@

                              4.8 – Functions and Types


                              lua_call

                              -[-(nargs + 1), +nresults, e] +[-(nargs+1), +nresults, e]

                              void lua_call (lua_State *L, int nargs, int nresults);

                              @@ -3025,12 +3087,12 @@

                              4.8 – Functions and Types


                              lua_checkstack

                              -[-0, +0, -] +[-0, +0, –]

                              int lua_checkstack (lua_State *L, int extra);

                              Ensures that there are at least extra free stack slots in the stack. -It returns false if it cannot grant the request, +It returns false if it cannot fulfill the request, because it would cause the stack to be larger than a fixed maximum size (typically at least a few thousand elements) or because it cannot allocate memory for the new stack size. @@ -3043,7 +3105,7 @@

                              4.8 – Functions and Types


                              lua_close

                              -[-0, +0, -] +[-0, +0, –]

                              void lua_close (lua_State *L);

                              @@ -3052,10 +3114,9 @@

                              4.8 – Functions and Types

                              and frees all dynamic memory used by this state. On several platforms, you may not need to call this function, because all resources are naturally released when the host program ends. -On the other hand, long-running programs, -such as a daemon or a web server, -might need to release states as soon as they are not needed, -to avoid growing too large. +On the other hand, long-running programs that create multiple states, +such as daemons or web servers, +might need to close states as soon as they are not needed. @@ -3066,6 +3127,7 @@

                              4.8 – Functions and Types

                              int lua_compare (lua_State *L, int index1, int index2, int op);

                              +Compares two Lua values. Returns 1 if the value at acceptable index index1 satisfies op when compared with the value at acceptable index index2, following the semantics of the corresponding Lua operator @@ -3106,7 +3168,7 @@

                              4.8 – Functions and Types


                              lua_copy

                              -[-0, +0, -] +[-0, +0, –]

                              void lua_copy (lua_State *L, int fromidx, int toidx);

                              @@ -3176,7 +3238,7 @@

                              4.8 – Functions and Types

                              The error message (which can actually be a Lua value of any type) must be on the stack top. This function does a long jump, -and therefore never returns. +and therefore never returns (see luaL_error). @@ -3245,10 +3307,20 @@

                              4.8 – Functions and Types

                              (i.e., not stopped). +
                            • LUA_GCGEN: +changes the collector to generational mode +(see §2.5). +
                            • + +
                            • LUA_GCINC: +changes the collector to incremental mode. +This is the default mode. +
                            • +

                            -For more details about some options, +For more details about these options, see collectgarbage. @@ -3256,7 +3328,7 @@

                            4.8 – Functions and Types


                            lua_getallocf

                            -[-0, +0, -] +[-0, +0, –]

                            lua_Alloc lua_getallocf (lua_State *L, void **ud);

                            @@ -3269,7 +3341,7 @@

                            4.8 – Functions and Types


                            lua_getctx

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_getctx  (lua_State *L, int *ctx);

                            @@ -3293,7 +3365,7 @@

                            4.8 – Functions and Types

                            Lua may also call its continuation function to handle errors during the call. That is, upon an error in the function called by lua_pcallk, -Lua may not return lua_pcallk +Lua may not return to the original function but instead may call the continuation function. In that case, a call to lua_getctx will return the error code (the value that would be returned by lua_pcallk); @@ -3324,21 +3396,19 @@

                            4.8 – Functions and Types

                            Pushes onto the stack the value of the global name. -It is defined as a macro.


                            lua_getmetatable

                            -[-0, +(0|1), -] +[-0, +(0|1), –]

                            int lua_getmetatable (lua_State *L, int index);

                            Pushes onto the stack the metatable of the value at the given acceptable index. -If the index is not valid, -or if the value does not have a metatable, +If the value does not have a metatable, the function returns 0 and pushes nothing on the stack. @@ -3366,7 +3436,7 @@

                            4.8 – Functions and Types


                            lua_gettop

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_gettop (lua_State *L);

                            @@ -3380,7 +3450,7 @@

                            4.8 – Functions and Types


                            lua_getuservalue

                            -[-0, +1, -] +[-0, +1, –]

                            void lua_getuservalue (lua_State *L, int index);

                            @@ -3393,7 +3463,7 @@

                            4.8 – Functions and Types


                            lua_insert

                            -[-1, +1, -] +[-1, +1, –]

                            void lua_insert (lua_State *L, int index);

                            @@ -3423,11 +3493,11 @@

                            4.8 – Functions and Types


                            lua_isboolean

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isboolean (lua_State *L, int index);

                            -Returns 1 if the value at the given acceptable index has type boolean, +Returns 1 if the value at the given acceptable index is a boolean, and 0 otherwise. @@ -3435,7 +3505,7 @@

                            4.8 – Functions and Types


                            lua_iscfunction

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_iscfunction (lua_State *L, int index);

                            @@ -3447,7 +3517,7 @@

                            4.8 – Functions and Types


                            lua_isfunction

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isfunction (lua_State *L, int index);

                            @@ -3459,7 +3529,7 @@

                            4.8 – Functions and Types


                            lua_islightuserdata

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_islightuserdata (lua_State *L, int index);

                            @@ -3471,7 +3541,7 @@

                            4.8 – Functions and Types


                            lua_isnil

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isnil (lua_State *L, int index);

                            @@ -3483,7 +3553,7 @@

                            4.8 – Functions and Types


                            lua_isnone

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isnone (lua_State *L, int index);

                            @@ -3496,7 +3566,7 @@

                            4.8 – Functions and Types


                            lua_isnoneornil

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isnoneornil (lua_State *L, int index);

                            @@ -3510,7 +3580,7 @@

                            4.8 – Functions and Types


                            lua_isnumber

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isnumber (lua_State *L, int index);

                            @@ -3523,7 +3593,7 @@

                            4.8 – Functions and Types


                            lua_isstring

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isstring (lua_State *L, int index);

                            @@ -3536,7 +3606,7 @@

                            4.8 – Functions and Types


                            lua_istable

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_istable (lua_State *L, int index);

                            @@ -3548,7 +3618,7 @@

                            4.8 – Functions and Types


                            lua_isthread

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isthread (lua_State *L, int index);

                            @@ -3560,7 +3630,7 @@

                            4.8 – Functions and Types


                            lua_isuserdata

                            -[-0, +0, -] +[-0, +0, –]

                            int lua_isuserdata (lua_State *L, int index);

                            @@ -3585,7 +3655,7 @@

                            4.8 – Functions and Types


                            lua_load

                            -[-0, +1, -] +[-0, +1, –]

                            int lua_load (lua_State *L,
                                           lua_Reader reader,
                                           void *data,
                            @@ -3601,13 +3671,13 @@ 

                            4.8 – Functions and Types

                              -
                            • LUA_OK (0): no errors;
                            • +
                            • LUA_OK: no errors;
                            • LUA_ERRSYNTAX: -syntax error during pre-compilation;
                            • +syntax error during precompilation;
                            • LUA_ERRMEM: -memory allocation error.
                            • +memory allocation error;
                            • LUA_ERRGCMM: error while running a __gc metamethod. @@ -3623,7 +3693,7 @@

                              4.8 – Functions and Types

                              -lua_load automatically detects whether the chunk is text or binary, +lua_load automatically detects whether the chunk is text or binary and loads it accordingly (see program luac). @@ -3642,25 +3712,25 @@

                              4.8 – Functions and Types

                              If the resulting function has one upvalue, this upvalue is set to the value of the global environment stored at index LUA_RIDX_GLOBALS in the registry (see §4.5). -(When loading main chunks, -this upvalue will be the _ENV variable (see §2.2).) +When loading main chunks, +this upvalue will be the _ENV variable (see §2.2).

                              lua_newstate

                              -[-0, +0, -] +[-0, +0, –]

                              lua_State *lua_newstate (lua_Alloc f, void *ud);

                              Creates a new thread running in a new, independent state. -Returns NULL if cannot create the thread/state +Returns NULL if cannot create the thread or the state (due to lack of memory). The argument f is the allocator function; Lua does all memory allocation for this state through this function. The second argument, ud, is an opaque pointer that Lua -simply passes to the allocator in every call. +passes to the allocator in every call. @@ -3686,7 +3756,7 @@

                              4.8 – Functions and Types

                              Creates a new thread, pushes it on the stack, and returns a pointer to a lua_State that represents this new thread. The new thread returned by this function shares with the original thread -all global objects (such as tables), +its global environment, but has an independent execution stack. @@ -3707,15 +3777,7 @@

                              4.8 – Functions and Types

                              This function allocates a new block of memory with the given size, pushes onto the stack a new full userdata with the block address, and returns this address. - - -

                              -Userdata represent C values in Lua. -A full userdata represents a block of memory. -It is an object (like a table): -you must create it, it can have its own metatable, -and you can detect when it is being collected. -A full userdata is only equal to itself (under raw equality). +The host program can freely use this memory. @@ -3780,7 +3842,7 @@

                              4.8 – Functions and Types


                              lua_pcall

                              -[-(nargs + 1), +(nresults|1), -] +[-(nargs + 1), +(nresults|1), –]

                              int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);

                              @@ -3855,9 +3917,13 @@

                              4.8 – Functions and Types


                              lua_pcallk

                              -[-(nargs + 1), +(nresults|1), -] -

                              int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
                              -                int ctx, lua_CFunction k);
                              +[-(nargs + 1), +(nresults|1), –] +
                              int lua_pcallk (lua_State *L,
                              +                int nargs,
                              +                int nresults,
                              +                int errfunc,
                              +                int ctx,
                              +                lua_CFunction k);

                              This function behaves exactly like lua_pcall, @@ -3868,7 +3934,7 @@

                              4.8 – Functions and Types


                              lua_pop

                              -[-n, +0, -] +[-n, +0, –]

                              void lua_pop (lua_State *L, int n);

                              @@ -3879,7 +3945,7 @@

                              4.8 – Functions and Types


                              lua_pushboolean

                              -[-0, +1, -] +[-0, +1, –]

                              void lua_pushboolean (lua_State *L, int b);

                              @@ -3920,14 +3986,14 @@

                              4.8 – Functions and Types

                              When n is zero, this function creates a light C function, which is just a pointer to the C function. -In that case, it cannot throw a memory error. +In that case, it never throws a memory error.

                              lua_pushcfunction

                              -[-0, +1, -] +[-0, +1, –]

                              void lua_pushcfunction (lua_State *L, lua_CFunction f);

                              @@ -3948,7 +4014,9 @@

                              4.8 – Functions and Types

                                    #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
                              -
                              +

                            +Note that f is used twice. + @@ -3980,7 +4048,7 @@

                            4.8 – Functions and Types

                            '%f' (inserts a lua_Number), '%p' (inserts a pointer as a hexadecimal numeral), '%d' (inserts an int), and -'%c' (inserts an int as a character). +'%c' (inserts an int as a byte).
                          @@ -3989,7 +4057,7 @@

                          4.8 – Functions and Types


                          lua_pushinteger

                          -[-0, +1, -] +[-0, +1, –]

                          void lua_pushinteger (lua_State *L, lua_Integer n);

                          @@ -4000,7 +4068,7 @@

                          4.8 – Functions and Types


                          lua_pushlightuserdata

                          -[-0, +1, -] +[-0, +1, –]

                          void lua_pushlightuserdata (lua_State *L, void *p);

                          @@ -4027,7 +4095,7 @@

                          4.8 – Functions and Types

                          This macro is equivalent to lua_pushlstring, but can be used only when s is a literal string. -In these cases, it automatically provides the string length. +It automatically provides the string length. @@ -4055,7 +4123,7 @@

                          4.8 – Functions and Types


                          lua_pushnil

                          -[-0, +1, -] +[-0, +1, –]

                          void lua_pushnil (lua_State *L);

                          @@ -4066,7 +4134,7 @@

                          4.8 – Functions and Types


                          lua_pushnumber

                          -[-0, +1, -] +[-0, +1, –]

                          void lua_pushnumber (lua_State *L, lua_Number n);

                          @@ -4100,7 +4168,7 @@

                          4.8 – Functions and Types


                          lua_pushthread

                          -[-0, +1, -] +[-0, +1, –]

                          int lua_pushthread (lua_State *L);

                          @@ -4112,7 +4180,7 @@

                          4.8 – Functions and Types


                          lua_pushvalue

                          -[-0, +1, -] +[-0, +1, –]

                          void lua_pushvalue (lua_State *L, int index);

                          @@ -4138,7 +4206,7 @@

                          4.8 – Functions and Types


                          lua_rawequal

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_rawequal (lua_State *L, int index1, int index2);

                          @@ -4153,7 +4221,7 @@

                          4.8 – Functions and Types


                          lua_rawget

                          -[-1, +1, -] +[-1, +1, –]

                          void lua_rawget (lua_State *L, int index);

                          @@ -4165,7 +4233,7 @@

                          4.8 – Functions and Types


                          lua_rawgeti

                          -[-0, +1, -] +[-0, +1, –]

                          void lua_rawgeti (lua_State *L, int index, int n);

                          @@ -4178,8 +4246,23 @@

                          4.8 – Functions and Types

                          +

                          lua_rawgetp

                          +[-0, +1, –] +

                          void lua_rawgetp (lua_State *L, int index, const void *p);
                          + +

                          +Pushes onto the stack the value t[k], +where t is the table at the given valid index and +k is the pointer p represented as a light userdata. +The access is raw; +that is, it does not invoke metamethods. + + + + +


                          lua_rawlen

                          -[-0, +0, -] +[-0, +0, –]

                          size_t lua_rawlen (lua_State *L, int index);

                          @@ -4226,6 +4309,26 @@

                          4.8 – Functions and Types

                          +

                          lua_rawsetp

                          +[-1, +0, m] +

                          void lua_rawsetp (lua_State *L, int index, const void *p);
                          + +

                          +Does the equivalent of t[k] = v, +where t is the table at the given valid index, +k is the pointer p represented as a light userdata, +and v is the value at the top of the stack. + + +

                          +This function pops the value from the stack. +The assignment is raw; +that is, it does not invoke metamethods. + + + + +


                          lua_Reader

                          typedef const char * (*lua_Reader) (lua_State *L,
                                                               void *data,
                          @@ -4250,9 +4353,7 @@ 

                          4.8 – Functions and Types


                          lua_register

                          [-0, +0, e] -

                          void lua_register (lua_State *L,
                          -                   const char *name,
                          -                   lua_CFunction f);
                          +
                          void lua_register (lua_State *L, const char *name, lua_CFunction f);

                          Sets the C function f as the new value of global name. @@ -4267,7 +4368,7 @@

                          4.8 – Functions and Types


                          lua_remove

                          -[-1, +0, -] +[-1, +0, –]

                          void lua_remove (lua_State *L, int index);

                          @@ -4281,7 +4382,7 @@

                          4.8 – Functions and Types


                          lua_replace

                          -[-1, +0, -] +[-1, +0, –]

                          void lua_replace (lua_State *L, int index);

                          @@ -4295,8 +4396,8 @@

                          4.8 – Functions and Types


                          lua_resume

                          -[-?, +?, -] -

                          int lua_resume (lua_State *L, int narg);
                          +[-?, +?, –] +
                          int lua_resume (lua_State *L, lua_State *from, int narg);

                          Starts and resumes a coroutine in a given thread. @@ -4330,11 +4431,17 @@

                          4.8 – Functions and Types

                          and then call lua_resume. +

                          +The parameter from represents the coroutine that is resuming L. +If there is no such coroutine, +this parameter can be NULL. + +


                          lua_setallocf

                          -[-0, +0, -] +[-0, +0, –]

                          void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

                          @@ -4371,14 +4478,13 @@

                          4.8 – Functions and Types

                          Pops a value from the stack and sets it as the new value of global name. -It is defined as a macro.


                          lua_setmetatable

                          -[-1, +0, -] +[-1, +0, –]

                          void lua_setmetatable (lua_State *L, int index);

                          @@ -4411,7 +4517,7 @@

                          4.8 – Functions and Types


                          lua_settop

                          -[-?, +?, -] +[-?, +?, –]

                          void lua_settop (lua_State *L, int index);

                          @@ -4426,7 +4532,7 @@

                          4.8 – Functions and Types


                          lua_setuservalue

                          -[-1, +0, -] +[-1, +0, –]

                          void lua_setuservalue (lua_State *L, int index);

                          @@ -4457,7 +4563,7 @@

                          4.8 – Functions and Types


                          lua_status

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_status (lua_State *L);

                          @@ -4482,7 +4588,7 @@

                          4.8 – Functions and Types


                          lua_toboolean

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_toboolean (lua_State *L, int index);

                          @@ -4501,7 +4607,7 @@

                          4.8 – Functions and Types


                          lua_tocfunction

                          -[-0, +0, -] +[-0, +0, –]

                          lua_CFunction lua_tocfunction (lua_State *L, int index);

                          @@ -4514,18 +4620,18 @@

                          4.8 – Functions and Types


                          lua_tointeger

                          -[-0, +0, -] +[-0, +0, –]

                          lua_Integer lua_tointeger (lua_State *L, int index);

                          -A macro equivalent to lua_tointegerx(L, index, NULL). +Equivalent to lua_tointegerx with isnum equal to NULL.


                          lua_tointegerx

                          -[-0, +0, -] +[-0, +0, –]

                          lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);

                          @@ -4533,7 +4639,7 @@

                          4.8 – Functions and Types

                          to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §3.4.2); -otherwise, lua_tointegerx returns 0. +otherwise, lua_tointegerx returns 0.

                          @@ -4542,7 +4648,7 @@

                          4.8 – Functions and Types

                          -If isnum is different from NULL, +If isnum is not NULL, its referent is assigned a boolean value that indicates whether the operation succeeded. @@ -4561,20 +4667,20 @@

                          4.8 – Functions and Types

                          The Lua value must be a string or a number; otherwise, the function returns NULL. If the value is a number, -then lua_tolstring also +then lua_tolstring also changes the actual value in the stack to a string. (This change confuses lua_next -when lua_tolstring is applied to keys during a table traversal.) +when lua_tolstring is applied to keys during a table traversal.)

                          -lua_tolstring returns a fully aligned pointer +lua_tolstring returns a fully aligned pointer to a string inside the Lua state. This string always has a zero ('\0') after its last character (as in C), but can contain other zeros in its body. Because Lua has garbage collection, -there is no guarantee that the pointer returned by lua_tolstring +there is no guarantee that the pointer returned by lua_tolstring will be valid after the corresponding value is removed from the stack. @@ -4582,18 +4688,18 @@

                          4.8 – Functions and Types


                          lua_tonumber

                          -[-0, +0, -] +[-0, +0, –]

                          lua_Number lua_tonumber (lua_State *L, int index);

                          -A macro equivalent to lua_tonumberx(L, index, NULL). +Equivalent to lua_tonumberx with isnum equal to NULL.


                          lua_tonumberx

                          -[-0, +0, -] +[-0, +0, –]

                          lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);

                          @@ -4605,7 +4711,7 @@

                          4.8 – Functions and Types

                          -If isnum is different from NULL, +If isnum is not NULL, its referent is assigned a boolean value that indicates whether the operation succeeded. @@ -4614,14 +4720,14 @@

                          4.8 – Functions and Types


                          lua_topointer

                          -[-0, +0, -] +[-0, +0, –]

                          const void *lua_topointer (lua_State *L, int index);

                          Converts the value at the given acceptable index to a generic C pointer (void*). The value can be a userdata, a table, a thread, or a function; -otherwise, lua_topointer returns NULL. +otherwise, lua_topointer returns NULL. Different objects will give different pointers. There is no way to convert the pointer back to its original value. @@ -4645,7 +4751,7 @@

                          4.8 – Functions and Types


                          lua_tothread

                          -[-0, +0, -] +[-0, +0, –]

                          lua_State *lua_tothread (lua_State *L, int index);

                          @@ -4659,18 +4765,18 @@

                          4.8 – Functions and Types


                          lua_tounsigned

                          -[-0, +0, -] +[-0, +0, –]

                          lua_Unsigned lua_tounsigned (lua_State *L, int index);

                          -A macro equivalent to lua_tounsignedx(L, index, NULL). +Equivalent to lua_tounsignedx with isnum equal to NULL.


                          lua_tounsignedx

                          -[-0, +0, -] +[-0, +0, –]

                          lua_Unsigned lua_tounsignedx (lua_State *L, int index, int *isnum);

                          @@ -4678,7 +4784,7 @@

                          4.8 – Functions and Types

                          to the unsigned integral type lua_Unsigned. The Lua value must be a number or a string convertible to a number (see §3.4.2); -otherwise, lua_tounsignedx returns 0. +otherwise, lua_tounsignedx returns 0.

                          @@ -4690,7 +4796,7 @@

                          4.8 – Functions and Types

                          -If isnum is different from NULL, +If isnum is not NULL, its referent is assigned a boolean value that indicates whether the operation succeeded. @@ -4699,7 +4805,7 @@

                          4.8 – Functions and Types


                          lua_touserdata

                          -[-0, +0, -] +[-0, +0, –]

                          void *lua_touserdata (lua_State *L, int index);

                          @@ -4714,13 +4820,12 @@

                          4.8 – Functions and Types


                          lua_type

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_type (lua_State *L, int index);

                          Returns the type of the value in the given acceptable index, -or LUA_TNONE for a non-valid index -(that is, an index to an "empty" stack position). +or LUA_TNONE for a non-valid index. The types returned by lua_type are coded by the following constants defined in lua.h: LUA_TNIL, @@ -4739,7 +4844,7 @@

                          4.8 – Functions and Types


                          lua_typename

                          -[-0, +0, -] +[-0, +0, –]

                          const char *lua_typename  (lua_State *L, int tp);

                          @@ -4807,11 +4912,11 @@

                          4.8 – Functions and Types


                          lua_xmove

                          -[-?, +?, -] +[-?, +?, –]

                          void lua_xmove (lua_State *from, lua_State *to, int n);

                          -Exchange values between different threads of the same global state. +Exchange values between different threads of the same state.

                          @@ -4823,7 +4928,7 @@

                          4.8 – Functions and Types


                          lua_yield

                          -[-?, +?, -] +[-?, +?, –]

                          int lua_yield  (lua_State *L, int nresults);

                          @@ -4838,7 +4943,7 @@

                          4.8 – Functions and Types


                          lua_yieldk

                          -[-?, +?, -] +[-?, +?, –]

                          int lua_yieldk  (lua_State *L, int nresults, int ctx, lua_CFunction k);

                          @@ -4850,7 +4955,7 @@

                          4.8 – Functions and Types

                          return expression of a C function, as follows:
                          -     return lua_yield (L, nresults, i, k);
                          +     return lua_yieldk (L, n, i, k);
                           

                          When a C function calls lua_yieldk in that way, the running coroutine suspends its execution, @@ -4928,7 +5033,7 @@

                          4.9 – The Debug Interface

                          it means that the function was defined in a file where the file name follows the '@'. If source starts with a '=', -the rest of it should describe the source in a user-dependent manner. +the remainder of its contents describe the source in a user-dependent manner. Otherwise, the function was defined in a string where source is that string. @@ -4994,7 +5099,7 @@

                          4.9 – The Debug Interface

                        • isvararg: -whether the function is a vararg function +true if the function is a vararg function (always true for C functions).
                        • @@ -5004,7 +5109,7 @@

                          4.9 – The Debug Interface


                          lua_gethook

                          -[-0, +0, -] +[-0, +0, –]

                          lua_Hook lua_gethook (lua_State *L);

                          @@ -5015,7 +5120,7 @@

                          4.9 – The Debug Interface


                          lua_gethookcount

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_gethookcount (lua_State *L);

                          @@ -5026,7 +5131,7 @@

                          4.9 – The Debug Interface


                          lua_gethookmask

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_gethookmask (lua_State *L);

                          @@ -5115,7 +5220,7 @@

                          4.9 – The Debug Interface


                          lua_getlocal

                          -[-0, +(0|1), -] +[-0, +(0|1), –]

                          const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);

                          @@ -5156,7 +5261,7 @@

                          4.9 – The Debug Interface


                          lua_getstack

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_getstack (lua_State *L, int level, lua_Debug *ar);

                          @@ -5179,7 +5284,7 @@

                          4.9 – The Debug Interface


                          lua_getupvalue

                          -[-0, +(0|1), -] +[-0, +(0|1), –]

                          const char *lua_getupvalue (lua_State *L, int funcindex, int n);

                          @@ -5241,7 +5346,7 @@

                          4.9 – The Debug Interface


                          lua_sethook

                          -[-0, +0, -] +[-0, +0, –]

                          int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

                          @@ -5294,7 +5399,7 @@

                          4.9 – The Debug Interface


                          lua_setlocal

                          -[-(0|1), +0, -] +[-(0|1), +0, –]

                          const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);

                          @@ -5316,7 +5421,7 @@

                          4.9 – The Debug Interface


                          lua_setupvalue

                          -[-(0|1), +0, -] +[-(0|1), +0, –]

                          const char *lua_setupvalue (lua_State *L, int funcindex, int n);

                          @@ -5337,7 +5442,7 @@

                          4.9 – The Debug Interface


                          lua_upvalueid

                          -[-0, +0, -] +[-0, +0, –]

                          void *lua_upvalueid (lua_State *L, int funcindex, int n);

                          @@ -5386,7 +5491,7 @@

                          5 – The Auxiliary Library

                          -All functions from the auxiliary library +All functions and types from the auxiliary library are defined in header file lauxlib.h and have a prefix luaL_. @@ -5395,6 +5500,8 @@

                          5 – The Auxiliary Library

                          All functions in the auxiliary library are built on top of the basic API, and so they provide nothing that cannot be done with that API. +Nevertheless, the use of the auxiliary library ensures +more consistency to your code.

                          @@ -5432,7 +5539,7 @@

                          5.1 – Functions and Types

                          void luaL_addchar (luaL_Buffer *B, char c);

                          -Adds the character c to the buffer B +Adds the byte c to the buffer B (see luaL_Buffer). @@ -5474,7 +5581,7 @@

                          5.1 – Functions and Types

                          Adds the zero-terminated string pointed to by s to the buffer B (see luaL_Buffer). -The string should not contain embedded zeros. +The string cannot contain embedded zeros. @@ -5509,12 +5616,8 @@

                          5.1 – Functions and Types

                          Checks whether cond is true. -If not, raises an error with the following message, -where func is retrieved from the call stack: +If not, raises an error with a standard message. -

                          -     bad argument #<narg> to <func> (<extramsg>)
                          -
                          @@ -5524,12 +5627,9 @@

                          5.1 – Functions and Types

                          int luaL_argerror (lua_State *L, int narg, const char *extramsg);

                          -Raises an error with the following message, -where func is retrieved from the call stack: +Raises an error with a standard message +that includes extramsg as a comment. -

                          -     bad argument #<narg> to <func> (<extramsg>)
                          -

                          This function never returns, @@ -5553,17 +5653,17 @@

                          5.1 – Functions and Types

                            -
                          • First you declare a variable b of type luaL_Buffer.
                          • +
                          • First declare a variable b of type luaL_Buffer.
                          • -
                          • Then you initialize it with a call luaL_buffinit(L, &b).
                          • +
                          • Then initialize it with a call luaL_buffinit(L, &b).
                          • -Then you add string pieces to the buffer calling any of +Then add string pieces to the buffer calling any of the luaL_add* functions.
                          • -You finish by calling luaL_pushresult(&b). +Finish by calling luaL_pushresult(&b). This call leaves the final string on the top of the stack.
                          • @@ -5575,15 +5675,15 @@

                            5.1 – Functions and Types

                              -
                            • First you declare a variable b of type luaL_Buffer.
                            • +
                            • First declare a variable b of type luaL_Buffer.
                            • -
                            • Then you initialize it and preallocate a space of +
                            • Then initialize it and preallocate a space of size sz with a call luaL_buffinitsize(L, &b, sz).
                            • -
                            • Then you copy the string into that space.
                            • +
                            • Then copy the string into that space.
                            • -You finish by calling luaL_pushresult(&b, sz), +Finish by calling luaL_pushresult(&b, sz), where sz is the total size of the resulting string copied into that space.
                            • @@ -5611,7 +5711,7 @@

                              5.1 – Functions and Types


                              luaL_buffinit

                              -[-0, +0, -] +[-0, +0, –]

                              void luaL_buffinit (lua_State *L, luaL_Buffer *B);

                              @@ -5647,7 +5747,7 @@

                              5.1 – Functions and Types

                              If the object at index obj has a metatable and this metatable has a field e, -this function calls this field and passes the object as its only argument. +this function calls this field passing the object as its only argument. In this case this function returns true and pushes onto the stack the value returned by the call. If there is no metatable or no metamethod, @@ -5755,7 +5855,7 @@

                              5.1 – Functions and Types

                              If def is not NULL, the function uses def as a default value when -there is no argument narg or if this argument is nil. +there is no argument narg or when this argument is nil.

                              @@ -5836,7 +5936,7 @@

                              5.1 – Functions and Types


                              luaL_checkversion

                              -[-0, +0, -] +[-0, +0, –]

                              void luaL_checkversion (lua_State *L);

                              @@ -5870,7 +5970,7 @@

                              5.1 – Functions and Types


                              luaL_dostring

                              -[-0, +?, -] +[-0, +?, –]

                              int luaL_dostring (lua_State *L, const char *str);

                              @@ -5952,7 +6052,7 @@

                              5.1 – Functions and Types


                              luaL_getmetatable

                              -[-0, +1, -] +[-0, +1, –]

                              void luaL_getmetatable (lua_State *L, const char *tname);

                              @@ -6012,7 +6112,7 @@

                              5.1 – Functions and Types


                              luaL_loadbuffer

                              -[-0, +1, -] +[-0, +1, –]

                              int luaL_loadbuffer (lua_State *L,
                                                    const char *buff,
                                                    size_t sz,
                              @@ -6035,7 +6135,16 @@ 

                              5.1 – Functions and Types


                              luaL_loadfile

                              [-0, +1, m] -

                              int luaL_loadfile (lua_State *L, const char *filename);
                              +
                              int luaL_loadfile (lua_State *L, const char *filename);

                              +Equivalent to luaL_loadfilex with mode equal to NULL. + + + + +


                              luaL_loadfilex

                              +[-0, +1, m] +

                              int luaL_loadfilex (lua_State *L, const char *filename,
                              +                                            const char *mode);

                              Loads a file as a Lua chunk. @@ -6046,10 +6155,16 @@

                              5.1 – Functions and Types

                              The first line in the file is ignored if it starts with a #. +

                              +The string mode works as in function load, +with the addition that +a NULL value is equivalent to the string "bt". + +

                              This function returns the same results as lua_load, but it has an extra error code LUA_ERRFILE -if it cannot open/read the file. +if it cannot open/read the file or the file has a wrong mode.

                              @@ -6061,7 +6176,7 @@

                              5.1 – Functions and Types


                              luaL_loadstring

                              -[-0, +1, -] +[-0, +1, –]

                              int luaL_loadstring (lua_State *L, const char *s);

                              @@ -6141,7 +6256,7 @@

                              5.1 – Functions and Types


                              luaL_newstate

                              -[-0, +0, -] +[-0, +0, –]

                              lua_State *luaL_newstate (void);

                              @@ -6434,7 +6549,7 @@

                              5.1 – Functions and Types


                              luaL_setmetatable

                              -[-0, +0, -] +[-0, +0, –]

                              void luaL_setmetatable (lua_State *L, const char *tname);

                              @@ -6499,7 +6614,7 @@

                              5.1 – Functions and Types


                              luaL_typename

                              -[-0, +0, -] +[-0, +0, –]

                              const char *luaL_typename (lua_State *L, int index);

                              @@ -6510,7 +6625,7 @@

                              5.1 – Functions and Types


                              luaL_unref

                              -[-0, +0, -] +[-0, +0, –]

                              void luaL_unref (lua_State *L, int t, int ref);

                              @@ -6575,28 +6690,28 @@

                              6 – Standard Libraries

                                -
                              • basic library;
                              • +
                              • basic library (§6.1);
                              • -
                              • package library;
                              • +
                              • coroutine library (§6.2);
                              • -
                              • coroutine library;
                              • +
                              • package library (§6.3);
                              • -
                              • string manipulation;
                              • +
                              • string manipulation (§6.4);
                              • -
                              • table manipulation;
                              • +
                              • table manipulation (§6.5);
                              • -
                              • mathematical functions (sin, log, etc.);
                              • +
                              • mathematical functions (§6.6) (sin, log, etc.);
                              • -
                              • bitwise operations;
                              • +
                              • bitwise operations (§6.7);
                              • -
                              • input and output;
                              • +
                              • input and output (§6.8);
                              • -
                              • operating system facilities;
                              • +
                              • operating system facilities (§6.9);
                              • -
                              • debug facilities.
                              • +
                              • debug facilities (§6.10).

                              -Except for the basic and package libraries, +Except for the basic and the package libraries, each library provides all its functions as fields of a global table or as methods of its objects. @@ -6627,7 +6742,7 @@

                              6 – Standard Libraries

                              6.1 – Basic Functions

                              -The basic library provides some core functions to Lua. +The basic library provides core functions to Lua. If you do not include this library in your application, you should check carefully whether you need to provide implementations for some of its facilities. @@ -6660,13 +6775,13 @@

                              6.1 – Basic Functions

                            • "stop": -stops automatic invocation of the garbage collector. -The collector will run only when explcitly invoked, +stops automatic execution of the garbage collector. +The collector will run only when explicitly invoked, until a call to restart it.
                            • "restart": -restarts automatic invocation the garbage collector. +restarts automatic execution of the garbage collector.
                            • "count": @@ -6709,6 +6824,16 @@

                              6.1 – Basic Functions

                              (i.e., not stopped).
                            • +
                            • "generational": +changes the collector to generational mode. +This is an experimental feature (see §2.5). +
                            • + +
                            • "incremental": +changes the collector to incremental mode. +This is the default mode. +
                            • +
                            @@ -6789,7 +6914,7 @@

                            6.1 – Basic Functions

                                  for i,v in ipairs(t) do body end
                             

                            -will iterate over the pairs (1,t[1]), (2,t[2]), ···, +will iterate over the pairs (1,t[1]), (2,t[2]), ..., up to the first integer key absent from the table. @@ -6823,8 +6948,8 @@

                            6.1 – Basic Functions

                            the first upvalue is set to the value of the global environment or to env, if that parameter is given. -(When loading main chunks, -the first upvalue will be the _ENV variable (see §2.2).) +When loading main chunks, +the first upvalue will be the _ENV variable (see §2.2).

                            @@ -6832,21 +6957,22 @@

                            6.1 – Basic Functions

                            and debug information (see §4.9). When absent, it defaults to ld, if ld is a string, -or to "=(load)". +or to "=(load)" otherwise.

                            The string mode controls whether the chunk can be text or binary (that is, a precompiled chunk). -A letter 't' in mode allows a text chunk; -a letter 'b' allows a binary chunk. +It may be the string "b" (only binary chunks), +"t" (only text chunks), +or "bt" (both binary and text). The default is "bt".

                            -


                            loadfile ([filename])

                            +

                            loadfile ([filename [, mode [, env]]])

                            @@ -6945,13 +7071,14 @@

                            6.1 – Basic Functions


                            print (···)

                            -Receives any number of arguments, +Receives any number of arguments and prints their values to stdout, -using the tostring function to convert them to strings. +using the tostring function to convert each argument to a string. print is not intended for formatted output, but only as a quick way to show a value, -typically for debugging. -For formatted output, use string.format. +for instance for debugging. +For complete control over the output, +use string.format and io.write. @@ -6990,7 +7117,7 @@

                            6.1 – Basic Functions

                            Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, -index any value different from nil, +index any value different from nil and NaN, and value any Lua value. @@ -7035,37 +7162,43 @@

                            6.1 – Basic Functions


                            tonumber (e [, base])

                            -Tries to convert its argument to a number. -If the argument is already a number or a string convertible -to a number, then tonumber returns this number; + + +

                            +When called with no base, +tonumber tries to convert its argument to a number. +If the argument is already a number or +a string convertible to a number (see §3.4.2), +then tonumber returns this number; otherwise, it returns nil.

                            -An optional argument specifies the base to interpret the numeral. +When called with base, +then e should be a string to be interpreted as +an integer numeral in that base. The base may be any integer between 2 and 36, inclusive. In bases above 10, the letter 'A' (in either upper or lower case) represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. -In base 10 (the default), -the numeral is converted following the coercion rules (see §3.4.2). -In other bases, only integers are accepted. +If the string e is not a valid numeral in the given base, +the function returns nil.

                            -


                            tostring (e)

                            -Receives an argument of any type and +

                            tostring (v)

                            +Receives a value of any type and converts it to a string in a reasonable format. -For complete control of how numbers are converted, -use string.format. +(For complete control of how numbers are converted, +use string.format.)

                            -If the metatable of e has a "__tostring" field, +If the metatable of v has a "__tostring" field, then tostring calls the corresponding value -with e as argument, +with v as argument, and uses the result of the call as its result. @@ -7139,11 +7272,11 @@

                            6.2 – Coroutine Manipulation

                            Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. -The values val1, ··· are passed +The values val1, ... are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; -the values val1, ··· are passed +the values val1, ... are passed as the results from the yield. @@ -7280,7 +7413,7 @@

                            6.3 – Modules

                            If there is any error loading or running the module, or if it cannot find any loader for the module, -then require signals an error. +then require raises an error. @@ -7309,8 +7442,8 @@

                            6.3 – Modules

                            is replaced by the executable's directory. Default is '!'. -
                          • The fifth line is a mark to ignore all before it when building the -luaopen_ function name. +
                          • The fifth line is a mark to ignore all text before it +when building the luaopen_ function name. Default is '-'.
                          @@ -7372,7 +7505,7 @@

                          6.3 – Modules

                          Otherwise, it looks for a function funcname inside the library and returns this function as a C function. -(So, funcname must follow the protocol (see lua_CFunction)). +(So, funcname must follow the prototype lua_CFunction).

                          @@ -7409,7 +7542,7 @@

                          6.3 – Modules

                          the value of the environment variable LUA_PATH_5_2 or the environment variable LUA_PATH or with a default path defined in luaconf.h, -if the environment variable is not defined. +if those environment variables are not defined. Any ";;" in the value of the environment variable is replaced by the default path. @@ -7511,7 +7644,7 @@

                          6.3 – Modules

                          -All searchers except the first (preload) return as the extra value +All searchers except the first one (preload) return as the extra value the file name where the module was found, as returned by package.searchpath. The first searcher returns no extra value. @@ -7520,7 +7653,7 @@

                          6.3 – Modules

                          -


                          package.searchpath (name, path [, sep])

                          +

                          package.searchpath (name, path [, sep [, rep]])

                          @@ -7528,17 +7661,16 @@

                          6.3 – Modules

                          -A path is string containing a sequence of +A path is a string containing a sequence of templates separated by semicolons. For each template, -the function changes each interrogation -mark in the template by a copy of name +the function replaces each interrogation mark (if any) +in the template with a copy of name wherein all occurrences of sep (a dot, by default) -were replaced by the system's directory separator, +were replaced by rep +(the system's directory separator, by default), and then tries to open the resulting file name. -If sep is the empty string, -the replacement is not done.

                          @@ -7583,7 +7715,7 @@

                          6.4 – String Manipulation

                          It also sets a metatable for strings where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. -For instance, string.byte(s, i) +For instance, string.byte(s,i) can be written as s:byte(i). @@ -7594,13 +7726,15 @@

                          6.4 – String Manipulation


                          string.byte (s [, i [, j]])

                          Returns the internal numerical codes of the characters s[i], -s[i+1], ···, s[j]. +s[i+1], ..., s[j]. The default value for i is 1; the default value for j is i. +These indices are corrected +following the same rules of function string.sub.

                          -Note that numerical codes are not necessarily portable across platforms. +Numerical codes are not necessarily portable across platforms. @@ -7614,7 +7748,7 @@

                          6.4 – String Manipulation

                          -Note that numerical codes are not necessarily portable across platforms. +Numerical codes are not necessarily portable across platforms. @@ -7709,7 +7843,7 @@

                          6.4 – String Manipulation


                          string.gmatch (s, pattern)

                          Returns an iterator function that, each time it is called, -returns the next captures from pattern over string s. +returns the next captures from pattern over the string s. If pattern specifies no captures, then the whole match is produced in each call. @@ -7737,7 +7871,7 @@

                          6.4 – String Manipulation

                          -For this function, a '^' at the start of a pattern does not +For this function, a caret '^' at the start of a pattern does not work as an anchor, as this would prevent the iteration. @@ -7884,6 +8018,17 @@

                          6.4 – String Manipulation

                          with length i. +

                          +If, after the translation of negative indices, +i is less than zero, +it is corrected to zero. +If j is greater than the string length, +it is corrected to that length. +If, after these corrections, +i is greater than j, +the function returns the empty string. + +

                          @@ -8050,7 +8195,7 @@

                          Pattern Item:

                          Pattern:

                          A pattern is a sequence of pattern items. -A '^' at the beginning of a pattern anchors the match at the +A caret '^' at the beginning of a pattern anchors the match at the beginning of the subject string. A '$' at the end of a pattern anchors the match at the end of the subject string. @@ -8589,7 +8734,7 @@

                          6.7 – Bitwise Operations

                          -Returns the bitwise and of its operands. +Returns the bitwise and of its operands. @@ -8614,7 +8759,7 @@

                          6.7 – Bitwise Operations

                          -Returns the bitwise or of its operands. +Returns the bitwise or of its operands. @@ -8625,7 +8770,7 @@

                          6.7 – Bitwise Operations

                          Returns a boolean signaling -whether the bitwise and of its operands is different from zero. +whether the bitwise and of its operands is different from zero. @@ -8635,7 +8780,7 @@

                          6.7 – Bitwise Operations

                          -Returns the bitwise exclusive or of its operands. +Returns the bitwise exclusive or of its operands. @@ -8845,7 +8990,7 @@

                          6.8 – Input and Output Facilities

                          -


                          io.lines ([filename] ···)

                          +

                          io.lines ([filename ···])

                          @@ -8863,6 +9008,11 @@

                          6.8 – Input and Output Facilities

                          In this case it does not close the file when the loop ends. +

                          +In case of errors this function raises the error, +instead of returning an error code. + +

                          @@ -9007,15 +9157,20 @@

                          6.8 – Input and Output Facilities

                          reads the file according to the given formats. When no format is given, uses "*l" as a default. -Therefore, the construction +As an example, the construction
                                for c in file:lines(1) do body end
                           

                          will iterate over all characters of the file, starting at the current position. -(Unlike io.lines, this function does not close the file -when the loop ends.) +Unlike io.lines, this function does not close the file +when the loop ends. + + +

                          +In case of errors this function raises the error, +instead of returning an error code. @@ -9062,7 +9217,7 @@

                          6.8 – Input and Output Facilities

                        • number: -reads a string with up to this number of characters, +reads a string with up to this number of bytes, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, @@ -9088,9 +9243,9 @@

                          6.8 – Input and Output Facilities

                        • "cur": base is current position;
                        • "end": base is end of file;

                        -In case of success, function seek returns the final file position, +In case of success, seek returns the final file position, measured in bytes from the beginning of the file. -If this function fails, it returns nil, +If seek fails, it returns nil, plus a string describing the error. @@ -9123,8 +9278,8 @@

                        6.8 – Input and Output Facilities

                      • "full": full buffering; output operation is performed only -when the buffer is full (or when you explicitly flush the file -(see io.flush)). +when the buffer is full or when +you explicitly flush the file (see io.flush).
                      • "line": @@ -9146,11 +9301,8 @@

                        6.8 – Input and Output Facilities

                        -Writes the value of each of its arguments to -the file. +Writes the value of each of its arguments to file. The arguments must be strings or numbers. -To write other values, -use tostring or string.format before write.

                        @@ -9202,8 +9354,8 @@

                        6.9 – Operating System Facilities

                        After this optional character, if format is the string "*t", then date returns a table with the following fields: -year (four digits), month (1--12), day (1--31), -hour (0--23), min (0--59), sec (0--61), +year (four digits), month (1–12), day (1–31), +hour (0–23), min (0–59), sec (0–61), wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean). @@ -9314,7 +9466,7 @@

                        6.9 – Operating System Facilities

                        Deletes the file (or empty directory, on POSIX systems) with the given name. If this function fails, it returns nil, -plus a string describing the error. +plus a string describing the error and the error code. @@ -9326,7 +9478,7 @@

                        6.9 – Operating System Facilities

                        Renames file or directory named oldname to newname. If this function fails, it returns nil, -plus a string describing the error. +plus a string describing the error and the error code. @@ -9337,7 +9489,7 @@

                        6.9 – Operating System Facilities

                        Sets the current locale of the program. -locale is a string specifying a locale; +locale is a system-dependent string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; @@ -9369,8 +9521,12 @@

                        6.9 – Operating System Facilities

                        Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, -and may have fields hour, min, sec, and isdst -(for a description of these fields, see the os.date function). +and may have fields +hour (default is 12), +min (default is 0), +sec (default is 0), +and isdst (default is nil). +For a description of these fields, see the os.date function.

                        @@ -9380,7 +9536,7 @@

                        6.9 – Operating System Facilities

                        of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to -date and difftime. +os.date and os.difftime. @@ -9421,9 +9577,9 @@

                        6.10 – The Debug Library

                        This library provides -the functionality of the debug interface to Lua programs. +the functionality of the debug interface (§4.9) to Lua programs. You should exert care when using this library. -Several of these functions +Several of its functions violate basic assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside; @@ -9458,7 +9614,7 @@

                        6.10 – The Debug Library

                        Note that commands for debug.debug are not lexically nested -within any function, and so have no direct access to local variables. +within any function and so have no direct access to local variables. @@ -9477,20 +9633,20 @@

                        6.10 – The Debug Library

                        -


                        debug.getinfo ([thread,] function [, what])

                        +

                        debug.getinfo ([thread,] f [, what])

                        Returns a table with information about a function. -You can give the function directly, -or you can give a number as the value of function, -which means the function running at level function of the call stack +You can give the function directly +or you can give a number as the value of f, +which means the function running at level f of the call stack of the given thread: level 0 is the current function (getinfo itself); level 1 is the function that called getinfo (except for tail calls, which do not count on the stack); and so on. -If function is a number larger than the number of active functions, +If f is a number larger than the number of active functions, then getinfo returns nil. @@ -9554,11 +9710,11 @@

                        6.10 – The Debug Library

                        -


                        debug.getmetatable (object)

                        +

                        debug.getmetatable (value)

                        -Returns the metatable of the given object +Returns the metatable of the given value or nil if it does not have a metatable. @@ -9575,12 +9731,12 @@

                        6.10 – The Debug Library

                        -


                        debug.getupvalue (func, up)

                        +

                        debug.getupvalue (f, up)

                        This function returns the name and the value of the upvalue -with index up of the function func. +with index up of the function f. The function returns nil if there is no upvalue with the given index. @@ -9662,24 +9818,24 @@

                        6.10 – The Debug Library

                        -


                        debug.setmetatable (object, table)

                        +

                        debug.setmetatable (value, table)

                        -Sets the metatable for the given object to the given table +Sets the metatable for the given value to the given table (which can be nil). -Returns object. +Returns value.

                        -


                        debug.setupvalue (func, up, value)

                        +

                        debug.setupvalue (f, up, value)

                        This function assigns the value value to the upvalue -with index up of the function func. +with index up of the function f. The function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue. @@ -9723,7 +9879,7 @@

                        6.10 – The Debug Library

                        -


                        debug.upvalueid (function, n)

                        +

                        debug.upvalueid (f, n)

                        @@ -9743,12 +9899,12 @@

                        6.10 – The Debug Library

                        -


                        debug.upvaluejoin (func1, n1, func2, n2)

                        +

                        debug.upvaluejoin (f1, n1, f2, n2)

                        -Make the n1-th upvalue of the Lua closure func1 -refer to the n2-th upvalue of the Lua closure func2. +Make the n1-th upvalue of the Lua closure f1 +refer to the n2-th upvalue of the Lua closure f2. @@ -9779,6 +9935,7 @@

                        7 – Lua Standalone

                      • -l mod: "requires" mod;
                      • -i: enters interactive mode after running script;
                      • -v: prints version information;
                      • +
                      • -E: ignores environment variables;
                      • --: stops handling options;
                      • -: executes stdin as a file and stops handling options.

                      @@ -9791,24 +9948,34 @@

                      7 – Lua Standalone

                      -Before running any argument, +When called without option -E, the interpreter checks for an environment variable LUA_INIT_5_2 -(or LUA_INIT if it is not defined). -If its format is @filename, +(or LUA_INIT if it is not defined) +before running any argument. +If the variable content has the format @filename, then lua executes the file. Otherwise, lua executes the string itself.

                      -All options are handled in order, except -i. +When called with option -E, +besides ignoring LUA_INIT, +the interpreter also resets the values of +package.path and package.cpath +with the default paths defined in luaconf.h, +in effect ignoring the values of LUA_PATH and LUA_CPATH. + + +

                      +All options are handled in order, except -i and -E. For instance, an invocation like

                            $ lua -e'a=1' -e 'print(a)' script.lua
                       

                      -will first set a to 1, then print the value of a (which is '1'), +will first set a to 1, then print the value of a, and finally run the file script.lua with no arguments. -(Here $ is the shell prompt. Your prompt can be different.) +(Here $ is the shell prompt. Your prompt may be different.)

                      @@ -9835,7 +10002,7 @@

                      7 – Lua Standalone

                      [1] = "t1", [2] = "t2" }

                      and finally runs the file b.lua. -The script is called with arg[1], arg[2], ··· +The script is called with arg[1], arg[2], ... as arguments; it can also access these arguments with the vararg expression '...'. @@ -9862,29 +10029,8 @@

                      7 – Lua Standalone

                      When finishing normally, the interpreter closes its main Lua state (see lua_close). -The script can avoid this step by terminating -through os.exit. - - -

                      -If the global variable _PROMPT contains a string, -then its value is used as the prompt. -Similarly, if the global variable _PROMPT2 contains a string, -its value is used as the secondary prompt -(issued during incomplete statements). -Therefore, both prompts can be changed directly on the command line -or in any Lua programs by assigning to _PROMPT. -See the next example: - -

                      -     $ lua -e"_PROMPT='myprompt> '" -i
                      -

                      -(The outer pair of quotes is for the shell, -the inner pair is for Lua.) -Note the use of -i to enter interactive mode; -otherwise, -the program would just end silently -right after the assignment to _PROMPT. +The script can avoid this step by +calling os.exit to terminate.

                      @@ -9900,7 +10046,7 @@

                      7 – Lua Standalone

                      #!/usr/local/bin/lua

                      (Of course, -the location of the Lua interpreter can be different in your machine. +the location of the Lua interpreter may be different in your machine. If lua is in your PATH, then @@ -9914,9 +10060,9 @@

                      7 – Lua Standalone

                      8 – Incompatibilities with the Previous Version

                      -Here we list the incompatibilities that you can find when moving a program +Here we list the incompatibilities that you may find when moving a program from Lua 5.1 to Lua 5.2. -You can avoid some incompatibilities compiling Lua with +You can avoid some incompatibilities by compiling Lua with appropriate options (see file luaconf.h). However, all these compatibility options will be removed in the next version of Lua. @@ -9934,7 +10080,7 @@

                      8.1 – Changes in the Language

                      -C functions do not have environments any more. +C functions no longer have environments. Use an upvalue with a shared table if you need to keep shared state among several C functions. (You may use luaL_setfuncs to open a C library @@ -9964,8 +10110,8 @@

                      8.1 – Changes in the Language

                    • The event tail return in debug hooks was removed. Instead, tail calls generate a special new event, -tail call, so that the debugger can know there will -not be a corresponding return event. +tail call, so that the debugger can know that +there will not be a corresponding return event.
                    • @@ -9985,8 +10131,8 @@

                      8.2 – Changes in the Libraries

                    • Function module is deprecated. -Modules are not expected to set global variables anymore, -and it is easy to set up a module with regular Lua code. +It is easy to set up a module with regular Lua code. +Modules are not expected to set global variables.
                    • @@ -10036,12 +10182,17 @@

                      8.2 – Changes in the Libraries

                      (load and loadfile) are potentially insecure when loading untrusted binary data. (Actually, those functions were already insecure because -of bugs in the verification algorithm.) +of flaws in the verification algorithm.) When in doubt, use the mode argument in function load to restrict it to loading textual chunks.
                    • +
                    • +The standard paths in the official distribution may +change between versions. +
                    • +
                    @@ -10060,13 +10211,12 @@

                    8.3 – Changes in the API

                    Pseudoindex LUA_ENVIRONINDEX and functions lua_getfenv/lua_setfenv were removed, -as C functions do not have environments any more. +as C functions no longer have environments.
                  • Function luaL_register is deprecated. -Use luaL_setfuncs so that your module does not -create globals anymore. +Use luaL_setfuncs so that your module does not create globals. (Modules are not expected to set global variables anymore.)
                  • @@ -10081,7 +10231,7 @@

                    8.3 – Changes in the API

                  • Finalizers (__gc metamethods) for userdata are called in the -reverse order that they were marked, +reverse order that they were marked for finalization, not that they were created (see §2.5.1). (Most userdata are marked immediately after they are created.) Moreover, @@ -10202,10 +10352,10 @@

                    9 – The Complete Syntax of Lua


                    Last update: -Fri Jul 8 17:11:02 BRT 2011 +Thu Nov 24 11:54:31 BRST 2011 diff --git a/doc/readme.html b/doc/readme.html index 5cb41d4954..f0c77a1604 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -6,18 +6,21 @@ @@ -27,14 +30,9 @@

                    Lua -Welcome to Lua 5.2 (beta) +Welcome to Lua 5.2

                    -

                    -[!] -This is a beta version of Lua 5.2. -Some details may change in the final version. -

                    about · @@ -86,7 +84,7 @@

                    Installing Lua

                    You need to build it before using it. Building Lua should be straightforward because -Lua is implemented in pure ANSI C, and compiles unmodified in all known +Lua is implemented in pure ANSI C and compiles unmodified in all known platforms that have an ANSI C compiler. Lua also compiles unmodified as C++. The instructions given below for building Lua are for Unix-like platforms. @@ -120,15 +118,16 @@

                    Building Lua

                    1. Open a terminal window and move to -the top-level directory, which is named lua-5.2.0. +the top-level directory, which is named lua-5.2.0. The Makefile there controls both the build process and the installation process.

                    2. Do "make" and see if your platform is listed. The platforms currently supported are: -
                      - aix ansi bsd freebsd generic linux macosx mingw posix solaris -
                      +

                      +

                      + aix ansi bsd freebsd generic linux macosx mingw posix solaris +

                      If your platform is listed, just do "make xxx", where xxx is your platform name. @@ -138,7 +137,7 @@

                      Building Lua

                    3. The compilation takes only a few moments -and produces three files in the src directory: +and produces three files in the src directory: lua (the interpreter), luac (the compiler), and liblua.a (the library). @@ -147,12 +146,15 @@

                      Building Lua

                      To check that Lua has been built correctly, do "make test" after building Lua. This will run the interpreter and print its version string.
                    +

                    +If you're running Linux and get compilation errors, +make sure you have installed the readline development package.

                    Installing Lua

                    Once you have built Lua, you may want to install it in an official place in your system. In this case, do "make install". The official - place and the way to install files are defined in Makefile. You'll + place and the way to install files are defined in the Makefile. You'll probably need the right permissions to install files.

                    @@ -198,9 +200,9 @@

                    Customization

                    Three kinds of things can be customized by editing a file:

                      -
                    • Where and how to install Lua — edit Makefile. -
                    • How to build Lua — edit src/Makefile. -
                    • Lua features — edit src/luaconf.h. +
                    • Where and how to install Lua — edit Makefile. +
                    • How to build Lua — edit src/Makefile. +
                    • Lua features — edit src/luaconf.h.

                    @@ -211,13 +213,13 @@

                    Customization

                    On the other hand, if you need to customize some Lua features, you'll need - to edit src/luaconf.h before building and installing Lua. + to edit src/luaconf.h before building and installing Lua. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. Further customization is available to experts by editing the Lua sources.

                    - We strongly recommend that you enable dynamic loading in src/luaconf.h. + We strongly recommend that you enable dynamic loading in src/luaconf.h. This is done automatically for all platforms listed above that have this feature and also for Windows. @@ -238,7 +240,6 @@

                    Building Lua on other systems

                    ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c -
                    interpreter:
                    @@ -257,11 +258,11 @@

                    Building Lua on other systems

                    those dynamic libraries — but don't link the Lua library into each dynamic library. For Unix, we recommend that the Lua library be linked statically into the host program and its symbols exported for - dynamic linking; src/Makefile does this for the Lua interpreter. + dynamic linking; src/Makefile does this for the Lua interpreter. For Windows, we recommend that the Lua library be a DLL.

                    - As mentioned above, you may edit src/luaconf.h to customize + As mentioned above, you may edit src/luaconf.h to customize some features before building Lua.

                    Changes since Lua 5.1

                    @@ -290,7 +291,7 @@

                    Language

                    • no more fenv for threads or functions
                    • tables honor the __len metamethod -
                    • hex and \* escapes in strings +
                    • hex and \z escapes in strings
                    • support for hexadecimal floats
                    • order metamethods work for different types
                    • no more verification of opcode consistency @@ -302,8 +303,8 @@

                      Language

                      Libraries

                      • arguments for function called through xpcall -
                      • optional 'mode' argument to load (to control binary x text) -
                      • optional 'env' argument to load (environment for loaded chunk) +
                      • optional 'mode' argument to load and loadfile (to control binary x text) +
                      • optional 'env' argument to load and loadfile (environment for loaded chunk)
                      • loadlib may load libraries with global names (RTLD_GLOBAL)
                      • new function package.searchpath
                      • modules receive their paths when loaded @@ -324,15 +325,23 @@

                        Libraries

                        C API

                        • main thread predefined in the registry -
                        • new constants LUA_OK and LUA_ERRGCMM -
                        • new lua_compare, lua_arith, and lua_len -
                        • new lua_version and luaL_checkversion +
                        • new functions +lua_absindex, +lua_arith, +lua_compare, +lua_copy, +lua_len, +lua_rawgetp, +lua_rawsetp, +lua_upvalueid, +lua_upvaluejoin, +lua_version. +
                        • new functions +luaL_checkversion, +luaL_setmetatable, +luaL_testudata, +luaL_tolstring.
                        • lua_pushstring and pushlstring return string -
                        • new luaL_testudata and luaL_setmetatable -
                        • new luaL_tolstring -
                        • new lua_copy -
                        • new lua_absindex -
                        • new lua_upvalueid and lua_upvaluejoin
                        • nparams and isvararg available in debug API
                        • new lua_Unsigned
                        @@ -340,15 +349,17 @@

                        C API

                        Implementation

                        • max constants per function raised to 226 +
                        • generational mode for garbage collection (experimental) +
                        • NaN trick (experimental)
                        • internal (immutable) version of ctypes
                        • simpler implementation for string buffers -
                        • udata with finalizers are kept in a separated list for the GC -
                        • CallInfo stack now is a linked list
                        • parser uses much less C-stack space (no more auto arrays) -
                        • new hash for floats -
                        • handling of non-string error messages in the standalone interpreter -
                        • generational mode for garbage collection (experimental) -
                        • NaN trick (experimental) +
                        + +

                        Lua standalone interpreter

                        +
                          +
                        • new -E option to avoid environment variables +
                        • handling of non-string error messages

                        License

                        @@ -369,7 +380,7 @@

                        License

                        For details, see this. -
                        +
                        Copyright © 1994–2011 Lua.org, PUC-Rio.

                        @@ -393,14 +404,15 @@

                        License

                        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                        +


                        Last update: -Fri Jun 24 11:30:57 BRT 2011 +Wed Nov 23 16:17:22 BRST 2011 diff --git a/src/Makefile b/src/Makefile index a77f35db09..bba1693f92 100644 --- a/src/Makefile +++ b/src/Makefile @@ -112,6 +112,7 @@ mingw: $(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe + $(MAKE) "LUAC_T=luac.exe" luac.exe posix: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX" diff --git a/src/lapi.c b/src/lapi.c index 7761419e8a..5437fb0c28 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.149 2011/06/13 14:13:06 roberto Exp $ +** $Id: lapi.c,v 2.157 2011/11/16 18:51:36 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -34,9 +34,13 @@ const char lua_ident[] = "$LuaAuthors: " LUA_AUTHORS " $"; +/* value at a non-valid index */ +#define NONVALIDVALUE cast(TValue *, luaO_nilobject) -#define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject, \ - "invalid index") +/* corresponding test */ +#define isvalid(o) ((o) != luaO_nilobject) + +#define api_checkvalidindex(L, i) api_check(L, isvalid(i), "invalid index") static TValue *index2addr (lua_State *L, int idx) { @@ -44,7 +48,7 @@ static TValue *index2addr (lua_State *L, int idx) { if (idx > 0) { TValue *o = ci->func + idx; api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); - if (o >= L->top) return cast(TValue *, luaO_nilobject); + if (o >= L->top) return NONVALIDVALUE; else return o; } else if (idx > LUA_REGISTRYINDEX) { @@ -57,12 +61,10 @@ static TValue *index2addr (lua_State *L, int idx) { idx = LUA_REGISTRYINDEX - idx; api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); if (ttislcf(ci->func)) /* light C function? */ - return cast(TValue *, luaO_nilobject); /* it has no upvalues */ + return NONVALIDVALUE; /* it has no upvalues */ else { CClosure *func = clCvalue(ci->func); - return (idx <= func->nupvalues) - ? &func->upvalue[idx-1] - : cast(TValue *, luaO_nilobject); + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; } } } @@ -237,7 +239,7 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (o == luaO_nilobject) ? LUA_TNONE : ttypenv(o); + return (isvalid(o) ? ttypenv(o) : LUA_TNONE); } @@ -275,8 +277,7 @@ LUA_API int lua_isuserdata (lua_State *L, int idx) { LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = index2addr(L, index1); StkId o2 = index2addr(L, index2); - return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaV_rawequalobj(o1, o2); + return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; } @@ -305,17 +306,17 @@ LUA_API void lua_arith (lua_State *L, int op) { LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { StkId o1, o2; - int i; + int i = 0; lua_lock(L); /* may call tag method */ o1 = index2addr(L, index1); o2 = index2addr(L, index2); - if (o1 == luaO_nilobject || o2 == luaO_nilobject) - i = 0; - else switch (op) { - case LUA_OPEQ: i = equalobj(L, o1, o2); break; - case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; - case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; - default: api_check(L, 0, "invalid option"); i = 0; + if (isvalid(o1) && isvalid(o2)) { + switch (op) { + case LUA_OPEQ: i = equalobj(L, o1, o2); break; + case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; + case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; + default: api_check(L, 0, "invalid option"); + } } lua_unlock(L); return i; @@ -595,6 +596,17 @@ LUA_API int lua_pushthread (lua_State *L) { */ +LUA_API void lua_getglobal (lua_State *L, const char *var) { + Table *reg = hvalue(&G(L)->l_registry); + const TValue *gt; /* global table */ + lua_lock(L); + gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + setsvalue2s(L, L->top++, luaS_new(L, var)); + luaV_gettable(L, gt, L->top - 1, L->top - 1); + lua_unlock(L); +} + + LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); @@ -628,11 +640,24 @@ LUA_API void lua_rawget (lua_State *L, int idx) { LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { - StkId o; + StkId t; lua_lock(L); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - setobj2s(L, L->top, luaH_getint(hvalue(o), n)); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setobj2s(L, L->top, luaH_getint(hvalue(t), n)); + api_incr_top(L); + lua_unlock(L); +} + + +LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) { + StkId t; + TValue k; + lua_lock(L); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setpvalue(&k, cast(void *, p)); + setobj2s(L, L->top, luaH_get(hvalue(t), &k)); api_incr_top(L); lua_unlock(L); } @@ -700,6 +725,19 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) { */ +LUA_API void lua_setglobal (lua_State *L, const char *var) { + Table *reg = hvalue(&G(L)->l_registry); + const TValue *gt; /* global table */ + lua_lock(L); + api_checknelems(L, 1); + gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + setsvalue2s(L, L->top++, luaS_new(L, var)); + luaV_settable(L, gt, L->top - 1, L->top - 2); + L->top -= 2; /* pop value and key */ + lua_unlock(L); +} + + LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); @@ -732,6 +770,7 @@ LUA_API void lua_rawset (lua_State *L, int idx) { t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); + invalidateTMcache(hvalue(t)); luaC_barrierback(L, gcvalue(t), L->top-1); L->top -= 2; lua_unlock(L); @@ -739,13 +778,28 @@ LUA_API void lua_rawset (lua_State *L, int idx) { LUA_API void lua_rawseti (lua_State *L, int idx, int n) { - StkId o; + StkId t; lua_lock(L); api_checknelems(L, 1); - o = index2addr(L, idx); - api_check(L, ttistable(o), "table expected"); - setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1); - luaC_barrierback(L, gcvalue(o), L->top-1); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + luaH_setint(L, hvalue(t), n, L->top - 1); + luaC_barrierback(L, gcvalue(t), L->top-1); + L->top--; + lua_unlock(L); +} + + +LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { + StkId t; + TValue k; + lua_lock(L); + api_checknelems(L, 1); + t = index2addr(L, idx); + api_check(L, ttistable(t), "table expected"); + setpvalue(&k, cast(void *, p)); + setobj2t(L, luaH_set(L, hvalue(t), &k), L->top - 1); + luaC_barrierback(L, gcvalue(t), L->top - 1); L->top--; lua_unlock(L); } @@ -1128,7 +1182,6 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { - static const char *aux_upvalue (StkId fi, int n, TValue **val, GCObject **owner) { switch (ttype(fi)) { @@ -1141,15 +1194,13 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, } case LUA_TLCL: { /* Lua closure */ LClosure *f = clLvalue(fi); - const char *name; + TString *name; Proto *p = f->p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->upvals[n-1]->v; if (owner) *owner = obj2gco(f->upvals[n - 1]); - name = getstr(p->upvalues[n-1].name); - if (name == NULL) /* no debug information? */ - name = ""; - return name; + name = p->upvalues[n-1].name; + return (name == NULL) ? "" : getstr(name); } default: return NULL; /* not a closure */ } @@ -1158,7 +1209,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; - TValue *val; + TValue *val = NULL; /* initialized to avoid warnings */ lua_lock(L); name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); if (name) { @@ -1172,8 +1223,8 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; - TValue *val; - GCObject *owner; + TValue *val = NULL; /* initialized to avoid warnings */ + GCObject *owner = NULL; /* initialized to avoid warnings */ StkId fi; lua_lock(L); fi = index2addr(L, funcindex); diff --git a/src/lauxlib.c b/src/lauxlib.c index b765cfddfa..d61a8ef889 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.233 2011/06/16 14:11:04 roberto Exp $ +** $Id: lauxlib.c,v 1.236 2011/11/14 17:10:24 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -41,11 +41,10 @@ ** return 1 + string at top if find a good name. */ static int findfield (lua_State *L, int objidx, int level) { - int found = 0; if (level == 0 || !lua_istable(L, -1)) return 0; /* not found */ lua_pushnil(L); /* start 'next' loop */ - while (!found && lua_next(L, -2)) { /* for each pair in table */ + while (lua_next(L, -2)) { /* for each pair in table */ if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ if (lua_rawequal(L, objidx, -1)) { /* found object? */ lua_pop(L, 1); /* remove value (but keep name) */ @@ -86,7 +85,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) { lua_pushfstring(L, "function " LUA_QS, ar->name); else if (*ar->what == 'm') /* main? */ lua_pushfstring(L, "main chunk"); - else if (*ar->what == 'C' || *ar->what == 't') { + else if (*ar->what == 'C') { if (pushglobalfuncname(L, ar)) { lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); lua_remove(L, -2); /* remove name */ @@ -331,7 +330,9 @@ LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { - if (!lua_checkstack(L, space)) { + /* keep some extra space to run error routines, if needed */ + const int extra = LUA_MINSTACK; + if (!lua_checkstack(L, space + extra)) { if (msg) luaL_error(L, "stack overflow (%s)", msg); else @@ -591,6 +592,16 @@ static int errfile (lua_State *L, const char *what, int fnameindex) { } +static int checkmode (lua_State *L, const char *mode, const char *x) { + if (mode && strchr(mode, x[0]) == NULL) { + lua_pushfstring(L, + "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode); + return LUA_ERRFILE; + } + else return LUA_OK; +} + + static int skipBOM (LoadF *lf) { const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */ int c; @@ -623,7 +634,8 @@ static int skipcomment (LoadF *lf, int *cp) { } -LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { +LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, + const char *mode) { LoadF lf; int status, readstatus; int c; @@ -639,14 +651,23 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { } if (skipcomment(&lf, &c)) /* read initial portion */ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ - if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ - lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ - if (lf.f == NULL) return errfile(L, "reopen", fnameindex); - skipcomment(&lf, &c); /* re-read initial portion */ + if (c == LUA_SIGNATURE[0]) { /* binary file? */ + if ((status = checkmode(L, mode, "binary")) != LUA_OK) + goto closefile; + if (filename) { + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return errfile(L, "reopen", fnameindex); + skipcomment(&lf, &c); /* re-read initial portion */ + } + } + else { /* text file */ + if ((status = checkmode(L, mode, "text")) != LUA_OK) + goto closefile; } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ status = lua_load(L, getF, &lf, lua_tostring(L, -1)); + closefile: readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { diff --git a/src/lauxlib.h b/src/lauxlib.h index a7aa0d761c..48b1afa01f 100644 --- a/src/lauxlib.h +++ b/src/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.117 2011/06/16 14:10:12 roberto Exp $ +** $Id: lauxlib.h,v 1.119 2011/11/14 17:10:24 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -72,7 +72,11 @@ LUALIB_API int (luaL_execresult) (lua_State *L, int stat); LUALIB_API int (luaL_ref) (lua_State *L, int t); LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); -LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); +LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); + +#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) + LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); @@ -163,6 +167,31 @@ LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); /* }====================================================== */ + +/* +** {====================================================== +** File handles for IO library +** ======================================================= +*/ + +/* +** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and +** initial structure 'luaL_Stream' (it may contain other fields +** after that initial structure). +*/ + +#define LUA_FILEHANDLE "FILE*" + + +typedef struct luaL_Stream { + FILE *f; /* stream (NULL for incompletely created streams) */ + lua_CFunction closef; /* to close stream (NULL for closed streams) */ +} luaL_Stream; + +/* }====================================================== */ + + + /* compatibility with old module system */ #if defined(LUA_COMPAT_MODULE) diff --git a/src/lbaselib.c b/src/lbaselib.c index e4daf5d432..472a96c80b 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.264 2011/07/05 12:49:35 roberto Exp $ +** $Id: lbaselib.c,v 1.270 2011/11/23 17:29:04 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -46,20 +46,22 @@ static int luaB_print (lua_State *L) { #define SPACECHARS " \f\n\r\t\v" static int luaB_tonumber (lua_State *L) { - int base = luaL_optint(L, 2, 10); - luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - if (base == 10) { /* standard conversion */ - luaL_checkany(L, 1); - if (lua_isnumber(L, 1)) { - lua_pushnumber(L, lua_tonumber(L, 1)); + if (lua_isnoneornil(L, 2)) { /* standard conversion */ + int isnum; + lua_Number n = lua_tonumberx(L, 1, &isnum); + if (isnum) { + lua_pushnumber(L, n); return 1; - } /* else not a number */ + } /* else not a number; must be something */ + luaL_checkany(L, 1); } else { size_t l; const char *s = luaL_checklstring(L, 1, &l); const char *e = s + l; /* end point for 's' */ + int base = luaL_checkint(L, 2); int neg = 0; + luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); s += strspn(s, SPACECHARS); /* skip initial spaces */ if (*s == '-') { s++; neg = 1; } /* handle signal */ else if (*s == '+') s++; @@ -158,7 +160,7 @@ static int luaB_rawset (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", - "setmajorinc", "isrunning", "gen", "inc", NULL}; + "setmajorinc", "isrunning", "generational", "incremental", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; @@ -253,7 +255,14 @@ static int load_aux (lua_State *L, int status) { static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); - return load_aux(L, luaL_loadfile(L, fname)); + const char *mode = luaL_optstring(L, 2, NULL); + int env = !lua_isnone(L, 3); /* 'env' parameter? */ + int status = luaL_loadfilex(L, fname, mode); + if (status == LUA_OK && env) { /* 'env' parameter? */ + lua_pushvalue(L, 3); + lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */ + } + return load_aux(L, status); } @@ -265,7 +274,6 @@ static int luaB_loadfile (lua_State *L) { typedef struct { -char c; const char *mode; } loaddata; @@ -276,11 +284,11 @@ char c; ** pushed on the stack) in case of errors. */ static const char *checkrights (lua_State *L, const char *mode, const char *s) { - if (strchr(mode, 'b') == NULL && *s == LUA_SIGNATURE[0]) - return lua_pushstring(L, "attempt to load a binary chunk"); - if (strchr(mode, 't') == NULL && *s != LUA_SIGNATURE[0]) - return lua_pushstring(L, "attempt to load a text chunk"); - return NULL; /* chunk in allowed format */ + const char *x = (*s == LUA_SIGNATURE[0]) ? "binary" : "text"; + if (strchr(mode, x[0]) == NULL) + return lua_pushfstring(L, + "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode); + else return NULL; } @@ -390,27 +398,32 @@ static int luaB_select (lua_State *L) { } -static int pcallcont (lua_State *L) { - int errfunc = 0; /* =0 to avoid warnings */ - int status = lua_getctx(L, &errfunc); - lua_assert(status != LUA_OK); - lua_pushboolean(L, (status == LUA_YIELD)); /* first result (status) */ - if (errfunc) /* came from xpcall? */ - lua_replace(L, 1); /* put first result in place of error function */ - else /* came from pcall */ - lua_insert(L, 1); /* open space for first result */ +static int finishpcall (lua_State *L, int status) { + if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */ + lua_settop(L, 0); /* create space for return values */ + lua_pushboolean(L, 0); + lua_pushstring(L, "stack overflow"); + return 2; /* return false, msg */ + } + lua_pushboolean(L, status); /* first result (status) */ + lua_replace(L, 1); /* put first result in first slot */ return lua_gettop(L); } +static int pcallcont (lua_State *L) { + int status = lua_getctx(L, NULL); + return finishpcall(L, (status == LUA_YIELD)); +} + + static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); - status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, pcallcont); - luaL_checkstack(L, 1, NULL); - lua_pushboolean(L, (status == LUA_OK)); - lua_insert(L, 1); - return lua_gettop(L); /* return status + all results */ + lua_pushnil(L); + lua_insert(L, 1); /* create space for status result */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); + return finishpcall(L, (status == LUA_OK)); } @@ -421,11 +434,8 @@ static int luaB_xpcall (lua_State *L) { lua_pushvalue(L, 1); /* exchange function... */ lua_copy(L, 2, 1); /* ...and error handler */ lua_replace(L, 2); - status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 1, pcallcont); - luaL_checkstack(L, 1, NULL); - lua_pushboolean(L, (status == LUA_OK)); - lua_replace(L, 1); - return lua_gettop(L); /* return status + all results */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont); + return finishpcall(L, (status == LUA_OK)); } diff --git a/src/lcode.c b/src/lcode.c index 00966a1269..614e452f9c 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.56 2011/05/31 18:27:56 roberto Exp $ +** $Id: lcode.c,v 2.60 2011/08/30 16:26:41 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -44,8 +44,8 @@ void luaK_nil (FuncState *fs, int from, int n) { int pl = pfrom + GETARG_B(*previous); if ((pfrom <= from && from <= pl + 1) || (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ - if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ - if (pl > l) l = pl; /* l = max(l, pl) */ + if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ + if (pl > l) l = pl; /* l = max(l, pl) */ SETARG_A(*previous, from); SETARG_B(*previous, l - from); return; @@ -213,11 +213,11 @@ static int luaK_code (FuncState *fs, Instruction i) { Proto *f = fs->f; dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ - luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, + luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "opcodes"); f->code[fs->pc] = i; /* save corresponding line information */ - luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, + luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, MAX_INT, "opcodes"); f->lineinfo[fs->pc] = fs->ls->lastline; return fs->pc++; @@ -289,7 +289,7 @@ static void freeexp (FuncState *fs, expdesc *e) { static int addk (FuncState *fs, TValue *key, TValue *v) { - lua_State *L = fs->L; + lua_State *L = fs->ls->L; TValue *idx = luaH_set(L, fs->h, key); Proto *f = fs->f; int k, oldsize; @@ -304,6 +304,8 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { /* constant not found; create a new entry */ oldsize = f->sizek; k = fs->nk; + /* numerical value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ setnvalue(idx, cast_num(k)); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); @@ -316,14 +318,14 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { int luaK_stringK (FuncState *fs, TString *s) { TValue o; - setsvalue(fs->L, &o, s); + setsvalue(fs->ls->L, &o, s); return addk(fs, &o, &o); } int luaK_numberK (FuncState *fs, lua_Number r) { int n; - lua_State *L = fs->L; + lua_State *L = fs->ls->L; TValue o; setnvalue(&o, r); if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ @@ -350,7 +352,7 @@ static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ - sethvalue(fs->L, &k, fs->h); + sethvalue(fs->ls->L, &k, fs->h); return addk(fs, &k, &v); } @@ -641,7 +643,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { } -static void luaK_goiffalse (FuncState *fs, expdesc *e) { +void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { diff --git a/src/lcode.h b/src/lcode.h index 26a5daafcc..5a1fa9feac 100644 --- a/src/lcode.h +++ b/src/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.57 2011/04/07 18:14:12 roberto Exp $ +** $Id: lcode.h,v 1.58 2011/08/30 16:26:41 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -62,6 +62,7 @@ LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); +LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); diff --git a/src/lcorolib.c b/src/lcorolib.c index 981ca381fd..0edde26daf 100644 --- a/src/lcorolib.c +++ b/src/lcorolib.c @@ -1,5 +1,5 @@ /* -** $Id: lcorolib.c,v 1.2 2010/07/02 11:38:13 roberto Exp $ +** $Id: lcorolib.c,v 1.3 2011/08/23 17:24:34 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ @@ -28,7 +28,7 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { return -1; /* error flag */ } lua_xmove(L, co, narg); - status = lua_resume(co, narg); + status = lua_resume(co, L, narg); if (status == LUA_OK || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres + 1)) { diff --git a/src/lctype.c b/src/lctype.c index 387c93aa9c..55e433a5dd 100644 --- a/src/lctype.c +++ b/src/lctype.c @@ -1,9 +1,12 @@ /* -** $Id: lctype.c,v 1.10 2011/06/24 12:25:33 roberto Exp $ +** $Id: lctype.c,v 1.11 2011/10/03 16:19:23 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ +#define lctype_c +#define LUA_CORE + #include "lctype.h" #if !LUA_USE_CTYPE /* { */ diff --git a/src/lctype.h b/src/lctype.h index b24d92507c..99c7d12237 100644 --- a/src/lctype.h +++ b/src/lctype.h @@ -1,5 +1,5 @@ /* -** $Id: lctype.h,v 1.11 2011/06/27 18:22:46 roberto Exp $ +** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ @@ -11,7 +11,7 @@ /* -** WARNING: the functions defined here do not necessarily correspond +** WARNING: the functions defined here do not necessarily correspond ** to the similar functions in the standard C ctype.h. They are ** optimized for the specific needs of Lua */ diff --git a/src/ldblib.c b/src/ldblib.c index 78f6cc0613..3c2f159572 100644 --- a/src/ldblib.c +++ b/src/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.130 2011/04/08 19:17:36 roberto Exp $ +** $Id: ldblib.c,v 1.131 2011/10/24 14:54:05 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -260,8 +260,7 @@ static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail call"}; gethooktable(L); - lua_pushlightuserdata(L, L); - lua_rawget(L, -2); + lua_rawgetp(L, -1, L); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) @@ -308,9 +307,8 @@ static int db_sethook (lua_State *L) { func = hookf; mask = makemask(smask, count); } gethooktable(L); - lua_pushlightuserdata(L, L1); lua_pushvalue(L, arg+1); - lua_rawset(L, -3); /* set new hook */ + lua_rawsetp(L, -2, L1); /* set new hook */ lua_pop(L, 1); /* remove hook table */ lua_sethook(L1, func, mask, count); /* set hooks */ return 0; @@ -327,8 +325,7 @@ static int db_gethook (lua_State *L) { lua_pushliteral(L, "external hook"); else { gethooktable(L); - lua_pushlightuserdata(L, L1); - lua_rawget(L, -2); /* get hook */ + lua_rawgetp(L, -1, L1); /* get hook */ lua_remove(L, -2); /* remove hook table */ } lua_pushstring(L, unmakemask(mask, buff)); diff --git a/src/ldebug.c b/src/ldebug.c index a2565cf592..786dcd043b 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.82 2011/06/02 19:31:40 roberto Exp $ +** $Id: ldebug.c,v 2.87 2011/10/07 20:45:19 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -94,6 +94,13 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { } +static const char *upvalname (Proto *p, int uv) { + TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); + if (s == NULL) return "?"; + else return getstr(s); +} + + static const char *findvararg (CallInfo *ci, int n, StkId *pos) { int nparams = clLvalue(ci->func)->p->numparams; if (n >= ci->u.l.base - ci->func - nparams) @@ -190,12 +197,14 @@ static void collectvalidlines (lua_State *L, Closure *f) { } else { int i; + TValue v; int *lineinfo = f->l.p->lineinfo; - Table *t = luaH_new(L); - sethvalue(L, L->top, t); + Table *t = luaH_new(L); /* new table to store active lines */ + sethvalue(L, L->top, t); /* push it on stack */ incr_top(L); - for (i=0; il.p->sizelineinfo; i++) - setbvalue(luaH_setint(L, t, lineinfo[i]), 1); + setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ + for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ + luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ } } @@ -230,7 +239,11 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'n': { - ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; + /* calling function is a known Lua function? */ + if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) + ar->namewhat = getfuncname(L, ci->previous, &ar->name); + else + ar->namewhat = NULL; if (ar->namewhat == NULL) { ar->namewhat = ""; /* not found */ ar->name = NULL; @@ -284,17 +297,16 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { ** ======================================================= */ -static const char *getobjname (lua_State *L, CallInfo *ci, int reg, +static const char *getobjname (Proto *p, int lastpc, int reg, const char **name); /* ** find a "name" for the RK value 'c' */ -static void kname (lua_State *L, CallInfo *ci, int c, int oreg, - const char *what, const char **name) { +static void kname (Proto *p, int pc, int c, const char **name) { if (ISK(c)) { /* is 'c' a constant? */ - TValue *kvalue = &ci_func(ci)->p->k[INDEXK(c)]; + TValue *kvalue = &p->k[INDEXK(c)]; if (ttisstring(kvalue)) { /* literal constant? */ *name = svalue(kvalue); /* it is its own name */ return; @@ -302,8 +314,7 @@ static void kname (lua_State *L, CallInfo *ci, int c, int oreg, /* else no reasonable name found */ } else { /* 'c' is a register */ - if (c != oreg) /* not the original register? */ - what = getobjname(L, ci, c, name); /* search for 'c' */ + const char *what = getobjname(p, pc, c, name); /* search for 'c' */ if (what && *what == 'c') { /* found a constant name? */ return; /* 'name' already filled */ } @@ -313,85 +324,30 @@ static void kname (lua_State *L, CallInfo *ci, int c, int oreg, } -static const char *getobjname (lua_State *L, CallInfo *ci, int reg, - const char **name) { - Proto *p = ci_func(ci)->p; - const char *what = NULL; - int lastpc = currentpc(ci); +/* +** try to find last instruction before 'lastpc' that modified register 'reg' +*/ +static int findsetreg (Proto *p, int lastpc, int reg) { int pc; - *name = luaF_getlocalname(p, reg + 1, lastpc); - if (*name) /* is a local? */ - return "local"; - /* else try symbolic execution */ + int setreg = -1; /* keep last instruction that changed 'reg' */ for (pc = 0; pc < lastpc; pc++) { Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); switch (op) { - case OP_MOVE: { - if (reg == a) { - int b = GETARG_B(i); /* move from 'b' to 'a' */ - if (b < a) - what = getobjname(L, ci, b, name); /* get name for 'b' */ - else what = NULL; - } - break; - } - case OP_GETTABUP: - case OP_GETTABLE: { - if (reg == a) { - int k = GETARG_C(i); /* key index */ - int t = GETARG_B(i); - const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ - ? luaF_getlocalname(p, t + 1, pc) - : getstr(p->upvalues[t].name); - kname(L, ci, k, a, what, name); - what = (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; - } - break; - } - case OP_GETUPVAL: { - if (reg == a) { - int u = GETARG_B(i); /* upvalue index */ - TString *tn = p->upvalues[u].name; - *name = tn ? getstr(tn) : "?"; - what = "upvalue"; - } - break; - } - case OP_LOADK: - case OP_LOADKX: { - if (reg == a) { - int b = (op == OP_LOADK) ? GETARG_Bx(i) - : GETARG_Ax(p->code[pc + 1]); - if (ttisstring(&p->k[b])) { - what = "constant"; - *name = svalue(&p->k[b]); - } - } - break; - } case OP_LOADNIL: { int b = GETARG_B(i); if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ - what = NULL; - break; - } - case OP_SELF: { - if (reg == a) { - int k = GETARG_C(i); /* key index */ - kname(L, ci, k, a, what, name); - what = "method"; - } + setreg = pc; break; } case OP_TFORCALL: { - if (reg >= a + 2) what = NULL; /* affect all regs above its base */ + if (reg >= a + 2) setreg = pc; /* affect all regs above its base */ break; } case OP_CALL: case OP_TAILCALL: { - if (reg >= a) what = NULL; /* affect all registers above base */ + if (reg >= a) setreg = pc; /* affect all registers above base */ break; } case OP_JMP: { @@ -403,35 +359,87 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg, break; } case OP_TEST: { - if (reg == a) what = NULL; /* jumped code can change 'a' */ + if (reg == a) setreg = pc; /* jumped code can change 'a' */ break; } default: - if (testAMode(op) && reg == a) what = NULL; + if (testAMode(op) && reg == a) /* any instruction that set A */ + setreg = pc; break; } } - return what; + return setreg; +} + + +static const char *getobjname (Proto *p, int lastpc, int reg, + const char **name) { + int pc; + *name = luaF_getlocalname(p, reg + 1, lastpc); + if (*name) /* is a local? */ + return "local"; + /* else try symbolic execution */ + pc = findsetreg(p, lastpc, reg); + if (pc != -1) { /* could find instruction? */ + Instruction i = p->code[pc]; + OpCode op = GET_OPCODE(i); + switch (op) { + case OP_MOVE: { + int b = GETARG_B(i); /* move from 'b' to 'a' */ + if (b < GETARG_A(i)) + return getobjname(p, pc, b, name); /* get name for 'b' */ + break; + } + case OP_GETTABUP: + case OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + int t = GETARG_B(i); /* table index */ + const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ + ? luaF_getlocalname(p, t + 1, pc) + : upvalname(p, t); + kname(p, pc, k, name); + return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; + } + case OP_GETUPVAL: { + *name = upvalname(p, GETARG_B(i)); + return "upvalue"; + } + case OP_LOADK: + case OP_LOADKX: { + int b = (op == OP_LOADK) ? GETARG_Bx(i) + : GETARG_Ax(p->code[pc + 1]); + if (ttisstring(&p->k[b])) { + *name = svalue(&p->k[b]); + return "constant"; + } + break; + } + case OP_SELF: { + int k = GETARG_C(i); /* key index */ + kname(p, pc, k, name); + return "method"; + } + default: break; /* go through to return NULL */ + } + } + return NULL; /* could not find reasonable name */ } static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { TMS tm; - Instruction i; - if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous)) - return NULL; /* calling function is not Lua (or is unknown) */ - ci = ci->previous; /* calling function */ - i = ci_func(ci)->p->code[currentpc(ci)]; - if (GET_OPCODE(i) == OP_EXTRAARG) /* extra argument? */ - i = ci_func(ci)->p->code[currentpc(ci) - 1]; /* get 'real' instruction */ + Proto *p = ci_func(ci)->p; /* calling function */ + int pc = currentpc(ci); /* calling instruction index */ + Instruction i = p->code[pc]; /* calling instruction */ switch (GET_OPCODE(i)) { case OP_CALL: - case OP_TAILCALL: - return getobjname(L, ci, GETARG_A(i), name); - case OP_TFORCALL: { + case OP_TAILCALL: /* get function name */ + return getobjname(p, pc, GETARG_A(i), name); + case OP_TFORCALL: { /* for iterator */ *name = "for iterator"; return "for iterator"; } + /* all other instructions can call only through metamethods */ case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: tm = TM_INDEX; break; @@ -473,12 +481,12 @@ static int isinstack (CallInfo *ci, const TValue *o) { static const char *getupvalname (CallInfo *ci, const TValue *o, - const char **name) { + const char **name) { LClosure *c = ci_func(ci); int i; for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v == o) { - *name = getstr(c->p->upvalues[i].name); + *name = upvalname(c->p, i); return "upvalue"; } } @@ -494,7 +502,8 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ if (!kind && isinstack(ci, o)) /* no? try a register */ - kind = getobjname(L, ci, cast_int(o - ci->u.l.base), &name); + kind = getobjname(ci_func(ci)->p, currentpc(ci), + cast_int(o - ci->u.l.base), &name); } if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", @@ -511,7 +520,7 @@ void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { } -void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { +l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { TValue temp; if (luaV_tonumber(p1, &temp) == NULL) p2 = p1; /* first operand is wrong */ @@ -519,14 +528,13 @@ void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { } -int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { +l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = objtypename(p1); const char *t2 = objtypename(p2); if (t1 == t2) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); - return 0; } @@ -546,7 +554,7 @@ static void addinfo (lua_State *L, const char *msg) { } -void luaG_errormsg (lua_State *L) { +l_noret luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); @@ -559,7 +567,7 @@ void luaG_errormsg (lua_State *L) { } -void luaG_runerror (lua_State *L, const char *fmt, ...) { +l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); addinfo(L, luaO_pushvfstring(L, fmt, argp)); diff --git a/src/ldebug.h b/src/ldebug.h index 6590c56bba..fe39556b06 100644 --- a/src/ldebug.h +++ b/src/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.6 2011/06/02 19:31:40 roberto Exp $ +** $Id: ldebug.h,v 2.7 2011/10/07 20:45:19 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -21,14 +21,14 @@ #define ci_func(ci) (clLvalue((ci)->func)) -LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, - const char *opname); -LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2); -LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, - const TValue *p2); -LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); -LUAI_FUNC void luaG_errormsg (lua_State *L); +LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, + const char *opname); +LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2); +LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC l_noret luaG_errormsg (lua_State *L); #endif diff --git a/src/ldo.c b/src/ldo.c index a34b0d0bbb..0f8c26ea2b 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.98 2011/06/28 15:42:04 roberto Exp $ +** $Id: ldo.c,v 2.101 2011/10/07 20:45:19 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -100,7 +100,7 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { } -void luaD_throw (lua_State *L, int errcode) { +l_noret luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { /* thread has an error handler? */ L->errorJmp->status = errcode; /* set status */ LUAI_THROW(L, L->errorJmp); /* jump to it */ @@ -123,7 +123,7 @@ void luaD_throw (lua_State *L, int errcode) { int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { - unsigned short oldnCcalls = G(L)->nCcalls; + unsigned short oldnCcalls = L->nCcalls; struct lua_longjmp lj; lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ @@ -132,7 +132,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ - G(L)->nCcalls = oldnCcalls; + L->nCcalls = oldnCcalls; return lj.status; } @@ -344,7 +344,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { } default: { /* not a function */ func = tryfuncTM(L, func); /* retry with 'function' tag method */ - return luaD_precall(L, func, nresults); + return luaD_precall(L, func, nresults); /* now it must be a function */ } } } @@ -382,18 +382,17 @@ int luaD_poscall (lua_State *L, StkId firstResult) { ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { - global_State *g = G(L); - if (++g->nCcalls >= LUAI_MAXCCALLS) { - if (g->nCcalls == LUAI_MAXCCALLS) + if (++L->nCcalls >= LUAI_MAXCCALLS) { + if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); - else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } if (!allowyield) L->nny++; if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ luaV_execute(L); /* call it */ if (!allowyield) L->nny--; - g->nCcalls--; + L->nCcalls--; luaC_checkGC(L); } @@ -404,7 +403,7 @@ static void finishCcall (lua_State *L) { lua_assert(ci->u.c.k != NULL); /* must have a continuation */ lua_assert(L->nny == 0); /* finish 'luaD_call' */ - G(L)->nCcalls--; + L->nCcalls--; /* finish 'lua_callk' */ adjustresults(L, ci->nresults); /* call continuation function */ @@ -473,7 +472,7 @@ static int recover (lua_State *L, int status) { ** coroutine itself. (Such errors should not be handled by any coroutine ** error handler and should not kill the coroutine.) */ -static void resume_error (lua_State *L, const char *msg, StkId firstArg) { +static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { L->top = firstArg; /* remove args from the stack */ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ incr_top(L); @@ -487,7 +486,7 @@ static void resume_error (lua_State *L, const char *msg, StkId firstArg) { static void resume (lua_State *L, void *ud) { StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; - if (G(L)->nCcalls >= LUAI_MAXCCALLS) + if (L->nCcalls >= LUAI_MAXCCALLS) resume_error(L, "C stack overflow", firstArg); if (L->status == LUA_OK) { /* may be starting a coroutine */ if (ci != &L->base_ci) /* not in base level? */ @@ -514,7 +513,7 @@ static void resume (lua_State *L, void *ud) { api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } - G(L)->nCcalls--; /* finish 'luaD_call' */ + L->nCcalls--; /* finish 'luaD_call' */ luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ } unroll(L, NULL); @@ -522,11 +521,11 @@ static void resume (lua_State *L, void *ud) { } -LUA_API int lua_resume (lua_State *L, int nargs) { +LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { int status; lua_lock(L); luai_userstateresume(L, nargs); - ++G(L)->nCcalls; /* count resume */ + L->nCcalls = (from) ? from->nCcalls + 1 : 1; L->nny = 0; /* allow yields */ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, L->top - nargs); @@ -546,7 +545,8 @@ LUA_API int lua_resume (lua_State *L, int nargs) { lua_assert(status == L->status); } L->nny = 1; /* do not allow yields */ - --G(L)->nCcalls; + L->nCcalls--; + lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); lua_unlock(L); return status; } diff --git a/src/ldo.h b/src/ldo.h index 88962d9c5d..edfe0070b4 100644 --- a/src/ldo.h +++ b/src/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.18 2009/12/17 12:28:57 roberto Exp $ +** $Id: ldo.h,v 2.19 2011/10/07 20:45:19 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -38,7 +38,7 @@ LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_shrinkstack (lua_State *L); -LUAI_FUNC void luaD_throw (lua_State *L, int errcode); +LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); #endif diff --git a/src/ldump.c b/src/ldump.c index 77b578d777..699e1dc4e9 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.18 2011/05/06 13:35:17 lhf Exp $ +** $Id: ldump.c,v 1.19 2011/11/23 17:48:18 lhf Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -111,8 +111,8 @@ static void DumpUpvalues(const Proto* f, DumpState* D) DumpInt(n,D); for (i=0; iupvalues[i].instack, D); - DumpChar(f->upvalues[i].idx, D); + DumpChar(f->upvalues[i].instack,D); + DumpChar(f->upvalues[i].idx,D); } } diff --git a/src/lgc.c b/src/lgc.c index 598cc71c7e..37de55ca31 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.109 2011/05/05 19:42:25 roberto Exp $ +** $Id: lgc.c,v 2.114 2011/10/03 17:54:25 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -100,12 +100,13 @@ static void reallymarkobject (global_State *g, GCObject *o); /* -** mark a table entry as dead (therefore removing it from the table) +** if key is not marked, mark its entry as dead (therefore removing it +** from the table) */ static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); - if (iscollectable(gkey(n))) - setdeadvalue(gkey(n)); /* dead key; remove it */ + if (valiswhite(gkey(n))) + setdeadvalue(gkey(n)); /* unused and unmarked key; remove it */ } @@ -116,13 +117,13 @@ static void removeentry (Node *n) { ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ -static int iscleared (const TValue *o, int iskey) { +static int iscleared (const TValue *o) { if (!iscollectable(o)) return 0; else if (ttisstring(o)) { stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ return 0; } - else return iswhite(gcvalue(o)) || (!iskey && isfinalized(gcvalue(o))); + else return iswhite(gcvalue(o)); } @@ -152,7 +153,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { */ void luaC_barrierback_ (lua_State *L, GCObject *o) { global_State *g = G(L); - lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE); black2gray(o); /* make object gray (again) */ gco2t(o)->gclist = g->grayagain; g->grayagain = o; @@ -342,6 +343,9 @@ static void markroot (global_State *g) { static void traverseweakvalue (global_State *g, Table *h) { Node *n, *limit = gnode(h, sizenode(h)); + /* if there is array part, assume it may have white values (do not + traverse it just to check) */ + int hasclears = (h->sizearray > 0); for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ @@ -349,15 +353,21 @@ static void traverseweakvalue (global_State *g, Table *h) { else { lua_assert(!ttisnil(gkey(n))); markvalue(g, gkey(n)); /* mark key */ + if (!hasclears && iscleared(gval(n))) /* is there a white value? */ + hasclears = 1; /* table will have to be cleared */ } } - linktable(h, &g->weak); /* link into appropriate list */ + if (hasclears) + linktable(h, &g->weak); /* has to be cleared later */ + else /* no white values */ + linktable(h, &g->grayagain); /* no need to clean */ } static int traverseephemeron (global_State *g, Table *h) { int marked = 0; /* true if an object is marked in this traversal */ - int hasclears = 0; /* true if table has unmarked pairs */ + int hasclears = 0; /* true if table has white keys */ + int prop = 0; /* true if table has entry "white-key -> white-value" */ Node *n, *limit = gnode(h, sizenode(h)); int i; /* traverse array part (numeric keys are 'strong') */ @@ -372,19 +382,22 @@ static int traverseephemeron (global_State *g, Table *h) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ + else if (iscleared(gkey(n))) { /* key is not marked (yet)? */ + hasclears = 1; /* table must be cleared */ + if (valiswhite(gval(n))) /* value not marked yet? */ + prop = 1; /* must propagate again */ + } else if (valiswhite(gval(n))) { /* value not marked yet? */ - if (iscleared(gkey(n), 1)) /* key is not marked (yet)? */ - hasclears = 1; /* may have to propagate mark from key to value */ - else { /* key is marked, so mark value */ - marked = 1; /* value was not marked */ - reallymarkobject(g, gcvalue(gval(n))); - } + marked = 1; + reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ } } - if (hasclears) /* does table have unmarked pairs? */ - linktable(h, &g->ephemeron); /* will have to propagate again */ - else /* nothing to propagate */ - linktable(h, &g->weak); /* avoid convergence phase */ + if (prop) + linktable(h, &g->ephemeron); /* have to propagate again */ + else if (hasclears) /* does table have white keys? */ + linktable(h, &g->allweak); /* may have to clean white keys */ + else /* no white keys */ + linktable(h, &g->grayagain); /* no need to clean */ return marked; } @@ -526,11 +539,26 @@ static void propagateall (global_State *g) { } -static void traverselistofgrays (global_State *g, GCObject **l) { +static void propagatelist (global_State *g, GCObject *l) { lua_assert(g->gray == NULL); /* no grays left */ - g->gray = *l; /* now 'l' is new gray list */ - *l = NULL; - propagateall(g); + g->gray = l; + propagateall(g); /* traverse all elements from 'l' */ +} + +/* +** retraverse all gray lists. Because tables may be reinserted in other +** lists when traversed, traverse the original lists to avoid traversing +** twice the same table (which is not wrong, but inefficient) +*/ +static void retraversegrays (global_State *g) { + GCObject *weak = g->weak; /* save original lists */ + GCObject *grayagain = g->grayagain; + GCObject *ephemeron = g->ephemeron; + g->weak = g->grayagain = g->ephemeron = NULL; + propagateall(g); /* traverse main gray list */ + propagatelist(g, grayagain); + propagatelist(g, weak); + propagatelist(g, ephemeron); } @@ -562,21 +590,39 @@ static void convergeephemerons (global_State *g) { /* -** clear collected entries from all weaktables in list 'l' +** clear entries with unmarked keys from all weaktables in list 'l' up +** to element 'f' +*/ +static void clearkeys (GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { + Table *h = gco2t(l); + Node *n, *limit = gnode(h, sizenode(h)); + for (n = gnode(h, 0); n < limit; n++) { + if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* and remove entry from table */ + } + } + } +} + + +/* +** clear entries with unmarked values from all weaktables in list 'l' up +** to element 'f' */ -static void cleartable (GCObject *l) { - for (; l != NULL; l = gco2t(l)->gclist) { +static void clearvalues (GCObject *l, GCObject *f) { + for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnode(h, sizenode(h)); int i; for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; - if (iscleared(o, 0)) /* value was collected? */ + if (iscleared(o)) /* value was collected? */ setnilvalue(o); /* remove value */ } for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && /* non-empty entry? */ - (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) { + if (!ttisnil(gval(n)) && iscleared(gval(n))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } @@ -743,10 +789,10 @@ static void GCTM (lua_State *L, int propagateerrors) { /* -** move all unreachable objects that need finalization from list 'finobj' -** to list 'tobefnz' +** move all unreachable objects (or 'all' objects) that need +** finalization from list 'finobj' to list 'tobefnz' (to be finalized) */ -void luaC_separateudata (lua_State *L, int all) { +static void separatetobefnz (lua_State *L, int all) { global_State *g = G(L); GCObject **p = &g->finobj; GCObject *curr; @@ -842,14 +888,13 @@ static void callallpendingfinalizers (lua_State *L, int propagateerrors) { void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); int i; + separatetobefnz(L, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL); callallpendingfinalizers(L, 0); - /* following "white" makes all objects look dead */ - g->currentwhite = WHITEBITS; + g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->finobj); - lua_assert(g->finobj == NULL); + sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ sweepwholelist(L, &g->allgc); - lua_assert(g->allgc == NULL); for (i = 0; i < g->strt.size; i++) /* free all string lists */ sweepwholelist(L, &g->strt.hash[i]); lua_assert(g->strt.nuse == 0); @@ -858,6 +903,7 @@ void luaC_freeallobjects (lua_State *L) { static void atomic (lua_State *L) { global_State *g = G(L); + GCObject *origweak, *origall; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ @@ -866,20 +912,24 @@ static void atomic (lua_State *L) { /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); /* traverse objects caught by write barrier and by 'remarkupvals' */ - propagateall(g); - traverselistofgrays(g, &g->weak); /* remark weak tables */ - traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ - traverselistofgrays(g, &g->grayagain); /* remark gray again */ + retraversegrays(g); convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ - luaC_separateudata(L, 0); /* separate userdata to be finalized */ + /* clear values from weak tables, before checking finalizers */ + clearvalues(g->weak, NULL); + clearvalues(g->allweak, NULL); + origweak = g->weak; origall = g->allweak; + separatetobefnz(L, 0); /* separate objects to be finalized */ markbeingfnz(g); /* mark userdata that will be finalized */ propagateall(g); /* remark, to propagate `preserveness' */ convergeephemerons(g); - /* remove collected objects from weak tables */ - cleartable(g->weak); - cleartable(g->ephemeron); - cleartable(g->allweak); + /* at this point, all resurrected objects are marked. */ + /* remove dead objects from weak tables */ + clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */ + clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */ + /* clear values from resurrected weak tables */ + clearvalues(g->weak, origweak); + clearvalues(g->allweak, origall); g->sweepstrgc = 0; /* prepare to sweep strings */ g->gcstate = GCSsweepstring; g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ diff --git a/src/lgc.h b/src/lgc.h index 0fae4dd292..aa5dfce212 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.50 2011/01/26 16:30:02 roberto Exp $ +** $Id: lgc.h,v 2.52 2011/10/03 17:54:25 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -63,9 +63,6 @@ #define l_setbit(x,b) setbits(x, bitmask(b)) #define resetbit(x,b) resetbits(x, bitmask(b)) #define testbit(x,b) testbits(x, bitmask(b)) -#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) -#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) - /* Layout for bit use in `marked' field: */ @@ -125,7 +122,6 @@ #define luaC_barrierproto(L,p,c) \ { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } -LUAI_FUNC void luaC_separateudata (lua_State *L, int all); LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_forcestep (lua_State *L); diff --git a/src/liolib.c b/src/liolib.c index 41e7ec5591..0c9314c738 100644 --- a/src/liolib.c +++ b/src/liolib.c @@ -1,10 +1,20 @@ /* -** $Id: liolib.c,v 2.101 2011/06/27 19:42:31 roberto Exp $ +** $Id: liolib.c,v 2.107 2011/11/14 16:55:35 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ +/* +** POSIX idiosyncrasy! +** This definition must come before the inclusion of 'stdio.h'; it +** should not affect non-POSIX systems +*/ +#if !defined(_FILE_OFFSET_BITS) +#define _FILE_OFFSET_BITS 64 +#endif + + #include #include #include @@ -21,9 +31,12 @@ /* -** lua_popen spawns a new process connected to the current one through -** the file streams. +** {====================================================== +** lua_popen spawns a new process connected to the current +** one through the file streams. +** ======================================================= */ + #if !defined(lua_popen) /* { */ #if defined(LUA_USE_POPEN) /* { */ @@ -48,22 +61,48 @@ #endif /* } */ +/* }====================================================== */ + + +/* +** {====================================================== +** lua_fseek/lua_ftell: configuration for longer offsets +** ======================================================= +*/ + +#if !defined(lua_fseek) /* { */ + +#if defined(LUA_USE_POSIX) + +#define l_fseek(f,o,w) fseeko(f,o,w) +#define l_ftell(f) ftello(f) +#define l_seeknum off_t + +#elif defined(LUA_WIN) + +#define l_fseek(f,o,w) _fseeki64(f,o,w) +#define l_ftell(f) _ftelli64(f) +#define l_seeknum __int64 + +#else + +#define l_fseek(f,o,w) fseek(f,o,w) +#define l_ftell(f) ftell(f) +#define l_seeknum long + +#endif + +#endif /* } */ + +/* }====================================================== */ + #define IO_PREFIX "_IO_" #define IO_INPUT (IO_PREFIX "input") #define IO_OUTPUT (IO_PREFIX "output") -typedef struct LStream { - FILE *f; /* stream */ - lua_CFunction closef; /* to close stream (NULL for closed streams) */ -} LStream; - - -static void fileerror (lua_State *L, int arg, const char *filename) { - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); - luaL_argerror(L, arg, lua_tostring(L, -1)); -} +typedef luaL_Stream LStream; #define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) @@ -159,6 +198,14 @@ static LStream *newfile (lua_State *L) { } +static void opencheck (lua_State *L, const char *fname, const char *mode) { + LStream *p = newfile(L); + p->f = fopen(fname, mode); + if (p->f == NULL) + luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno)); +} + + static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); @@ -169,7 +216,7 @@ static int io_open (lua_State *L) { (mode[i] != '+' || ++i) && /* skip if char is '+' */ (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ (mode[i] == '\0'))) - return luaL_error(L, "invalid mode " LUA_QL("%s") + return luaL_error(L, "invalid mode " LUA_QS " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; @@ -215,12 +262,8 @@ static FILE *getiofile (lua_State *L, const char *findex) { static int g_iofile (lua_State *L, const char *f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); - if (filename) { - LStream *p = newfile(L); - p->f = fopen(filename, mode); - if (p->f == NULL) - fileerror(L, 1, filename); - } + if (filename) + opencheck(L, filename, mode); else { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); @@ -277,10 +320,7 @@ static int io_lines (lua_State *L) { } else { /* open a new file */ const char *filename = luaL_checkstring(L, 1); - LStream *p = newfile(L); - p->f = fopen(filename, "r"); - if (p->f == NULL) - fileerror(L, 1, filename); + opencheck(L, filename, "r"); lua_replace(L, 1); /* put file at index 1 */ toclose = 1; /* close it after iteration */ } @@ -444,9 +484,10 @@ static int io_readline (lua_State *L) { if (!lua_isnil(L, -n)) /* read at least one value? */ return n; /* return them */ else { /* first result is nil: EOF or error */ - if (!lua_isnil(L, -1)) /* is there error information? */ - return luaL_error(L, "%s", lua_tostring(L, -1)); /* error */ - /* else EOF */ + if (n > 1) { /* is there error information? */ + /* 2nd result is error message */ + return luaL_error(L, "%s", lua_tostring(L, -n + 1)); + } if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); @@ -496,12 +537,15 @@ static int f_seek (lua_State *L) { static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); - long offset = luaL_optlong(L, 3, 0); - op = fseek(f, offset, mode[op]); + lua_Number p3 = luaL_optnumber(L, 3, 0); + l_seeknum offset = (l_seeknum)p3; + luaL_argcheck(L, (lua_Number)offset == p3, 3, + "not an integer in proper range"); + op = l_fseek(f, offset, mode[op]); if (op) return luaL_fileresult(L, 0, NULL); /* error */ else { - lua_pushinteger(L, ftell(f)); + lua_pushnumber(L, (lua_Number)l_ftell(f)); return 1; } } diff --git a/src/llex.c b/src/llex.c index 289abfd84d..f73f74b277 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.53 2011/07/08 20:01:38 roberto Exp $ +** $Id: llex.c,v 2.58 2011/08/15 19:41:58 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -126,8 +126,10 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TValue *o; /* entry for `str' */ TString *ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_setstr(L, ls->fs->h, ts); - if (ttisnil(o)) { + o = luaH_set(L, ls->fs->h, L->top - 1); + if (ttisnil(o)) { /* not in use yet? (see 'addK') */ + /* boolean value does not need GC barrier; + table has no metatable, so it does not need to invalidate cache */ setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); } @@ -297,39 +299,29 @@ static void escerror (LexState *ls, int *c, int n, const char *msg) { static int readhexaesc (LexState *ls) { - int c[3]; /* keep input for error message */ - int i = 2; /* at least 'x?' will go to error message */ - c[0] = 'x'; - c[1] = next(ls); /* first hexa digit */ - if (lisxdigit(c[1])) { - c[i++] = next(ls); /* second hexa digit */ - if (lisxdigit(c[2])) - return (luaO_hexavalue(c[1]) << 4) + luaO_hexavalue(c[2]); - /* else go through to error */ + int c[3], i; /* keep input for error message */ + int r = 0; /* result accumulator */ + c[0] = 'x'; /* for error message */ + for (i = 1; i < 3; i++) { /* read two hexa digits */ + c[i] = next(ls); + if (!lisxdigit(c[i])) + escerror(ls, c, i + 1, "hexadecimal digit expected"); + r = (r << 4) + luaO_hexavalue(c[i]); } - escerror(ls, c, i, "hexadecimal digit expected"); - return 0; /* to avoid warnings */ + return r; } static int readdecesc (LexState *ls) { - int c[3], r; - int i = 2; /* at least two chars will be read */ - c[0] = ls->current; /* first char must be a digit */ - c[1] = next(ls); /* read second char */ - r = c[0] - '0'; /* partial result */ - if (lisdigit(c[1])) { - c[i++] = next(ls); /* read third char */ - r = 10*r + c[1] - '0'; /* update result */ - if (lisdigit(c[2])) { - r = 10*r + c[2] - '0'; /* update result */ - if (r > UCHAR_MAX) - escerror(ls, c, i, "decimal escape too large"); - return r; - } + int c[3], i; + int r = 0; /* result accumulator */ + for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ + c[i] = ls->current; + r = 10*r + c[i] - '0'; + next(ls); } - /* else, has read one character that was not a digit */ - zungetc(ls->z); /* return it to input stream */ + if (r > UCHAR_MAX) + escerror(ls, c, i, "decimal escape too large"); return r; } @@ -349,37 +341,38 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { int c; /* final character to be saved */ next(ls); /* do not save the `\' */ switch (ls->current) { - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case 'x': c = readhexaesc(ls); break; - case '\n': - case '\r': save(ls, '\n'); inclinenumber(ls); continue; - case '\\': case '\"': case '\'': c = ls->current; break; - case EOZ: continue; /* will raise an error next loop */ + case 'a': c = '\a'; goto read_save; + case 'b': c = '\b'; goto read_save; + case 'f': c = '\f'; goto read_save; + case 'n': c = '\n'; goto read_save; + case 'r': c = '\r'; goto read_save; + case 't': c = '\t'; goto read_save; + case 'v': c = '\v'; goto read_save; + case 'x': c = readhexaesc(ls); goto read_save; + case '\n': case '\r': + inclinenumber(ls); c = '\n'; goto only_save; + case '\\': case '\"': case '\'': + c = ls->current; goto read_save; + case EOZ: goto no_save; /* will raise an error next loop */ case 'z': { /* zap following span of spaces */ next(ls); /* skip the 'z' */ while (lisspace(ls->current)) { if (currIsNewline(ls)) inclinenumber(ls); else next(ls); } - continue; /* do not save 'c' */ + goto no_save; } default: { if (!lisdigit(ls->current)) escerror(ls, &ls->current, 1, "invalid escape sequence"); /* digital escape \ddd */ c = readdecesc(ls); - break; + goto only_save; } } - next(ls); - save(ls, c); - break; + read_save: next(ls); /* read next character */ + only_save: save(ls, c); /* save 'c' */ + no_save: break; } default: save_and_next(ls); diff --git a/src/llimits.h b/src/llimits.h index b64c7b7d65..17293ca054 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.90 2011/07/02 15:57:25 roberto Exp $ +** $Id: llimits.h,v 1.93 2011/10/07 20:45:19 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -30,7 +30,6 @@ typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) -#define MIN_LMEM ((l_mem)~((~(lu_mem)0)>>1)) #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ @@ -62,9 +61,9 @@ typedef LUAI_UACNUMBER l_uacNumber; /* to avoid problems with conditions too long */ #define lua_longassert(c) { if (!(c)) lua_assert(0); } #else -#define lua_assert(c) /* empty */ +#define lua_assert(c) ((void)0) #define check_exp(c,e) (e) -#define lua_longassert(c) /* empty */ +#define lua_longassert(c) ((void)0) #endif /* @@ -97,6 +96,19 @@ typedef LUAI_UACNUMBER l_uacNumber; #define cast_uchar(i) cast(unsigned char, (i)) +/* +** non-return type +*/ +#if defined(__GNUC__) +#define l_noret void __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define l_noret void __declspec(noreturn) +#else +#define l_noret void +#endif + + + /* ** maximum depth for nested C calls and syntactical nested non-terminals ** in a program. (Value must fit in an unsigned short int.) diff --git a/src/lmem.c b/src/lmem.c index c3775dfb31..3e8fa8ace5 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.81 2010/12/20 19:40:07 roberto Exp $ +** $Id: lmem.c,v 1.82 2011/09/20 19:25:23 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -106,7 +106,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { if ((total % 200) == 0) { if (f == NULL) f = fopen(TRACEMEM, "w"); fprintf(f, "%lu %u %d %d\n", total, - g->totalbytes, g->GCdebt, g->gcstate * 1000); + gettotalbytes(g), g->GCdebt, g->gcstate * 10000); } } #endif diff --git a/src/loadlib.c b/src/loadlib.c index 0313d8e44e..acf5af6b09 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.100 2011/07/05 12:49:35 roberto Exp $ +** $Id: loadlib.c,v 1.104 2011/11/10 11:42:58 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -9,6 +9,14 @@ */ +/* +** if needed, includes windows header before everything else +*/ +#if defined(LUA_DL_DLL) +#include +#endif + + #include #include @@ -62,6 +70,20 @@ #endif +/* +** LUA_CSUBSEP is the character that replaces dots in submodule names +** when searching for a C loader. +** LUA_LSUBSEP is the character that replaces dots in submodule names +** when searching for a Lua loader. +*/ +#if !defined(LUA_CSUBSEP) +#define LUA_CSUBSEP LUA_DIRSEP +#endif + +#if !defined(LUA_LSUBSEP) +#define LUA_LSUBSEP LUA_DIRSEP +#endif + /* prefix for open functions in C libraries */ #define LUA_POF "luaopen_" @@ -133,8 +155,6 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { ** ======================================================================= */ -#include - #undef setprogdir /* @@ -322,10 +342,12 @@ static const char *pushnexttemplate (lua_State *L, const char *path) { static const char *searchpath (lua_State *L, const char *name, const char *path, - const char *sep) { + const char *sep, + const char *dirsep) { + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); if (*sep != '\0') /* non-empty separator? */ - name = luaL_gsub(L, name, sep, LUA_DIRSEP); /* replace it by proper one */ - lua_pushliteral(L, ""); /* error accumulator */ + name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); @@ -334,8 +356,9 @@ static const char *searchpath (lua_State *L, const char *name, return filename; /* return that file name */ lua_pushfstring(L, "\n\tno file " LUA_QS, filename); lua_remove(L, -2); /* remove file name */ - lua_concat(L, 2); /* add entry to possible error message */ + luaL_addvalue(&msg); /* concatenate error msg. entry */ } + luaL_pushresult(&msg); /* create error message */ return NULL; /* not found */ } @@ -343,7 +366,8 @@ static const char *searchpath (lua_State *L, const char *name, static int ll_searchpath (lua_State *L) { const char *f = searchpath(L, luaL_checkstring(L, 1), luaL_checkstring(L, 2), - luaL_optstring(L, 3, ".")); + luaL_optstring(L, 3, "."), + luaL_optstring(L, 4, LUA_DIRSEP)); if (f != NULL) return 1; else { /* error message is on top of the stack */ lua_pushnil(L); @@ -354,13 +378,14 @@ static int ll_searchpath (lua_State *L) { static const char *findfile (lua_State *L, const char *name, - const char *pname) { + const char *pname, + const char *dirsep) { const char *path; lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); - return searchpath(L, name, path, "."); + return searchpath(L, name, path, ".", dirsep); } @@ -379,7 +404,7 @@ static int checkload (lua_State *L, int stat, const char *filename) { static int searcher_Lua (lua_State *L) { const char *filename; const char *name = luaL_checkstring(L, 1); - filename = findfile(L, name, "path"); + filename = findfile(L, name, "path", LUA_LSUBSEP); if (filename == NULL) return 1; /* module not found in this path */ return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); } @@ -405,7 +430,7 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) { static int searcher_C (lua_State *L) { const char *name = luaL_checkstring(L, 1); - const char *filename = findfile(L, name, "cpath"); + const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); if (filename == NULL) return 1; /* module not found in this path */ return checkload(L, (loadfunc(L, filename, name) == 0), filename); } @@ -418,7 +443,7 @@ static int searcher_Croot (lua_State *L) { int stat; if (p == NULL) return 0; /* is root */ lua_pushlstring(L, name, p - name); - filename = findfile(L, lua_tostring(L, -1), "cpath"); + filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); if (filename == NULL) return 1; /* root not found */ if ((stat = loadfunc(L, filename, name)) != 0) { if (stat != ERRFUNC) @@ -444,35 +469,46 @@ static int searcher_preload (lua_State *L) { } -static int ll_require (lua_State *L) { - const char *name = luaL_checkstring(L, 1); +static void findloader (lua_State *L, const char *name) { int i; - lua_settop(L, 1); /* _LOADED table will be at index 2 */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, 2, name); - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded */ - /* else must load it; iterate over available seachers to find a loader */ - lua_getfield(L, lua_upvalueindex(1), "searchers"); - if (!lua_istable(L, -1)) + luaL_Buffer msg; /* to build error message */ + luaL_buffinit(L, &msg); + lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */ + if (!lua_istable(L, 3)) luaL_error(L, LUA_QL("package.searchers") " must be a table"); - lua_pushliteral(L, ""); /* error message accumulator */ - for (i=1; ; i++) { - lua_rawgeti(L, -2, i); /* get a seacher */ - if (lua_isnil(L, -1)) /* no more searchers? */ + /* iterate over available seachers to find a loader */ + for (i = 1; ; i++) { + lua_rawgeti(L, 3, i); /* get a seacher */ + if (lua_isnil(L, -1)) { /* no more searchers? */ + lua_pop(L, 1); /* remove nil */ + luaL_pushresult(&msg); /* create error message */ luaL_error(L, "module " LUA_QS " not found:%s", - name, lua_tostring(L, -2)); + name, lua_tostring(L, -1)); + } lua_pushstring(L, name); lua_call(L, 1, 2); /* call it */ if (lua_isfunction(L, -2)) /* did it find a loader? */ - break; /* module loader found */ + return; /* module loader found */ else if (lua_isstring(L, -2)) { /* searcher returned error message? */ lua_pop(L, 1); /* remove extra return */ - lua_concat(L, 2); /* accumulate error message */ + luaL_addvalue(&msg); /* concatenate error message */ } else lua_pop(L, 2); /* remove both returns */ } +} + + +static int ll_require (lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_settop(L, 1); /* _LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, 2, name); /* _LOADED[name] */ + if (lua_toboolean(L, -1)) /* is it there? */ + return 1; /* package is already loaded */ + /* else must load package */ + lua_pop(L, 1); /* remove 'getfield' result */ + findloader(L, name); lua_pushstring(L, name); /* pass name as argument to module loader */ lua_insert(L, -2); /* name is 1st argument (before search data) */ lua_call(L, 2, 1); /* run loader to load module */ @@ -516,9 +552,11 @@ static void set_env (lua_State *L) { static void dooptions (lua_State *L, int n) { int i; for (i = 2; i <= n; i++) { - lua_pushvalue(L, i); /* get option (a function) */ - lua_pushvalue(L, -2); /* module */ - lua_call(L, 1, 0); + if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */ + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } } } diff --git a/src/lobject.c b/src/lobject.c index d8cc3ce90d..148d4bcea0 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.52 2011/06/24 12:25:02 roberto Exp $ +** $Id: lobject.c,v 2.53 2011/07/27 12:13:08 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -103,8 +103,8 @@ static int isneg (const char **s) { static lua_Number readhexa (const char **s, lua_Number r, int *count) { - while (lisxdigit(cast_uchar(**s))) { /* read integer part */ - r = (r * 16.0) + cast_num(luaO_hexavalue(cast_uchar(*(*s)++))); + for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ + r = (r * 16.0) + cast_num(luaO_hexavalue(cast_uchar(**s))); (*count)++; } return r; @@ -157,7 +157,9 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { int luaO_str2d (const char *s, size_t len, lua_Number *result) { char *endptr; - if (strpbrk(s, "xX")) /* hexa? */ + if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ + return 0; + else if (strpbrk(s, "xX")) /* hexa? */ *result = lua_strx2number(s, &endptr); else *result = lua_str2number(s, &endptr); diff --git a/src/lobject.h b/src/lobject.h index d69d615339..06246bfa5e 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.61 2011/07/04 20:29:02 roberto Exp $ +** $Id: lobject.h,v 2.64 2011/10/31 17:48:22 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -132,7 +132,7 @@ typedef struct lua_TValue TValue; #define ttislcf(o) checktag((o), LUA_TLCF) #define ttisuserdata(o) checktag((o), ctb(LUA_TUSERDATA)) #define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) -#define ttisdeadkey(o) checktag((o), ctb(LUA_TDEADKEY)) +#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) #define ttisequal(o1,o2) (rttype(o1) == rttype(o2)) @@ -151,6 +151,8 @@ typedef struct lua_TValue TValue; #define hvalue(o) check_exp(ttistable(o), &val_(o).gc->h) #define bvalue(o) check_exp(ttisboolean(o), val_(o).b) #define thvalue(o) check_exp(ttisthread(o), &val_(o).gc->th) +/* a dead value may get the 'gc' field, but cannot access its contents */ +#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) @@ -224,7 +226,7 @@ typedef struct lua_TValue TValue; val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \ checkliveness(G(L),io); } -#define setdeadvalue(obj) settt_(obj, ctb(LUA_TDEADKEY)) +#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) @@ -262,51 +264,73 @@ typedef struct lua_TValue TValue; ** ======================================================= */ -#if defined(LUA_NANTRICKLE) || defined(LUA_NANTRICKBE) +#if defined(LUA_NANTRICK) \ + || defined(LUA_NANTRICK_LE) \ + || defined(LUA_NANTRICK_BE) /* ** numbers are represented in the 'd_' field. All other values have the -** value (NNMARK | tag) in 'tt_'. A number with such pattern would be +** value (NNMARK | tag) in 'tt__'. A number with such pattern would be ** a "signaled NaN", which is never generated by regular operations by ** the CPU (nor by 'strtod') */ #if !defined(NNMARK) #define NNMARK 0x7FF7A500 +#define NNMASK 0x7FFFFF00 #endif #undef TValuefields #undef NILCONSTANT -#if defined(LUA_NANTRICKLE) + +#if defined(LUA_NANTRICK_LE) + /* little endian */ #define TValuefields \ - union { struct { Value v_; int tt_; } i; double d_; } u + union { struct { Value v__; int tt__; } i; double d__; } u #define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}} -#else +/* field-access macros */ +#define v_(o) ((o)->u.i.v__) +#define d_(o) ((o)->u.d__) +#define tt_(o) ((o)->u.i.tt__) + +#elif defined(LUA_NANTRICK_BE) + /* big endian */ #define TValuefields \ - union { struct { int tt_; Value v_; } i; double d_; } u + union { struct { int tt__; Value v__; } i; double d__; } u #define NILCONSTANT {{tag2tt(LUA_TNIL), {NULL}}} +/* field-access macros */ +#define v_(o) ((o)->u.i.v__) +#define d_(o) ((o)->u.d__) +#define tt_(o) ((o)->u.i.tt__) + +#elif !defined(TValuefields) +#error option 'LUA_NANTRICK' needs declaration for 'TValuefields' + #endif + +/* correspondence with standard representation */ +#undef val_ +#define val_(o) v_(o) +#undef num_ +#define num_(o) d_(o) + + #undef numfield #define numfield /* no such field; numbers are the entire struct */ /* basic check to distinguish numbers from non-numbers */ #undef ttisnumber -#define ttisnumber(o) (((o)->u.i.tt_ & 0x7fffff00) != NNMARK) +#define ttisnumber(o) ((tt_(o) & NNMASK) != NNMARK) #define tag2tt(t) (NNMARK | (t)) -#undef val_ -#define val_(o) ((o)->u.i.v_) -#undef num_ -#define num_(o) ((o)->u.d_) - #undef rttype -#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : (o)->u.i.tt_ & 0xff) +#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff) #undef settt_ -#define settt_(o,t) ((o)->u.i.tt_=tag2tt(t)) +#define settt_(o,t) (tt_(o) = tag2tt(t)) #undef setnvalue #define setnvalue(obj,x) \ @@ -324,11 +348,11 @@ typedef struct lua_TValue TValue; */ #undef checktag -#define checktag(o,t) ((o)->u.i.tt_ == tag2tt(t)) +#define checktag(o,t) (tt_(o) == tag2tt(t)) #undef ttisequal #define ttisequal(o1,o2) \ - (ttisnumber(o1) ? ttisnumber(o2) : ((o1)->u.i.tt_ == (o2)->u.i.tt_)) + (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) @@ -435,11 +459,11 @@ typedef struct Proto { TValue *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ - int *lineinfo; /* map from opcodes to source lines */ - LocVar *locvars; /* information about local variables */ + int *lineinfo; /* map from opcodes to source lines (debug information) */ + LocVar *locvars; /* information about local variables (debug information) */ Upvaldesc *upvalues; /* upvalue information */ union Closure *cache; /* last created closure with this prototype */ - TString *source; + TString *source; /* used for debug information */ int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of `k' */ int sizecode; diff --git a/src/lopcodes.h b/src/lopcodes.h index 01c69bdb27..07d2b3f39a 100644 --- a/src/lopcodes.h +++ b/src/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.141 2011/04/19 16:22:13 roberto Exp $ +** $Id: lopcodes.h,v 1.142 2011/07/15 12:50:29 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -196,7 +196,7 @@ OP_LEN,/* A B R(A) := length of R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ -OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */ +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ diff --git a/src/lparser.c b/src/lparser.c index d9c41739f3..a53a9312d5 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.113 2011/07/02 15:58:14 roberto Exp $ +** $Id: lparser.c,v 2.122 2011/10/31 17:46:04 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -41,8 +41,8 @@ */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ - int firstlabel; /* index of first label in this block */ - int firstgoto; /* index of first pending goto in this block */ + short firstlabel; /* index of first label in this block */ + short firstgoto; /* index of first pending goto in this block */ lu_byte nactvar; /* # active locals outside the block */ lu_byte upval; /* true if some variable in the block is an upvalue */ lu_byte isloop; /* true if `block' is a loop */ @@ -81,13 +81,14 @@ static void error_expected (LexState *ls, int token) { static void errorlimit (FuncState *fs, int limit, const char *what) { + lua_State *L = fs->ls->L; const char *msg; int line = fs->f->linedefined; const char *where = (line == 0) ? "main function" - : luaO_pushfstring(fs->L, "function at line %d", line); - msg = luaO_pushfstring(fs->L, "too many %s (limit is %d) in %s", - what, limit, where); + : luaO_pushfstring(L, "function at line %d", line); + msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", + what, limit, where); luaX_syntaxerror(fs->ls, msg); } @@ -182,7 +183,7 @@ static void new_localvar (LexState *ls, TString *name) { MAXVARS, "local variables"); luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, dyd->actvar.size, Vardesc, MAX_INT, "local variables"); - dyd->actvar.arr[dyd->actvar.n++].idx = cast(unsigned short, reg); + dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); } @@ -231,13 +232,13 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); - luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues, + luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, Upvaldesc, MAXUPVAL, "upvalues"); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; f->upvalues[fs->nups].instack = (v->k == VLOCAL); f->upvalues[fs->nups].idx = cast_byte(v->u.info); f->upvalues[fs->nups].name = name; - luaC_objbarrier(fs->L, f, name); + luaC_objbarrier(fs->ls->L, f, name); return fs->nups++; } @@ -327,13 +328,13 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { static void enterlevel (LexState *ls) { - global_State *g = G(ls->L); - ++g->nCcalls; - checklimit(ls->fs, g->nCcalls, LUAI_MAXCCALLS, "syntax levels"); + lua_State *L = ls->L; + ++L->nCcalls; + checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "syntax levels"); } -#define leavelevel(ls) (G((ls)->L)->nCcalls--) +#define leavelevel(ls) ((ls)->L->nCcalls--) static void closegoto (LexState *ls, int g, Labeldesc *label) { @@ -343,9 +344,10 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { Labeldesc *gt = &gl->arr[g]; lua_assert(eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { + TString *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = luaO_pushfstring(ls->L, " at line %d jumps into the scope of local " LUA_QS, - getstr(gt->name), gt->line, getstr(getlocvar(fs, gt->nactvar)->varname)); + getstr(gt->name), gt->line, getstr(vname)); semerror(ls, msg); } luaK_patchlist(fs, gt->pc, label->pc); @@ -382,7 +384,8 @@ static int findlabel (LexState *ls, int g) { static int newlabelentry (LexState *ls, Labellist *l, TString *name, int line, int pc) { int n = l->n; - luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, MAX_INT, "labels"); + luaM_growvector(ls->L, l->arr, n, l->size, + Labeldesc, SHRT_MAX, "labels/gotos"); l->arr[n].name = name; l->arr[n].line = line; l->arr[n].nactvar = ls->fs->nactvar; @@ -418,7 +421,7 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) { int i = bl->firstgoto; Labellist *gl = &fs->ls->dyd->gt; /* correct pending gotos to current block and try to close it - with visible labels */ + with visible labels */ while (i < gl->n) { Labeldesc *gt = &gl->arr[i]; if (gt->nactvar > bl->nactvar) { @@ -514,7 +517,6 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { Proto *f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; - fs->L = L; ls->fs = fs; fs->pc = 0; fs->lasttarget = 0; @@ -1039,7 +1041,7 @@ static const struct { ** subexpr -> (simpleexp | 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) { +static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { BinOpr op; UnOpr uop; enterlevel(ls); @@ -1105,31 +1107,34 @@ struct LHS_assign { /* -** check whether, in an assignment to a local variable, the local variable -** is needed in a previous assignment (to a table). If so, save original -** local value in a safe place and use this safe copy in the previous -** assignment. +** check whether, in an assignment to an upvalue/local variable, the +** upvalue/local variable is begin used in a previous assignment to a +** table. If so, save original upvalue/local value in a safe place and +** use this safe copy in the previous assignment. */ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; - for (; lh; lh = lh->prev) { - /* conflict in table 't'? */ - if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { - conflict = 1; - lh->v.u.ind.vt = VLOCAL; - lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ - } - /* conflict in index 'idx'? */ - if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { - conflict = 1; - lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + for (; lh; lh = lh->prev) { /* check all previous assignments */ + if (lh->v.k == VINDEXED) { /* assigning to a table? */ + /* table is the upvalue/local being assigned now? */ + if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { + conflict = 1; + lh->v.u.ind.vt = VLOCAL; + lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ + } + /* index is the local being assigned? (index cannot be upvalue) */ + if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { + conflict = 1; + lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ + } } } if (conflict) { + /* copy upvalue/local value to a temporary (in position 'extra') */ OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; - luaK_codeABC(fs, op, fs->freereg, v->u.info, 0); /* make copy */ + luaK_codeABC(fs, op, extra, v->u.info, 0); luaK_reserveregs(fs, 1); } } @@ -1144,7 +1149,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { primaryexp(ls, &nv.v); if (nv.v.k != VINDEXED) check_conflict(ls, lh, &nv.v); - checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls, + checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, "variable names"); assignment(ls, &nv, nvars+1); } @@ -1178,10 +1183,18 @@ static int cond (LexState *ls) { } -static void gotostat (LexState *ls, TString *label, int line) { - /* create new entry for this goto */ - int g = newlabelentry(ls, &ls->dyd->gt, label, line, luaK_jump(ls->fs)); - findlabel(ls, g); +static void gotostat (LexState *ls, int pc) { + int line = ls->linenumber; + TString *label; + int g; + if (testnext(ls, TK_GOTO)) + label = str_checkname(ls); + else { + luaX_next(ls); /* skip break */ + label = luaS_new(ls->L, "break"); + } + g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); + findlabel(ls, g); /* close it if label already defined */ } @@ -1190,7 +1203,7 @@ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { int i; for (i = fs->bl->firstlabel; i < ll->n; i++) { if (eqstr(label, ll->arr[i].name)) { - const char *msg = luaO_pushfstring(fs->ls->L, + const char *msg = luaO_pushfstring(fs->ls->L, "label " LUA_QS " already defined on line %d", getstr(label), ll->arr[i].line); semerror(fs->ls, msg); @@ -1360,38 +1373,51 @@ static void forstat (LexState *ls, int line) { } -static int test_then_block (LexState *ls) { +static void test_then_block (LexState *ls, int *escapelist) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ - int condexit; + BlockCnt bl; + FuncState *fs = ls->fs; + expdesc v; + int jf; /* instruction to skip 'then' code (if condition is false) */ luaX_next(ls); /* skip IF or ELSEIF */ - condexit = cond(ls); + expr(ls, &v); /* read condition */ checknext(ls, TK_THEN); - block(ls); /* `then' part */ - return condexit; + if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { + luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ + enterblock(fs, &bl, 0); /* must enter block before 'goto' */ + gotostat(ls, v.t); /* handle goto/break */ + if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ + leaveblock(fs); + return; /* and that is it */ + } + else /* must skip over 'then' part if condition is false */ + jf = luaK_jump(fs); + } + else { /* regular case (not goto/break) */ + luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ + enterblock(fs, &bl, 0); + jf = v.f; + } + statlist(ls); /* `then' part */ + leaveblock(fs); + if (ls->t.token == TK_ELSE || + ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ + luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ + luaK_patchtohere(fs, jf); } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; - int flist; - int escapelist = NO_JUMP; - flist = test_then_block(ls); /* IF cond THEN block */ - while (ls->t.token == TK_ELSEIF) { - luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, flist); - flist = test_then_block(ls); /* ELSEIF cond THEN block */ - } - if (ls->t.token == TK_ELSE) { - luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, flist); - luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ + int escapelist = NO_JUMP; /* exit list for finished parts */ + test_then_block(ls, &escapelist); /* IF cond THEN block */ + while (ls->t.token == TK_ELSEIF) + test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ + if (testnext(ls, TK_ELSE)) block(ls); /* `else' part */ - } - else - luaK_concat(fs, &escapelist, flist); - luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); + luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ } @@ -1551,15 +1577,9 @@ static void statement (LexState *ls) { retstat(ls); break; } - case TK_BREAK: { /* stat -> breakstat */ - luaX_next(ls); /* skip BREAK */ - /* code it as "goto 'break'" */ - gotostat(ls, luaS_new(ls->L, "break"), line); - break; - } + case TK_BREAK: /* stat -> breakstat */ case TK_GOTO: { /* stat -> 'goto' NAME */ - luaX_next(ls); /* skip GOTO */ - gotostat(ls, str_checkname(ls), line); + gotostat(ls, luaK_jump(ls->fs)); break; } default: { /* stat -> func | assignment */ @@ -1595,8 +1615,8 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, close_func(&lexstate); L->top--; /* pop name */ lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); - return funcstate.f; /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); + return funcstate.f; } diff --git a/src/lparser.h b/src/lparser.h index 4e7e06fc52..caabf46ccc 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.68 2011/02/23 13:13:10 roberto Exp $ +** $Id: lparser.h,v 1.69 2011/07/27 18:09:01 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -55,7 +55,7 @@ typedef struct expdesc { /* description of active local variable */ typedef struct Vardesc { - unsigned short idx; /* variable index in stack */ + short idx; /* variable index in stack */ } Vardesc; @@ -98,18 +98,17 @@ typedef struct FuncState { Table *h; /* table to find (and reuse) elements in `k' */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ - struct lua_State *L; /* copy of the Lua state */ struct BlockCnt *bl; /* chain of current blocks */ int pc; /* next position to code (equivalent to `ncode') */ - int lasttarget; /* `pc' of last `jump target' */ + int lasttarget; /* 'label' of last 'jump label' */ int jpc; /* list of pending jumps to `pc' */ - int freereg; /* first free register */ int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ - int firstlocal; /* index of first local var of this function */ - short nlocvars; /* number of elements in `locvars' */ + int firstlocal; /* index of first local var (in Dyndata array) */ + short nlocvars; /* number of elements in 'f->locvars' */ lu_byte nactvar; /* number of active local variables */ lu_byte nups; /* number of upvalues */ + lu_byte freereg; /* first free register */ } FuncState; diff --git a/src/lstate.c b/src/lstate.c index 45dac3c590..6e2801c490 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.89 2010/12/20 19:40:07 roberto Exp $ +** $Id: lstate.c,v 2.92 2011/10/03 17:54:25 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -136,10 +136,10 @@ static void init_registry (lua_State *L, global_State *g) { luaH_resize(L, registry, LUA_RIDX_LAST, 0); /* registry[LUA_RIDX_MAINTHREAD] = L */ setthvalue(L, &mt, L); - setobj2t(L, luaH_setint(L, registry, LUA_RIDX_MAINTHREAD), &mt); + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt); /* registry[LUA_RIDX_GLOBALS] = table of globals */ sethvalue(L, &mt, luaH_new(L)); - setobj2t(L, luaH_setint(L, registry, LUA_RIDX_GLOBALS), &mt); + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt); } @@ -171,6 +171,7 @@ static void preinit_state (lua_State *L, global_State *g) { L->ci = NULL; L->stacksize = 0; L->errorJmp = NULL; + L->nCcalls = 0; L->hook = NULL; L->hookmask = 0; L->basehookcount = 0; @@ -191,7 +192,7 @@ static void close_state (lua_State *L) { luaZ_freebuffer(L, &g->buff); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); - (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); + (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ } @@ -237,7 +238,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); L->marked = luaC_white(g); g->gckind = KGC_NORMAL; - g->nCcalls = 0; preinit_state(L, g); g->frealloc = f; g->ud = ud; @@ -279,9 +279,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); - luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_separateudata(L, 1); /* separate all udata with GC metamethods */ - lua_assert(L->next == NULL); luai_userstateclose(L); close_state(L); } diff --git a/src/lstate.h b/src/lstate.h index 9d21e7e8fe..4743d74103 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.72 2011/06/02 19:31:40 roberto Exp $ +** $Id: lstate.h,v 2.74 2011/09/30 12:45:07 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -47,8 +47,6 @@ struct lua_longjmp; /* defined in ldo.c */ #define EXTRA_STACK 5 -#define BASIC_CI_SIZE 8 - #define BASIC_STACK_SIZE (2*LUA_MINSTACK) @@ -118,7 +116,6 @@ typedef struct global_State { lu_mem lastmajormem; /* memory in use after last major collection */ stringtable strt; /* hash table for strings */ TValue l_registry; - unsigned short nCcalls; /* number of nested C calls */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ @@ -161,6 +158,7 @@ struct lua_State { StkId stack; /* stack base */ int stacksize; unsigned short nny; /* number of non-yieldable calls in stack */ + unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; int basehookcount; diff --git a/src/lstrlib.c b/src/lstrlib.c index 5e200f1cea..84193ebdfc 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.170 2011/06/28 17:13:52 roberto Exp $ +** $Id: lstrlib.c,v 1.172 2011/10/25 12:01:20 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -138,7 +138,7 @@ static int str_byte (lua_State *L) { if (pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); - if (posi + n <= pose) /* overflow? */ + if (posi + n <= pose) /* (size_t -> int) overflow? */ return luaL_error(L, "string slice too long"); luaL_checkstack(L, n, "string slice too long"); for (i=0; isizearray; @@ -314,7 +307,7 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { /* re-insert elements from vanishing slice */ for (i=nasize; iarray[i])) - setobjt2t(L, luaH_setint(L, t, i+1), &t->array[i]); + luaH_setint(L, t, i + 1, &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); @@ -322,8 +315,11 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; - if (!ttisnil(gval(old))) + if (!ttisnil(gval(old))) { + /* doesn't need barrier/invalidate cache, as entry was + already present in the table */ setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); + } } if (!isdummy(nold)) luaM_freearray(L, nold, twoto(oldhsize)); /* free old array */ @@ -398,14 +394,19 @@ static Node *getfreepos (Table *t) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -static TValue *newkey (lua_State *L, Table *t, const TValue *key) { - Node *mp = mainposition(t, key); +TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { + Node *mp; + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisnumber(key) && luai_numisnan(L, nvalue(key))) + luaG_runerror(L, "table index is NaN"); + mp = mainposition(t, key); if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ Node *othern; Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ - return luaH_set(L, t, key); /* re-insert key into grown table */ + /* whatever called 'newkey' take care of TM cache and GC barrier */ + return luaH_set(L, t, key); /* insert key into grown table */ } lua_assert(!isdummy(n)); othern = mainposition(t, gkey(mp)); @@ -493,41 +494,29 @@ const TValue *luaH_get (Table *t, const TValue *key) { } +/* +** beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { const TValue *p = luaH_get(t, key); - t->flags = 0; if (p != luaO_nilobject) return cast(TValue *, p); - else { - if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && luai_numisnan(L, nvalue(key))) - luaG_runerror(L, "table index is NaN"); - return newkey(L, t, key); - } + else return luaH_newkey(L, t, key); } -TValue *luaH_setint (lua_State *L, Table *t, int key) { +void luaH_setint (lua_State *L, Table *t, int key, TValue *value) { const TValue *p = luaH_getint(t, key); + TValue *cell; if (p != luaO_nilobject) - return cast(TValue *, p); + cell = cast(TValue *, p); else { TValue k; setnvalue(&k, cast_num(key)); - return newkey(L, t, &k); - } -} - - -TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { - const TValue *p = luaH_getstr(t, key); - if (p != luaO_nilobject) - return cast(TValue *, p); - else { - TValue k; - setsvalue(L, &k, key); - return newkey(L, t, &k); + cell = luaH_newkey(L, t, &k); } + setobj2t(L, cell, value); } diff --git a/src/ltable.h b/src/ltable.h index c14b028323..2f6f5c2dc8 100644 --- a/src/ltable.h +++ b/src/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.14 2010/06/25 12:18:10 roberto Exp $ +** $Id: ltable.h,v 2.16 2011/08/17 20:26:47 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -15,12 +15,14 @@ #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) +#define invalidateTMcache(t) ((t)->flags = 0) + LUAI_FUNC const TValue *luaH_getint (Table *t, int key); -LUAI_FUNC TValue *luaH_setint (lua_State *L, Table *t, int key); +LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); -LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); +LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); LUAI_FUNC Table *luaH_new (lua_State *L); LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); diff --git a/src/ltablib.c b/src/ltablib.c index 06353c7b4c..5c3abc3525 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.61 2011/07/05 12:49:35 roberto Exp $ +** $Id: ltablib.c,v 1.62 2011/09/30 12:45:45 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -86,7 +86,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, int i) { if (!lua_isstring(L, -1)) luaL_error(L, "invalid value (%s) at index %d in table for " LUA_QL("concat"), luaL_typename(L, -1), i); - luaL_addvalue(b); + luaL_addvalue(b); } diff --git a/src/lua.c b/src/lua.c index 8b317c6a0e..e1410000b0 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.200 2011/06/16 14:30:58 roberto Exp $ +** $Id: lua.c,v 1.202 2011/08/17 20:19:52 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -118,6 +118,7 @@ static void print_usage (const char *badoption) { " -i enter interactive mode after executing " LUA_QL("script") "\n" " -l name require library " LUA_QL("name") "\n" " -v show version information\n" + " -E ignore environment variables\n" " -- stop handling options\n" " - stop handling options and execute stdin\n" , @@ -348,7 +349,16 @@ static int handle_script (lua_State *L, char **argv, int n) { #define noextrachars(x) {if ((x)[2] != '\0') return -1;} -static int collectargs (char **argv, int *pi, int *pv, int *pe) { +/* indices of various argument indicators in array args */ +#define has_i 0 /* -i */ +#define has_v 1 /* -v */ +#define has_e 2 /* -e */ +#define has_E 3 /* -E */ + +#define num_has 4 /* number of 'has_*' */ + + +static int collectargs (char **argv, int *args) { int i; for (i = 1; argv[i] != NULL; i++) { if (argv[i][0] != '-') /* not an option? */ @@ -359,15 +369,18 @@ static int collectargs (char **argv, int *pi, int *pv, int *pe) { return (argv[i+1] != NULL ? i+1 : 0); case '\0': return i; + case 'E': + args[has_E] = 1; + break; case 'i': noextrachars(argv[i]); - *pi = 1; /* go through */ + args[has_i] = 1; /* go through */ case 'v': noextrachars(argv[i]); - *pv = 1; + args[has_v] = 1; break; case 'e': - *pe = 1; /* go through */ + args[has_e] = 1; /* go through */ case 'l': /* both options need an argument */ if (argv[i][2] == '\0') { /* no concatenated argument? */ i++; /* try next 'argv' */ @@ -426,32 +439,46 @@ static int handle_luainit (lua_State *L) { } +static void resetpaths (lua_State *L) { + lua_getglobal(L, "package"); + if (!lua_istable(L, -1)) /* no module 'package'? */ + return; /* nothing to be done */ + lua_pushliteral(L, LUA_PATH_DEFAULT); + lua_setfield(L, -2, "path"); /* package.path = default */ + lua_pushliteral(L, LUA_CPATH_DEFAULT); + lua_setfield(L, -2, "cpath"); /* package.cpath = default */ + lua_pop(L, 1); /* remove 'package' */ +} + + static int pmain (lua_State *L) { int argc = (int)lua_tointeger(L, 1); char **argv = (char **)lua_touserdata(L, 2); int script; - int has_i = 0, has_v = 0, has_e = 0; + int args[num_has]; + args[has_i] = args[has_v] = args[has_e] = args[has_E] = 0; if (argv[0] && argv[0][0]) progname = argv[0]; - script = collectargs(argv, &has_i, &has_v, &has_e); + script = collectargs(argv, args); if (script < 0) { /* invalid arg? */ print_usage(argv[-script]); return 0; } - if (has_v) print_version(); + if (args[has_v]) print_version(); /* open standard libraries */ luaL_checkversion(L); lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ luaL_openlibs(L); /* open libraries */ lua_gc(L, LUA_GCRESTART, 0); - /* run LUA_INIT */ - if (handle_luainit(L) != LUA_OK) return 0; + if (args[has_E]) /* avoid LUA_INIT? */ + resetpaths(L); + else if (handle_luainit(L) != LUA_OK) return 0; /* execute arguments -e and -l */ if (!runargs(L, argv, (script > 0) ? script : argc)) return 0; /* execute main script (if there is one) */ if (script && handle_script(L, argv, script) != LUA_OK) return 0; - if (has_i) /* -i option? */ + if (args[has_i]) /* -i option? */ dotty(L); - else if (script == 0 && !has_e && !has_v) { /* no arguments? */ + else if (script == 0 && !args[has_e] && !args[has_v]) { /* no arguments? */ if (lua_stdin_is_tty()) { print_version(); dotty(L); diff --git a/src/lua.h b/src/lua.h index 518d44c47b..2d94f0847f 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.278 2011/07/02 16:00:15 roberto Exp $ +** $Id: lua.h,v 1.281 2011/10/24 16:53:05 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -19,7 +19,7 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" #define LUA_VERSION_NUM 502 -#define LUA_VERSION_RELEASE "0" " (beta)" +#define LUA_VERSION_RELEASE "0" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE @@ -215,10 +215,12 @@ LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ +LUA_API void (lua_getglobal) (lua_State *L, const char *var); LUA_API void (lua_gettable) (lua_State *L, int idx); LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawget) (lua_State *L, int idx); LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); +LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); @@ -228,10 +230,12 @@ LUA_API void (lua_getuservalue) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ +LUA_API void (lua_setglobal) (lua_State *L, const char *var); LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API void (lua_setuservalue) (lua_State *L, int idx); @@ -261,7 +265,7 @@ LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, lua_CFunction k); #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) -LUA_API int (lua_resume) (lua_State *L, int narg); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); LUA_API int (lua_status) (lua_State *L); /* @@ -314,13 +318,6 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define lua_newtable(L) lua_createtable(L, 0, 0) -#define lua_setglobal(L,s) \ - (lua_pushglobaltable(L), lua_pushvalue(L, -2), \ - lua_setfield(L, -2, (s)), lua_pop(L, 2)) - -#define lua_getglobal(L,s) \ - (lua_pushglobaltable(L), lua_getfield(L, -1, (s)), lua_remove(L, -2)) - #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) diff --git a/src/luac.c b/src/luac.c index 62ff9cc5c3..fe91beeac3 100644 --- a/src/luac.c +++ b/src/luac.c @@ -1,5 +1,5 @@ /* -** $Id: luac.c,v 1.67 2011/06/21 12:29:00 lhf Exp $ +** $Id: luac.c,v 1.68 2011/11/23 17:48:18 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ @@ -53,7 +53,7 @@ static void usage(const char* message) fprintf(stderr, "usage: %s [options] [filenames]\n" "Available options are:\n" - " -l list\n" + " -l list (use -l -l for full listing)\n" " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" @@ -203,7 +203,7 @@ int main(int argc, char* argv[]) } /* -** $Id: print.c,v 1.67 2011/05/06 13:37:15 lhf Exp $ +** $Id: print.c,v 1.68 2011/09/30 10:21:20 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -218,7 +218,6 @@ int main(int argc, char* argv[]) #include "lobject.h" #include "lopcodes.h" -#define Sizeof(x) ((int)sizeof(x)) #define VOID(p) ((const void*)(p)) static void PrintString(const TString* ts) diff --git a/src/luaconf.h b/src/luaconf.h index 1135e50844..a5d624709c 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.161 2011/07/08 20:07:11 roberto Exp $ +** $Id: luaconf.h,v 1.166 2011/11/09 14:47:14 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -29,8 +29,8 @@ #endif -#if !defined(LUA_ANSI) && defined(_WIN32) -#define LUA_WIN +#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_WIN /* enable goodies for regular Windows platforms */ #endif #if defined(LUA_WIN) @@ -210,10 +210,14 @@ /* @@ luai_writestring/luai_writeline define how 'print' prints its results. +** They are only used in libraries and the stand-alone program. (The #if +** avoids including 'stdio.h' everywhere.) */ +#if defined(LUA_LIB) || defined(lua_c) || defined(luaall_c) #include #define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) #define luai_writeline() (luai_writestring("\n", 1), fflush(stdout)) +#endif /* @@ luai_writestringerror defines how to print error messages. @@ -459,7 +463,7 @@ /* On a Microsoft compiler on a Pentium, use assembler to avoid clashes with a DirectX idiosyncrasy */ -#if defined(_MSC_VER) && defined(M_IX86) /* { */ +#if defined(LUA_WIN) && defined(_M_IX86) /* { */ #define MS_ASMTRICK @@ -492,12 +496,13 @@ /* -@@ LUA_NANTRICKLE/LUA_NANTRICKBE controls the use of a trick to pack all -** types into a single double value, using NaN values to represent -** non-number values. The trick only works on 32-bit machines (ints and -** pointers are 32-bit values) with numbers represented as IEEE 754-2008 -** doubles with conventional endianess (12345678 or 87654321), in CPUs -** that do not produce signaling NaN values (all NaNs are quiet). +@@ LUA_NANTRICK_LE/LUA_NANTRICK_BE controls the use of a trick to +** pack all types into a single double value, using NaN values to +** represent non-number values. The trick only works on 32-bit machines +** (ints and pointers are 32-bit values) with numbers represented as +** IEEE 754-2008 doubles with conventional endianess (12345678 or +** 87654321), in CPUs that do not produce signaling NaN values (all NaNs +** are quiet). */ #if defined(LUA_CORE) && \ defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ @@ -506,7 +511,7 @@ #if defined(__i386__) || defined(__i386) || defined(__X86__) || \ defined(_M_IX86) -#define LUA_NANTRICKLE +#define LUA_NANTRICK_LE #endif diff --git a/src/lvm.c b/src/lvm.c index e4f90af40a..de3407768c 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.141 2011/06/09 18:24:22 roberto Exp $ +** $Id: lvm.c,v 2.144 2011/10/07 20:45:19 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -127,29 +127,38 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; - TValue temp; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); - TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ - if (!ttisnil(oldval) || /* result is not nil? */ - (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ - setobj2t(L, oldval, val); + TValue *oldval = cast(TValue *, luaH_get(h, key)); + /* if previous value is not nil, there must be a previous entry + in the table; moreover, a metamethod has no relevance */ + if (!ttisnil(oldval) || + /* previous value is nil; must check the metamethod */ + ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && + /* no metamethod; is there a previous entry in the table? */ + (oldval != luaO_nilobject || + /* no previous entry; must create one. (The next test is + always true; we only need the assignment.) */ + (oldval = luaH_newkey(L, h, key), 1)))) { + /* no metamethod and (now) there is an entry with given key */ + setobj2t(L, oldval, val); /* assign new value to that entry */ + invalidateTMcache(h); luaC_barrierback(L, obj2gco(h), val); return; } - /* else will try the tag method */ + /* else will try the metamethod */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) - luaG_typeerror(L, t, "index"); + else /* not a table; check metamethod */ + if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + luaG_typeerror(L, t, "index"); + /* there is a metamethod */ if (ttisfunction(tm)) { callTM(L, tm, t, key, val, 0); return; } - /* else repeat with 'tm' */ - setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ - t = &temp; + t = tm; /* else repeat with 'tm' */ } luaG_runerror(L, "loop in settable"); } @@ -217,9 +226,9 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { return luai_numlt(L, nvalue(l), nvalue(r)); else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; - else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) - return res; - return luaG_ordererror(L, l, r); + else if ((res = call_orderTM(L, l, r, TM_LT)) < 0) + luaG_ordererror(L, l, r); + return res; } @@ -229,11 +238,11 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { return luai_numle(L, nvalue(l), nvalue(r)); else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; - else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ + else if ((res = call_orderTM(L, l, r, TM_LE)) >= 0) /* first try `le' */ return res; - else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ - return !res; - return luaG_ordererror(L, l, r); + else if ((res = call_orderTM(L, r, l, TM_LT)) < 0) /* else try `lt' */ + luaG_ordererror(L, l, r); + return !res; } @@ -808,7 +817,7 @@ void luaV_execute (lua_State *L) { luaH_resizearray(L, h, last); /* pre-allocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; - setobj2t(L, luaH_setint(L, h, last--), val); + luaH_setint(L, h, last--, val); luaC_barrierback(L, obj2gco(h), val); } L->top = ci->top; /* correct top (in case of previous open call) */ diff --git a/src/lzio.c b/src/lzio.c index 7d2677bd6a..354f94e7c5 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,5 +1,5 @@ /* -** $Id: lzio.c,v 1.33 2011/02/23 13:13:10 roberto Exp $ +** $Id: lzio.c,v 1.34 2011/07/15 12:35:32 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ @@ -29,7 +29,7 @@ int luaZ_fill (ZIO *z) { return EOZ; z->n = size - 1; /* discount char being returned */ z->p = buff; - return char2int(*(z->p++)); + return cast_uchar(*(z->p++)); } diff --git a/src/lzio.h b/src/lzio.h index 4174986d4b..08682301e8 100644 --- a/src/lzio.h +++ b/src/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.24 2011/02/23 13:13:10 roberto Exp $ +** $Id: lzio.h,v 1.26 2011/07/15 12:48:03 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -17,11 +17,7 @@ typedef struct Zio ZIO; -#define char2int(c) cast(int, cast(unsigned char, (c))) - -#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) - -#define zungetc(z) ((z)->n++, (z)->p--) +#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) typedef struct Mbuffer { From dfa489618335f21b74e1b2040a64b28dcbe048a6 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 25 Nov 2011 12:00:00 +0000 Subject: [PATCH 65/97] Lua 5.2.0-rc2 --- doc/manual.html | 8 ++++---- src/liolib.c | 6 ++++-- src/loadlib.c | 4 ++-- src/luaconf.h | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 9e16e6b0e8..8b3a85e5ac 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -33,7 +33,7 @@

                        - + @@ -8020,8 +8020,8 @@

                        6.4 – String Manipulation

                        If, after the translation of negative indices, -i is less than zero, -it is corrected to zero. +i is less than 1, +it is corrected to 1. If j is greater than the string length, it is corrected to that length. If, after these corrections, @@ -10352,7 +10352,7 @@

                        9 – The Complete Syntax of Lua


                        Last update: -Thu Nov 24 11:54:31 BRST 2011 +Fri Nov 25 11:37:49 BRST 2011

                        - + @@ -3659,15 +3659,19 @@

                        4.8 – Functions and Types

                        int lua_load (lua_State *L,
                                       lua_Reader reader,
                                       void *data,
                        -              const char *source);
                        + const char *source, + const char *mode);

                        -Loads a Lua chunk. +Loads a Lua chunk (without running it). If there are no errors, -lua_load pushes the compiled chunk as a Lua +lua_load pushes the compiled chunk as a Lua function on top of the stack. Otherwise, it pushes an error message. -The return values of lua_load are: + + +

                        +The return values of lua_load are:

                        -This function only loads a chunk; -it does not run it. - - -

                        -lua_load automatically detects whether the chunk is text or binary -and loads it accordingly (see program luac). - - -

                        -The lua_load function uses a user-supplied reader function +The lua_load function uses a user-supplied reader function to read the chunk (see lua_Reader). The data argument is an opaque value passed to the reader function. @@ -3708,6 +3702,14 @@

                        4.8 – Functions and Types

                        which is used for error messages and in debug information (see §4.9). +

                        +id{lua_load} automatically detects whether the chunk is text or binary +and loads it accordingly (see program luac). +The string mode works as in function load, +with the addition that +a NULL value is equivalent to the string "bt". + +

                        If the resulting function has one upvalue, this upvalue is set to the value of the global environment @@ -6118,6 +6120,21 @@

                        5.1 – Functions and Types

                        size_t sz, const char *name); +

                        +Equivalent to luaL_loadbufferx with mode equal to NULL. + + + + + +


                        luaL_loadbufferx

                        +[-0, +1, –] +

                        int luaL_loadbufferx (lua_State *L,
                        +                      const char *buff,
                        +                      size_t sz,
                        +                      const char *name,
                        +                      const char *mode);
                        +

                        Loads a buffer as a Lua chunk. This function uses lua_load to load the chunk in the @@ -6128,6 +6145,7 @@

                        5.1 – Functions and Types

                        This function returns the same results as lua_load. name is the chunk name, used for debug information and error messages. +The string mode works as in function lua_load. @@ -6135,12 +6153,15 @@

                        5.1 – Functions and Types


                        luaL_loadfile

                        [-0, +1, m] -

                        int luaL_loadfile (lua_State *L, const char *filename);

                        +

                        int luaL_loadfile (lua_State *L, const char *filename);
                        + +

                        Equivalent to luaL_loadfilex with mode equal to NULL. +


                        luaL_loadfilex

                        [-0, +1, m]

                        int luaL_loadfilex (lua_State *L, const char *filename,
                        @@ -6156,9 +6177,7 @@ 

                        5.1 – Functions and Types

                        -The string mode works as in function load, -with the addition that -a NULL value is equivalent to the string "bt". +The string mode works as in function lua_load.

                        @@ -8292,7 +8311,6 @@

                        6.5 – Table Manipulation

                        Returns a new table with all parameters stored into keys 1, 2, etc. and with a field "n" with the total number of parameters. -Also returns, as a second result, the total number of parameters. Note that the resulting table may not be a sequence. @@ -9376,6 +9394,11 @@

                        6.9 – Operating System Facilities

                        (that is, os.date() is equivalent to os.date("%c")). +

                        +On some systems, +this function may be not thread safe. + +

                        @@ -10184,8 +10207,8 @@

                        8.2 – Changes in the Libraries

                        (Actually, those functions were already insecure because of flaws in the verification algorithm.) When in doubt, -use the mode argument in function load -to restrict it to loading textual chunks. +use the mode argument of those functions +to restrict them to loading textual chunks.
                      • @@ -10260,6 +10283,11 @@

                        8.3 – Changes in the API

                        Function lua_objlen was renamed lua_rawlen.
                      • +
                      • +Function lua_load has an extra parameter, mode. +Pass NULL to simulate the old behavior. +
                      • +
                      @@ -10352,7 +10380,7 @@

                      9 – The Complete Syntax of Lua


                      Last update: -Fri Nov 25 11:37:49 BRST 2011 +Tue Nov 29 15:37:33 BRST 2011

                      - + @@ -2026,7 +2026,7 @@

                      3.4.5 – Concatenation

                      denoted by two dots ('..'). If both operands are strings or numbers, then they are converted to strings according to the rules mentioned in §3.4.2. -Otherwise, the "concat" metamethod is called (see §2.4). +Otherwise, the __concat metamethod is called (see §2.4). @@ -3703,7 +3703,7 @@

                      4.8 – Functions and Types

                      -id{lua_load} automatically detects whether the chunk is text or binary +lua_load automatically detects whether the chunk is text or binary and loads it accordingly (see program luac). The string mode works as in function load, with the addition that @@ -6957,7 +6957,7 @@

                      6.1 – Basic Functions

                      -If there are no errors, +If there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. @@ -7847,9 +7847,11 @@

                      6.4 – String Manipulation

                      G, and g all expect a number as argument. Options c, d, i, o, u, X, and x -expect an integer as argument; -the range of that integer may be limited by +also expect a number, +but the range of that number may be limited by the underlying C implementation. +For options o, u, X, and x, +the number cannot be negative. Option q expects a string; option s expects a string without embedded zeros. If the argument to option s is not a string, @@ -9247,7 +9249,7 @@

                      6.8 – Input and Output Facilities

                      -


                      file:seek ([whence] [, offset])

                      +

                      file:seek ([whence [, offset]])

                      @@ -10380,7 +10382,7 @@

                      9 – The Complete Syntax of Lua


                      Last update: -Tue Nov 29 15:37:33 BRST 2011 +Wed Nov 30 18:23:56 BRST 2011

                      - + @@ -2706,6 +2706,14 @@

                      4.6 – Error Handling in C

                      (e.g., doing a long jump to your own recovery point outside Lua). +

                      +The panic function runs as if it were a message handler (see §2.3); +in particular, the error message is at the top of the stack. +However, there is no guarantees about stack space. +To push anything on the stack, +the panic function should first check the available space (see §4.2). + +

                      Most functions in the API can throw an error, for instance due to a memory allocation error. @@ -2952,13 +2960,6 @@

                      4.8 – Functions and Types

                      Sets a new panic function and returns the old one (see §4.6). -

                      -The panic function should not try to run anything on the failed Lua state. -However, it can still use the debug API (see §4.9) -to gather information about the state. -In particular, the error message is at the top of the stack. - - @@ -10382,7 +10383,7 @@

                      9 – The Complete Syntax of Lua


                      Last update: -Mon Dec 5 11:07:57 BRST 2011 +Wed Dec 7 16:31:58 BRST 2011

                      - + @@ -10341,7 +10341,7 @@

                      9 – The Complete Syntax of Lua

                      explist ::= exp {‘,’ exp} - exp ::= nil | false | true | Number | String | ‘...’ | function | + exp ::= nil | false | true | Number | String | ‘...’ | functiondef | prefixexp | tableconstructor | exp binop exp | unop exp prefixexp ::= var | functioncall | ‘(’ exp ‘)’ @@ -10383,7 +10383,7 @@

                      9 – The Complete Syntax of Lua


                      Last update: -Wed Dec 7 16:31:58 BRST 2011 +Thu Dec 8 10:36:53 BRST 2011

                      - + @@ -2745,7 +2745,7 @@

                      4.7 – Handling Yields in C

                      except for three functions: lua_yieldk, lua_callk, and lua_pcallk. All those functions receive a continuation function -(as a parameter called k) to continue execution after an yield. +(as a parameter called k) to continue execution after a yield.

                      @@ -3371,7 +3371,7 @@

                      4.8 – Functions and Types

                      In that case, a call to lua_getctx will return the error code (the value that would be returned by lua_pcallk); the value of ctx will be set to the context information, -as in the case of an yield. +as in the case of a yield. @@ -6741,7 +6741,8 @@

                      6 – Standard Libraries

                      the C host program should call the luaL_openlibs function, which opens all standard libraries. Alternatively, -it can open them individually by calling +the host program can open them individually by using +luaL_requiref to call luaopen_base (for the basic library), luaopen_package (for the package library), luaopen_coroutine (for the coroutine library), @@ -6752,10 +6753,7 @@

                      6 – Standard Libraries

                      luaopen_io (for the I/O library), luaopen_os (for the Operating System library), and luaopen_debug (for the debug library). -These functions are declared in lualib.h -and should not be called directly: -you must call them like any other Lua C function, -e.g., by using lua_call. +These functions are declared in lualib.h. @@ -9986,10 +9984,11 @@

                      7 – Lua Standalone

                      When called with option -E, besides ignoring LUA_INIT, -the interpreter also resets the values of +Lua also ignores +the values of LUA_PATH and LUA_CPATH, +setting the values of package.path and package.cpath -with the default paths defined in luaconf.h, -in effect ignoring the values of LUA_PATH and LUA_CPATH. +with the default paths defined in luaconf.h.

                      @@ -10291,6 +10290,11 @@

                      8.3 – Changes in the API

                      Pass NULL to simulate the old behavior.
                    • +
                    • +Function lua_resume has an extra parameter, from. +Pass NULL or the thread doing the call. +
                    • +
                    @@ -10383,7 +10387,7 @@

                    9 – The Complete Syntax of Lua


                    Last update: -Thu Dec 8 10:36:53 BRST 2011 +Mon Dec 12 15:21:08 BRST 2011 diff --git a/doc/lua.css b/doc/lua.css index 54708f823d..7fafbb1bb6 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -3,8 +3,8 @@ body { background-color: #FFFFFF ; font-family: Helvetica, Arial, sans-serif ; text-align: justify ; - margin-right: 20px ; - margin-left: 20px ; + margin-right: 30px ; + margin-left: 30px ; } h1, h2, h3, h4 { @@ -16,9 +16,9 @@ h1, h2, h3, h4 { h2 { padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 20px ; - padding-right: 20px ; - margin-left: -20px ; + padding-left: 30px ; + padding-right: 30px ; + margin-left: -30px ; background-color: #E0E0FF ; } diff --git a/doc/manual.css b/doc/manual.css index ac357a896c..b49b362937 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -18,7 +18,7 @@ span.apii { p+h1, ul+h1 { padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 20px ; - margin-left: -20px ; + padding-left: 30px ; + margin-left: -30px ; background-color: #E0E0FF ; } diff --git a/doc/manual.html b/doc/manual.html index 360d3168b5..cd6dda5222 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@

                    by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

                    -Copyright © 2011 Lua.org, PUC-Rio. +Copyright © 2011–2012 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -33,7 +33,7 @@

                    - + @@ -913,6 +913,14 @@

                    2.5.1 – Garbage-Collection Metamethods

                    its finalizer will never be called twice. +

                    +When you close a state (see lua_close), +Lua calls the finalizers of all objects marked for collection, +following the reverse order that they were marked. +If any finalizer marks new objects for collection during that phase, +these new objects will not be finalized. + + @@ -1206,7 +1214,7 @@

                    3.1 – Lexical Conventions

                    The escape sequence '\z' skips the following span of white-space characters, including line breaks; -it is particularly useful to break and indent a long string +it is particularly useful to break and indent a long literal string into multiple lines without adding the newlines and spaces into the string contents. @@ -1234,7 +1242,7 @@

                    3.1 – Lexical Conventions

                    and so on. A closing long bracket is defined similarly; for instance, a closing long bracket of level 4 is written as ]====]. -A long string starts with an opening long bracket of any level and +A long literal starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. It can contain any text except a closing bracket of the proper level. Literals in this bracketed form can run for several lines, @@ -2922,7 +2930,7 @@

                    4.8 – Functions and Types


                    lua_arith

                    [-(2|1), +1, e] -

                    int lua_arith (lua_State *L, int op);
                    +
                    void lua_arith (lua_State *L, int op);

                    Performs an arithmetic operation over the two values @@ -4400,7 +4408,7 @@

                    4.8 – Functions and Types


                    lua_resume

                    [-?, +?, –] -

                    int lua_resume (lua_State *L, lua_State *from, int narg);
                    +
                    int lua_resume (lua_State *L, lua_State *from, int nargs);

                    Starts and resumes a coroutine in a given thread. @@ -4410,7 +4418,7 @@

                    4.8 – Functions and Types

                    To start a coroutine, you push onto the thread stack the main function plus any arguments; then you call lua_resume, -with narg being the number of arguments. +with nargs being the number of arguments. This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. @@ -4550,14 +4558,15 @@

                    4.8 – Functions and Types

                    typedef struct lua_State lua_State;

                    -An opaque structure that keeps the whole state of a Lua interpreter. +An opaque structure that points to a thread and indirectly +(through the thread) to the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. -All information about a state is kept in this structure. +All information about a state is accessible through this structure.

                    -A pointer to this state must be passed as the first argument to +A pointer to this structure must be passed as the first argument to every function in the library, except to lua_newstate, which creates a Lua state from scratch. @@ -5149,7 +5158,7 @@

                    4.9 – The Debug Interface

                    int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

                    -Returns information about a specific function or function invocation. +Gets information about a specific function or function invocation.

                    @@ -5268,7 +5277,7 @@

                    4.9 – The Debug Interface

                    int lua_getstack (lua_State *L, int level, lua_Debug *ar);

                    -Get information about the interpreter runtime stack. +Gets information about the interpreter runtime stack.

                    @@ -5345,6 +5354,11 @@

                    4.9 – The Debug Interface

                    this execution occurs without any calls to hooks. +

                    +Hook functions cannot yield +(that is, call lua_yieldk or lua_yield). + + @@ -5450,7 +5464,7 @@

                    4.9 – The Debug Interface

                    Returns an unique identifier for the upvalue numbered n -from the closure at index fidx. +from the closure at index funcindex. Parameters funcindex and n are as in the lua_getupvalue (see lua_getupvalue) (but n cannot be greater than the number of upvalues). @@ -5467,13 +5481,14 @@

                    4.9 – The Debug Interface

                    -

                    lua_upvaluejoin

                    -
                    void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
                    -                                    int fidx2, int n2);
                    +

                    lua_upvaluejoin

                    +[-0, +0, –] +

                    void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
                    +                                    int funcindex2, int n2);

                    -Make the n1-th upvalue of the Lua closure at index fidx1 -refer to the n2-th upvalue of the Lua closure at index fidx2. +Make the n1-th upvalue of the Lua closure at index funcindex1 +refer to the n2-th upvalue of the Lua closure at index funcindex2. @@ -5614,7 +5629,7 @@

                    5.1 – Functions and Types

                    [-0, +0, v]
                    void luaL_argcheck (lua_State *L,
                                         int cond,
                    -                    int narg,
                    +                    int arg,
                                         const char *extramsg);

                    @@ -5627,7 +5642,7 @@

                    5.1 – Functions and Types


                    luaL_argerror

                    [-0, +0, v] -

                    int luaL_argerror (lua_State *L, int narg, const char *extramsg);
                    +
                    int luaL_argerror (lua_State *L, int arg, const char *extramsg);

                    Raises an error with a standard message @@ -5686,7 +5701,7 @@

                    5.1 – Functions and Types

                  • Then copy the string into that space.
                  • -Finish by calling luaL_pushresult(&b, sz), +Finish by calling luaL_pushresultsize(&b, sz), where sz is the total size of the resulting string copied into that space.
                  • @@ -5762,11 +5777,11 @@

                    5.1 – Functions and Types


                    luaL_checkany

                    [-0, +0, v] -

                    void luaL_checkany (lua_State *L, int narg);
                    +
                    void luaL_checkany (lua_State *L, int arg);

                    Checks whether the function has an argument -of any type (including nil) at position narg. +of any type (including nil) at position arg. @@ -5774,10 +5789,10 @@

                    5.1 – Functions and Types


                    luaL_checkint

                    [-0, +0, v] -

                    int luaL_checkint (lua_State *L, int narg);
                    +
                    int luaL_checkint (lua_State *L, int arg);

                    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to an int. @@ -5786,10 +5801,10 @@

                    5.1 – Functions and Types


                    luaL_checkinteger

                    [-0, +0, v] -

                    lua_Integer luaL_checkinteger (lua_State *L, int narg);
                    +
                    lua_Integer luaL_checkinteger (lua_State *L, int arg);

                    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to a lua_Integer. @@ -5798,10 +5813,10 @@

                    5.1 – Functions and Types


                    luaL_checklong

                    [-0, +0, v] -

                    long luaL_checklong (lua_State *L, int narg);
                    +
                    long luaL_checklong (lua_State *L, int arg);

                    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to a long. @@ -5810,10 +5825,10 @@

                    5.1 – Functions and Types


                    luaL_checklstring

                    [-0, +0, v] -

                    const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
                    +
                    const char *luaL_checklstring (lua_State *L, int arg, size_t *l);

                    -Checks whether the function argument narg is a string +Checks whether the function argument arg is a string and returns this string; if l is not NULL fills *l with the string's length. @@ -5829,10 +5844,10 @@

                    5.1 – Functions and Types


                    luaL_checknumber

                    [-0, +0, v] -

                    lua_Number luaL_checknumber (lua_State *L, int narg);
                    +
                    lua_Number luaL_checknumber (lua_State *L, int arg);

                    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number. @@ -5842,12 +5857,12 @@

                    5.1 – Functions and Types


                    luaL_checkoption

                    [-0, +0, v]

                    int luaL_checkoption (lua_State *L,
                    -                      int narg,
                    +                      int arg,
                                           const char *def,
                                           const char *const lst[]);

                    -Checks whether the function argument narg is a string and +Checks whether the function argument arg is a string and searches for this string in the array lst (which must be NULL-terminated). Returns the index in the array where the string was found. @@ -5858,7 +5873,7 @@

                    5.1 – Functions and Types

                    If def is not NULL, the function uses def as a default value when -there is no argument narg or when this argument is nil. +there is no argument arg or when this argument is nil.

                    @@ -5886,10 +5901,10 @@

                    5.1 – Functions and Types


                    luaL_checkstring

                    [-0, +0, v] -

                    const char *luaL_checkstring (lua_State *L, int narg);
                    +
                    const char *luaL_checkstring (lua_State *L, int arg);

                    -Checks whether the function argument narg is a string +Checks whether the function argument arg is a string and returns this string. @@ -5903,10 +5918,10 @@

                    5.1 – Functions and Types


                    luaL_checktype

                    [-0, +0, v] -

                    void luaL_checktype (lua_State *L, int narg, int t);
                    +
                    void luaL_checktype (lua_State *L, int arg, int t);

                    -Checks whether the function argument narg has type t. +Checks whether the function argument arg has type t. See lua_type for the encoding of types for t. @@ -5915,10 +5930,10 @@

                    5.1 – Functions and Types


                    luaL_checkudata

                    [-0, +0, v] -

                    void *luaL_checkudata (lua_State *L, int narg, const char *tname);
                    +
                    void *luaL_checkudata (lua_State *L, int arg, const char *tname);

                    -Checks whether the function argument narg is a userdata +Checks whether the function argument arg is a userdata of the type tname (see luaL_newmetatable) and returns the userdata address (see lua_touserdata). @@ -5928,10 +5943,10 @@

                    5.1 – Functions and Types


                    luaL_checkunsigned

                    [-0, +0, v] -

                    lua_Unsigned luaL_checkunsigned (lua_State *L, int narg);
                    +
                    lua_Unsigned luaL_checkunsigned (lua_State *L, int arg);

                    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to a lua_Unsigned. @@ -6100,7 +6115,7 @@

                    5.1 – Functions and Types


                    luaL_len

                    -[-0, +1, e] +[-0, +0, e]

                    int luaL_len (lua_State *L, int index);

                    @@ -6108,7 +6123,7 @@

                    5.1 – Functions and Types

                    as a number; it is equivalent to the '#' operator in Lua (see §3.4.6). Raises an error if the result of the operation is not a number. -(This only can happen through metamethods.) +(This case only can happen through metamethods.) @@ -6309,10 +6324,10 @@

                    5.1 – Functions and Types


                    luaL_optint

                    [-0, +0, v] -

                    int luaL_optint (lua_State *L, int narg, int d);
                    +
                    int luaL_optint (lua_State *L, int arg, int d);

                    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to an int. If this argument is absent or is nil, returns d. @@ -6325,11 +6340,11 @@

                    5.1 – Functions and Types


                    luaL_optinteger

                    [-0, +0, v]

                    lua_Integer luaL_optinteger (lua_State *L,
                    -                             int narg,
                    +                             int arg,
                                                  lua_Integer d);

                    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to a lua_Integer. If this argument is absent or is nil, returns d. @@ -6341,10 +6356,10 @@

                    5.1 – Functions and Types


                    luaL_optlong

                    [-0, +0, v] -

                    long luaL_optlong (lua_State *L, int narg, long d);
                    +
                    long luaL_optlong (lua_State *L, int arg, long d);

                    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to a long. If this argument is absent or is nil, returns d. @@ -6357,12 +6372,12 @@

                    5.1 – Functions and Types


                    luaL_optlstring

                    [-0, +0, v]

                    const char *luaL_optlstring (lua_State *L,
                    -                             int narg,
                    +                             int arg,
                                                  const char *d,
                                                  size_t *l);

                    -If the function argument narg is a string, +If the function argument arg is a string, returns this string. If this argument is absent or is nil, returns d. @@ -6379,10 +6394,10 @@

                    5.1 – Functions and Types


                    luaL_optnumber

                    [-0, +0, v] -

                    lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
                    +
                    lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);

                    -If the function argument narg is a number, +If the function argument arg is a number, returns this number. If this argument is absent or is nil, returns d. @@ -6395,11 +6410,11 @@

                    5.1 – Functions and Types


                    luaL_optstring

                    [-0, +0, v]

                    const char *luaL_optstring (lua_State *L,
                    -                            int narg,
                    +                            int arg,
                                                 const char *d);

                    -If the function argument narg is a string, +If the function argument arg is a string, returns this string. If this argument is absent or is nil, returns d. @@ -6412,11 +6427,11 @@

                    5.1 – Functions and Types


                    luaL_optunsigned

                    [-0, +0, v]

                    lua_Unsigned luaL_optunsigned (lua_State *L,
                    -                               int narg,
                    +                               int arg,
                                                    lua_Unsigned u);

                    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to a lua_Unsigned. If this argument is absent or is nil, returns u. @@ -6583,7 +6598,7 @@

                    5.1 – Functions and Types


                    luaL_testudata

                    [-0, +0, m] -

                    void *luaL_testudata (lua_State *L, int narg, const char *tname);
                    +
                    void *luaL_testudata (lua_State *L, int arg, const char *tname);

                    This function works like luaL_checkudata, @@ -6749,7 +6764,7 @@

                    6 – Standard Libraries

                    luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), -luaopen_bitlib (for the bit library), +luaopen_bit32 (for the bit library), luaopen_io (for the I/O library), luaopen_os (for the Operating System library), and luaopen_debug (for the debug library). @@ -7914,24 +7929,26 @@

                    6.4 – String Manipulation

                    The character % works as an escape character: any sequence in repl of the form %d, with d between 1 and 9, -stands for the value of the d-th captured substring (see below). +stands for the value of the d-th captured substring. The sequence %0 stands for the whole match. The sequence %% stands for a single %.

                    If repl is a table, then the table is queried for every match, -using the first capture as the key; -if the pattern specifies no captures, -then the whole match is used as the key. +using the first capture as the key.

                    If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, -in order; +in order. + + +

                    +In any case, if the pattern specifies no captures, -then the whole match is passed as a sole argument. +then it behaves as if the whole pattern was inside a capture.

                    @@ -10091,6 +10108,9 @@

                    8 – Incompatibilities with the Previous Version

                    appropriate options (see file luaconf.h). However, all these compatibility options will be removed in the next version of Lua. +Similarly, +all features marked as deprecated in Lua 5.1 +have been removed in Lua 5.2. @@ -10387,10 +10407,10 @@

                    9 – The Complete Syntax of Lua


                    Last update: -Mon Dec 12 15:21:08 BRST 2011 +Wed May 23 13:28:41 BRT 2012 diff --git a/doc/readme.html b/doc/readme.html index f0c77a1604..7bd1829d2b 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -101,14 +101,6 @@

                    Installing Lua

                    Lua for Windows, an easy-to-use distribution of Lua that includes many useful libraries. - -

                    Building Lua

                    @@ -118,7 +110,7 @@

                    Building Lua

                    1. Open a terminal window and move to -the top-level directory, which is named lua-5.2.0. +the top-level directory, which is named lua-5.2.1. The Makefile there controls both the build process and the installation process.

                    2. @@ -381,7 +373,7 @@

                      License

                      this.
                      -Copyright © 1994–2011 Lua.org, PUC-Rio. +Copyright © 1994–2012 Lua.org, PUC-Rio.

                      Permission is hereby granted, free of charge, to any person obtaining a copy @@ -409,10 +401,10 @@

                      License


                      Last update: -Wed Nov 23 16:17:22 BRST 2011 +Thu May 17 11:09:49 BRT 2012 diff --git a/src/lapi.c b/src/lapi.c index e96ceb9e14..736d964834 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.159 2011/11/30 12:32:05 roberto Exp $ +** $Id: lapi.c,v 2.163 2012/05/23 15:42:27 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -1045,17 +1045,17 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { } case LUA_GCSTEP: { if (g->gckind == KGC_GEN) { /* generational mode? */ - res = (g->lastmajormem == 0); /* 1 if will do major collection */ + res = (g->GCestimate == 0); /* true if it will do major collection */ luaC_forcestep(L); /* do a single step */ } else { - while (data-- >= 0) { - luaC_forcestep(L); - if (g->gcstate == GCSpause) { /* end of cycle? */ - res = 1; /* signal it */ - break; - } - } + lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE; + if (g->gcrunning) + debt += g->GCdebt; /* include current debt */ + luaE_setdebt(g, debt); + luaC_forcestep(L); + if (g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ } break; } diff --git a/src/lauxlib.c b/src/lauxlib.c index 5f4916eaef..24d4abb2b4 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.242 2012/03/19 22:57:14 roberto Exp $ +** $Id: lauxlib.c,v 1.243 2012/04/20 17:05:17 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -892,10 +892,8 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ lua_pop(L, 1); /* remove _LOADED table */ if (glb) { - lua_pushglobaltable(L); - lua_pushvalue(L, -2); /* copy of 'mod' */ - lua_setfield(L, -2, modname); /* _G[modname] = module */ - lua_pop(L, 1); /* remove _G table */ + lua_pushvalue(L, -1); /* copy of 'mod' */ + lua_setglobal(L, modname); /* _G[modname] = module */ } } diff --git a/src/lbaselib.c b/src/lbaselib.c index 1dfae30146..dbfcb02cfc 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.273 2011/11/30 13:03:24 roberto Exp $ +** $Id: lbaselib.c,v 1.274 2012/04/27 14:13:19 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -293,6 +293,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ *size = 0; return NULL; } diff --git a/src/lcorolib.c b/src/lcorolib.c index 0edde26daf..c7932d90f2 100644 --- a/src/lcorolib.c +++ b/src/lcorolib.c @@ -1,5 +1,5 @@ /* -** $Id: lcorolib.c,v 1.3 2011/08/23 17:24:34 roberto Exp $ +** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ @@ -80,8 +80,9 @@ static int luaB_auxwrap (lua_State *L) { static int luaB_cocreate (lua_State *L) { - lua_State *NL = lua_newthread(L); + lua_State *NL; luaL_checktype(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L); lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; diff --git a/src/ldo.c b/src/ldo.c index 26f9a6747e..0a5ed6be44 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.102 2011/11/29 15:55:08 roberto Exp $ +** $Id: ldo.c,v 2.104 2012/05/08 13:53:33 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -402,8 +402,6 @@ static void finishCcall (lua_State *L) { int n; lua_assert(ci->u.c.k != NULL); /* must have a continuation */ lua_assert(L->nny == 0); - /* finish 'luaD_call' */ - L->nCcalls--; /* finish 'lua_callk' */ adjustresults(L, ci->nresults); /* call continuation function */ @@ -484,9 +482,10 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { ** do the work for 'lua_resume' in protected mode */ static void resume (lua_State *L, void *ud) { + int nCcalls = L->nCcalls; StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; - if (L->nCcalls >= LUAI_MAXCCALLS) + if (nCcalls >= LUAI_MAXCCALLS) resume_error(L, "C stack overflow", firstArg); if (L->status == LUA_OK) { /* may be starting a coroutine */ if (ci != &L->base_ci) /* not in base level? */ @@ -513,11 +512,11 @@ static void resume (lua_State *L, void *ud) { api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } - L->nCcalls--; /* finish 'luaD_call' */ luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ } unroll(L, NULL); } + lua_assert(nCcalls == L->nCcalls); } @@ -627,24 +626,23 @@ static void checkmode (lua_State *L, const char *mode, const char *x) { static void f_parser (lua_State *L, void *ud) { int i; - Proto *tf; Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { checkmode(L, p->mode, "binary"); - tf = luaU_undump(L, p->z, &p->buff, p->name); + cl = luaU_undump(L, p->z, &p->buff, p->name); } else { checkmode(L, p->mode, "text"); - tf = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + } + lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); + for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ + UpVal *up = luaF_newupval(L); + cl->l.upvals[i] = up; + luaC_objbarrier(L, cl, up); } - setptvalue2s(L, L->top, tf); - incr_top(L); - cl = luaF_newLclosure(L, tf); - setclLvalue(L, L->top - 1, cl); - for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ - cl->l.upvals[i] = luaF_newupval(L); } diff --git a/src/ldump.c b/src/ldump.c index ae1c780fd1..d5e6a47cb3 100644 --- a/src/ldump.c +++ b/src/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 1.20 2012/03/21 18:11:35 lhf Exp $ +** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ diff --git a/src/lfunc.c b/src/lfunc.c index 9492283a1e..4fd27fe5eb 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.28 2012/01/20 22:05:50 roberto Exp $ +** $Id: lfunc.c,v 2.29 2012/05/08 13:53:33 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -27,10 +27,9 @@ Closure *luaF_newCclosure (lua_State *L, int n) { } -Closure *luaF_newLclosure (lua_State *L, Proto *p) { - int n = p->sizeupvalues; +Closure *luaF_newLclosure (lua_State *L, int n) { Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; - c->l.p = p; + c->l.p = NULL; c->l.nupvalues = cast_byte(n); while (n--) c->l.upvals[n] = NULL; return c; diff --git a/src/lfunc.h b/src/lfunc.h index fe8efde031..e236a717c6 100644 --- a/src/lfunc.h +++ b/src/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.7 2012/01/20 22:05:50 roberto Exp $ +** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -20,7 +20,7 @@ LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, Proto *p); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); diff --git a/src/lgc.c b/src/lgc.c index ce42163705..e15da8b241 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.119 2012/01/25 21:05:40 roberto Exp $ +** $Id: lgc.c,v 2.128 2012/05/23 15:43:14 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -24,34 +24,35 @@ -/* how much to allocate before next GC step */ -#define GCSTEPSIZE 1024 +/* cost of sweeping one element (half the size of a small object) */ +#define GCSWEEPCOST ((sizeof(TString) + 4) / 2) /* maximum number of elements to sweep in each single step */ -#define GCSWEEPMAX 40 - -/* cost of sweeping one element */ -#define GCSWEEPCOST 1 +#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) /* maximum number of finalizers to call in each GC step */ #define GCFINALIZENUM 4 -/* cost of marking the root set */ -#define GCROOTCOST 10 +/* (arbitrary) cost of atomic step */ +#define GCATOMICCOST GCSTEPSIZE -/* cost of atomic step */ -#define GCATOMICCOST 1000 -/* basic cost to traverse one object (to be added to the links the - object may have) */ -#define TRAVCOST 5 +/* +** macro to apply the "speed" of the garbage collector: the constant +** 80 makes the standard 'stepmul' of 200 results in the GC handling +** 80/200 = 1/2.5 = 0.4Kbytes for every 1Kb allocated. +** (The computation tries to avoid overflows or underflows.) +*/ +#define workrate(x,mul) \ + ((x) < MAX_INT/80 ? ((x) * 80) / mul : ((x) / mul) * 80) /* ** standard negative debt for GC; a reasonable "time" to wait before ** starting a new cycle */ -#define stddebt(g) (-cast(l_mem, gettotalbytes(g)/100) * g->gcpause) +#define stddebtest(g,e) (-cast(l_mem, (e)/100) * g->gcpause) +#define stddebt(g) stddebtest(g, gettotalbytes(g)) /* @@ -65,12 +66,6 @@ #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) -/* -** dirty trick: we know that 'reallymarkobject' does not use 'g' when -** object is a string -*/ -#define stringmark(s) markobject(NULL, s) - #define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT) @@ -127,10 +122,10 @@ static void removeentry (Node *n) { ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ -static int iscleared (const TValue *o) { +static int iscleared (global_State *g, const TValue *o) { if (!iscollectable(o)) return 0; else if (ttisstring(o)) { - stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */ return 0; } else return iswhite(gcvalue(o)); @@ -250,53 +245,57 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, ** upvalues are already linked in 'headuv' list.) */ static void reallymarkobject (global_State *g, GCObject *o) { + lu_mem size; white2gray(o); switch (gch(o)->tt) { case LUA_TSHRSTR: case LUA_TLNGSTR: { - gray2black(o); - return; /* nothing else to mark */ + size = sizestring(gco2ts(o)); + break; /* nothing else to mark; make it black */ } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; markobject(g, mt); markobject(g, gco2u(o)->env); - gray2black(o); /* all pointers marked */ - return; + size = sizeudata(gco2u(o)); + break; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); - if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */ - gray2black(o); /* make it black */ - return; + if (uv->v != &uv->u.value) /* open? */ + return; /* open upvalues remain gray */ + size = sizeof(UpVal); + break; } case LUA_TLCL: { gco2lcl(o)->gclist = g->gray; g->gray = o; - break; + return; } case LUA_TCCL: { gco2ccl(o)->gclist = g->gray; g->gray = o; - break; + return; } case LUA_TTABLE: { linktable(gco2t(o), &g->gray); - break; + return; } case LUA_TTHREAD: { gco2th(o)->gclist = g->gray; g->gray = o; - break; + return; } case LUA_TPROTO: { gco2p(o)->gclist = g->gray; g->gray = o; - break; + return; } - default: lua_assert(0); + default: lua_assert(0); return; } + gray2black(o); + g->GCmemtrav += size; } @@ -369,7 +368,7 @@ static void traverseweakvalue (global_State *g, Table *h) { else { lua_assert(!ttisnil(gkey(n))); markvalue(g, gkey(n)); /* mark key */ - if (!hasclears && iscleared(gval(n))) /* is there a white value? */ + if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ hasclears = 1; /* table will have to be cleared */ } } @@ -398,7 +397,7 @@ static int traverseephemeron (global_State *g, Table *h) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ - else if (iscleared(gkey(n))) { /* key is not marked (yet)? */ + else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ hasclears = 1; /* table must be cleared */ if (valiswhite(gval(n))) /* value not marked yet? */ prop = 1; /* must propagate again */ @@ -436,30 +435,26 @@ static void traversestrongtable (global_State *g, Table *h) { } -static int traversetable (global_State *g, Table *h) { +static lu_mem traversetable (global_State *g, Table *h) { + const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); markobject(g, h->metatable); - if (mode && ttisstring(mode)) { /* is there a weak mode? */ - int weakkey = (strchr(svalue(mode), 'k') != NULL); - int weakvalue = (strchr(svalue(mode), 'v') != NULL); - if (weakkey || weakvalue) { /* is really weak? */ - black2gray(obj2gco(h)); /* keep table gray */ - if (!weakkey) { /* strong keys? */ - traverseweakvalue(g, h); - return TRAVCOST + sizenode(h); - } - else if (!weakvalue) { /* strong values? */ - traverseephemeron(g, h); - return TRAVCOST + h->sizearray + sizenode(h); - } - else { - linktable(h, &g->allweak); /* nothing to traverse now */ - return TRAVCOST; - } - } /* else go through */ + if (mode && ttisstring(mode) && /* is there a weak mode? */ + ((weakkey = strchr(svalue(mode), 'k')), + (weakvalue = strchr(svalue(mode), 'v')), + (weakkey || weakvalue))) { /* is really weak? */ + black2gray(obj2gco(h)); /* keep table gray */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h); + else /* all weak */ + linktable(h, &g->allweak); /* nothing to traverse now */ } - traversestrongtable(g, h); - return TRAVCOST + h->sizearray + (2 * sizenode(h)); + else /* not weak */ + traversestrongtable(g, h); + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * sizenode(h); } @@ -467,91 +462,101 @@ static int traverseproto (global_State *g, Proto *f) { int i; if (f->cache && iswhite(obj2gco(f->cache))) f->cache = NULL; /* allow cache to be collected */ - stringmark(f->source); + markobject(g, f->source); for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ - stringmark(f->upvalues[i].name); + markobject(g, f->upvalues[i].name); for (i = 0; i < f->sizep; i++) /* mark nested protos */ markobject(g, f->p[i]); for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ - stringmark(f->locvars[i].varname); - return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; + markobject(g, f->locvars[i].varname); + return sizeof(Proto) + sizeof(Instruction) * f->sizecode + + sizeof(Proto *) * f->sizep + + sizeof(TValue) * f->sizek + + sizeof(int) * f->sizelineinfo + + sizeof(LocVar) * f->sizelocvars + + sizeof(Upvaldesc) * f->sizeupvalues; } -static int traverseCclosure (global_State *g, CClosure *cl) { +static lu_mem traverseCclosure (global_State *g, CClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ markvalue(g, &cl->upvalue[i]); - return TRAVCOST + cl->nupvalues; + return sizeCclosure(cl->nupvalues); } -static int traverseLclosure (global_State *g, LClosure *cl) { +static lu_mem traverseLclosure (global_State *g, LClosure *cl) { int i; - lua_assert(cl->nupvalues == cl->p->sizeupvalues); markobject(g, cl->p); /* mark its prototype */ for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ markobject(g, cl->upvals[i]); - return TRAVCOST + cl->nupvalues; + return sizeLclosure(cl->nupvalues); } -static int traversestack (global_State *g, lua_State *L) { - StkId o = L->stack; +static lu_mem traversestack (global_State *g, lua_State *th) { + StkId o = th->stack; if (o == NULL) return 1; /* stack not completely built yet */ - for (; o < L->top; o++) + for (; o < th->top; o++) markvalue(g, o); if (g->gcstate == GCSatomic) { /* final traversal? */ - StkId lim = L->stack + L->stacksize; /* real end of stack */ + StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); } - return TRAVCOST + cast_int(o - L->stack); + return sizeof(lua_State) + sizeof(TValue) * th->stacksize; } /* ** traverse one gray object, turning it to black (except for threads, ** which are always gray). -** Returns number of values traversed. */ -static int propagatemark (global_State *g) { +static void propagatemark (global_State *g) { + lu_mem size; GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); switch (gch(o)->tt) { case LUA_TTABLE: { Table *h = gco2t(o); - g->gray = h->gclist; - return traversetable(g, h); + g->gray = h->gclist; /* remove from 'gray' list */ + size = traversetable(g, h); + break; } case LUA_TLCL: { LClosure *cl = gco2lcl(o); - g->gray = cl->gclist; - return traverseLclosure(g, cl); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseLclosure(g, cl); + break; } case LUA_TCCL: { CClosure *cl = gco2ccl(o); - g->gray = cl->gclist; - return traverseCclosure(g, cl); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseCclosure(g, cl); + break; } case LUA_TTHREAD: { lua_State *th = gco2th(o); - g->gray = th->gclist; + g->gray = th->gclist; /* remove from 'gray' list */ th->gclist = g->grayagain; - g->grayagain = o; + g->grayagain = o; /* insert into 'grayagain' list */ black2gray(o); - return traversestack(g, th); + size = traversestack(g, th); + break; } case LUA_TPROTO: { Proto *p = gco2p(o); - g->gray = p->gclist; - return traverseproto(g, p); + g->gray = p->gclist; /* remove from 'gray' list */ + size = traverseproto(g, p); + break; } - default: lua_assert(0); return 0; + default: lua_assert(0); return; } + g->GCmemtrav += size; } @@ -614,12 +619,12 @@ static void convergeephemerons (global_State *g) { ** clear entries with unmarked keys from all weaktables in list 'l' up ** to element 'f' */ -static void clearkeys (GCObject *l, GCObject *f) { +static void clearkeys (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) { + if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } @@ -632,18 +637,18 @@ static void clearkeys (GCObject *l, GCObject *f) { ** clear entries with unmarked values from all weaktables in list 'l' up ** to element 'f' */ -static void clearvalues (GCObject *l, GCObject *f) { +static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); int i; for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; - if (iscleared(o)) /* value was collected? */ + if (iscleared(g, o)) /* value was collected? */ setnilvalue(o); /* remove value */ } for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && iscleared(gval(n))) { + if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } @@ -713,7 +718,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { int ow = otherwhite(g); int toclear, toset; /* bits to clear and to set in all live objects */ int tostop; /* stop sweep when this is true */ - l_mem debt = g->GCdebt; /* current debt */ if (isgenerational(g)) { /* generational mode? */ toclear = ~0; /* clear nothing */ toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ @@ -732,20 +736,16 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { freeobj(L, curr); /* erase 'curr' */ } else { + if (testbits(marked, tostop)) + return NULL; /* stop sweeping this list */ if (gch(curr)->tt == LUA_TTHREAD) sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ - if (testbits(marked, tostop)) { - static GCObject *nullp = NULL; - p = &nullp; /* stop sweeping this list */ - break; - } /* update marks */ gch(curr)->marked = cast_byte((marked & toclear) | toset); p = &gch(curr)->next; /* go to next element */ } } - luaE_setdebt(g, debt); /* sweeping should not change debt */ - return p; + return (*p == NULL) ? NULL : p; } /* }====================================================== */ @@ -858,11 +858,18 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; - for (p = &g->allgc; *p != o; p = &gch(*p)->next) ; - *p = gch(o)->next; /* remove 'o' from root list */ - gch(o)->next = g->finobj; /* link it in list 'finobj' */ + GCheader *ho = gch(o); + /* avoid removing current sweep object */ + if (g->sweepgc == &ho->next) { + /* step to next object in the list */ + g->sweepgc = (ho->next == NULL) ? NULL : &gch(ho->next)->next; + } + /* search for pointer pointing to 'o' */ + for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } + *p = ho->next; /* remove 'o' from root list */ + ho->next = g->finobj; /* link it in list 'finobj' */ g->finobj = o; - l_setbit(gch(o)->marked, SEPARATED); /* mark it as such */ + l_setbit(ho->marked, SEPARATED); /* mark it as such */ resetoldbit(o); /* see MOVE OLD rule */ } } @@ -880,6 +887,24 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { #define sweepphases \ (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) + +/* +** enter first sweep phase (strings) and prepare pointers for other +** sweep phases. The calls to 'sweeplist' attempt to make pointers +** point to an object inside the list (instead of to the header), so +** that the real sweep do not need to skip objects created between "now" +** and the start of the real sweep. +*/ +static void entersweep (lua_State *L) { + global_State *g = G(L); + g->gcstate = GCSsweepstring; + lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); + g->sweepstrgc = 0; /* prepare to sweep strings, ... */ + g->sweepfin = sweeplist(L, &g->finobj, 1); /* finalizable objects, ... */ + g->sweepgc = sweeplist(L, &g->allgc, 1); /* and regular objects */ +} + + /* ** change GC mode */ @@ -889,15 +914,14 @@ void luaC_changemode (lua_State *L, int mode) { if (mode == KGC_GEN) { /* change to generational mode */ /* make sure gray lists are consistent */ luaC_runtilstate(L, bitmask(GCSpropagate)); - g->lastmajormem = gettotalbytes(g); + g->GCestimate = gettotalbytes(g); g->gckind = KGC_GEN; } else { /* change to incremental mode */ /* sweep all objects to turn them back to white (as white has not changed, nothing extra will be collected) */ - g->sweepstrgc = 0; - g->gcstate = GCSsweepstring; g->gckind = KGC_NORMAL; + entersweep(L); luaC_runtilstate(L, ~sweepphases); } } @@ -946,8 +970,8 @@ static void atomic (lua_State *L) { convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ /* clear values from weak tables, before checking finalizers */ - clearvalues(g->weak, NULL); - clearvalues(g->allweak, NULL); + clearvalues(g, g->weak, NULL); + clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; separatetobefnz(L, 0); /* separate objects to be finalized */ markbeingfnz(g); /* mark userdata that will be finalized */ @@ -955,63 +979,64 @@ static void atomic (lua_State *L) { convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ - clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */ - clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */ + clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ + clearkeys(g, g->allweak, NULL); /* clear keys from all allweak tables */ /* clear values from resurrected weak tables */ - clearvalues(g->weak, origweak); - clearvalues(g->allweak, origall); - g->sweepstrgc = 0; /* prepare to sweep strings */ - g->gcstate = GCSsweepstring; + clearvalues(g, g->weak, origweak); + clearvalues(g, g->allweak, origall); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + entersweep(L); /* prepare to sweep strings */ /*lua_checkmemory(L);*/ } -static l_mem singlestep (lua_State *L) { +static lu_mem singlestep (lua_State *L) { global_State *g = G(L); switch (g->gcstate) { case GCSpause: { + g->GCmemtrav = 0; /* start to count memory traversed */ if (!isgenerational(g)) markroot(g); /* start a new collection */ - /* in any case, root must be marked */ + /* in any case, root must be marked at this point */ lua_assert(!iswhite(obj2gco(g->mainthread)) && !iswhite(gcvalue(&g->l_registry))); g->gcstate = GCSpropagate; - return GCROOTCOST; + return g->GCmemtrav; } case GCSpropagate: { - if (g->gray) - return propagatemark(g); + if (g->gray) { + lu_mem oldtrav = g->GCmemtrav; + propagatemark(g); + return g->GCmemtrav - oldtrav; /* memory traversed in this step */ + } else { /* no more `gray' objects */ g->gcstate = GCSatomic; /* finish mark phase */ + g->GCestimate = g->GCmemtrav; /* save what was counted */ atomic(L); return GCATOMICCOST; } } case GCSsweepstring: { - if (g->sweepstrgc < g->strt.size) { - sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); - return GCSWEEPCOST; - } - else { /* no more strings to sweep */ - g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */ + int i; + for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++) + sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]); + g->sweepstrgc += i; + if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */ g->gcstate = GCSsweepudata; - return 0; - } + return i * GCSWEEPCOST; } case GCSsweepudata: { - if (*g->sweepgc) { - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + if (g->sweepfin) { + g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX); return GCSWEEPMAX*GCSWEEPCOST; } else { - g->sweepgc = &g->allgc; /* go to next phase */ g->gcstate = GCSsweep; - return GCSWEEPCOST; + return 0; } } case GCSsweep: { - if (*g->sweepgc) { + if (g->sweepgc) { g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); return GCSWEEPMAX*GCSWEEPCOST; } @@ -1042,15 +1067,16 @@ void luaC_runtilstate (lua_State *L, int statesmask) { static void generationalcollection (lua_State *L) { global_State *g = G(L); - if (g->lastmajormem == 0) { /* signal for another major collection? */ + if (g->GCestimate == 0) { /* signal for another major collection? */ luaC_fullgc(L, 0); /* perform a full regular collection */ - g->lastmajormem = gettotalbytes(g); /* update control */ + g->GCestimate = gettotalbytes(g); /* update control */ } else { + lu_mem estimate = g->GCestimate; luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ luaC_runtilstate(L, bitmask(GCSpause)); - if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc) - g->lastmajormem = 0; /* signal for a major collection */ + if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) + g->GCestimate = 0; /* signal for a major collection */ } luaE_setdebt(g, stddebt(g)); } @@ -1058,27 +1084,31 @@ static void generationalcollection (lua_State *L) { static void step (lua_State *L) { global_State *g = G(L); - l_mem lim = g->gcstepmul; /* how much to work */ + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (stepmul <= 0) stepmul = 1; do { /* always perform at least one single step */ - lim -= singlestep(L); - } while (lim > 0 && g->gcstate != GCSpause); - if (g->gcstate != GCSpause) - luaE_setdebt(g, g->GCdebt - GCSTEPSIZE); - else - luaE_setdebt(g, stddebt(g)); + lu_mem work = singlestep(L); /* do some work */ + work = workrate(work, stepmul); /* apply work rate */ + debt -= work; + } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + debt = stddebtest(g, g->GCestimate); /* pause until next cycle */ + luaE_setdebt(g, debt); } /* -** performs a basic GC step even if the collector is stopped +** performs a basic GC step */ void luaC_forcestep (lua_State *L) { global_State *g = G(L); int i; if (isgenerational(g)) generationalcollection(L); else step(L); - for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++) - GCTM(L, 1); /* Call a few pending finalizers */ + /* run a few finalizers (or all of them at the end of a collect cycle) */ + for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) + GCTM(L, 1); /* call one finalizer */ } @@ -1086,10 +1116,13 @@ void luaC_forcestep (lua_State *L) { ** performs a basic GC step only if collector is running */ void luaC_step (lua_State *L) { - if (G(L)->gcrunning) luaC_forcestep(L); + global_State *g = G(L); + if (g->gcrunning) luaC_forcestep(L); + else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */ } + /* ** performs a full GC cycle; if "isemergency", does not call ** finalizers (which could change stack positions) @@ -1097,16 +1130,19 @@ void luaC_step (lua_State *L) { void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); int origkind = g->gckind; + int someblack = keepinvariant(g); lua_assert(origkind != KGC_EMERGENCY); - if (!isemergency) /* do not run finalizers during emergency GC */ + if (isemergency) /* do not run finalizers during emergency GC */ + g->gckind = KGC_EMERGENCY; + else { + g->gckind = KGC_NORMAL; callallpendingfinalizers(L, 1); - if (keepinvariant(g)) { /* marking phase? */ + } + if (someblack) { /* may there be some black objects? */ /* must sweep all objects to turn them back to white (as white has not changed, nothing will be collected) */ - g->sweepstrgc = 0; - g->gcstate = GCSsweepstring; + entersweep(L); } - g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL; /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collector */ diff --git a/src/lgc.h b/src/lgc.h index 045593039e..bdd5cce6cf 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.53 2012/01/23 20:29:12 roberto Exp $ +** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -20,13 +20,19 @@ ** is that a black object can never point to a white one. Moreover, ** any gray object must be in a "gray list" (gray, grayagain, weak, ** allweak, ephemeron) so that it can be visited again before finishing -** the collection cycle. (These rule does not apply to strings, -** which are never black but do not need to be visited again.) -** These lists have no meaning when the invariant is not being enforced -** (e.g., sweep phase). +** the collection cycle. These lists have no meaning when the invariant +** is not being enforced (e.g., sweep phase). */ + +/* how much to allocate before next GC step */ +#if !defined(GCSTEPSIZE) +/* ~100 small strings */ +#define GCSTEPSIZE (cast_int(100 * sizeof(TString))) +#endif + + /* ** Possible states of the Garbage Collector */ diff --git a/src/llimits.h b/src/llimits.h index 98f8fea0d7..6b2b4b9a01 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.96 2012/01/25 21:05:40 roberto Exp $ +** $Id: llimits.h,v 1.98 2012/05/11 14:10:50 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -124,15 +124,6 @@ typedef LUAI_UACNUMBER l_uacNumber; #define MAXUPVAL UCHAR_MAX -/* -** maximum length for short strings, that is, strings that are -** internalized. (Cannot be smaller than reserved words or tags -** for metamethods; #"function" = 8, #"__newindex" = 10; should -** not be larger than 255, to allow future changes) -*/ -#define LUA_MAXSHORTLEN (8 * sizeof(void*)) - - /* ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) @@ -218,31 +209,36 @@ typedef lu_int32 Instruction; #elif defined(LUA_IEEE754TRICK) /* }{ */ /* the next trick should work on any machine using IEEE754 with - a 32-bit integer type */ + a 32-bit int type */ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #if !defined(LUA_IEEEENDIAN) /* { */ #define LUAI_EXTRAIEEE \ static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; -#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33) +#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33) #else +#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN #define LUAI_EXTRAIEEE /* empty */ #endif /* } */ #define lua_number2int32(i,n,t) \ { LUAI_EXTRAIEEE \ volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ - (i) = (t)u.l_p[LUA_IEEEENDIAN]; } + (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; } #define luai_hashnum(i,n) \ { volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \ (i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */ #define lua_number2int(i,n) lua_number2int32(i, n, int) -#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) #define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) +/* the trick can be expanded to lua_Integer when it is a 32-bit value */ +#if defined(LUA_IEEELL) +#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) +#endif + #endif /* } */ diff --git a/src/lmathlib.c b/src/lmathlib.c index b17237f0b0..c3c605e86b 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.80 2011/07/05 12:49:35 roberto Exp $ +** $Id: lmathlib.c,v 1.81 2012/05/18 17:47:53 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -17,17 +17,17 @@ #include "lualib.h" -#undef PI -#define PI (3.14159265358979323846) -#define RADIANS_PER_DEGREE (PI/180.0) - - /* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */ #if !defined(l_tg) #define l_tg(x) (x) #endif +#undef PI +#define PI (l_tg(3.1415926535897932384626433832795)) +#define RADIANS_PER_DEGREE (PI/180.0) + + static int math_abs (lua_State *L) { lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1))); diff --git a/src/lmem.c b/src/lmem.c index 792deb3cfc..3f88496e09 100644 --- a/src/lmem.c +++ b/src/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.83 2011/11/30 12:42:49 roberto Exp $ +** $Id: lmem.c,v 1.84 2012/05/23 15:41:53 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -94,22 +94,6 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { } lua_assert((nsize == 0) == (newblock == NULL)); g->GCdebt = (g->GCdebt + nsize) - realosize; -#if defined(TRACEMEM) - { /* auxiliary patch to monitor garbage collection. - ** To plot, gnuplot with following command: - ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines - */ - static unsigned long total = 0; /* our "time" */ - static FILE *f = NULL; /* output file */ - total++; /* "time" always grows */ - if ((total % 200) == 0) { - if (f == NULL) f = fopen(TRACEMEM, "w"); - fprintf(f, "%lu %u %d %d\n", total, - gettotalbytes(g), g->GCdebt, g->gcstate * 10000); - } - } -#endif - return newblock; } diff --git a/src/loadlib.c b/src/loadlib.c index 783bc12be3..ea332f44e3 100644 --- a/src/loadlib.c +++ b/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.108 2011/12/12 16:34:03 roberto Exp $ +** $Id: loadlib.c,v 1.110 2012/04/26 19:38:52 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -92,9 +92,9 @@ #define LUA_OFSEP "_" -#define LIBPREFIX "LOADLIB: " +/* table (in the registry) that keeps handles for all loaded C libraries */ +#define CLIBS "_CLIBS" -#define POF LUA_POF #define LIB_FAIL "open" @@ -248,48 +248,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #endif - -static void **ll_register (lua_State *L, const char *path) { - void **plib; - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ - if (!lua_isnil(L, -1)) /* is there an entry? */ - plib = (void **)lua_touserdata(L, -1); - else { /* no entry yet; create one */ - lua_pop(L, 1); /* remove result from gettable */ - plib = (void **)lua_newuserdata(L, sizeof(const void *)); - *plib = NULL; - luaL_setmetatable(L, "_LOADLIB"); - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_pushvalue(L, -2); - lua_settable(L, LUA_REGISTRYINDEX); - } +static void *ll_checkclib (lua_State *L, const char *path) { + void *plib; + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ return plib; } +static void ll_addtoclib (lua_State *L, const char *path, void *plib) { + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ +} + + /* -** __gc tag method: calls library's `ll_unloadlib' function with the lib -** handle +** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib +** handles in list CLIBS */ static int gctm (lua_State *L) { - void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); - if (*lib) ll_unloadlib(*lib); - *lib = NULL; /* mark library as closed */ + int n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + ll_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } return 0; } static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { - void **reg = ll_register(L, path); - if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); - if (*reg == NULL) return ERRLIB; /* unable to load library */ + void *reg = ll_checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) { /* must load library? */ + reg = ll_load(L, path, *sym == '*'); + if (reg == NULL) return ERRLIB; /* unable to load library */ + ll_addtoclib(L, path, reg); + } if (*sym == '*') { /* loading only library (no function)? */ lua_pushboolean(L, 1); /* return 'true' */ return 0; /* no errors */ } else { - lua_CFunction f = ll_sym(L, *reg, sym); + lua_CFunction f = ll_sym(L, reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); /* else create new function */ @@ -418,12 +424,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) { if (mark) { int stat; funcname = lua_pushlstring(L, modname, mark - modname); - funcname = lua_pushfstring(L, POF"%s", funcname); + funcname = lua_pushfstring(L, LUA_POF"%s", funcname); stat = ll_loadfunc(L, filename, funcname); if (stat != ERRFUNC) return stat; modname = mark + 1; /* else go ahead and try old-style name */ } - funcname = lua_pushfstring(L, POF"%s", modname); + funcname = lua_pushfstring(L, LUA_POF"%s", modname); return ll_loadfunc(L, filename, funcname); } @@ -666,18 +672,10 @@ static const luaL_Reg ll_funcs[] = { }; -static const lua_CFunction searchers[] = - {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; - - -LUAMOD_API int luaopen_package (lua_State *L) { +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = + {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; int i; - /* create new type _LOADLIB */ - luaL_newmetatable(L, "_LOADLIB"); - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); - /* create `package' table */ - luaL_newlib(L, pk_funcs); /* create 'searchers' table */ lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); /* fill it with pre-defined searchers */ @@ -686,6 +684,19 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_pushcclosure(L, searchers[i], 1); lua_rawseti(L, -2, i+1); } +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + /* create table CLIBS to keep track of loaded C libraries */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); + lua_createtable(L, 0, 1); /* metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); + /* create `package' table */ + luaL_newlib(L, pk_funcs); + createsearcherstable(L); #if defined(LUA_COMPAT_LOADERS) lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */ diff --git a/src/lobject.h b/src/lobject.h index 20dd44d45b..ca75a028c2 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.68 2012/01/25 21:05:40 roberto Exp $ +** $Id: lobject.h,v 2.70 2012/05/11 14:10:50 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -236,11 +236,6 @@ typedef struct lua_TValue TValue; val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ checkliveness(G(L),io); } -#define setptvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \ - checkliveness(G(L),io); } - #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) @@ -271,6 +266,8 @@ typedef struct lua_TValue TValue; #define setsvalue2n setsvalue +/* check whether a number is valid (useful only for NaN trick) */ +#define luai_checknum(L,o,c) { /* empty */ } /* @@ -278,10 +275,7 @@ typedef struct lua_TValue TValue; ** NaN Trick ** ======================================================= */ - -#if defined(LUA_NANTRICK) \ - || defined(LUA_NANTRICK_LE) \ - || defined(LUA_NANTRICK_BE) +#if defined(LUA_NANTRICK) /* ** numbers are represented in the 'd_' field. All other values have the @@ -289,15 +283,23 @@ typedef struct lua_TValue TValue; ** a "signaled NaN", which is never generated by regular operations by ** the CPU (nor by 'strtod') */ -#if !defined(NNMARK) + +/* allows for external implementation for part of the trick */ +#if !defined(NNMARK) /* { */ + + +#if !defined(LUA_IEEEENDIAN) +#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN' +#endif + + #define NNMARK 0x7FF7A500 #define NNMASK 0x7FFFFF00 -#endif #undef TValuefields #undef NILCONSTANT -#if defined(LUA_NANTRICK_LE) +#if (LUA_IEEEENDIAN == 0) /* { */ /* little endian */ #define TValuefields \ @@ -308,7 +310,7 @@ typedef struct lua_TValue TValue; #define d_(o) ((o)->u.d__) #define tt_(o) ((o)->u.i.tt__) -#elif defined(LUA_NANTRICK_BE) +#else /* }{ */ /* big endian */ #define TValuefields \ @@ -319,10 +321,9 @@ typedef struct lua_TValue TValue; #define d_(o) ((o)->u.d__) #define tt_(o) ((o)->u.i.tt__) -#elif !defined(TValuefields) -#error option 'LUA_NANTRICK' needs declaration for 'TValuefields' +#endif /* } */ -#endif +#endif /* } */ /* correspondence with standard representation */ @@ -372,14 +373,9 @@ typedef struct lua_TValue TValue; (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) - +#undef luai_checknum #define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } - -#else - -#define luai_checknum(L,o,c) { /* empty */ } - #endif /* }====================================================== */ diff --git a/src/lopcodes.c b/src/lopcodes.c index 2e34676687..ef73692754 100644 --- a/src/lopcodes.c +++ b/src/lopcodes.c @@ -1,5 +1,6 @@ /* -** $Id: lopcodes.c,v 1.48 2011/04/19 16:22:13 roberto Exp $ +** $Id: lopcodes.c,v 1.49 2012/05/14 13:34:18 roberto Exp $ +** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ diff --git a/src/loslib.c b/src/loslib.c index 881667dac8..489755b6f5 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.38 2011/11/30 12:35:05 roberto Exp $ +** $Id: loslib.c,v 1.39 2012/05/23 15:37:09 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -26,11 +26,12 @@ #if !defined(LUA_STRFTIMEOPTIONS) #if !defined(LUA_USE_POSIX) -#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } +#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } #else -#define LUA_STRFTIMEOPTIONS { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ - "E", "cCxXyY", \ - "O", "deHImMSuUVwWy" } +#define LUA_STRFTIMEOPTIONS \ + { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \ + "", "E", "cCxXyY", \ + "O", "deHImMSuUVwWy" } #endif #endif @@ -43,7 +44,7 @@ */ #if defined(LUA_USE_MKSTEMP) #include -#define LUA_TMPNAMBUFSIZE 32 +#define LUA_TMPNAMBUFSIZE 32 #define lua_tmpnam(b,e) { \ strcpy(b, "/tmp/lua_XXXXXX"); \ e = mkstemp(b); \ @@ -52,8 +53,8 @@ #elif !defined(lua_tmpnam) -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } #endif diff --git a/src/lparser.c b/src/lparser.c index ac4093cc96..b3eb3ca923 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.125 2012/01/23 23:05:18 roberto Exp $ +** $Id: lparser.c,v 2.128 2012/05/20 14:51:23 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -493,21 +493,30 @@ static void leaveblock (FuncState *fs) { /* -** adds prototype being created into its parent list of prototypes -** and codes instruction to create new closure +** adds a new prototype into list of prototypes */ -static void codeclosure (LexState *ls, Proto *clp, expdesc *v) { - FuncState *fs = ls->fs->prev; - Proto *f = fs->f; /* prototype of function creating new closure */ +static Proto *addprototype (LexState *ls) { + Proto *clp; + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; /* prototype of current function */ if (fs->np >= f->sizep) { int oldsize = f->sizep; - luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, - MAXARG_Bx, "functions"); + luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; } - f->p[fs->np++] = clp; - luaC_objbarrier(ls->L, f, clp); - init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); + f->p[fs->np++] = clp = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; +} + + +/* +** codes instruction to create new closure in parent function +*/ +static void codeclosure (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs->prev; + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */ } @@ -529,13 +538,9 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { fs->nactvar = 0; fs->firstlocal = ls->dyd->actvar.n; fs->bl = NULL; - f = luaF_newproto(L); - fs->f = f; + f = fs->f; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ - /* anchor prototype (to avoid being collected) */ - setptvalue2s(L, L->top, f); - incr_top(L); fs->h = luaH_new(L); /* anchor table of constants (to avoid being collected) */ sethvalue2s(L, L->top, fs->h); @@ -568,20 +573,6 @@ static void close_func (LexState *ls) { anchor_token(ls); L->top--; /* pop table of constants */ luaC_checkGC(L); - L->top--; /* pop prototype (after possible collection) */ -} - - -/* -** opens the main function, which is a regular vararg function with an -** upvalue named LUA_ENV -*/ -static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) { - expdesc v; - open_func(ls, fs, bl); - fs->f->is_vararg = 1; /* main function is always vararg */ - init_exp(&v, VLOCAL, 0); - newupvalue(fs, ls->envn, &v); /* create environment upvalue */ } @@ -795,8 +786,9 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) { /* body -> `(' parlist `)' block END */ FuncState new_fs; BlockCnt bl; - open_func(ls, &new_fs, &bl); + new_fs.f = addprototype(ls); new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); checknext(ls, '('); if (ismethod) { new_localvarliteral(ls, "self"); /* create 'self' parameter */ @@ -807,7 +799,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) { statlist(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); - codeclosure(ls, new_fs.f, e); + codeclosure(ls, e); close_func(ls); } @@ -879,8 +871,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) { */ -static void prefixexp (LexState *ls, expdesc *v) { - /* prefixexp -> NAME | '(' expr ')' */ +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; @@ -901,12 +893,12 @@ static void prefixexp (LexState *ls, expdesc *v) { } -static void primaryexp (LexState *ls, expdesc *v) { - /* primaryexp -> - prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ +static void suffixedexp (LexState *ls, expdesc *v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; int line = ls->linenumber; - prefixexp(ls, v); + primaryexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* fieldsel */ @@ -941,7 +933,7 @@ static void primaryexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | - constructor | FUNCTION body | primaryexp */ + constructor | FUNCTION body | suffixedexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); @@ -981,7 +973,7 @@ static void simpleexp (LexState *ls, expdesc *v) { return; } default: { - primaryexp(ls, v); + suffixedexp(ls, v); return; } } @@ -1141,10 +1133,10 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; check_condition(ls, vkisvar(lh->v.k), "syntax error"); - if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ + if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ struct LHS_assign nv; nv.prev = lh; - primaryexp(ls, &nv.v); + suffixedexp(ls, &nv.v); if (nv.v.k != VINDEXED) check_conflict(ls, lh, &nv.v); checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, @@ -1210,6 +1202,13 @@ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { } +/* skip no-op statements */ +static void skipnoopstat (LexState *ls) { + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); +} + + static void labelstat (LexState *ls, TString *label, int line) { /* label -> '::' NAME '::' */ FuncState *fs = ls->fs; @@ -1219,9 +1218,7 @@ static void labelstat (LexState *ls, TString *label, int line) { checknext(ls, TK_DBCOLON); /* skip double colon */ /* create new entry for this label */ l = newlabelentry(ls, ll, label, line, fs->pc); - /* skip other no-op statements */ - while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) - statement(ls); + skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ /* assume that locals are already out of scope */ ll->arr[l].nactvar = fs->bl->nactvar; @@ -1384,6 +1381,7 @@ static void test_then_block (LexState *ls, int *escapelist) { luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ enterblock(fs, &bl, 0); /* must enter block before 'goto' */ gotostat(ls, v.t); /* handle goto/break */ + skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ leaveblock(fs); return; /* and that is it */ @@ -1480,13 +1478,15 @@ static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; struct LHS_assign v; - primaryexp(ls, &v.v); - if (v.v.k == VCALL) /* stat -> func */ - SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ - else { /* stat -> assignment */ + suffixedexp(ls, &v.v); + if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ v.prev = NULL; assignment(ls, &v, 1); } + else { /* stat -> func */ + check_condition(ls, v.v.k == VCALL, "syntax error"); + SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ + } } @@ -1594,27 +1594,42 @@ static void statement (LexState *ls) { /* }====================================================================== */ -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar) { +/* +** compiles the main function, which is a regular vararg function with an +** upvalue named LUA_ENV +*/ +static void mainfunc (LexState *ls, FuncState *fs) { + BlockCnt bl; + expdesc v; + open_func(ls, fs, &bl); + fs->f->is_vararg = 1; /* main function is always vararg */ + init_exp(&v, VLOCAL, 0); /* create and... */ + newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ + luaX_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); +} + + +Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { LexState lexstate; FuncState funcstate; - BlockCnt bl; - TString *tname = luaS_new(L, name); - setsvalue2s(L, L->top, tname); /* push name to protect it */ + Closure *cl = luaF_newLclosure(L, 1); /* create main closure */ + /* anchor closure (to avoid being collected) */ + setclLvalue(L, L->top, cl); incr_top(L); + funcstate.f = cl->l.p = luaF_newproto(L); + funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ lexstate.buff = buff; lexstate.dyd = dyd; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; - luaX_setinput(L, &lexstate, z, tname, firstchar); - open_mainfunc(&lexstate, &funcstate, &bl); - luaX_next(&lexstate); /* read first token */ - statlist(&lexstate); /* main body */ - check(&lexstate, TK_EOS); - close_func(&lexstate); - L->top--; /* pop name */ + luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); + mainfunc(&lexstate, &funcstate); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); - return funcstate.f; + return cl; /* it's on the stack too */ } diff --git a/src/lparser.h b/src/lparser.h index caabf46ccc..301167d4f5 100644 --- a/src/lparser.h +++ b/src/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.69 2011/07/27 18:09:01 roberto Exp $ +** $Id: lparser.h,v 1.70 2012/05/08 13:53:33 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -112,8 +112,8 @@ typedef struct FuncState { } FuncState; -LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar); +LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); #endif diff --git a/src/lstate.c b/src/lstate.c index e3aec6a39a..1a16500337 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.93 2012/02/01 21:57:15 roberto Exp $ +** $Id: lstate.c,v 2.97 2012/05/23 15:37:09 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -39,7 +39,7 @@ #endif -#define MEMERRMSG "not enough memory" +#define MEMERRMSG "not enough memory" /* @@ -48,7 +48,7 @@ */ #if !defined(luai_makeseed) #include -#define luai_makeseed(L) cast(size_t, time(NULL)) +#define luai_makeseed() cast(size_t, time(NULL)) #endif @@ -280,7 +280,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; g->gcrunning = 0; /* no GC while building state */ - g->lastmajormem = 0; + g->GCestimate = 0; g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; @@ -292,6 +292,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->allgc = NULL; g->finobj = NULL; g->tobefnz = NULL; + g->sweepgc = g->sweepfin = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; g->totalbytes = sizeof(LG); diff --git a/src/lstate.h b/src/lstate.h index 1691ed92dd..936afc2d58 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.77 2012/02/01 21:57:15 roberto Exp $ +** $Id: lstate.h,v 2.80 2012/05/22 17:50:39 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -113,7 +113,8 @@ typedef struct global_State { void *ud; /* auxiliary data to `frealloc' */ lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ - lu_mem lastmajormem; /* memory in use after last major collection */ + lu_mem GCmemtrav; /* memory traversed by the GC */ + lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ stringtable strt; /* hash table for strings */ TValue l_registry; unsigned int seed; /* randomized seed for hashes */ @@ -124,7 +125,8 @@ typedef struct global_State { int sweepstrgc; /* position of sweep in `strt' */ GCObject *allgc; /* list of all collectable objects */ GCObject *finobj; /* list of collectable objects with finalizers */ - GCObject **sweepgc; /* current position of sweep */ + GCObject **sweepgc; /* current position of sweep in list 'allgc' */ + GCObject **sweepfin; /* current position of sweep in list 'finobj' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of tables with weak values */ diff --git a/src/lstring.c b/src/lstring.c index d89ac8f20b..8b959f19d0 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.22 2012/02/01 21:57:15 roberto Exp $ +** $Id: lstring.c,v 2.24 2012/05/11 14:14:42 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -18,13 +18,24 @@ #include "lstring.h" +/* +** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to +** compute its hash +*/ +#if !defined(LUAI_HASHLIMIT) +#define LUAI_HASHLIMIT 5 +#endif + + /* ** equality for long strings */ int luaS_eqlngstr (TString *a, TString *b) { size_t len = a->tsv.len; lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR); - return (len == b->tsv.len) && (memcmp(getstr(a), getstr(b), len) == 0); + return (a == b) || /* same instance or... */ + ((len == b->tsv.len) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ } @@ -40,8 +51,9 @@ int luaS_eqstr (TString *a, TString *b) { unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { unsigned int h = seed ^ l; size_t l1; - for (l1 = 0; l1 < l; l1++) - h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1])); + size_t step = (l >> LUAI_HASHLIMIT) + 1; + for (l1 = l; l1 >= step; l1 -= step) + h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); return h; } @@ -142,7 +154,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { ** new string (with explicit length) */ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - if (l <= LUA_MAXSHORTLEN) /* short string? */ + if (l <= LUAI_MAXSHORTLEN) /* short string? */ return internshrstr(L, str, l); else { if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) diff --git a/src/lstrlib.c b/src/lstrlib.c index f5d61fd859..e13098bb6e 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.173 2011/11/30 18:24:56 roberto Exp $ +** $Id: lstrlib.c,v 1.176 2012/05/23 15:37:09 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -30,7 +30,7 @@ /* macro to `unsign' a character */ -#define uchar(c) ((unsigned char)(c)) +#define uchar(c) ((unsigned char)(c)) @@ -119,7 +119,9 @@ static int str_rep (lua_State *L) { char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ memcpy(p, s, l * sizeof(char)); p += l; - memcpy(p, sep, lsep * sizeof(char)); p += lsep; + if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */ + memcpy(p, sep, lsep * sizeof(char)); p += lsep; + } } memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ luaL_pushresultsize(&b, totallen); @@ -745,20 +747,17 @@ static int str_gsub (lua_State *L) { #if !defined(LUA_INTFRMLEN) /* { */ #if defined(LUA_USE_LONGLONG) -#define LUA_INTFRMLEN "ll" -#define LUA_INTFRM_T long long +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long #else -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long #endif #endif /* } */ -#define MAX_UINTFRM ((lua_Number)(~(unsigned LUA_INTFRM_T)0)) -#define MAX_INTFRM ((lua_Number)((~(unsigned LUA_INTFRM_T)0)/2)) -#define MIN_INTFRM (-(lua_Number)((~(unsigned LUA_INTFRM_T)0)/2) - 1) /* ** LUA_FLTFRMLEN is the length modifier for float conversions in @@ -767,8 +766,8 @@ static int str_gsub (lua_State *L) { */ #if !defined(LUA_FLTFRMLEN) -#define LUA_FLTFRMLEN "" -#define LUA_FLTFRM_T double +#define LUA_FLTFRMLEN "" +#define LUA_FLTFRM_T double #endif @@ -870,18 +869,22 @@ static int str_format (lua_State *L) { } case 'd': case 'i': { lua_Number n = luaL_checknumber(L, arg); - luaL_argcheck(L, (MIN_INTFRM - 1) < n && n < (MAX_INTFRM + 1), arg, + LUA_INTFRM_T ni = (LUA_INTFRM_T)n; + lua_Number diff = n - (lua_Number)ni; + luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a number in proper range"); addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, (LUA_INTFRM_T)n); + nb = sprintf(buff, form, ni); break; } case 'o': case 'u': case 'x': case 'X': { lua_Number n = luaL_checknumber(L, arg); - luaL_argcheck(L, 0 <= n && n < (MAX_UINTFRM + 1), arg, + unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; + lua_Number diff = n - (lua_Number)ni; + luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a non-negative number in proper range"); addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, (unsigned LUA_INTFRM_T)n); + nb = sprintf(buff, form, ni); break; } case 'e': case 'E': case 'f': diff --git a/src/ltable.c b/src/ltable.c index 7f28e80854..ffa5ecb36a 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.70 2012/02/01 21:57:15 roberto Exp $ +** $Id: ltable.c,v 2.71 2012/05/23 15:37:09 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -48,10 +48,10 @@ #define MAXASIZE (1 << MAXBITS) -#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashstr(t,str) hashpow2(t, (str)->tsv.hash) -#define hashboolean(t,p) hashpow2(t, p) +#define hashboolean(t,p) hashpow2(t, p) /* diff --git a/src/lua.c b/src/lua.c index e20ab86d27..7614c7030b 100644 --- a/src/lua.c +++ b/src/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.203 2011/12/12 16:34:03 roberto Exp $ +** $Id: lua.c,v 1.205 2012/05/23 15:37:09 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -45,13 +45,13 @@ */ #if defined(LUA_USE_ISATTY) #include -#define lua_stdin_is_tty() isatty(0) +#define lua_stdin_is_tty() isatty(0) #elif defined(LUA_WIN) #include #include -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) #else -#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ #endif @@ -66,19 +66,19 @@ #include #include #include -#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ -#define lua_freeline(L,b) ((void)L, free(b)) +#define lua_freeline(L,b) ((void)L, free(b)) #elif !defined(lua_readline) -#define lua_readline(L,b,p) \ +#define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } -#define lua_freeline(L,b) { (void)L; (void)b; } +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } #endif @@ -223,16 +223,11 @@ static int dostring (lua_State *L, const char *s, const char *name) { static int dolibrary (lua_State *L, const char *name) { int status; - lua_pushglobaltable(L); - lua_getfield(L, -1, "require"); + lua_getglobal(L, "require"); lua_pushstring(L, name); - status = docall(L, 1, 1); - if (status == LUA_OK) { - lua_setfield(L, -2, name); /* global[name] = require return */ - lua_pop(L, 1); /* remove global table */ - } - else - lua_remove(L, -2); /* remove global table (below error msg.) */ + status = docall(L, 1, 1); /* call 'require(name)' */ + if (status == LUA_OK) + lua_setglobal(L, name); /* global[name] = require return */ return report(L, status); } diff --git a/src/lua.h b/src/lua.h index 49d24b94cd..a3a3a70c69 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.282 2011/11/29 15:55:08 roberto Exp $ +** $Id: lua.h,v 1.283 2012/04/20 13:18:26 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -19,11 +19,11 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" #define LUA_VERSION_NUM 502 -#define LUA_VERSION_RELEASE "0" " (work1)" +#define LUA_VERSION_RELEASE "1" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2011 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2012 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -413,7 +413,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2011 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2012 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/luaconf.h b/src/luaconf.h index bab401e9a9..e4335df904 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.170 2011/12/06 16:58:36 roberto Exp $ +** $Id: luaconf.h,v 1.172 2012/05/11 14:14:42 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -223,6 +223,13 @@ (fprintf(stderr, (s), (p)), fflush(stderr)) +/* +@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is, +** strings that are internalized. (Cannot be smaller than reserved words +** or tags for metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#define LUAI_MAXSHORTLEN 40 @@ -453,66 +460,76 @@ #define LUA_UNSIGNED unsigned LUA_INT32 -#if defined(LUA_CORE) /* { */ -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ +/* +** Some tricks with doubles +*/ -/* On a Microsoft compiler on a Pentium, use assembler to avoid clashes - with a DirectX idiosyncrasy */ +#if defined(LUA_CORE) && \ + defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ +/* +** The next definitions activate some tricks to speed up the +** conversion from doubles to integer types, mainly to LUA_UNSIGNED. +** +@@ MS_ASMTRICK uses Microsoft assembler to avoid clashes with a +** DirectX idiosyncrasy. +** +@@ LUA_IEEE754TRICK uses a trick that should work on any machine +** using IEEE754 with a 32-bit integer type. +** +@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be +** defined when LUA_INTEGER is a 32-bit integer. +** +@@ LUA_IEEEENDIAN is the endianness of doubles in your machine +** (0 for little endian, 1 for big endian); if not defined, Lua will +** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK). +** +@@ LUA_NANTRICK controls the use of a trick to pack all types into +** a single double value, using NaN values to represent non-number +** values. The trick only works on 32-bit machines (ints and pointers +** are 32-bit values) with numbers represented as IEEE 754-2008 doubles +** with conventional endianess (12345678 or 87654321), in CPUs that do +** not produce signaling NaN values (all NaNs are quiet). +*/ + +/* Microsoft compiler on a Pentium (32 bit) ? */ #if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ #define MS_ASMTRICK +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK -#else /* }{ */ -/* the next definition uses a trick that should work on any machine - using IEEE754 with a 32-bit integer type */ - -#define LUA_IEEE754TRICK - -/* -@@ LUA_IEEEENDIAN is the endianness of doubles in your machine -** (0 for little endian, 1 for big endian); if not defined, Lua will -** check it dynamically. -*/ -/* check for known architectures */ -#if defined(__i386__) || defined(__i386) || defined(__X86__) || \ - defined (__x86_64) -#define LUA_IEEEENDIAN 0 -#elif defined(__POWERPC__) || defined(__ppc__) -#define LUA_IEEEENDIAN 1 -#endif -#endif /* } */ +/* pentium 32 bits? */ +#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ -#endif /* } */ +#define LUA_IEEE754TRICK +#define LUA_IEEELL +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK -#endif /* } */ +/* pentium 64 bits? */ +#elif defined(__x86_64) /* }{ */ -/* }================================================================== */ +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 0 +#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ -/* -@@ LUA_NANTRICK_LE/LUA_NANTRICK_BE controls the use of a trick to -** pack all types into a single double value, using NaN values to -** represent non-number values. The trick only works on 32-bit machines -** (ints and pointers are 32-bit values) with numbers represented as -** IEEE 754-2008 doubles with conventional endianess (12345678 or -** 87654321), in CPUs that do not produce signaling NaN values (all NaNs -** are quiet). -*/ -#if defined(LUA_CORE) && \ - defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 1 -/* little-endian architectures that satisfy those conditions */ -#if defined(__i386__) || defined(__i386) || defined(__X86__) || \ - defined(_M_IX86) +#else /* }{ */ -#define LUA_NANTRICK_LE +/* assume IEEE754 and a 32-bit integer type */ +#define LUA_IEEE754TRICK -#endif +#endif /* } */ #endif /* } */ +/* }================================================================== */ + diff --git a/src/lundump.c b/src/lundump.c index c2173daf9e..54de011a45 100644 --- a/src/lundump.c +++ b/src/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 1.72 2012/03/21 18:11:35 lhf Exp $ +** $Id: lundump.c,v 2.22 2012/05/08 13:53:33 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -39,7 +39,7 @@ static l_noret error(LoadState* S, const char* why) #define LoadVector(S,b,n,size) LoadMem(S,b,n,size) #if !defined(luai_verifycode) -#define luai_verifycode(L,b,f) (f) +#define luai_verifycode(L,b,f) /* empty */ #endif static void LoadBlock(LoadState* S, void* b, size_t size) @@ -91,7 +91,7 @@ static void LoadCode(LoadState* S, Proto* f) LoadVector(S,f->code,n,sizeof(Instruction)); } -static Proto* LoadFunction(LoadState* S); +static void LoadFunction(LoadState* S, Proto* f); static void LoadConstants(LoadState* S, Proto* f) { @@ -125,7 +125,11 @@ static void LoadConstants(LoadState* S, Proto* f) f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; for (i=0; ip[i]=NULL; - for (i=0; ip[i]=LoadFunction(S); + for (i=0; ip[i]=luaF_newproto(S->L); + LoadFunction(S,f->p[i]); + } } static void LoadUpvalues(LoadState* S, Proto* f) @@ -164,10 +168,8 @@ static void LoadDebug(LoadState* S, Proto* f) for (i=0; iupvalues[i].name=LoadString(S); } -static Proto* LoadFunction(LoadState* S) +static void LoadFunction(LoadState* S, Proto* f) { - Proto* f=luaF_newproto(S->L); - setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); f->numparams=LoadByte(S); @@ -177,8 +179,6 @@ static Proto* LoadFunction(LoadState* S) LoadConstants(S,f); LoadUpvalues(S,f); LoadDebug(S,f); - S->L->top--; - return f; } /* the code below must be consistent with the code in luaU_header */ @@ -203,9 +203,10 @@ static void LoadHeader(LoadState* S) /* ** load precompiled chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) +Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) { LoadState S; + Closure* cl; if (*name=='@' || *name=='=') S.name=name+1; else if (*name==LUA_SIGNATURE[0]) @@ -216,7 +217,19 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) S.Z=Z; S.b=buff; LoadHeader(&S); - return luai_verifycode(L,buff,LoadFunction(&S)); + cl=luaF_newLclosure(L,1); + setclLvalue(L,L->top,cl); incr_top(L); + cl->l.p=luaF_newproto(L); + LoadFunction(&S,cl->l.p); + if (cl->l.p->sizeupvalues != 1) + { + Proto* p=cl->l.p; + cl=luaF_newLclosure(L,cl->l.p->sizeupvalues); + cl->l.p=p; + setclLvalue(L,L->top-1,cl); + } + luai_verifycode(L,buff,cl->l.p); + return cl; } #define MYINT(s) (s[0]-'0') diff --git a/src/lundump.h b/src/lundump.h index b63993ffe5..2b8accecb8 100644 --- a/src/lundump.h +++ b/src/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.44 2011/05/06 13:35:17 lhf Exp $ +** $Id: lundump.h,v 1.39 2012/05/08 13:53:33 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -11,7 +11,7 @@ #include "lzio.h" /* load one chunk; from lundump.c */ -LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); +LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); /* make header; from lundump.c */ LUAI_FUNC void luaU_header (lu_byte* h); diff --git a/src/lvm.c b/src/lvm.c index cb8d76ae5b..accc7c08bf 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.149 2012/01/25 21:05:40 roberto Exp $ +** $Id: lvm.c,v 2.151 2012/05/14 17:50:49 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -395,7 +395,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, int nup = p->sizeupvalues; Upvaldesc *uv = p->upvalues; int i; - Closure *ncl = luaF_newLclosure(L, p); + Closure *ncl = luaF_newLclosure(L, nup); + ncl->l.p = p; setclLvalue(L, ra, ncl); /* anchor new closure in stack */ for (i = 0; i < nup; i++) { /* fill in its upvalues */ if (uv[i].instack) /* upvalue refers to local variable? */ @@ -501,7 +502,11 @@ void luaV_finishOp (lua_State *L) { #define Protect(x) { {x;}; base = ci->u.l.base; } -#define checkGC(L,c) Protect(luaC_condGC(L, c); luai_threadyield(L);) +#define checkGC(L,c) \ + Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \ + luaC_step(L); \ + L->top = ci->top;}) /* restore top */ \ + luai_threadyield(L); ) #define arith_op(op,tm) { \ @@ -594,11 +599,7 @@ void luaV_execute (lua_State *L) { sethvalue(L, ra, t); if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - checkGC(L, - L->top = ra + 1; /* limit of live values */ - luaC_step(L); - L->top = ci->top; /* restore top */ - ) + checkGC(L, ra + 1); ) vmcase(OP_SELF, StkId rb = RB(i); @@ -650,10 +651,7 @@ void luaV_execute (lua_State *L) { ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */ rb = b + base; setobjs2s(L, ra, rb); - checkGC(L, - L->top = (ra >= rb ? ra + 1 : rb); /* limit of live values */ - luaC_step(L); - ) + checkGC(L, (ra >= rb ? ra + 1 : rb)); L->top = ci->top; /* restore top */ ) vmcase(OP_JMP, @@ -831,11 +829,7 @@ void luaV_execute (lua_State *L) { pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ else setclLvalue(L, ra, ncl); /* push cashed closure */ - checkGC(L, - L->top = ra + 1; /* limit of live values */ - luaC_step(L); - L->top = ci->top; /* restore top */ - ) + checkGC(L, ra + 1); ) vmcase(OP_VARARG, int b = GETARG_B(i) - 1; diff --git a/src/lzio.c b/src/lzio.c index 354f94e7c5..8b77054e0b 100644 --- a/src/lzio.c +++ b/src/lzio.c @@ -1,6 +1,6 @@ /* -** $Id: lzio.c,v 1.34 2011/07/15 12:35:32 roberto Exp $ -** a generic input stream interface +** $Id: lzio.c,v 1.35 2012/05/14 13:34:18 roberto Exp $ +** Buffered streams ** See Copyright Notice in lua.h */ From 5a152a0a57f98f38472fac54b62fa8cdb9708d29 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Mon, 28 May 2012 12:00:00 +0000 Subject: [PATCH 74/97] Lua 5.2.1-rc2 --- doc/contents.html | 4 ++-- doc/manual.html | 2 +- src/lgc.c | 47 +++++++++++++++++++++++++++++------------------ src/llimits.h | 4 +++- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/doc/contents.html b/doc/contents.html index 8340ff356d..9f5060519f 100644 --- a/doc/contents.html +++ b/doc/contents.html @@ -35,7 +35,7 @@

                      Copyright © 2011–2012 Lua.org, PUC-Rio. Freely available under the terms of the -Lua license. +Lua license.

                      Contents

                      @@ -521,7 +521,7 @@

                      auxiliary library


                      Last update: -Wed May 23 13:28:09 BRT 2012 +Sat May 26 08:52:25 BRT 2012

                      - + @@ -2828,8 +2828,7 @@

                      4.8 – Functions and Types

                      The third field, x, tells whether the function may throw errors: '-' means the function never throws any error; -'m' means the function may throw only memory allocation errors; -'e' means the function may throw other kinds of errors; +'e' means the function may throw errors; 'v' means the function may throw an error on purpose. @@ -3191,7 +3190,7 @@

                      4.8 – Functions and Types


                      lua_createtable

                      -[-0, +1, m] +[-0, +1, e]

                      void lua_createtable (lua_State *L, int narr, int nrec);

                      @@ -3210,7 +3209,7 @@

                      4.8 – Functions and Types


                      lua_dump

                      -[-0, +0, m] +[-0, +0, e]

                      int lua_dump (lua_State *L, lua_Writer writer, void *data);

                      @@ -3748,7 +3747,7 @@

                      4.8 – Functions and Types


                      lua_newtable

                      -[-0, +1, m] +[-0, +1, e]

                      void lua_newtable (lua_State *L);

                      @@ -3760,7 +3759,7 @@

                      4.8 – Functions and Types


                      lua_newthread

                      -[-0, +1, m] +[-0, +1, e]

                      lua_State *lua_newthread (lua_State *L);

                      @@ -3781,7 +3780,7 @@

                      4.8 – Functions and Types


                      lua_newuserdata

                      -[-0, +1, m] +[-0, +1, e]

                      void *lua_newuserdata (lua_State *L, size_t size);

                      @@ -3967,7 +3966,7 @@

                      4.8 – Functions and Types


                      lua_pushcclosure

                      -[-n, +1, m] +[-n, +1, e]

                      void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

                      @@ -4033,7 +4032,7 @@

                      4.8 – Functions and Types


                      lua_pushfstring

                      -[-0, +1, m] +[-0, +1, e]

                      const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

                      @@ -4100,7 +4099,7 @@

                      4.8 – Functions and Types


                      lua_pushliteral

                      -[-0, +1, m] +[-0, +1, e]

                      const char *lua_pushliteral (lua_State *L, const char *s);

                      @@ -4113,7 +4112,7 @@

                      4.8 – Functions and Types


                      lua_pushlstring

                      -[-0, +1, m] +[-0, +1, e]

                      const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

                      @@ -4156,7 +4155,7 @@

                      4.8 – Functions and Types


                      lua_pushstring

                      -[-0, +1, m] +[-0, +1, e]

                      const char *lua_pushstring (lua_State *L, const char *s);

                      @@ -4203,7 +4202,7 @@

                      4.8 – Functions and Types


                      lua_pushvfstring

                      -[-0, +1, m] +[-0, +1, e]

                      const char *lua_pushvfstring (lua_State *L,
                                                     const char *fmt,
                                                     va_list argp);
                      @@ -4290,7 +4289,7 @@

                      4.8 – Functions and Types


                      lua_rawset

                      -[-2, +0, m] +[-2, +0, e]

                      void lua_rawset (lua_State *L, int index);

                      @@ -4302,7 +4301,7 @@

                      4.8 – Functions and Types


                      lua_rawseti

                      -[-1, +0, m] +[-1, +0, e]

                      void lua_rawseti (lua_State *L, int index, int n);

                      @@ -4321,7 +4320,7 @@

                      4.8 – Functions and Types


                      lua_rawsetp

                      -[-1, +0, m] +[-1, +0, e]

                      void lua_rawsetp (lua_State *L, int index, const void *p);

                      @@ -4669,7 +4668,7 @@

                      4.8 – Functions and Types


                      lua_tolstring

                      -[-0, +0, m] +[-0, +0, e]

                      const char *lua_tolstring (lua_State *L, int index, size_t *len);

                      @@ -4752,7 +4751,7 @@

                      4.8 – Functions and Types


                      lua_tostring

                      -[-0, +0, m] +[-0, +0, e]

                      const char *lua_tostring (lua_State *L, int index);

                      @@ -5154,7 +5153,7 @@

                      4.9 – The Debug Interface


                      lua_getinfo

                      -[-(0|1), +(0|1|2), m] +[-(0|1), +(0|1|2), e]

                      int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

                      @@ -5553,7 +5552,7 @@

                      5.1 – Functions and Types


                      luaL_addchar

                      -[-?, +?, m] +[-?, +?, e]

                      void luaL_addchar (luaL_Buffer *B, char c);

                      @@ -5565,7 +5564,7 @@

                      5.1 – Functions and Types


                      luaL_addlstring

                      -[-?, +?, m] +[-?, +?, e]

                      void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

                      @@ -5579,7 +5578,7 @@

                      5.1 – Functions and Types


                      luaL_addsize

                      -[-?, +?, m] +[-?, +?, e]

                      void luaL_addsize (luaL_Buffer *B, size_t n);

                      @@ -5592,7 +5591,7 @@

                      5.1 – Functions and Types


                      luaL_addstring

                      -[-?, +?, m] +[-?, +?, e]

                      void luaL_addstring (luaL_Buffer *B, const char *s);

                      @@ -5606,7 +5605,7 @@

                      5.1 – Functions and Types


                      luaL_addvalue

                      -[-1, +?, m] +[-1, +?, e]

                      void luaL_addvalue (luaL_Buffer *B);

                      @@ -5743,7 +5742,7 @@

                      5.1 – Functions and Types


                      luaL_buffinitsize

                      -[-?, +?, m] +[-?, +?, e]

                      char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);

                      @@ -5970,7 +5969,7 @@

                      5.1 – Functions and Types


                      luaL_dofile

                      -[-0, +?, m] +[-0, +?, e]

                      int luaL_dofile (lua_State *L, const char *filename);

                      @@ -6029,7 +6028,7 @@

                      5.1 – Functions and Types


                      luaL_execresult

                      -[-0, +3, m] +[-0, +3, e]

                      int luaL_execresult (lua_State *L, int stat);

                      @@ -6042,7 +6041,7 @@

                      5.1 – Functions and Types


                      luaL_fileresult

                      -[-0, +(1|3), m] +[-0, +(1|3), e]

                      int luaL_fileresult (lua_State *L, int stat, const char *fname);

                      @@ -6055,7 +6054,7 @@

                      5.1 – Functions and Types


                      luaL_getmetafield

                      -[-0, +(0|1), m] +[-0, +(0|1), e]

                      int luaL_getmetafield (lua_State *L, int obj, const char *e);

                      @@ -6082,7 +6081,7 @@

                      5.1 – Functions and Types


                      luaL_getsubtable

                      -[-0, +1, m] +[-0, +1, e]

                      int luaL_getsubtable (lua_State *L, int idx, const char *fname);

                      @@ -6098,7 +6097,7 @@

                      5.1 – Functions and Types


                      luaL_gsub

                      -[-0, +1, m] +[-0, +1, e]

                      const char *luaL_gsub (lua_State *L,
                                              const char *s,
                                              const char *p,
                      @@ -6168,7 +6167,7 @@ 

                      5.1 – Functions and Types


                      luaL_loadfile

                      -[-0, +1, m] +[-0, +1, e]

                      int luaL_loadfile (lua_State *L, const char *filename);

                      @@ -6179,7 +6178,7 @@

                      5.1 – Functions and Types


                      luaL_loadfilex

                      -[-0, +1, m] +[-0, +1, e]

                      int luaL_loadfilex (lua_State *L, const char *filename,
                                                                   const char *mode);
                      @@ -6233,7 +6232,7 @@

                      5.1 – Functions and Types


                      luaL_newlib

                      -[-0, +1, m] +[-0, +1, e]

                      int luaL_newlib (lua_State *L, const luaL_Reg *l);

                      @@ -6249,7 +6248,7 @@

                      5.1 – Functions and Types


                      luaL_newlibtable

                      -[-0, +1, m] +[-0, +1, e]

                      int luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

                      @@ -6270,7 +6269,7 @@

                      5.1 – Functions and Types


                      luaL_newmetatable

                      -[-0, +1, m] +[-0, +1, e]

                      int luaL_newmetatable (lua_State *L, const char *tname);

                      @@ -6442,7 +6441,7 @@

                      5.1 – Functions and Types


                      luaL_prepbuffer

                      -[-?, +?, m] +[-?, +?, e]

                      char *luaL_prepbuffer (luaL_Buffer *B);

                      @@ -6454,7 +6453,7 @@

                      5.1 – Functions and Types


                      luaL_prepbuffsize

                      -[-?, +?, m] +[-?, +?, e]

                      char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);

                      @@ -6470,7 +6469,7 @@

                      5.1 – Functions and Types


                      luaL_pushresult

                      -[-?, +1, m] +[-?, +1, e]

                      void luaL_pushresult (luaL_Buffer *B);

                      @@ -6482,7 +6481,7 @@

                      5.1 – Functions and Types


                      luaL_pushresultsize

                      -[-?, +1, m] +[-?, +1, e]

                      void luaL_pushresultsize (luaL_Buffer *B, size_t sz);

                      @@ -6493,7 +6492,7 @@

                      5.1 – Functions and Types


                      luaL_ref

                      -[-1, +0, m] +[-1, +0, e]

                      int luaL_ref (lua_State *L, int t);

                      @@ -6597,7 +6596,7 @@

                      5.1 – Functions and Types


                      luaL_testudata

                      -[-0, +0, m] +[-0, +0, e]

                      void *luaL_testudata (lua_State *L, int arg, const char *tname);

                      @@ -6633,7 +6632,7 @@

                      5.1 – Functions and Types


                      luaL_traceback

                      -[-0, +1, m] +[-0, +1, e]

                      void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                                            int level);
                      @@ -6680,7 +6679,7 @@

                      5.1 – Functions and Types


                      luaL_where

                      -[-0, +1, m] +[-0, +1, e]

                      void luaL_where (lua_State *L, int lvl);

                      @@ -10407,7 +10406,7 @@

                      9 – The Complete Syntax of Lua


                      Last update: -Wed May 23 13:28:41 BRT 2012 +Fri Jun 1 12:38:38 BRT 2012

                      - + @@ -3350,7 +3350,7 @@

                      4.8 – Functions and Types


                      lua_getctx

                      [-0, +0, –] -

                      int lua_getctx  (lua_State *L, int *ctx);
                      +
                      int lua_getctx (lua_State *L, int *ctx);

                      This function is called by a continuation function (see §4.7) @@ -4856,7 +4856,7 @@

                      4.8 – Functions and Types


                      lua_typename

                      [-0, +0, –] -

                      const char *lua_typename  (lua_State *L, int tp);
                      +
                      const char *lua_typename (lua_State *L, int tp);

                      Returns the name of the type encoded by the value tp, @@ -4940,7 +4940,7 @@

                      4.8 – Functions and Types


                      lua_yield

                      [-?, +?, –] -

                      int lua_yield  (lua_State *L, int nresults);
                      +
                      int lua_yield (lua_State *L, int nresults);

                      This function is equivalent to lua_yieldk, @@ -4955,7 +4955,7 @@

                      4.8 – Functions and Types


                      lua_yieldk

                      [-?, +?, –] -

                      int lua_yieldk  (lua_State *L, int nresults, int ctx, lua_CFunction k);
                      +
                      int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k);

                      Yields a coroutine. @@ -5354,8 +5354,17 @@

                      4.9 – The Debug Interface

                      -Hook functions cannot yield -(that is, call lua_yieldk or lua_yield). +Hook functions cannot have continuations, +that is, they cannot call lua_yieldk, +lua_pcallk, or lua_callk with a non-null k. + + +

                      +Hook functions can yield under the following conditions: +Only count and line events can yield +and they cannot yield any value; +to yield a hook function must finish its execution +calling lua_yield with nresults equal to zero. @@ -10406,7 +10415,7 @@

                      9 – The Complete Syntax of Lua


                      Last update: -Fri Jun 1 12:38:38 BRT 2012 +Fri Jun 8 16:13:40 BRT 2012 diff --git a/doc/lua.css b/doc/lua.css index 7fafbb1bb6..240e85eb8b 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -16,10 +16,10 @@ h1, h2, h3, h4 { h2 { padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 30px ; - padding-right: 30px ; - margin-left: -30px ; + padding-left: 1em ; + padding-right: 1em ; background-color: #E0E0FF ; + border-radius: 8px ; } h3 { diff --git a/doc/manual.css b/doc/manual.css index b49b362937..269bd4358e 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -18,7 +18,9 @@ span.apii { p+h1, ul+h1 { padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 30px ; - margin-left: -30px ; + padding-left: 24px ; + margin-left: -24px ; background-color: #E0E0FF ; + border-radius: 8px ; } + diff --git a/doc/manual.html b/doc/manual.html index 4ba084dfc8..80fdb10ec9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@

                      by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

                      -Copyright © 2011–2012 Lua.org, PUC-Rio. +Copyright © 2011–2013 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -33,7 +33,7 @@

                      - + @@ -424,7 +424,6 @@

                      2.4 – Metatables and Metamethods

                            rawget(getmetatable(obj) or {}, event)
                       

                      - This means that the access to a metamethod does not invoke other metamethods, and access to objects with no metatables does not fail (it simply results in nil). @@ -915,7 +914,7 @@

                      2.5.1 – Garbage-Collection Metamethods

                      When you close a state (see lua_close), -Lua calls the finalizers of all objects marked for collection, +Lua calls the finalizers of all objects marked for finalization, following the reverse order that they were marked. If any finalizer marks new objects for collection during that phase, these new objects will not be finalized. @@ -1255,8 +1254,7 @@

                      3.1 – Lexical Conventions

                      -When parsing a from a string source, -any byte in a literal string not +Any byte in a literal string not explicitly affected by the previous rules represents itself. However, Lua opens files for parsing in text mode, and the system file functions may have problems with @@ -1409,6 +1407,35 @@

                      3.3.1 – Blocks

                      stat ::= ‘;
                      +

                      +Function calls and assignments +can start with an open parenthesis. +This possibility leads to an ambiguity in Lua's grammar. +Consider the following fragment: + +

                      +     a = b + c
                      +     (print or io.write)('done')
                      +

                      +The grammar could see it in two ways: + +

                      +     a = b + c(print or io.write)('done')
                      +     
                      +     a = b + c; (print or io.write)('done')
                      +

                      +The current parser always sees such constructions +in the first way, +interpreting the open parenthesis +as the start of the arguments to a call. +To avoid this ambiguity, +it is a good practice to always precede with a semicolon +statements that start with a parenthesis: + +

                      +     ;(print or io.write)('done')
                      +
                      +

                      A block can be explicitly delimited to produce a single statement: @@ -1428,7 +1455,7 @@

                      3.3.1 – Blocks

                      3.3.2 – Chunks

                      -The unit of execution of Lua is called a chunk. +The unit of compilation of Lua is called a chunk. Syntactically, a chunk is simply a block: @@ -1859,7 +1886,8 @@

                      3.4 – Expressions

                      (unless the expression is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, -discarding all values except the first one. +either discarding all values except the first one +or adding a single nil if there are no values.

                      @@ -2559,32 +2587,35 @@

                      4.3 – Valid and Acceptable Indices

                      A valid index is an index that refers to a -valid position within the stack, that is, -it lies between 1 and the stack top +real position within the stack, that is, +its position lies between 1 and the stack top (1 ≤ abs(index) ≤ top). -Usually, functions that need a specific stack position -(e.g., lua_remove) require valid indices. +Usually, functions that can modify the value at an index +require valid indices. + + +

                      +Unless otherwise noted, +any function that accepts valid indices also accepts pseudo-indices, +which represent some Lua values that are accessible to C code +but which are not in the stack. +Pseudo-indices are used to access the registry +and the upvalues of a C function (see §4.4).

                      Functions that do not need a specific stack position, but only a value in the stack (e.g., query functions), can be called with acceptable indices. -An acceptable index refers to a position within -the space allocated for the stack, +An acceptable index can be any valid index, +including the pseudo-indices, +but it also can be any positive index after the stack top +within the space allocated for the stack, that is, indices up to the stack size. -More formally, we define an acceptable index -as follows: - -

                      -     (index < 0 && abs(index) <= top) ||
                      -     (index > 0 && index <= stack size)
                      -

                      (Note that 0 is never an acceptable index.) -When a function is called, -its stack size is top + LUA_MINSTACK. -You can change its stack size through function lua_checkstack. +Except when noted otherwise, +functions in the API work with acceptable indices.

                      @@ -2598,16 +2629,8 @@

                      4.3 – Valid and Acceptable Indices

                      For functions that can be called with acceptable indices, any non-valid index is treated as if it -contains a value of a virtual type LUA_TNONE. - - -

                      -Unless otherwise noted, -any function that accepts valid indices also accepts pseudo-indices, -which represent some Lua values that are accessible to C code -but which are not in the stack. -Pseudo-indices are used to access the registry -and the upvalues of a C function (see §4.4). +contains a value of a virtual type LUA_TNONE, +which behaves like a nil value. @@ -2628,13 +2651,13 @@

                      4.4 – C Closures

                      Whenever a C function is called, its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro -lua_upvalueindex. +lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), where n is greater than the number of upvalues of the current function (but not greater than 256), -produces an acceptable (but invalid) index. +produces an acceptable but invalid index. @@ -2647,7 +2670,8 @@

                      4.5 – Registry

                      a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index -LUA_REGISTRYINDEX. +LUA_REGISTRYINDEX, +which is a valid index. Any C library can store data into this table, but it should take care to choose keys that are different from those used @@ -2692,8 +2716,8 @@

                      4.6 – Error Handling in C

                      Internally, Lua uses the C longjmp facility to handle errors. -(You can also choose to use exceptions if you use C++; -see file luaconf.h.) +(You can also choose to use exceptions if you compile Lua as C++; +search for LUAI_THROW in the source code.) When Lua faces any error (such as a memory allocation error, type errors, syntax errors, and runtime errors) @@ -3136,8 +3160,8 @@

                      4.8 – Functions and Types

                      Compares two Lua values. -Returns 1 if the value at acceptable index index1 satisfies op -when compared with the value at acceptable index index2, +Returns 1 if the value at index index1 satisfies op +when compared with the value at index index2, following the semantics of the corresponding Lua operator (that is, it may call metamethods). Otherwise returns 0. @@ -3180,7 +3204,7 @@

                      4.8 – Functions and Types

                      void lua_copy (lua_State *L, int fromidx, int toidx);

                      -Moves the element at the valid index fromidx +Moves the element at index fromidx into the valid index toidx without shifting any element (therefore replacing the value at that position). @@ -3390,7 +3414,7 @@

                      4.8 – Functions and Types

                      Pushes onto the stack the value t[k], -where t is the value at the given valid index. +where t is the value at the given index. As in Lua, this function may trigger a metamethod for the "index" event (see §2.4). @@ -3414,8 +3438,7 @@

                      4.8 – Functions and Types

                      int lua_getmetatable (lua_State *L, int index);

                      -Pushes onto the stack the metatable of the value at the given -acceptable index. +Pushes onto the stack the metatable of the value at the given index. If the value does not have a metatable, the function returns 0 and pushes nothing on the stack. @@ -3429,7 +3452,7 @@

                      4.8 – Functions and Types

                      Pushes onto the stack the value t[k], -where t is the value at the given valid index +where t is the value at the given index and k is the value at the top of the stack. @@ -3477,7 +3500,7 @@

                      4.8 – Functions and Types

                      Moves the top element into the given valid index, shifting up the elements above this index to open space. -Cannot be called with a pseudo-index, +This function cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. @@ -3505,7 +3528,7 @@

                      4.8 – Functions and Types

                      int lua_isboolean (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a boolean, +Returns 1 if the value at the given index is a boolean, and 0 otherwise. @@ -3517,7 +3540,7 @@

                      4.8 – Functions and Types

                      int lua_iscfunction (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a C function, +Returns 1 if the value at the given index is a C function, and 0 otherwise. @@ -3529,7 +3552,7 @@

                      4.8 – Functions and Types

                      int lua_isfunction (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a function +Returns 1 if the value at the given index is a function (either C or Lua), and 0 otherwise. @@ -3541,7 +3564,7 @@

                      4.8 – Functions and Types

                      int lua_islightuserdata (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a light userdata, +Returns 1 if the value at the given index is a light userdata, and 0 otherwise. @@ -3553,7 +3576,7 @@

                      4.8 – Functions and Types

                      int lua_isnil (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is nil, +Returns 1 if the value at the given index is nil, and 0 otherwise. @@ -3565,8 +3588,7 @@

                      4.8 – Functions and Types

                      int lua_isnone (lua_State *L, int index);

                      -Returns 1 if the given acceptable index is not valid -(that is, it refers to an element outside the current stack), +Returns 1 if the given index is not valid, and 0 otherwise. @@ -3578,8 +3600,7 @@

                      4.8 – Functions and Types

                      int lua_isnoneornil (lua_State *L, int index);

                      -Returns 1 if the given acceptable index is not valid -(that is, it refers to an element outside the current stack) +Returns 1 if the given index is not valid or if the value at this index is nil, and 0 otherwise. @@ -3592,7 +3613,7 @@

                      4.8 – Functions and Types

                      int lua_isnumber (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a number +Returns 1 if the value at the given index is a number or a string convertible to a number, and 0 otherwise. @@ -3605,7 +3626,7 @@

                      4.8 – Functions and Types

                      int lua_isstring (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a string +Returns 1 if the value at the given index is a string or a number (which is always convertible to a string), and 0 otherwise. @@ -3618,7 +3639,7 @@

                      4.8 – Functions and Types

                      int lua_istable (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a table, +Returns 1 if the value at the given index is a table, and 0 otherwise. @@ -3630,7 +3651,7 @@

                      4.8 – Functions and Types

                      int lua_isthread (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a thread, +Returns 1 if the value at the given index is a thread, and 0 otherwise. @@ -3642,7 +3663,7 @@

                      4.8 – Functions and Types

                      int lua_isuserdata (lua_State *L, int index);

                      -Returns 1 if the value at the given acceptable index is a userdata +Returns 1 if the value at the given index is a userdata (either full or light), and 0 otherwise. @@ -3654,7 +3675,7 @@

                      4.8 – Functions and Types

                      void lua_len (lua_State *L, int index);

                      -Returns the "length" of the value at the given acceptable index; +Returns the "length" of the value at the given index; it is equivalent to the '#' operator in Lua (see §3.4.6). The result is pushed on the stack. @@ -3718,6 +3739,12 @@

                      4.8 – Functions and Types

                      a NULL value is equivalent to the string "bt". +

                      +lua_load uses the stack internally, +so the reader function should always leave the stack +unmodified when returning. + +

                      If the resulting function has one upvalue, this upvalue is set to the value of the global environment @@ -4038,7 +4065,7 @@

                      4.8 – Functions and Types

                      Pushes onto the stack a formatted string and returns a pointer to this string. -It is similar to the C function sprintf, +It is similar to the ANSI C function sprintf, but has some important differences:

                        @@ -4066,6 +4093,17 @@

                        4.8 – Functions and Types

                        +

                        lua_pushglobaltable

                        +[-0, +1, –] +

                        void lua_pushglobaltable (lua_State *L);
                        + +

                        +Pushes the global environment onto the stack. + + + + +


                        lua_pushinteger

                        [-0, +1, –]

                        void lua_pushinteger (lua_State *L, lua_Integer n);
                        @@ -4189,12 +4227,23 @@

                        4.8 – Functions and Types

                        +

                        lua_pushunsigned

                        +[-0, +1, –] +

                        void lua_pushunsigned (lua_State *L, lua_Unsigned n);
                        + +

                        +Pushes a number with value n onto the stack. + + + + +


                        lua_pushvalue

                        [-0, +1, –]

                        void lua_pushvalue (lua_State *L, int index);

                        -Pushes a copy of the element at the given valid index +Pushes a copy of the element at the given index onto the stack. @@ -4220,7 +4269,7 @@

                        4.8 – Functions and Types

                        int lua_rawequal (lua_State *L, int index1, int index2);

                        -Returns 1 if the two values in acceptable indices index1 and +Returns 1 if the two values in indices index1 and index2 are primitively equal (that is, without calling metamethods). Otherwise returns 0. @@ -4248,7 +4297,7 @@

                        4.8 – Functions and Types

                        Pushes onto the stack the value t[n], -where t is the table at the given valid index. +where t is the table at the given index. The access is raw; that is, it does not invoke metamethods. @@ -4262,7 +4311,7 @@

                        4.8 – Functions and Types

                        Pushes onto the stack the value t[k], -where t is the table at the given valid index and +where t is the table at the given index and k is the pointer p represented as a light userdata. The access is raw; that is, it does not invoke metamethods. @@ -4276,7 +4325,7 @@

                        4.8 – Functions and Types

                        size_t lua_rawlen (lua_State *L, int index);

                        -Returns the raw "length" of the value at the given acceptable index: +Returns the raw "length" of the value at the given index: for strings, this is the string length; for tables, this is the result of the length operator ('#') with no metamethods; @@ -4306,7 +4355,7 @@

                        4.8 – Functions and Types

                        Does the equivalent of t[n] = v, -where t is the table at the given valid index +where t is the table at the given index and v is the value at the top of the stack. @@ -4325,7 +4374,7 @@

                        4.8 – Functions and Types

                        Does the equivalent of t[k] = v, -where t is the table at the given valid index, +where t is the table at the given index, k is the pointer p represented as a light userdata, and v is the value at the top of the stack. @@ -4384,7 +4433,7 @@

                        4.8 – Functions and Types

                        Removes the element at the given valid index, shifting down the elements above this index to fill the gap. -Cannot be called with a pseudo-index, +This function cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. @@ -4396,9 +4445,9 @@

                        4.8 – Functions and Types

                        void lua_replace (lua_State *L, int index);

                        -Moves the top element into the given position +Moves the top element into the given valid index without shifting any element -(therefore replacing the value at the given position), +(therefore replacing the value at the given index), and then pops the top element. @@ -4436,7 +4485,9 @@

                        4.8 – Functions and Types

                        -To resume a coroutine, you put on its stack only the values to +To resume a coroutine, +you remove any results from the last lua_yield, +put on its stack only the values to be passed as results from yield, and then call lua_resume. @@ -4468,7 +4519,7 @@

                        4.8 – Functions and Types

                        Does the equivalent to t[k] = v, -where t is the value at the given valid index +where t is the value at the given index and v is the value at the top of the stack. @@ -4499,8 +4550,7 @@

                        4.8 – Functions and Types

                        Pops a table from the stack and -sets it as the new metatable for the value at the given -acceptable index. +sets it as the new metatable for the value at the given index. @@ -4512,7 +4562,7 @@

                        4.8 – Functions and Types

                        Does the equivalent to t[k] = v, -where t is the value at the given valid index, +where t is the value at the given index, v is the value at the top of the stack, and k is the value just below the top. @@ -4531,7 +4581,7 @@

                        4.8 – Functions and Types

                        void lua_settop (lua_State *L, int index);

                        -Accepts any acceptable index, or 0, +Accepts any index, or 0, and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. @@ -4603,13 +4653,12 @@

                        4.8 – Functions and Types

                        int lua_toboolean (lua_State *L, int index);

                        -Converts the Lua value at the given acceptable index to a C boolean +Converts the Lua value at the given index to a C boolean value (0 or 1). Like all tests in Lua, lua_toboolean returns true for any Lua value different from false and nil; otherwise it returns false. -It also returns false when called with a non-valid index. (If you want to accept only actual boolean values, use lua_isboolean to test the value's type.) @@ -4622,7 +4671,7 @@

                        4.8 – Functions and Types

                        lua_CFunction lua_tocfunction (lua_State *L, int index);

                        -Converts a value at the given acceptable index to a C function. +Converts a value at the given index to a C function. That value must be a C function; otherwise, returns NULL. @@ -4646,7 +4695,7 @@

                        4.8 – Functions and Types

                        lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);

                        -Converts the Lua value at the given acceptable index +Converts the Lua value at the given index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §3.4.2); @@ -4672,7 +4721,7 @@

                        4.8 – Functions and Types

                        const char *lua_tolstring (lua_State *L, int index, size_t *len);

                        -Converts the Lua value at the given acceptable index to a C string. +Converts the Lua value at the given index to a C string. If len is not NULL, it also sets *len with the string length. The Lua value must be a string or a number; @@ -4714,7 +4763,7 @@

                        4.8 – Functions and Types

                        lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);

                        -Converts the Lua value at the given acceptable index +Converts the Lua value at the given index to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number (see §3.4.2); @@ -4735,7 +4784,7 @@

                        4.8 – Functions and Types

                        const void *lua_topointer (lua_State *L, int index);

                        -Converts the value at the given acceptable index to a generic +Converts the value at the given index to a generic C pointer (void*). The value can be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. @@ -4766,7 +4815,7 @@

                        4.8 – Functions and Types

                        lua_State *lua_tothread (lua_State *L, int index);

                        -Converts the value at the given acceptable index to a Lua thread +Converts the value at the given index to a Lua thread (represented as lua_State*). This value must be a thread; otherwise, the function returns NULL. @@ -4791,7 +4840,7 @@

                        4.8 – Functions and Types

                        lua_Unsigned lua_tounsignedx (lua_State *L, int index, int *isnum);

                        -Converts the Lua value at the given acceptable index +Converts the Lua value at the given index to the unsigned integral type lua_Unsigned. The Lua value must be a number or a string convertible to a number (see §3.4.2); @@ -4820,7 +4869,7 @@

                        4.8 – Functions and Types

                        void *lua_touserdata (lua_State *L, int index);

                        -If the value at the given acceptable index is a full userdata, +If the value at the given index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. @@ -4835,8 +4884,8 @@

                        4.8 – Functions and Types

                        int lua_type (lua_State *L, int index);

                        -Returns the type of the value in the given acceptable index, -or LUA_TNONE for a non-valid index. +Returns the type of the value in the given valid index, +or LUA_TNONE for a non-valid (but acceptable) index. The types returned by lua_type are coded by the following constants defined in lua.h: LUA_TNIL, @@ -4882,6 +4931,18 @@

                        4.8 – Functions and Types

                        +

                        lua_upvalueindex

                        +[-0, +0, –] +

                        int lua_upvalueindex (int i);
                        + +

                        +Returns the pseudo-index that represents the i-th upvalue of +the running function (see §4.4). + + + + +


                        lua_version

                        [-0, +0, v]

                        const lua_Number *lua_version (lua_State *L);
                        @@ -6095,7 +6156,7 @@

                        5.1 – Functions and Types

                        Ensures that the value t[fname], -where t is the value at the valid index idx, +where t is the value at index idx, is a table, and pushes that table onto the stack. Returns true if it finds a previous table there @@ -6127,7 +6188,7 @@

                        5.1 – Functions and Types

                        int luaL_len (lua_State *L, int index);

                        -Returns the "length" of the value at the given acceptable index +Returns the "length" of the value at the given index as a number; it is equivalent to the '#' operator in Lua (see §3.4.6). Raises an error if the result of the operation is not a number. @@ -6242,7 +6303,7 @@

                        5.1 – Functions and Types


                        luaL_newlib

                        [-0, +1, e] -

                        int luaL_newlib (lua_State *L, const luaL_Reg *l);
                        +
                        void luaL_newlib (lua_State *L, const luaL_Reg *l);

                        Creates a new table and registers there @@ -6258,7 +6319,7 @@

                        5.1 – Functions and Types


                        luaL_newlibtable

                        [-0, +1, e] -

                        int luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
                        +
                        void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

                        Creates a new table with a size optimized @@ -6622,7 +6683,7 @@

                        5.1 – Functions and Types

                        const char *luaL_tolstring (lua_State *L, int idx, size_t *len);

                        -Converts any Lua value at the given acceptable index to a C string +Converts any Lua value at the given index to a C string in a reasonable format. The resulting string is pushed onto the stack and also returned by the function. @@ -6986,11 +7047,14 @@

                        6.1 – Basic Functions

                        If the resulting function has upvalues, -the first upvalue is set to the value of the -global environment or to env, -if that parameter is given. -When loading main chunks, -the first upvalue will be the _ENV variable (see §2.2). +the first upvalue is set to the value of env, +if that parameter is given, +or to the value of the global environment. +(When you load a main chunk, +the resulting function will always have exactly one upvalue, +the _ENV variable (see §2.2). +When you load a binary chunk created from a function (see string.dump), +the resulting function can have arbitrary upvalues.)

                        @@ -7510,7 +7574,6 @@

                        6.3 – Modules

                        -


                        package.loaded

                        @@ -7546,7 +7609,8 @@

                        6.3 – Modules

                        Otherwise, it looks for a function funcname inside the library and returns this function as a C function. -(So, funcname must follow the prototype lua_CFunction). +So, funcname must follow the lua_CFunction prototype +(see lua_CFunction).

                        @@ -7842,7 +7906,7 @@

                        6.4 – String Manipulation

                        Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). -The format string follows the same rules as the C function sprintf. +The format string follows the same rules as the ANSI C function sprintf. The only differences are that the options/modifiers *, h, L, l, n, and p are not supported @@ -8306,7 +8370,7 @@

                        6.5 – Table Manipulation

                        Given a list where all elements are strings or numbers, -returns list[i]..sep..list[i+1] ··· sep..list[j]. +returns the string list[i]..sep..list[i+1] ··· sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. @@ -8990,6 +9054,11 @@

                        6.8 – Input and Output Facilities

                        (plus an error message as a second result and a system-dependent error code as a third result) and some value different from nil on success. +On non-Posix systems, +the computation of the error message and error code +in case of errors +may be not thread safe, +because they rely on the global C variable errno.

                        @@ -9410,7 +9479,7 @@

                        6.9 – Operating System Facilities

                        If format is not "*t", then date returns the date as a string, -formatted according to the same rules as the C function strftime. +formatted according to the same rules as the ANSI C function strftime.

                        @@ -9421,8 +9490,9 @@

                        6.9 – Operating System Facilities

                        -On some systems, -this function may be not thread safe. +On non-Posix systems, +this function may be not thread safe +because of its reliance on C function gmtime and C function localtime. @@ -9444,7 +9514,7 @@

                        6.9 – Operating System Facilities

                        -This function is equivalent to the C function system. +This function is equivalent to the ANSI C function system. It passes command to be executed by an operating system shell. Its first result is true if the command terminated successfully, @@ -9479,7 +9549,7 @@

                        6.9 – Operating System Facilities

                        -Calls the C function exit to terminate the host program. +Calls the ANSI C function exit to terminate the host program. If code is true, the returned status is EXIT_SUCCESS; if code is false, @@ -9560,6 +9630,11 @@

                        6.9 – Operating System Facilities

                        for the given category. +

                        +This function may be not thread safe +because of its reliance on C function setlocale. + +

                        @@ -9746,7 +9821,7 @@

                        6.10 – The Debug Library

                        -Variable names starting with '(' (open parentheses) +Variable names starting with '(' (open parenthesis) represent internal variables (loop control variables, temporaries, varargs, and C function locals). @@ -10415,10 +10490,10 @@

                        9 – The Complete Syntax of Lua


                        Last update: -Fri Jun 8 16:13:40 BRT 2012 +Tue Feb 19 16:28:19 BRT 2013 diff --git a/doc/readme.html b/doc/readme.html index 2ff294ec37..d1ba13ad16 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -109,7 +109,7 @@

                        Building Lua

                        1. Open a terminal window and move to -the top-level directory, which is named lua-5.2.1. +the top-level directory, which is named lua-5.2.2. The Makefile there controls both the build process and the installation process.

                        2. @@ -372,7 +372,7 @@

                          License

                          this.
                          -Copyright © 1994–2012 Lua.org, PUC-Rio. +Copyright © 1994–2013 Lua.org, PUC-Rio.

                          Permission is hereby granted, free of charge, to any person obtaining a copy @@ -400,10 +400,10 @@

                          License


                          Last update: -Tue May 29 21:57:51 BRT 2012 +Tue Feb 19 15:13:26 BRT 2013 diff --git a/src/Makefile b/src/Makefile index 8c9ee677ee..fea895bc06 100644 --- a/src/Makefile +++ b/src/Makefile @@ -103,7 +103,7 @@ freebsd: generic: $(ALL) linux: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline -lncurses" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" macosx: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" diff --git a/src/lapi.c b/src/lapi.c index 1854fe6159..62807d591f 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.164 2012/06/08 15:14:04 roberto Exp $ +** $Id: lapi.c,v 2.170 2012/12/05 19:49:55 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -40,7 +40,16 @@ const char lua_ident[] = /* corresponding test */ #define isvalid(o) ((o) != luaO_nilobject) -#define api_checkvalidindex(L, i) api_check(L, isvalid(i), "invalid index") +/* test for pseudo index */ +#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) + +/* test for valid but not pseudo index */ +#define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) + +#define api_checkvalidindex(L, o) api_check(L, isvalid(o), "invalid index") + +#define api_checkstackindex(L, i, o) \ + api_check(L, isstackindex(i, o), "index not in the stack") static TValue *index2addr (lua_State *L, int idx) { @@ -51,7 +60,7 @@ static TValue *index2addr (lua_State *L, int idx) { if (o >= L->top) return NONVALIDVALUE; else return o; } - else if (idx > LUA_REGISTRYINDEX) { + else if (!ispseudo(idx)) { /* negative index */ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } @@ -142,7 +151,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) { ** convert an acceptable stack index into an absolute index */ LUA_API int lua_absindex (lua_State *L, int idx) { - return (idx > 0 || idx <= LUA_REGISTRYINDEX) + return (idx > 0 || ispseudo(idx)) ? idx : cast_int(L->top - L->ci->func + idx); } @@ -174,7 +183,7 @@ LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); p = index2addr(L, idx); - api_checkvalidindex(L, p); + api_checkstackindex(L, idx, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); @@ -186,8 +195,9 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId q; lua_lock(L); p = index2addr(L, idx); - api_checkvalidindex(L, p); - for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + api_checkstackindex(L, idx, p); + for (q = L->top; q > p; q--) /* use L->top as a temporary */ + setobjs2s(L, q, q - 1); setobjs2s(L, p, L->top); lua_unlock(L); } @@ -217,7 +227,6 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { TValue *fr; lua_lock(L); fr = index2addr(L, fromidx); - api_checkvalidindex(L, fr); moveto(L, fr, toidx); lua_unlock(L); } @@ -281,7 +290,7 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { } -LUA_API void lua_arith (lua_State *L, int op) { +LUA_API void lua_arith (lua_State *L, int op) { StkId o1; /* 1st operand */ StkId o2; /* 2nd operand */ lua_lock(L); @@ -295,7 +304,7 @@ LUA_API void lua_arith (lua_State *L, int op) { o1 = L->top - 2; o2 = L->top - 1; if (ttisnumber(o1) && ttisnumber(o2)) { - changenvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); + setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); } else luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); @@ -611,7 +620,6 @@ LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); - api_checkvalidindex(L, t); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } @@ -621,7 +629,6 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; lua_lock(L); t = index2addr(L, idx); - api_checkvalidindex(L, t); setsvalue2s(L, L->top, luaS_new(L, k)); api_incr_top(L); luaV_gettable(L, t, L->top - 1, L->top - 1); @@ -709,7 +716,6 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); - api_checkvalidindex(L, o); api_check(L, ttisuserdata(o), "userdata expected"); if (uvalue(o)->env) { sethvalue(L, L->top, uvalue(o)->env); @@ -743,7 +749,6 @@ LUA_API void lua_settable (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 2); t = index2addr(L, idx); - api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); @@ -755,7 +760,6 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); - api_checkvalidindex(L, t); setsvalue2s(L, L->top++, luaS_new(L, k)); luaV_settable(L, t, L->top - 1, L->top - 2); L->top -= 2; /* pop value and key */ @@ -811,7 +815,6 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { lua_lock(L); api_checknelems(L, 1); obj = index2addr(L, objindex); - api_checkvalidindex(L, obj); if (ttisnil(L->top - 1)) mt = NULL; else { @@ -821,9 +824,10 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { switch (ttypenv(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; - if (mt) + if (mt) { luaC_objbarrierback(L, gcvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); + } break; } case LUA_TUSERDATA: { @@ -850,7 +854,6 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); - api_checkvalidindex(L, o); api_check(L, ttisuserdata(o), "userdata expected"); if (ttisnil(L->top - 1)) uvalue(o)->env = NULL; @@ -937,7 +940,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, func = 0; else { StkId o = index2addr(L, errfunc); - api_checkvalidindex(L, o); + api_checkstackindex(L, errfunc, o); func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ @@ -1006,7 +1009,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { } -LUA_API int lua_status (lua_State *L) { +LUA_API int lua_status (lua_State *L) { return L->status; } @@ -1103,7 +1106,7 @@ LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); luaG_errormsg(L); - lua_unlock(L); + /* code unreacheable; will unlock when control actually leaves the kernel */ return 0; /* to avoid warnings */ } diff --git a/src/lauxlib.c b/src/lauxlib.c index 36ae7e629f..42521bcee4 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.244 2012/05/31 20:28:45 roberto Exp $ +** $Id: lauxlib.c,v 1.247 2012/10/19 15:55:01 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -84,7 +84,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) { if (*ar->namewhat != '\0') /* is there a name? */ lua_pushfstring(L, "function " LUA_QS, ar->name); else if (*ar->what == 'm') /* main? */ - lua_pushfstring(L, "main chunk"); + lua_pushliteral(L, "main chunk"); else if (*ar->what == 'C') { if (pushglobalfuncname(L, ar)) { lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); @@ -158,7 +158,8 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling " LUA_QS " on bad self", ar.name); + return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + ar.name, extramsg); } if (ar.name == NULL) ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; @@ -214,7 +215,7 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { if (fname) lua_pushfstring(L, "%s: %s", fname, strerror(en)); else - lua_pushfstring(L, "%s", strerror(en)); + lua_pushstring(L, strerror(en)); lua_pushinteger(L, en); return 3; } @@ -438,7 +439,7 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { if (B->size - B->n < sz) { /* not enough space? */ char *newbuff; size_t newsize = B->size * 2; /* double buffer size */ - if (newsize - B->n < sz) /* not bit enough? */ + if (newsize - B->n < sz) /* not big enough? */ newsize = B->n + sz; if (newsize < B->n || newsize - B->n < sz) luaL_error(L, "buffer too large"); diff --git a/src/lbaselib.c b/src/lbaselib.c index dbfcb02cfc..983ca712f1 100644 --- a/src/lbaselib.c +++ b/src/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.274 2012/04/27 14:13:19 roberto Exp $ +** $Id: lbaselib.c,v 1.275 2012/12/03 20:18:02 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -242,10 +242,16 @@ static int luaB_ipairs (lua_State *L) { } -static int load_aux (lua_State *L, int status) { - if (status == LUA_OK) +static int load_aux (lua_State *L, int status, int envidx) { + if (status == LUA_OK) { + if (envidx != 0) { /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } return 1; - else { + } + else { /* error (message is on top of the stack) */ lua_pushnil(L); lua_insert(L, -2); /* put before error message */ return 2; /* return nil plus error message */ @@ -256,13 +262,9 @@ static int load_aux (lua_State *L, int status) { static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); const char *mode = luaL_optstring(L, 2, NULL); - int env = !lua_isnone(L, 3); /* 'env' parameter? */ + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ int status = luaL_loadfilex(L, fname, mode); - if (status == LUA_OK && env) { /* 'env' parameter? */ - lua_pushvalue(L, 3); - lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */ - } - return load_aux(L, status); + return load_aux(L, status, env); } @@ -307,9 +309,9 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { static int luaB_load (lua_State *L) { int status; size_t l; - int top = lua_gettop(L); const char *s = lua_tolstring(L, 1, &l); const char *mode = luaL_optstring(L, 3, "bt"); + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ if (s != NULL) { /* loading a string? */ const char *chunkname = luaL_optstring(L, 2, s); status = luaL_loadbufferx(L, s, l, chunkname, mode); @@ -320,11 +322,7 @@ static int luaB_load (lua_State *L) { lua_settop(L, RESERVEDSLOT); /* create reserved slot */ status = lua_load(L, generic_reader, NULL, chunkname, mode); } - if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */ - lua_pushvalue(L, 4); /* environment for loaded function */ - lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */ - } - return load_aux(L, status); + return load_aux(L, status, env); } /* }====================================================== */ diff --git a/src/lcode.c b/src/lcode.c index 614e452f9c..56c26ac8aa 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.60 2011/08/30 16:26:41 roberto Exp $ +** $Id: lcode.c,v 2.62 2012/08/16 17:34:28 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -330,10 +330,9 @@ int luaK_numberK (FuncState *fs, lua_Number r) { setnvalue(&o, r); if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ /* use raw representation as key to avoid numeric problems */ - setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r))); - incr_top(L); - n = addk(fs, L->top - 1, &o); - L->top--; + setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r))); + n = addk(fs, L->top - 1, &o); + L->top--; } else n = addk(fs, &o, &o); /* regular case */ @@ -426,7 +425,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_nil(fs, reg, 1); break; } - case VFALSE: case VTRUE: { + case VFALSE: case VTRUE: { luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); break; } diff --git a/src/ldebug.c b/src/ldebug.c index 43f8f046ff..7e04f9d09f 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.89 2012/01/20 22:05:50 roberto Exp $ +** $Id: ldebug.c,v 2.90 2012/08/16 17:34:28 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -196,7 +196,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { static void collectvalidlines (lua_State *L, Closure *f) { if (noLuaClosure(f)) { setnilvalue(L->top); - incr_top(L); + api_incr_top(L); } else { int i; @@ -204,7 +204,7 @@ static void collectvalidlines (lua_State *L, Closure *f) { int *lineinfo = f->l.p->lineinfo; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue(L, L->top, t); /* push it on stack */ - incr_top(L); + api_incr_top(L); setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ @@ -285,7 +285,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { setobjs2s(L, L->top, func); - incr_top(L); + api_incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, cl); @@ -563,7 +563,7 @@ l_noret luaG_errormsg (lua_State *L) { if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ - incr_top(L); + L->top++; luaD_call(L, L->top - 2, 1, 0); /* call it */ } luaD_throw(L, LUA_ERRRUN); diff --git a/src/ldo.c b/src/ldo.c index d18e33cd41..aafa3dca23 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.105 2012/06/08 15:14:04 roberto Exp $ +** $Id: ldo.c,v 2.108 2012/10/01 14:05:04 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -311,6 +311,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->callstatus = 0; + luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); @@ -338,6 +339,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA; L->top = ci->top; + luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) callhook(L, ci); return 0; @@ -393,7 +395,6 @@ void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { luaV_execute(L); /* call it */ if (!allowyield) L->nny--; L->nCcalls--; - luaC_checkGC(L); } @@ -402,7 +403,11 @@ static void finishCcall (lua_State *L) { int n; lua_assert(ci->u.c.k != NULL); /* must have a continuation */ lua_assert(L->nny == 0); - /* finish 'lua_callk' */ + if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ + ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ + L->errfunc = ci->u.c.old_errfunc; + } + /* finish 'lua_callk'/'lua_pcall' */ adjustresults(L, ci->nresults); /* call continuation function */ if (!(ci->callstatus & CIST_STAT)) /* no call status? */ @@ -473,7 +478,7 @@ static int recover (lua_State *L, int status) { static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { L->top = firstArg; /* remove args from the stack */ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ - incr_top(L); + api_incr_top(L); luaD_throw(L, -1); /* jump back to 'lua_resume' */ } @@ -558,7 +563,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { api_checknelems(L, nresults); if (L->nny > 0) { if (L != G(L)->mainthread) - luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + luaG_runerror(L, "attempt to yield across a C-call boundary"); else luaG_runerror(L, "attempt to yield from outside a coroutine"); } diff --git a/src/lfunc.c b/src/lfunc.c index 4fd27fe5eb..c2128405b9 100644 --- a/src/lfunc.c +++ b/src/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.29 2012/05/08 13:53:33 roberto Exp $ +** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -52,12 +52,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { GCObject *o = obj2gco(p); lua_assert(p->v != &p->u.value); + lua_assert(!isold(o) || isold(obj2gco(L))); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, o)) /* is it dead? */ changewhite(o); /* resurrect it */ return p; } - resetoldbit(o); /* may create a newer upval after this one */ pp = &p->next; } /* not found: create a new one */ diff --git a/src/lgc.c b/src/lgc.c index 06f972a725..9eec6e374b 100644 --- a/src/lgc.c +++ b/src/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp $ +** $Id: lgc.c,v 2.138 2012/10/19 19:00:33 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -43,21 +43,12 @@ */ #define STEPMULADJ 200 + /* ** macro to adjust 'pause': 'pause' is actually used like ** 'pause / PAUSEADJ' (value chosen by tests) */ -#define PAUSEADJ 200 - - - - -/* -** standard negative debt for GC; a reasonable "time" to wait before -** starting a new cycle -*/ -#define stddebtest(g,e) (-cast(l_mem, (e)/PAUSEADJ) * g->gcpause) -#define stddebt(g) stddebtest(g, gettotalbytes(g)) +#define PAUSEADJ 100 /* @@ -144,9 +135,9 @@ static int iscleared (global_State *g, const TValue *o) { void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(isgenerational(g) || g->gcstate != GCSpause); + lua_assert(g->gcstate != GCSpause); lua_assert(gch(o)->tt != LUA_TTABLE); - if (keepinvariant(g)) /* must keep invariant? */ + if (keepinvariantout(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ else { /* sweep phase */ lua_assert(issweepphase(g)); @@ -343,7 +334,7 @@ static void remarkupvals (global_State *g) { ** mark root set and reset all gray lists, to start a new ** incremental (or full) collection */ -static void markroot (global_State *g) { +static void restartcollection (global_State *g) { g->gray = g->grayagain = NULL; g->weak = g->allweak = g->ephemeron = NULL; markobject(g, g->mainthread); @@ -796,7 +787,7 @@ static GCObject *udata2finalize (global_State *g) { g->allgc = o; resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */ lua_assert(!isold(o)); /* see MOVE OLD rule */ - if (!keepinvariant(g)) /* not keeping invariant? */ + if (!keepinvariantout(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ return o; } @@ -855,7 +846,7 @@ static void separatetobefnz (lua_State *L, int all) { while ((curr = *p) != NULL) { /* traverse all finalizable objects */ lua_assert(!isfinalized(curr)); lua_assert(testbit(gch(curr)->marked, SEPARATED)); - if (!(all || iswhite(curr))) /* not being collected? */ + if (!(iswhite(curr) || all)) /* not being collected? */ p = &gch(curr)->next; /* don't bother with it */ else { l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ @@ -891,7 +882,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ho->next = g->finobj; /* link it in list 'finobj' */ g->finobj = o; l_setbit(ho->marked, SEPARATED); /* mark it as such */ - if (!keepinvariant(g)) /* not keeping invariant? */ + if (!keepinvariantout(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ else resetoldbit(o); /* see MOVE OLD rule */ @@ -908,6 +899,21 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { */ +/* +** set a reasonable "time" to wait before starting a new GC cycle; +** cycle will start when memory use hits threshold +*/ +static void setpause (global_State *g, l_mem estimate) { + l_mem debt, threshold; + estimate = estimate / PAUSEADJ; /* adjust 'estimate' */ + threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ + ? estimate * g->gcpause /* no overflow */ + : MAX_LMEM; /* overflow; truncate to maximum */ + debt = -cast(l_mem, threshold - gettotalbytes(g)); + luaE_setdebt(g, debt); +} + + #define sweepphases \ (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) @@ -985,7 +991,7 @@ void luaC_freeallobjects (lua_State *L) { static l_mem atomic (lua_State *L) { global_State *g = G(L); - l_mem work = -g->GCmemtrav; /* start counting work */ + l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ GCObject *origweak, *origall; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ @@ -1028,12 +1034,10 @@ static lu_mem singlestep (lua_State *L) { global_State *g = G(L); switch (g->gcstate) { case GCSpause: { - g->GCmemtrav = 0; /* start to count memory traversed */ - if (!isgenerational(g)) - markroot(g); /* start a new collection */ - /* in any case, root must be marked at this point */ - lua_assert(!iswhite(obj2gco(g->mainthread)) - && !iswhite(gcvalue(&g->l_registry))); + /* start to count memory traversed */ + g->GCmemtrav = g->strt.size * sizeof(GCObject*); + lua_assert(!isgenerational(g)); + restartcollection(g); g->gcstate = GCSpropagate; return g->GCmemtrav; } @@ -1105,18 +1109,23 @@ void luaC_runtilstate (lua_State *L, int statesmask) { static void generationalcollection (lua_State *L) { global_State *g = G(L); + lua_assert(g->gcstate == GCSpropagate); if (g->GCestimate == 0) { /* signal for another major collection? */ luaC_fullgc(L, 0); /* perform a full regular collection */ g->GCestimate = gettotalbytes(g); /* update control */ } else { lu_mem estimate = g->GCestimate; - luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ - luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */ + g->gcstate = GCSpropagate; /* skip restart */ if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) g->GCestimate = 0; /* signal for a major collection */ + else + g->GCestimate = estimate; /* keep estimate from last major coll. */ + } - luaE_setdebt(g, stddebt(g)); + setpause(g, gettotalbytes(g)); + lua_assert(g->gcstate == GCSpropagate); } @@ -1124,7 +1133,7 @@ static void incstep (lua_State *L) { global_State *g = G(L); l_mem debt = g->GCdebt; int stepmul = g->gcstepmul; - if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values */ + if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */ /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ debt = (debt / STEPMULADJ) + 1; debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; @@ -1133,10 +1142,11 @@ static void incstep (lua_State *L) { debt -= work; } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); if (g->gcstate == GCSpause) - debt = stddebtest(g, g->GCestimate); /* pause until next cycle */ - else + setpause(g, g->GCestimate); /* pause until next cycle */ + else { debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ - luaE_setdebt(g, debt); + luaE_setdebt(g, debt); + } } @@ -1172,7 +1182,6 @@ void luaC_step (lua_State *L) { void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); int origkind = g->gckind; - int someblack = keepinvariant(g); lua_assert(origkind != KGC_EMERGENCY); if (isemergency) /* do not run finalizers during emergency GC */ g->gckind = KGC_EMERGENCY; @@ -1180,22 +1189,21 @@ void luaC_fullgc (lua_State *L, int isemergency) { g->gckind = KGC_NORMAL; callallpendingfinalizers(L, 1); } - if (someblack) { /* may there be some black objects? */ + if (keepinvariant(g)) { /* may there be some black objects? */ /* must sweep all objects to turn them back to white (as white has not changed, nothing will be collected) */ entersweep(L); } /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); - /* run entire collector */ - luaC_runtilstate(L, ~bitmask(GCSpause)); - luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ + luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */ if (origkind == KGC_GEN) { /* generational mode? */ - /* generational mode must always start in propagate phase */ + /* generational mode must be kept in propagate phase */ luaC_runtilstate(L, bitmask(GCSpropagate)); } g->gckind = origkind; - luaE_setdebt(g, stddebt(g)); + setpause(g, gettotalbytes(g)); if (!isemergency) /* do not run finalizers during emergency GC */ callallpendingfinalizers(L, 1); } diff --git a/src/lgc.h b/src/lgc.h index bdd5cce6cf..dee270b4dc 100644 --- a/src/lgc.h +++ b/src/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp $ +** $Id: lgc.h,v 2.58 2012/09/11 12:53:08 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -50,14 +50,24 @@ #define isgenerational(g) ((g)->gckind == KGC_GEN) /* -** macro to tell when main invariant (white objects cannot point to black +** macros to tell when main invariant (white objects cannot point to black ** ones) must be kept. During a non-generational collection, the sweep ** phase may break the invariant, as objects turned white may point to ** still-black objects. The invariant is restored when sweep ends and ** all objects are white again. During a generational collection, the ** invariant must be kept all times. */ -#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) + +#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) + + +/* +** Outside the collector, the state in generational mode is kept in +** 'propagate', so 'keepinvariant' is always true. +*/ +#define keepinvariantout(g) \ + check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \ + g->gcstate <= GCSatomic) /* diff --git a/src/llex.c b/src/llex.c index c4d8c65b6f..dbd253be19 100644 --- a/src/llex.c +++ b/src/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.61 2012/01/23 23:05:51 roberto Exp $ +** $Id: llex.c,v 2.62 2012/12/05 19:57:00 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -73,16 +73,16 @@ void luaX_init (lua_State *L) { const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { + if (token < FIRST_RESERVED) { /* single-byte symbols? */ lua_assert(token == cast(unsigned char, token)); return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : luaO_pushfstring(ls->L, "char(%d)", token); } else { const char *s = luaX_tokens[token - FIRST_RESERVED]; - if (token < TK_EOS) + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ return luaO_pushfstring(ls->L, LUA_QS, s); - else + else /* names, strings, and numerals */ return s; } } diff --git a/src/llimits.h b/src/llimits.h index fc9de1a11b..1eee993384 100644 --- a/src/llimits.h +++ b/src/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.99 2012/05/28 20:32:28 roberto Exp $ +** $Id: llimits.h,v 1.102 2013/01/29 16:00:40 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -200,7 +200,7 @@ typedef lu_int32 Instruction; ** both small and large values (outside the range of integers). */ -#if defined(MS_ASMTRICK) /* { */ +#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */ /* trick with Microsoft assembler for X86 */ #define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} @@ -256,7 +256,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #if !defined(lua_number2unsigned) /* { */ /* the following definition assures proper modulo behavior */ -#if defined(LUA_NUMBER_DOUBLE) +#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT) #include #define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) #define lua_number2unsigned(i,n) \ @@ -282,7 +282,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #include #define luai_hashnum(i,n) { int e; \ - n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ + n = l_tg(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ lua_number2int(i, n); i += e; } #endif diff --git a/src/lmathlib.c b/src/lmathlib.c index c3c605e86b..a703c33b74 100644 --- a/src/lmathlib.c +++ b/src/lmathlib.c @@ -1,5 +1,5 @@ /* -** $Id: lmathlib.c,v 1.81 2012/05/18 17:47:53 roberto Exp $ +** $Id: lmathlib.c,v 1.82 2013/01/29 16:00:40 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ @@ -17,106 +17,101 @@ #include "lualib.h" -/* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */ -#if !defined(l_tg) -#define l_tg(x) (x) -#endif - - #undef PI -#define PI (l_tg(3.1415926535897932384626433832795)) -#define RADIANS_PER_DEGREE (PI/180.0) +#define PI ((lua_Number)(3.1415926535897932384626433832795)) +#define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0)) static int math_abs (lua_State *L) { - lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { - lua_pushnumber(L, l_tg(sin)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); return 1; } static int math_sinh (lua_State *L) { - lua_pushnumber(L, l_tg(sinh)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { - lua_pushnumber(L, l_tg(cos)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); return 1; } static int math_cosh (lua_State *L) { - lua_pushnumber(L, l_tg(cosh)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { - lua_pushnumber(L, l_tg(tan)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); return 1; } static int math_tanh (lua_State *L) { - lua_pushnumber(L, l_tg(tanh)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { - lua_pushnumber(L, l_tg(asin)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { - lua_pushnumber(L, l_tg(acos)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { - lua_pushnumber(L, l_tg(atan)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { - lua_pushnumber(L, l_tg(atan2)(luaL_checknumber(L, 1), + lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_ceil (lua_State *L) { - lua_pushnumber(L, l_tg(ceil)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { - lua_pushnumber(L, l_tg(floor)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1))); return 1; } static int math_fmod (lua_State *L) { - lua_pushnumber(L, l_tg(fmod)(luaL_checknumber(L, 1), + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_modf (lua_State *L) { lua_Number ip; - lua_Number fp = l_tg(modf)(luaL_checknumber(L, 1), &ip); + lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; } static int math_sqrt (lua_State *L) { - lua_pushnumber(L, l_tg(sqrt)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { - lua_pushnumber(L, l_tg(pow)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); return 1; } @@ -124,11 +119,11 @@ static int math_log (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number res; if (lua_isnoneornil(L, 2)) - res = l_tg(log)(x); + res = l_mathop(log)(x); else { lua_Number base = luaL_checknumber(L, 2); - if (base == 10.0) res = l_tg(log10)(x); - else res = l_tg(log)(x)/l_tg(log)(base); + if (base == (lua_Number)10.0) res = l_mathop(log10)(x); + else res = l_mathop(log)(x)/l_mathop(log)(base); } lua_pushnumber(L, res); return 1; @@ -136,13 +131,13 @@ static int math_log (lua_State *L) { #if defined(LUA_COMPAT_LOG10) static int math_log10 (lua_State *L) { - lua_pushnumber(L, l_tg(log10)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); return 1; } #endif static int math_exp (lua_State *L) { - lua_pushnumber(L, l_tg(exp)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); return 1; } @@ -158,14 +153,15 @@ static int math_rad (lua_State *L) { static int math_frexp (lua_State *L) { int e; - lua_pushnumber(L, l_tg(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int math_ldexp (lua_State *L) { - lua_pushnumber(L, l_tg(ldexp)(luaL_checknumber(L, 1), - luaL_checkint(L, 2))); + lua_Number x = luaL_checknumber(L, 1); + lua_Number ep = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); return 1; } @@ -210,15 +206,15 @@ static int math_random (lua_State *L) { } case 1: { /* only upper limit */ lua_Number u = luaL_checknumber(L, 1); - luaL_argcheck(L, 1.0 <= u, 1, "interval is empty"); - lua_pushnumber(L, l_tg(floor)(r*u) + 1.0); /* int in [1, u] */ + luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty"); + lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */ break; } case 2: { /* lower and upper limits */ lua_Number l = luaL_checknumber(L, 1); lua_Number u = luaL_checknumber(L, 2); luaL_argcheck(L, l <= u, 2, "interval is empty"); - lua_pushnumber(L, l_tg(floor)(r*(u-l+1)) + l); /* int in [l, u] */ + lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */ break; } default: return luaL_error(L, "wrong number of arguments"); diff --git a/src/lmem.h b/src/lmem.h index 535dfe07f3..a57071a168 100644 --- a/src/lmem.h +++ b/src/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.38 2011/12/02 13:26:54 roberto Exp $ +** $Id: lmem.h,v 1.39 2012/11/14 17:21:34 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -14,10 +14,17 @@ #include "lua.h" +/* +** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is +** always constant. +** The macro is somewhat complex to avoid warnings: +** +1 avoids warnings of "comparsion has constant result"; +** cast to 'void' avoids warnings of "value unused". +*/ #define luaM_reallocv(L,b,on,n,e) \ - ((cast(size_t, (n)+1) > MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ - (luaM_toobig(L), (void *)0) : \ - luaM_realloc_(L, (b), (on)*(e), (n)*(e))) + (cast(void, \ + (cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e))) #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) diff --git a/src/lobject.c b/src/lobject.c index cf0f75446d..d82510bdff 100644 --- a/src/lobject.c +++ b/src/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.55 2011/11/30 19:30:16 roberto Exp $ +** $Id: lobject.c,v 2.57 2013/01/29 16:00:40 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -104,7 +104,7 @@ static int isneg (const char **s) { static lua_Number readhexa (const char **s, lua_Number r, int *count) { for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ - r = (r * 16.0) + cast_num(luaO_hexavalue(cast_uchar(**s))); + r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); (*count)++; } return r; @@ -149,7 +149,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { *endptr = cast(char *, s); /* valid up to here */ ret: if (neg) r = -r; - return ldexp(r, e); + return l_tg(ldexp)(r, e); } #endif @@ -171,8 +171,7 @@ int luaO_str2d (const char *s, size_t len, lua_Number *result) { static void pushstr (lua_State *L, const char *str, size_t l) { - setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); - incr_top(L); + setsvalue2s(L, L->top++, luaS_newlstr(L, str, l)); } @@ -182,8 +181,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); - incr_top(L); + luaD_checkstack(L, 2); /* fmt + item */ + pushstr(L, fmt, e - fmt); switch (*(e+1)) { case 's': { const char *s = va_arg(argp, char *); @@ -198,13 +197,11 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { break; } case 'd': { - setnvalue(L->top, cast_num(va_arg(argp, int))); - incr_top(L); + setnvalue(L->top++, cast_num(va_arg(argp, int))); break; } case 'f': { - setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); - incr_top(L); + setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber))); break; } case 'p': { @@ -226,6 +223,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { n += 2; fmt = e+2; } + luaD_checkstack(L, 1); pushstr(L, fmt, strlen(fmt)); if (n > 0) luaV_concat(L, n + 1); return svalue(L->top - 1); diff --git a/src/lobject.h b/src/lobject.h index ca75a028c2..dd23b9143c 100644 --- a/src/lobject.h +++ b/src/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.70 2012/05/11 14:10:50 roberto Exp $ +** $Id: lobject.h,v 2.71 2012/09/11 18:21:44 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -52,8 +52,7 @@ #define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ -/* -** LUA_TSTRING variants */ +/* Variant tags for strings */ #define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ #define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ @@ -188,8 +187,6 @@ typedef struct lua_TValue TValue; #define setnvalue(obj,x) \ { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); } -#define changenvalue(o,x) check_exp(ttisnumber(o), num_(o)=(x)) - #define setnilvalue(obj) settt_(obj, LUA_TNIL) #define setfvalue(obj,x) \ diff --git a/src/loslib.c b/src/loslib.c index 489755b6f5..5170fd0d0f 100644 --- a/src/loslib.c +++ b/src/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.39 2012/05/23 15:37:09 roberto Exp $ +** $Id: loslib.c,v 1.40 2012/10/19 15:54:02 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -98,7 +98,7 @@ static int os_remove (lua_State *L) { static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); - return luaL_fileresult(L, rename(fromname, toname) == 0, fromname); + return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } diff --git a/src/lparser.c b/src/lparser.c index b3eb3ca923..d8f5b4ffc5 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.128 2012/05/20 14:51:23 roberto Exp $ +** $Id: lparser.c,v 2.130 2013/02/06 13:37:39 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -245,7 +245,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { static int searchvar (FuncState *fs, TString *n) { int i; - for (i=fs->nactvar-1; i >= 0; i--) { + for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { if (luaS_eqstr(n, getlocvar(fs, i)->varname)) return i; } @@ -512,12 +512,15 @@ static Proto *addprototype (LexState *ls) { /* -** codes instruction to create new closure in parent function +** codes instruction to create new closure in parent function. +** The OP_CLOSURE instruction must use the last available register, +** so that, if it invokes the GC, the GC knows which registers +** are in use at that time. */ static void codeclosure (LexState *ls, expdesc *v) { FuncState *fs = ls->fs->prev; init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); - luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */ + luaK_exp2nextreg(fs, v); /* fix it at the last register */ } diff --git a/src/lstate.c b/src/lstate.c index 3c00c28559..207a106d5b 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.98 2012/05/30 12:33:44 roberto Exp $ +** $Id: lstate.c,v 2.99 2012/10/02 17:40:53 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -48,7 +48,7 @@ */ #if !defined(luai_makeseed) #include -#define luai_makeseed() cast(size_t, time(NULL)) +#define luai_makeseed() cast(unsigned int, time(NULL)) #endif diff --git a/src/lstate.h b/src/lstate.h index 29f810ba04..c8a31f5c0b 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.81 2012/06/08 15:14:04 roberto Exp $ +** $Id: lstate.h,v 2.82 2012/07/02 13:37:04 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -137,7 +137,7 @@ typedef struct global_State { UpVal uvhead; /* head of double-linked list of all open upvalues */ Mbuffer buff; /* temporary buffer for string concatenation */ int gcpause; /* size of pause between successive GCs */ - int gcmajorinc; /* how much to wait for a major GC (only in gen. mode) */ + int gcmajorinc; /* pause between major collections (only in gen. mode) */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ struct lua_State *mainthread; diff --git a/src/lstring.c b/src/lstring.c index 8b959f19d0..8b5af0b2e7 100644 --- a/src/lstring.c +++ b/src/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.24 2012/05/11 14:14:42 roberto Exp $ +** $Id: lstring.c,v 2.26 2013/01/08 13:50:10 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -49,7 +49,7 @@ int luaS_eqstr (TString *a, TString *b) { unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { - unsigned int h = seed ^ l; + unsigned int h = seed ^ cast(unsigned int, l); size_t l1; size_t step = (l >> LUAI_HASHLIMIT) + 1; for (l1 = l; l1 >= step; l1 -= step) @@ -139,7 +139,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { o = gch(o)->next) { TString *ts = rawgco2ts(o); if (h == ts->tsv.hash && - ts->tsv.len == l && + l == ts->tsv.len && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ changewhite(o); /* resurrect it */ diff --git a/src/lstrlib.c b/src/lstrlib.c index e13098bb6e..fcc61c9a62 100644 --- a/src/lstrlib.c +++ b/src/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.176 2012/05/23 15:37:09 roberto Exp $ +** $Id: lstrlib.c,v 1.178 2012/08/14 18:12:34 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -194,7 +194,9 @@ static int str_dump (lua_State *L) { #define CAP_UNFINISHED (-1) #define CAP_POSITION (-2) + typedef struct MatchState { + int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ const char *src_init; /* init of source string */ const char *src_end; /* end ('\0') of source string */ const char *p_end; /* end ('\0') of pattern */ @@ -207,6 +209,16 @@ typedef struct MatchState { } MatchState; +/* recursive function */ +static const char *match (MatchState *ms, const char *s, const char *p); + + +/* maximum recursion depth for 'match' */ +#if !defined(MAXCCALLS) +#define MAXCCALLS 200 +#endif + + #define L_ESC '%' #define SPECIALS "^$*+?.([%-" @@ -294,19 +306,22 @@ static int matchbracketclass (int c, const char *p, const char *ec) { } -static int singlematch (int c, const char *p, const char *ep) { - switch (*p) { - case '.': return 1; /* matches any char */ - case L_ESC: return match_class(c, uchar(*(p+1))); - case '[': return matchbracketclass(c, p, ep-1); - default: return (uchar(*p) == c); +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } } } -static const char *match (MatchState *ms, const char *s, const char *p); - - static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (p >= ms->p_end - 1) @@ -331,7 +346,7 @@ static const char *matchbalance (MatchState *ms, const char *s, static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { ptrdiff_t i = 0; /* counts maximum expand for item */ - while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) + while (singlematch(ms, s + i, p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { @@ -349,7 +364,7 @@ static const char *min_expand (MatchState *ms, const char *s, const char *res = match(ms, s, ep+1); if (res != NULL) return res; - else if (ssrc_end && singlematch(uchar(*s), p, ep)) + else if (singlematch(ms, s, p, ep)) s++; /* try with one more repetition */ else return NULL; } @@ -393,79 +408,105 @@ static const char *match_capture (MatchState *ms, const char *s, int l) { static const char *match (MatchState *ms, const char *s, const char *p) { + if (ms->matchdepth-- == 0) + luaL_error(ms->L, "pattern too complex"); init: /* using goto's to optimize tail recursion */ - if (p == ms->p_end) /* end of pattern? */ - return s; /* match succeeded */ - switch (*p) { - case '(': { /* start capture */ - if (*(p+1) == ')') /* position capture? */ - return start_capture(ms, s, p+2, CAP_POSITION); - else - return start_capture(ms, s, p+1, CAP_UNFINISHED); - } - case ')': { /* end capture */ - return end_capture(ms, s, p+1); - } - case '$': { - if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */ - return (s == ms->src_end) ? s : NULL; /* check end of string */ - else goto dflt; - } - case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ - switch (*(p+1)) { - case 'b': { /* balanced string? */ - s = matchbalance(ms, s, p+2); - if (s == NULL) return NULL; - p+=4; goto init; /* else return match(ms, s, p+4); */ - } - case 'f': { /* frontier? */ - const char *ep; char previous; - p += 2; - if (*p != '[') - luaL_error(ms->L, "missing " LUA_QL("[") " after " - LUA_QL("%%f") " in pattern"); - ep = classend(ms, p); /* points to what is next */ - previous = (s == ms->src_init) ? '\0' : *(s-1); - if (matchbracketclass(uchar(previous), p, ep-1) || - !matchbracketclass(uchar(*s), p, ep-1)) return NULL; - p=ep; goto init; /* else return match(ms, s, ep); */ - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p+1))); - if (s == NULL) return NULL; - p+=2; goto init; /* else return match(ms, s, p+2) */ - } - default: goto dflt; + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; } - } - default: dflt: { /* pattern class plus optional suffix */ - const char *ep = classend(ms, p); /* points to what is next */ - int m = s < ms->src_end && singlematch(uchar(*s), p, ep); - switch (*ep) { - case '?': { /* optional */ - const char *res; - if (m && ((res=match(ms, s+1, ep+1)) != NULL)) - return res; - p=ep+1; goto init; /* else return match(ms, s, ep+1); */ - } - case '*': { /* 0 or more repetitions */ - return max_expand(ms, s, p, ep); - } - case '+': { /* 1 or more repetitions */ - return (m ? max_expand(ms, s+1, p, ep) : NULL); + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing " LUA_QL("[") " after " + LUA_QL("%%f") " in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; } - case '-': { /* 0 or more repetitions (minimum) */ - return min_expand(ms, s, p, ep); + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ } - default: { - if (!m) return NULL; - s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* go through */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } } + break; } } } + ms->matchdepth++; + return s; } @@ -561,12 +602,14 @@ static int str_find_aux (lua_State *L, int find) { p++; lp--; /* skip anchor character */ } ms.L = L; + ms.matchdepth = MAXCCALLS; ms.src_init = s; ms.src_end = s + ls; ms.p_end = p + lp; do { const char *res; ms.level = 0; + lua_assert(ms.matchdepth == MAXCCALLS); if ((res=match(&ms, s1, p)) != NULL) { if (find) { lua_pushinteger(L, s1 - s + 1); /* start */ @@ -600,6 +643,7 @@ static int gmatch_aux (lua_State *L) { const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); const char *src; ms.L = L; + ms.matchdepth = MAXCCALLS; ms.src_init = s; ms.src_end = s+ls; ms.p_end = p + lp; @@ -608,6 +652,7 @@ static int gmatch_aux (lua_State *L) { src++) { const char *e; ms.level = 0; + lua_assert(ms.matchdepth == MAXCCALLS); if ((e = match(&ms, src, p)) != NULL) { lua_Integer newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ @@ -705,12 +750,14 @@ static int str_gsub (lua_State *L) { p++; lp--; /* skip anchor character */ } ms.L = L; + ms.matchdepth = MAXCCALLS; ms.src_init = src; ms.src_end = src+srcl; ms.p_end = p + lp; while (n < max_s) { const char *e; ms.level = 0; + lua_assert(ms.matchdepth == MAXCCALLS); e = match(&ms, src, p); if (e) { n++; @@ -867,7 +914,7 @@ static int str_format (lua_State *L) { nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } - case 'd': case 'i': { + case 'd': case 'i': { lua_Number n = luaL_checknumber(L, arg); LUA_INTFRM_T ni = (LUA_INTFRM_T)n; lua_Number diff = n - (lua_Number)ni; @@ -877,7 +924,7 @@ static int str_format (lua_State *L) { nb = sprintf(buff, form, ni); break; } - case 'o': case 'u': case 'x': case 'X': { + case 'o': case 'u': case 'x': case 'X': { lua_Number n = luaL_checknumber(L, arg); unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; lua_Number diff = n - (lua_Number)ni; @@ -887,7 +934,7 @@ static int str_format (lua_State *L) { nb = sprintf(buff, form, ni); break; } - case 'e': case 'E': case 'f': + case 'e': case 'E': case 'f': #if defined(LUA_USE_AFORMAT) case 'a': case 'A': #endif diff --git a/src/ltable.c b/src/ltable.c index ffa5ecb36a..420391fc74 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.71 2012/05/23 15:37:09 roberto Exp $ +** $Id: ltable.c,v 2.72 2012/09/11 19:37:16 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -480,13 +480,13 @@ const TValue *luaH_getstr (Table *t, TString *key) { */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TNIL: return luaO_nilobject; case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); + case LUA_TNIL: return luaO_nilobject; case LUA_TNUMBER: { int k; lua_Number n = nvalue(key); lua_number2int(k, n); - if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ + if (luai_numeq(cast_num(k), n)) /* index is int? */ return luaH_getint(t, k); /* use specialized version */ /* else go through */ } diff --git a/src/ltablib.c b/src/ltablib.c index a52add03da..41f5df800f 100644 --- a/src/ltablib.c +++ b/src/ltablib.c @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.63 2011/11/28 17:26:30 roberto Exp $ +** $Id: ltablib.c,v 1.64 2013/02/06 18:29:03 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -16,8 +16,8 @@ #include "lualib.h" -#define aux_getn(L,n) \ - (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) +#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) + #if defined(LUA_COMPAT_MAXN) @@ -49,7 +49,7 @@ static int tinsert (lua_State *L) { case 3: { int i; pos = luaL_checkint(L, 2); /* 2nd argument is the position */ - if (pos > e) e = pos; /* `grow' array if necessary */ + luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ lua_rawgeti(L, 1, i-1); lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ @@ -66,17 +66,19 @@ static int tinsert (lua_State *L) { static int tremove (lua_State *L) { - int e = aux_getn(L, 1); - int pos = luaL_optint(L, 2, e); - if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ - return 0; /* nothing to remove */ + int size = aux_getn(L, 1); + int pos = luaL_optint(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); + else if (size == 0) /* empty table? */ + return 0; /* return nothing (nil) */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos 0 && b[l-1] == '\n') /* line ends with newline? */ diff --git a/src/lua.h b/src/lua.h index a3a3a70c69..8765f53b13 100644 --- a/src/lua.h +++ b/src/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.283 2012/04/20 13:18:26 roberto Exp $ +** $Id: lua.h,v 1.284 2013/02/19 18:39:04 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -19,11 +19,11 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" #define LUA_VERSION_NUM 502 -#define LUA_VERSION_RELEASE "1" +#define LUA_VERSION_RELEASE "2" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2012 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -413,7 +413,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2012 Lua.org, PUC-Rio. +* Copyright (C) 1994-2013 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/luaconf.h b/src/luaconf.h index e4335df904..46eeb2dd93 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.172 2012/05/11 14:14:42 roberto Exp $ +** $Id: luaconf.h,v 1.175 2013/01/29 16:00:40 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -405,10 +405,16 @@ #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ +/* +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations +*/ +#define l_mathop(x) (x) + + /* @@ lua_str2number converts a decimal numeric string to a number. @@ lua_strx2number converts an hexadecimal numeric string to a number. -** In C99, 'strtod' do both conversions. C89, however, has no function +** In C99, 'strtod' does both conversions. C89, however, has no function ** to convert floating hexadecimal strings to numbers. For these ** systems, you can leave 'lua_strx2number' undefined and Lua will ** provide its own implementation. @@ -427,8 +433,8 @@ /* the following operations need the math library */ #if defined(lobject_c) || defined(lvm_c) #include -#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) -#define luai_numpow(L,a,b) (pow(a,b)) +#define luai_nummod(L,a,b) ((a) - l_mathop(floor)((a)/(b))*(b)) +#define luai_numpow(L,a,b) (l_mathop(pow)(a,b)) #endif /* these are quite standard operations */ @@ -465,13 +471,12 @@ ** Some tricks with doubles */ -#if defined(LUA_CORE) && \ - defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ +#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ /* ** The next definitions activate some tricks to speed up the ** conversion from doubles to integer types, mainly to LUA_UNSIGNED. ** -@@ MS_ASMTRICK uses Microsoft assembler to avoid clashes with a +@@ LUA_MSASMTRICK uses Microsoft assembler to avoid clashes with a ** DirectX idiosyncrasy. ** @@ LUA_IEEE754TRICK uses a trick that should work on any machine @@ -495,7 +500,7 @@ /* Microsoft compiler on a Pentium (32 bit) ? */ #if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ -#define MS_ASMTRICK +#define LUA_MSASMTRICK #define LUA_IEEEENDIAN 0 #define LUA_NANTRICK diff --git a/src/lvm.c b/src/lvm.c index b77eac26d0..9713baf551 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.152 2012/06/08 15:14:04 roberto Exp $ +** $Id: lvm.c,v 2.154 2012/08/16 17:34:28 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -98,7 +98,6 @@ static void callTM (lua_State *L, const TValue *f, const TValue *p1, setobj2s(L, L->top++, p2); /* 2nd argument */ if (!hasres) /* no result? 'p3' is third argument */ setobj2s(L, L->top++, p3); /* 3rd argument */ - luaD_checkstack(L, 0); /* metamethod may yield only when called from Lua code */ luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); if (hasres) { /* if has result, move it to its place */ @@ -470,7 +469,7 @@ void luaV_finishOp (lua_State *L) { L->top = ci->top; /* adjust results */ break; } - case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: + case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: break; default: lua_assert(0); } diff --git a/src/lvm.h b/src/lvm.h index ec35822406..07e25f9c64 100644 --- a/src/lvm.h +++ b/src/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.17 2011/05/31 18:27:56 roberto Exp $ +** $Id: lvm.h,v 2.18 2013/01/08 14:06:55 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -19,8 +19,7 @@ #define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2)) -#define luaV_rawequalobj(t1,t2) \ - (ttisequal(t1,t2) && luaV_equalobj_(NULL,t1,t2)) +#define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2) /* not to called directly */ From 00ce46285bde86085185308a4197c15bc0b642bd Mon Sep 17 00:00:00 2001 From: Lua Team Date: Fri, 22 Feb 2013 12:00:00 +0000 Subject: [PATCH 78/97] Lua 5.2.2-rc2 --- README | 2 +- doc/readme.html | 4 +++- src/lbaselib.c | 5 +++-- src/lbitlib.c | 4 ++-- src/lcorolib.c | 4 ++-- src/llimits.h | 4 ++-- src/lmem.h | 4 ++-- src/lobject.c | 4 ++-- 8 files changed, 17 insertions(+), 14 deletions(-) diff --git a/README b/README index 202863211f..545f3249a0 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Lua 5.2.2, released on 20 Feb 2013. +This is Lua 5.2.2, released on 22 Feb 2013. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/doc/readme.html b/doc/readme.html index d1ba13ad16..5b9e47ecba 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -140,6 +140,8 @@

                          Building Lua

                          If you're running Linux and get compilation errors, make sure you have installed the readline development package. +If you get link errors after that, +then try "make linux MYLIBS=-ltermcap".

                          Installing Lua

                          @@ -400,7 +402,7 @@

                          License


                          Last update: -Tue Feb 19 15:13:26 BRT 2013 +Fri Feb 22 09:24:20 BRT 2013

                          - + @@ -8412,10 +8412,17 @@

                          6.5 – Table Manipulation

                          Removes from list the element at position pos, -shifting down the elements +returning the value of the removed element. +When pos is an integer between 1 and #list, +it shifts down the elements list[pos+1], list[pos+2], ···, list[#list] -and erasing element list[#list]. -Returns the value of the removed element. +and erases element list[#list]; +The index pos can also be 0, when #list is 0, +or #list + 1; +in those cases, the function erases the element list[pos]. + + +

                          The default value for pos is #list, so that a call table.remove(t) removes the last element of list t. @@ -10490,7 +10497,7 @@

                          9 – The Complete Syntax of Lua


                          Last update: -Tue Feb 19 16:28:19 BRT 2013 +Thu Mar 7 15:36:34 BRT 2013

                          - + @@ -8417,7 +8417,7 @@

                          6.5 – Table Manipulation

                          it shifts down the elements list[pos+1], list[pos+2], ···, list[#list] and erases element list[#list]; -The index pos can also be 0, when #list is 0, +The index pos can also be 0 when #list is 0, or #list + 1; in those cases, the function erases the element list[pos]. @@ -10497,7 +10497,7 @@

                          9 – The Complete Syntax of Lua


                          Last update: -Thu Mar 7 15:36:34 BRT 2013 +Thu Mar 21 12:58:59 BRT 2013 diff --git a/doc/manual.html b/doc/manual.html index 85365363fb..eeacdcc996 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2,7 +2,7 @@ -Lua 5.2 Reference Manual +Lua 5.3 Reference Manual @@ -13,7 +13,7 @@

                          -Lua 5.2 Reference Manual +Lua 5.3 Reference Manual

                          by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes @@ -33,7 +33,7 @@

                          - + @@ -119,14 +119,11 @@

                          2.1 – Values and Types

                          Boolean is the type of the values false and true. Both nil and false make a condition false; any other value makes it true. -Number represents real (double-precision floating-point) numbers. -Operations on numbers follow the same rules of -the underlying C implementation, -which, in turn, usually follows the IEEE 754 standard. -(It is easy to build Lua interpreters that use other -internal representations for numbers, -such as single-precision floats or long integers; -see file luaconf.h.) +Number represents both integer numbers and +real (floating-point) numbers. +Standard Lua uses 64-bit integers and double-precision floats, +but it is easy to compile Lua so that it +uses 32-bit integers and single-precision floats. String represents immutable sequences of bytes. Lua is 8-bit clean: @@ -829,7 +826,7 @@

                          2.5 – Garbage Collection

                          -As an experimental feature in Lua 5.2, +As an experimental feature in Lua 5.3, you can change the collector's operation mode from incremental to generational. A generational collector assumes that most objects die young, @@ -1293,11 +1290,19 @@

                          3.1 – Lexical Conventions

                          Hexadecimal constants also accept an optional fractional part plus an optional binary exponent, marked by a letter 'p' or 'P'. -Examples of valid numerical constants are +A numeric constant with an fractional dot or an exponent +denotes a floating-point number; +otherwise it denotes an integer number. +Examples of valid integer constants are
                          -     3     3.0     3.1416     314.16e-2     0.31416E1
                          -     0xff  0x0.1E  0xA23p-4   0X1.921FB54442D18P+1
                          +     3   345   0xff   0xBEBADA
                          +

                          +Examples of valid floating-point constants are + +

                          +     3.0     3.1416     314.16e-2     0.31416E1     34e1
                          +     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1
                           

                          @@ -1923,38 +1928,113 @@

                          3.4 – Expressions

                          3.4.1 – Arithmetic Operators

                          -Lua supports the usual arithmetic operators: +Lua supports the following arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), -/ (division), % (modulo), and ^ (exponentiation); +/ (division), // (integer division), +% (modulo), and ^ (exponentiation); and unary - (mathematical negation). -If the operands are numbers, or strings that can be converted to +Modulo is defined as the remainder of a division +that rounds the quotient towards minus infinite (floor). + + +

                          +With the exception of division, integer division, and exponentiation, +the arithmetic operators work as follows: +If both operands are integers, +the operation is performed over integers and the result is an integer. +Otherwise, if both operands are numbers +or strings that can be converted to numbers (see §3.4.2), -then all operations have the usual meaning. -Exponentiation works for any exponent. -For instance, x^(-0.5) computes the inverse of the square root of x. -Modulo is defined as +then they are converted to floating-point numbers, +the operation is performed following the usual rules +for floating-point arithmetic +(usually following the IEEE 754 standard), +and the result is a floating-point number. -

                          -     a % b == a - math.floor(a/b)*b
                          -

                          -That is, it is the remainder of a division that rounds -the quotient towards minus infinity. + +

                          +Division (/) always converts its operands to floating-point numbers +and its result is always a floating-point number. + + +

                          +Integer division (//) converts its operands to integer numbers +(see §3.4.2) +and its result is always an integer number. +The result is always rounded towards minus infinite (floor). +

                          +Exponentiation (^) checks whether both operands are integers and +the exponent is non-negative. +In that case, the exponentiation is performed as an integer operation +and the result is an integer number. +Otherwise, it is performed as a floatint-point operation (pow). + + +

                          +In case of overflows in integer arithmetic, +all operations wrap around, +according to the usual rules of two-complement arithmetic. -

                          3.4.2 – Coercion

                          + + +

                          3.4.2 – Coercions and Conversions

                          -Lua provides automatic conversion between -string and number values at run time. -Any arithmetic operation applied to a string tries to convert -this string to a number, following the rules of the Lua lexer. +Lua provides some automatic conversions between types at run time. +Most binary operations applied to mixed numbers +(integers and floats) convert the integer operand to a float; +this is called the usual rule. +Division always convert integer operands to floats, +and integer division always convert floating operands to integers. +The C API also converts both integers to floats and +floats to integers, as needed. +Moreover, string concatenation accepts numbers as arguments, +besides strings. + + +

                          +Lua also converts strings to numbers, +whenever a number is expected. +(This conversion may be deprecated in future versions.) + + +

                          +In a conversion from integer to float, +if the integer value has an exact representation as a float, +that is the result. +Otherwise, +the conversion gets the nearest higher or lower representable value. +This kind of conversion never fails. + + +

                          +The conversion from float to integer +first takes the floor of the float number. +If that value can be represented as an integer number +(that is, it is in the range of integer numbers), +that is the result. +Otherwise, the conversion fails. + + +

                          +The conversion from strings to floats +follows the rules of the Lua lexer. (The string may have leading and trailing spaces and a sign.) -Conversely, whenever a number is used where a string is expected, -the number is converted to a string, in a reasonable format. +There is no direct conversion from strings to integers: +If a string is provided where an integer is needed, +Lua converts the string to a float an then the float to an integer. + + +

                          +The conversion from numbers to strings use a reasonable, +non-specified format. +Floating-point numbers always produce strings with some +floating-point indication (either a decimal dot or an exponent). For complete control over how numbers are converted to strings, use the format function from the string library (see string.format). @@ -1976,7 +2056,15 @@

                          3.4.3 – Relational Operators

                          Equality (==) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. -Numbers and strings are compared in the usual way. +Strings are compared in the obvious way. +Numbers follow the usual rule for binary operations: +if both operands are integers, +the are compared as integers. +Otherwise, they are converted to floating-point numbers +and compared as such. + + +

                          Tables, userdata, and threads are compared by reference: two objects are considered equal only if they are the same object. @@ -1994,8 +2082,8 @@

                          3.4.3 – Relational Operators

                          -The conversion rules of §3.4.2 -do not apply to equality comparisons. +Equality comparisons never convert strings to numbers +or vice versa. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table. @@ -2007,7 +2095,9 @@

                          3.4.3 – Relational Operators

                          The order operators work as follows. -If both arguments are numbers, then they are compared as such. +If both arguments are numbers, +then they are compared following +the usual rule for binary operations. Otherwise, if both arguments are strings, then their values are compared according to the current locale. Otherwise, Lua tries to call the "lt" or the "le" @@ -2088,7 +2178,7 @@

                          3.4.6 – The Length Operator

                          table is a sequence, that is, the set of its positive numeric keys is equal to {1..n} -for some integer n. +for some non-negative integer n. In that case, n is its length. Note that a table like @@ -2116,7 +2206,7 @@

                          3.4.7 – Precedence

                          < > <= >= ~= == .. + - - * / % + * / // % not # - (unary) ^

                          @@ -3511,13 +3601,14 @@

                          4.8 – Functions and Types

                          typedef ptrdiff_t lua_Integer;

                          -The type used by the Lua API to represent signed integral values. +The type of integer numbers in Lua.

                          -By default it is a ptrdiff_t, -which is usually the largest signed integral type the machine handles -"comfortably". +By default it is defined as long long, +usually a 64-bit two-complement integer, +but it can also be long or int, +usually a 32-bit two-complement integer. @@ -3559,6 +3650,19 @@

                          4.8 – Functions and Types

                          +

                          lua_isinteger

                          +[-0, +0, –] +

                          int lua_isinteger (lua_State *L, int index);
                          + +

                          +Returns 1 if the value at the given index is an integer +(that is, the value is a number and is represented as an integer), +and 0 otherwise. + + + + +


                          lua_islightuserdata

                          [-0, +0, –]

                          int lua_islightuserdata (lua_State *L, int index);
                          @@ -3762,7 +3866,7 @@

                          4.8 – Functions and Types

                          Creates a new thread running in a new, independent state. -Returns NULL if cannot create the thread or the state +Returns NULL if it cannot create the thread or the state (due to lack of memory). The argument f is the allocator function; Lua does all memory allocation for this state through this function. @@ -3869,10 +3973,9 @@

                          4.8 – Functions and Types

                          typedef double lua_Number;

                          -The type of numbers in Lua. -By default, it is double, but that can be changed in luaconf.h. -Through this configuration file you can change -Lua to operate with another type for numbers (e.g., float or long). +The type of floating-point numbers in Lua. +By default, it is double, +but that can be changed in luaconf.h to a single float. @@ -4109,7 +4212,7 @@

                          4.8 – Functions and Types

                          void lua_pushinteger (lua_State *L, lua_Integer n);

                          -Pushes a number with value n onto the stack. +Pushes an integer with value n onto the stack. @@ -4293,7 +4396,7 @@

                          4.8 – Functions and Types


                          lua_rawgeti

                          [-0, +1, –] -

                          void lua_rawgeti (lua_State *L, int index, int n);
                          +
                          void lua_rawgeti (lua_State *L, int index, lua_Integer n);

                          Pushes onto the stack the value t[n], @@ -4351,7 +4454,7 @@

                          4.8 – Functions and Types


                          lua_rawseti

                          [-1, +0, e] -

                          void lua_rawseti (lua_State *L, int index, int n);
                          +
                          void lua_rawseti (lua_State *L, int index, lua_Integer n);

                          Does the equivalent of t[n] = v, @@ -4648,6 +4751,23 @@

                          4.8 – Functions and Types

                          +

                          lua_strtonum

                          +[-0, +1, –] +

                          int lua_strtonum (lua_State *L, const char *s, size_t len);
                          + +

                          +Converts the string s (with length len) to a number and +pushes that number into the stack. +The conversion can result in an integer or a float, +according to the lexical conventions of Lua (see §3.1). +The string may have leading and trailing spaces and a sign. +If the string is not a valid numeral, +returns 0 and pushes nothing. + + + + +


                          lua_toboolean

                          [-0, +0, –]

                          int lua_toboolean (lua_State *L, int index);
                          @@ -4697,16 +4817,11 @@

                          4.8 – Functions and Types

                          Converts the Lua value at the given index to the signed integral type lua_Integer. -The Lua value must be a number or a string convertible to a number -(see §3.4.2); +The Lua value must be an integer, +or a number or string convertible to an integer (see §3.4.2); otherwise, lua_tointegerx returns 0. -

                          -If the number is not an integer, -it is truncated in some non-specified way. - -

                          If isnum is not NULL, its referent is assigned a boolean value that @@ -4842,16 +4957,18 @@

                          4.8 – Functions and Types

                          Converts the Lua value at the given index to the unsigned integral type lua_Unsigned. -The Lua value must be a number or a string convertible to a number +The Lua value must be an integer, +or a float, +or a string convertible to a number (see §3.4.2); otherwise, lua_tounsignedx returns 0.

                          If the number is not an integer, -it is truncated in some non-specified way. -If the number is outside the range of representable values, -it is normalized to the remainder of its division by +it is rounded towards minus infinite (floor). +If the result is outside the range of representable values, +it is normalized to the module of its division by one more than the maximum representable value. @@ -4919,13 +5036,7 @@

                          4.8 – Functions and Types

                          typedef unsigned long lua_Unsigned;

                          -The type used by the Lua API to represent unsigned integral values. -It must have at least 32 bits. - - -

                          -By default it is an unsigned int or an unsigned long, -whichever can hold 32-bit values. +The unsigned version of lua_Integer. @@ -5861,8 +5972,9 @@

                          5.1 – Functions and Types

                          int luaL_checkint (lua_State *L, int arg);

                          -Checks whether the function argument arg is a number -and returns this number cast to an int. +Checks whether the function argument arg is an integer +(or can be converted to an integer) +and returns this integer cast to an int. @@ -5873,8 +5985,9 @@

                          5.1 – Functions and Types

                          lua_Integer luaL_checkinteger (lua_State *L, int arg);

                          -Checks whether the function argument arg is a number -and returns this number cast to a lua_Integer. +Checks whether the function argument arg is an integer +(or can be converted to an integer) +and returns this integer cast to a lua_Integer. @@ -5885,8 +5998,9 @@

                          5.1 – Functions and Types

                          long luaL_checklong (lua_State *L, int arg);

                          -Checks whether the function argument arg is a number -and returns this number cast to a long. +Checks whether the function argument arg is an integer +(or can be converted to an integer) +and returns this integer cast to a long. @@ -6016,7 +6130,7 @@

                          5.1 – Functions and Types

                          Checks whether the function argument arg is a number -and returns this number cast to a lua_Unsigned. +and returns this number converted to a lua_Unsigned. @@ -6185,13 +6299,13 @@

                          5.1 – Functions and Types


                          luaL_len

                          [-0, +0, e] -

                          int luaL_len (lua_State *L, int index);
                          +
                          lua_Integer luaL_len (lua_State *L, int index);

                          Returns the "length" of the value at the given index as a number; it is equivalent to the '#' operator in Lua (see §3.4.6). -Raises an error if the result of the operation is not a number. +Raises an error if the result of the operation is not an integer. (This case only can happen through metamethods.) @@ -6413,8 +6527,9 @@

                          5.1 – Functions and Types

                          lua_Integer d);

                          -If the function argument arg is a number, -returns this number cast to a lua_Integer. +If the function argument arg is an integer +(or convertible to an integer), +returns this integer. If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -6428,8 +6543,9 @@

                          5.1 – Functions and Types

                          long luaL_optlong (lua_State *L, int arg, long d);

                          -If the function argument arg is a number, -returns this number cast to a long. +If the function argument arg is an integer +(or convertible to an integer), +returns this integer cast to a long. If this argument is absent or is nil, returns d. Otherwise, raises an error. @@ -6501,7 +6617,7 @@

                          5.1 – Functions and Types

                          If the function argument arg is a number, -returns this number cast to a lua_Unsigned. +returns this number converted to a lua_Unsigned. If this argument is absent or is nil, returns u. Otherwise, raises an error. @@ -7273,11 +7389,17 @@

                          6.1 – Basic Functions

                          When called with no base, tonumber tries to convert its argument to a number. If the argument is already a number or -a string convertible to a number (see §3.4.2), +a string convertible to a number, then tonumber returns this number; otherwise, it returns nil. +

                          +The conversion of strings can result in integers or floats, +according to the lexical conventions of Lua (see §3.1). +(The string may have leading and trailing spaces and a sign.) + +

                          When called with base, then e should be a string to be interpreted as @@ -7329,7 +7451,7 @@

                          6.1 – Basic Functions


                          _VERSION

                          A global variable (not a function) that holds a string containing the current interpreter version. -The current contents of this variable is "Lua 5.2". +The current contents of this variable is "Lua 5.3". @@ -8478,6 +8600,9 @@

                          6.6 – Mathematical Functions

                          This library is an interface to the standard C math library. It provides all its functions inside the table math. +Unless stated otherwise, +all functions in this library operate with and return +floating-point numbers.

                          @@ -8628,6 +8753,29 @@

                          6.6 – Mathematical Functions

                          +

                          +


                          math.ifloor (x)

                          + + +

                          +Returns the largest integer smaller than or equal to x +as an integer number. +If the value does not fit in an integer, +returns nil. + + + + +

                          +


                          math.isfloat (x)

                          + + +

                          +Returns whether x is a floating-point number. + + + +


                          math.ldexp (m, e)

                          @@ -8724,14 +8872,12 @@

                          6.6 – Mathematical Functions

                          When called without arguments, -returns a uniform pseudo-random real number +returns a uniform pseudo-random float number in the range [0,1). -When called with an integer number m, -math.random returns -a uniform pseudo-random integer in the range [1, m]. -When called with two integer numbers m and n, +When called with two integer values m and n, math.random returns a uniform pseudo-random -integer in the range [m, n]. +integer number in the range [m, n]. +The call math.random(n) is equivalent to math.random(1,n). @@ -9885,6 +10031,18 @@

                          6.10 – The Debug Library

                          +

                          +


                          debug.numbits (t)

                          + + +

                          +Returns the number of bits in the underlying representation +of integer (if t is "i") +or float numbers (if t is "f"). + + + +


                          debug.sethook ([thread,] hook, mask [, count])

                          @@ -9893,7 +10051,7 @@

                          6.10 – The Debug Library

                          Sets the given function as a hook. The string mask and the number count describe when the hook will be called. -The string mask may have the following characters, +The string mask may have any combination of the following characters, with the given meaning:
                            @@ -9901,8 +10059,9 @@

                            6.10 – The Debug Library

                          • 'r': the hook is called every time Lua returns from a function;
                          • 'l': the hook is called every time Lua enters a new line of code.

                          -With a count different from zero, -the hook is called after every count instructions. +Moreover, +with a count different from zero, +the hook is called also after every count instructions.

                          @@ -10497,10 +10656,10 @@

                          9 – The Complete Syntax of Lua


                          Last update: -Thu Mar 21 12:58:59 BRT 2013 +Fri Jul 5 23:09:01 BRT 2013 diff --git a/doc/readme.html b/doc/readme.html index 5b9e47ecba..e3ff585050 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -1,7 +1,7 @@ -Lua 5.2 readme +Lua 5.3 readme -

                          - +Lua Lua 5.3 Reference Manual

                          The reference manual is the official definition of the Lua language. +
                          For a complete introduction to Lua programming, see the book Programming in Lua. -

                          +

                          + +

                          Copyright © 2015 Lua.org, PUC-Rio. Freely available under the terms of the @@ -39,7 +38,7 @@

                          Contents

                          -
                            +

                            Index

                            - - +
                            + -
                            - + diff --git a/doc/index.css b/doc/index.css new file mode 100644 index 0000000000..c961835731 --- /dev/null +++ b/doc/index.css @@ -0,0 +1,21 @@ +ul { + list-style-type: none ; +} + +ul.contents { + padding: 0 ; +} + +table { + border: none ; + border-spacing: 0 ; + border-collapse: collapse ; +} + +td { + vertical-align: top ; + padding: 0 ; + text-align: left ; + line-height: 1.25 ; + width: 15% ; +} diff --git a/doc/lua.css b/doc/lua.css index 3199a2b6e8..b614f3c084 100644 --- a/doc/lua.css +++ b/doc/lua.css @@ -3,84 +3,90 @@ html { } body { - border: solid #a0a0a0 1px ; - border-radius: 20px ; - padding: 26px ; - margin: 16px ; - color: #000000 ; background-color: #FFFFFF ; + color: #000000 ; font-family: Helvetica, Arial, sans-serif ; text-align: justify ; + line-height: 1.25 ; + margin: 16px auto ; + padding: 32px ; + border: solid #a0a0a0 1px ; + border-radius: 20px ; + max-width: 70em ; + width: 90% ; } h1, h2, h3, h4 { + color: #000080 ; font-family: Verdana, Geneva, sans-serif ; font-weight: normal ; font-style: normal ; + text-align: left ; } -h2 { - padding-top: 0.4em ; - padding-bottom: 0.4em ; - padding-left: 0.8em ; - padding-right: 0.8em ; - background-color: #D0D0FF ; - border-radius: 8px ; - border: solid #a0a0a0 1px ; +h1 { + font-size: 28pt ; } -h3 { - padding-left: 0.5em ; - border-left: solid #D0D0FF 1em ; +h1 img { + vertical-align: text-bottom ; } -table h3 { - padding-left: 0px ; - border-left: none ; +h2:before { + content: "\2756" ; + padding-right: 0.5em ; } -a:link { - color: #000080 ; - background-color: inherit ; +a { text-decoration: none ; } -a:visited { - background-color: inherit ; - text-decoration: none ; +a:link { + color: #000080 ; } a:link:hover, a:visited:hover { - color: #000080 ; background-color: #D0D0FF ; - border-radius: 4px; + color: #000080 ; + border-radius: 4px ; } a:link:active, a:visited:active { color: #FF0000 ; } -h1 a img { - vertical-align: text-bottom ; +div.menubar { + padding-bottom: 0.5em ; } -hr { - border: 0 ; - height: 1px ; - color: #a0a0a0 ; - background-color: #a0a0a0 ; - display: none ; +p.menubar { + margin-left: 2.5em ; } -table hr { - display: block ; +.menubar a:hover { + margin: -3px -3px -3px -3px ; + padding: 3px 3px 3px 3px ; + border-radius: 4px ; } :target { - background-color: #F8F8F8 ; + background-color: #F0F0F0 ; + margin: -8px ; padding: 8px ; - border: solid #a0a0a0 2px ; border-radius: 8px ; + outline: none ; +} + +hr { + display: none ; +} + +table hr { + background-color: #a0a0a0 ; + color: #a0a0a0 ; + border: 0 ; + height: 1px ; + display: block ; } .footer { @@ -103,3 +109,25 @@ pre.session { padding: 1em ; border-radius: 8px ; } + +td.gutter { + width: 4% ; +} + +table.columns { + border: none ; + border-spacing: 0 ; + border-collapse: collapse ; +} + +table.columns td { + vertical-align: top ; + padding: 0 ; + padding-bottom: 1em ; + text-align: justify ; + line-height: 1.25 ; +} + +p.logos a:link:hover, p.logos a:visited:hover { + background-color: inherit ; +} diff --git a/doc/manual.css b/doc/manual.css index ca613cd9fb..aa0e677dd5 100644 --- a/doc/manual.css +++ b/doc/manual.css @@ -8,20 +8,14 @@ pre, code { } span.apii { + color: gray ; float: right ; font-family: inherit ; font-style: normal ; font-size: small ; - color: gray ; } -p+h1, ul+h1 { - font-style: normal ; - padding-top: 0.4em ; - padding-bottom: 0.4em ; - padding-left: 16px ; - margin-left: -16px ; - background-color: #D0D0FF ; - border-radius: 8px ; - border: solid #000080 1px ; +h2:before { + content: "" ; + padding-right: 0em ; } diff --git a/doc/manual.html b/doc/manual.html index 5ed8f06922..8cdeacfdcf 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,39 +1,41 @@ - - - -Lua 5.3 Reference Manual - - + + +Lua 5.3 Reference Manual + + - + - + -
                            -

                            - +

                            +Lua Lua 5.3 Reference Manual -

                            + +

                            by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes -

                            - + +

                            + Copyright © 2015 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. - -


                            -

                            + -contents +

                            - + @@ -113,15 +115,15 @@

                            2.1 – Values and Types

                            nil, boolean, number, string, function, userdata, thread, and table. -Nil is the type of the value nil, +The type nil has one single value, nil, whose main property is to be different from any other value; it usually represents the absence of a useful value. -Boolean is the type of the values false and true. +The type boolean has two values, false and true. Both nil and false make a condition false; any other value makes it true. -Number represents both +The type number represents both integer numbers and real (floating-point) numbers. -String represents immutable sequences of bytes. +The type string represents immutable sequences of bytes. Lua is 8-bit clean: strings can contain any 8-bit value, @@ -132,6 +134,7 @@

                            2.1 – Values and Types

                            The type number uses two internal representations, +or two subtypes, one called integer and the other called float. Lua has explicit rules about when each representation is used, but it also converts between them automatically as needed (see §3.4.3). @@ -142,7 +145,7 @@

                            2.1 – Values and Types

                            Standard Lua uses 64-bit integers and double-precision (64-bit) floats, but you can also compile Lua so that it uses 32-bit integers and/or single-precision (32-bit) floats. -The option with 32 bits for both integers and floats +The option with 32 bits for both integers and floats is particularly attractive for small machines and embedded systems. (See macro LUA_32BITS in file luaconf.h.) @@ -185,8 +188,8 @@

                            2.1 – Values and Types

                            The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, but with any Lua value except nil and NaN. -(Not a Number is a special numeric value used to represent -undefined or unrepresentable results, such as 0/0.) +(Not a Number is a special numerical value used to represent +undefined or unrepresentable numerical results, such as 0/0.) Tables can be heterogeneous; that is, they can contain values of all types (except nil). Any key with value nil is not considered part of the table. @@ -207,7 +210,7 @@

                            2.1 – Values and Types

                            We use the term sequence to denote a table where -the set of all positive numeric keys is equal to {1..n} +the set of all positive numerical keys is equal to {1..n} for some non-negative integer n, which is called the length of the sequence (see §3.4.7). @@ -372,7 +375,7 @@

                            2.4 – Metatables and Metamethods

                            under certain special operations. You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable. -For instance, when a non-numeric value is the operand of an addition, +For instance, when a non-numerical value is the operand of an addition, Lua checks for a function in the field "__add" of the value's metatable. If it finds one, Lua calls this function to perform the addition. @@ -393,7 +396,7 @@

                            2.4 – Metatables and Metamethods

                            You can replace the metatable of tables using the setmetatable function. -You cannot change the metatable of other types from Lua +You cannot change the metatable of other types from Lua code (except by using the debug library (§6.10)); you must use the C API for that. @@ -425,12 +428,7 @@

                            2.4 – Metatables and Metamethods

                            string "__add". Note that queries for metamethods are always raw; the access to a metamethod does not invoke other metamethods. -You can emulate how Lua queries a metamethod for an object obj -with the following code: -
                            -     rawget(getmetatable(obj) or {}, "__" .. event_name)
                            -

                            For the unary operators (negation, length, and bitwise not), @@ -510,7 +508,7 @@

                            2.4 – Metatables and Metamethods

                            Behavior similar to the "add" operation, except that Lua will try a metamethod -if any operator is neither an integer +if any operand is neither an integer nor a value coercible to an integer (see §3.4.3). @@ -549,7 +547,7 @@

                            2.4 – Metatables and Metamethods

                            Behavior similar to the "add" operation, except that Lua will try a metamethod -if any operator is neither a string nor a number +if any operand is neither a string nor a number (which is always coercible to a string). @@ -599,6 +597,8 @@

                            2.4 – Metatables and Metamethods

                            assuming that a <= b is equivalent to not (b < a). As with the other comparison operators, the result is always a boolean. +(This use of the "__lt" event can be removed in future versions; +it is also slower than a real "__le" metamethod.)
                          • "index": @@ -661,6 +661,13 @@

                            2.4 – Metatables and Metamethods

                          +

                          +It is a good practice to add all needed metamethods to a table +before setting it as a metatable of some object. +In particular, the "__gc" metamethod works only when this order +is followed (see §2.5.1). + + @@ -752,8 +759,6 @@

                          2.5.1 – Garbage-Collection Metamethods

                          Note that if you set a metatable without a __gc field and later create that field in the metatable, the object will not be marked for finalization. -However, after an object has been marked, -you can freely change the __gc field of its metatable.

                          @@ -794,7 +799,7 @@

                          2.5.1 – Garbage-Collection Metamethods

                          its finalizer will be called again in the next cycle where the object is unreachable. In any case, -the object memory is freed only in the GC cycle where +the object memory is freed only in a GC cycle where the object is unreachable and not marked for finalization. @@ -822,8 +827,8 @@

                          2.5.2 – Weak Tables

                          A weak table can have weak keys, weak values, or both. -A table with weak keys allows the collection of its keys, -but prevents the collection of its values. +A table with weak values allows the collection of its values, +but prevents the collection of its keys. A table with both weak keys and weak values allows the collection of both keys and values. In any case, if either the key or the value is collected, @@ -913,10 +918,10 @@

                          2.6 – Coroutines

                          When you first call coroutine.resume, passing as its first argument a thread returned by coroutine.create, -the coroutine starts its execution, -at the first line of its main function. +the coroutine starts its execution by +calling its main function. Extra arguments passed to coroutine.resume are passed -as arguments to the coroutine's main function. +as arguments to that function. After the coroutine starts running, it runs until it terminates or yields. @@ -1195,7 +1200,7 @@

                          3.1 – Lexical Conventions

                          Hexadecimal constants also accept an optional fractional part plus an optional binary exponent, marked by a letter 'p' or 'P'. -A numeric constant with a fractional dot or an exponent +A numerical constant with a fractional dot or an exponent denotes a float; otherwise it denotes an integer. Examples of valid integer constants are @@ -1581,11 +1586,11 @@

                          3.3.5 – For Statement

                          The for statement has two forms: -one numeric and one generic. +one numerical and one generic.

                          -The numeric for loop repeats a block of code while a +The numerical for loop repeats a block of code while a control variable runs through an arithmetic progression. It has the following syntax: @@ -1879,13 +1884,13 @@

                          3.4.1 – Arithmetic Operators

                          Floor division (//) is a division -that rounds the quotient towards minus infinite, +that rounds the quotient towards minus infinity, that is, the floor of the division of its operands.

                          Modulo is defined as the remainder of a division -that rounds the quotient towards minus infinite (floor division). +that rounds the quotient towards minus infinity (floor division).

                          @@ -1972,8 +1977,9 @@

                          3.4.3 – Coercions and Conversions

                          First, the string is converted to an integer or a float, following its syntax and the rules of the Lua lexer. (The string may have also leading and trailing spaces and a sign.) -Then, the resulting number is converted to the required type -(float or integer) according to the previous rules. +Then, the resulting number (float or integer) +is converted to the type (float or integer) required by the context +(e.g., the operation that forced the conversion).

                          @@ -2006,11 +2012,7 @@

                          3.4.4 – Relational Operators

                          If the types are different, then the result is false. Otherwise, the values of the operands are compared. Strings are compared in the obvious way. -Numbers follow the usual rule for binary operations: -if both operands are integers, -they are compared as integers; -otherwise, they are converted to floats -and compared as such. +Numbers are equal if they denote the same mathematical value.

                          @@ -2045,8 +2047,8 @@

                          3.4.4 – Relational Operators

                          The order operators work as follows. If both arguments are numbers, -then they are compared following -the usual rule for binary operations. +then they are compared according to their mathematical values +(regardless of their subtypes). Otherwise, if both arguments are strings, then their values are compared according to the current locale. Otherwise, Lua tries to call the "lt" or the "le" @@ -2055,6 +2057,12 @@

                          3.4.4 – Relational Operators

                          and a >= b is translated to b <= a. +

                          +Following the IEEE 754 standard, +NaN is considered neither smaller than, +nor equal to, nor greater than any value (including itself). + + @@ -2126,7 +2134,7 @@

                          3.4.7 – The Length Operator

                          the length of a table t is only defined if the table is a sequence, that is, -the set of its positive numeric keys is equal to {1..n} +the set of its positive numerical keys is equal to {1..n} for some non-negative integer n. In that case, n is its length. Note that a table like @@ -2137,8 +2145,8 @@

                          3.4.7 – The Length Operator

                          is not a sequence, because it has the key 4 but does not have the key 3. (So, there is no n such that the set {1..n} is equal -to the set of positive numeric keys of that table.) -Note, however, that non-numeric keys do not interfere +to the set of positive numerical keys of that table.) +Note, however, that non-numerical keys do not interfere with whether a table is a sequence. @@ -2636,29 +2644,22 @@

                          4.3 – Valid and Acceptable Indices

                          A valid index is an index that refers to a -real position within the stack, that is, -its position lies between 1 and the stack top -(1 ≤ abs(index) ≤ top). - -Usually, functions that can modify the value at an index -require valid indices. - - -

                          -Unless otherwise noted, -any function that accepts valid indices also accepts pseudo-indices, -which represent some Lua values that are accessible to C code -but which are not in the stack. -Pseudo-indices are used to access the registry +position that stores a modifiable Lua value. +It comprises stack indices between 1 and the stack top +(1 ≤ abs(index) ≤ top) + +plus pseudo-indices, +which represent some positions that are accessible to C code +but that are not in the stack. +Pseudo-indices are used to access the registry (see §4.5) and the upvalues of a C function (see §4.4).

                          -Functions that do not need a specific stack position, -but only a value in the stack (e.g., query functions), +Functions that do not need a specific mutable position, +but only a value (e.g., query functions), can be called with acceptable indices. An acceptable index can be any valid index, -including the pseudo-indices, but it also can be any positive index after the stack top within the space allocated for the stack, that is, indices up to the stack size. @@ -2701,7 +2702,7 @@

                          4.4 – C Closures

                          its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro lua_upvalueindex. -The first value associated with a function is at position +The first upvalue associated with a function is at index lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), where n is greater than the number of upvalues of the @@ -2719,8 +2720,7 @@

                          4.5 – Registry

                          a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index -LUA_REGISTRYINDEX, -which is a valid index. +LUA_REGISTRYINDEX. Any C library can store data into this table, but it must take care to choose keys that are different from those used @@ -2981,7 +2981,8 @@

                          4.8 – Functions and Types

                          int lua_absindex (lua_State *L, int idx);

                          -Converts the acceptable index idx into an absolute index +Converts the acceptable index idx +into an equivalent absolute index (that is, one that does not depend on the stack top). @@ -3661,7 +3662,7 @@

                          4.8 – Functions and Types

                          (usually a 64-bit two-complement integer), but that can be changed to long or int (usually a 32-bit two-complement integer). -(See LUA_INT in luaconf.h.) +(See LUA_INT_TYPE in luaconf.h.)

                          @@ -4068,7 +4069,7 @@

                          4.8 – Functions and Types


                          lua_Number

                          -
                          typedef double lua_Number;
                          +
                          typedef ... lua_Number;

                          The type of floats in Lua. @@ -4076,8 +4077,8 @@

                          4.8 – Functions and Types

                          By default this type is double, -but that can be changed to a single float. -(See LUA_REAL in luaconf.h.) +but that can be changed to a single float or a long double. +(See LUA_FLOAT_TYPE in luaconf.h.) @@ -4133,7 +4134,7 @@

                          4.8 – Functions and Types

                          is exactly the original error message. Otherwise, msgh is the stack index of a message handler. -(In the current implementation, this index cannot be a pseudo-index.) +(This index cannot be a pseudo-index.) In case of runtime errors, this function will be called with the error message and its return value will be the message @@ -4267,20 +4268,11 @@

                          4.8 – Functions and Types

                          -Any function to be registered in Lua must +Any function to be callable by Lua must follow the correct protocol to receive its parameters and return its results (see lua_CFunction). -

                          -lua_pushcfunction is defined as a macro: - -

                          -     #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
                          -

                          -Note that f is used twice. - - @@ -4309,7 +4301,7 @@

                          4.8 – Functions and Types

                          '%%' (inserts the character '%'), '%s' (inserts a zero-terminated string, with no size restrictions), '%f' (inserts a lua_Number), -'%L' (inserts a lua_Integer), +'%I' (inserts a lua_Integer), '%p' (inserts a pointer as a hexadecimal numeral), '%d' (inserts an int), '%c' (inserts an int as a one-byte character), and @@ -4369,9 +4361,8 @@

                          4.8 – Functions and Types

                          const char *lua_pushliteral (lua_State *L, const char *s);

                          -This macro is equivalent to lua_pushlstring, -but can be used only when s is a literal string. -It automatically provides the string length. +This macro is equivalent to lua_pushstring, +but should be used only when s is a literal string. @@ -4598,9 +4589,9 @@

                          4.8 – Functions and Types

                          void lua_rawsetp (lua_State *L, int index, const void *p);

                          -Does the equivalent of t[k] = v, +Does the equivalent of t[p] = v, where t is the table at the given index, -k is the pointer p represented as a light userdata, +p is encoded as a light userdata, and v is the value at the top of the stack. @@ -4672,7 +4663,7 @@

                          4.8 – Functions and Types

                          Moves the top element into the given valid index without shifting any element -(therefore replacing the value at the given index), +(therefore replacing the value at that given index), and then pops the top element. @@ -4684,7 +4675,7 @@

                          4.8 – Functions and Types

                          int lua_resume (lua_State *L, lua_State *from, int nargs);

                          -Starts and resumes a coroutine in a given thread. +Starts and resumes a coroutine in the given thread L.

                          @@ -4731,12 +4722,16 @@

                          4.8 – Functions and Types

                          void lua_rotate (lua_State *L, int idx, int n);

                          -Rotates the stack elements from idx to the top n positions -in the direction of the top, for a positive n, +Rotates the stack elements between the valid index idx +and the top of the stack. +The elements are rotated n positions in the direction of the top, +for a positive n, or -n positions in the direction of the bottom, for a negative n. The absolute value of n must not be greater than the size of the slice being rotated. +This function cannot be called with a pseudo-index, +because a pseudo-index is not an actual stack position. @@ -5072,7 +5067,7 @@

                          4.8 – Functions and Types

                          -Typically this function is used only for debug information. +Typically this function is used only for hashing and debug information. @@ -5127,7 +5122,7 @@

                          4.8 – Functions and Types

                          or LUA_TNONE for a non-valid (but acceptable) index. The types returned by lua_type are coded by the following constants defined in lua.h: -LUA_TNIL, +LUA_TNIL (0), LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, @@ -5618,24 +5613,26 @@

                          4.9 – The Debug Interface

                          const char *lua_getupvalue (lua_State *L, int funcindex, int n);

                          -Gets information about a closure's upvalue. -(For Lua functions, -upvalues are the external local variables that the function uses, -and that are consequently included in its closure.) -lua_getupvalue gets the index n of an upvalue, -pushes the upvalue's value onto the stack, +Gets information about the n-th upvalue +of the closure at index funcindex. +It pushes the upvalue's value onto the stack and returns its name. -funcindex points to the closure in the stack. -(Upvalues have no particular order, -as they are active through the whole function. -So, they are numbered in an arbitrary order.) +Returns NULL (and pushes nothing) +when the index n is greater than the number of upvalues.

                          -Returns NULL (and pushes nothing) -when the index is greater than the number of upvalues. For C functions, this function uses the empty string "" as a name for all upvalues. +(For Lua functions, +upvalues are the external local variables that the function uses, +and that are consequently included in its closure.) + + +

                          +Upvalues have no particular order, +as they are active through the whole function. +They are numbered in an arbitrary order. @@ -5680,10 +5677,10 @@

                          4.9 – The Debug Interface

                          Hook functions can yield under the following conditions: -Only count and line events can yield -and they cannot yield any value; -to yield a hook function must finish its execution -calling lua_yield with nresults equal to zero. +Only count and line events can yield; +to yield, a hook function must finish its execution +calling lua_yield with nresults equal to zero +(that is, with no values). @@ -5748,9 +5745,7 @@

                          4.9 – The Debug Interface

                          Sets the value of a local variable of a given activation record. -Parameters ar and n are as in lua_getlocal -(see lua_getlocal). -lua_setlocal assigns the value at the top of the stack +It assigns the value at the top of the stack to the variable and returns its name. It also pops the value from the stack. @@ -5761,6 +5756,10 @@

                          4.9 – The Debug Interface

                          the number of active local variables. +

                          +Parameters ar and n are as in function lua_getlocal. + + @@ -5773,13 +5772,15 @@

                          4.9 – The Debug Interface

                          It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. -Parameters funcindex and n are as in the lua_getupvalue -(see lua_getupvalue).

                          Returns NULL (and pops nothing) -when the index is greater than the number of upvalues. +when the index n is greater than the number of upvalues. + + +

                          +Parameters funcindex and n are as in function lua_getupvalue. @@ -5792,9 +5793,6 @@

                          4.9 – The Debug Interface

                          Returns a unique identifier for the upvalue numbered n from the closure at index funcindex. -Parameters funcindex and n are as in the lua_getupvalue -(see lua_getupvalue) -(but n cannot be greater than the number of upvalues).

                          @@ -5805,6 +5803,11 @@

                          4.9 – The Debug Interface

                          will return identical ids for those upvalue indices. +

                          +Parameters funcindex and n are as in function lua_getupvalue, +but n cannot be greater than the number of upvalues. + + @@ -6367,9 +6370,9 @@

                          5.1 – Functions and Types

                          Pushes onto the stack the metatable associated with name tname -in the registry (see luaL_newmetatable). -If there is no metatable associated with tname, -returns false and pushes nil. +in the registry (see luaL_newmetatable) +(nil if there is no metatable associated with that name). +Returns the type of the pushed value. @@ -7332,8 +7335,8 @@

                          6.1 – Basic Functions

                          The order in which the indices are enumerated is not specified, -even for numeric indices. -(To traverse a table in numeric order, +even for numerical indices. +(To traverse a table in numerical order, use a numerical for.) @@ -7522,8 +7525,6 @@

                          6.1 – Basic Functions


                          tostring (v)

                          Receives a value of any type and converts it to a string in a human-readable format. -Floats always produce strings with some -floating-point indication (either a decimal dot or an exponent). (For complete control of how numbers are converted, use string.format.) @@ -7579,8 +7580,8 @@

                          6.1 – Basic Functions

                          6.2 – Coroutine Manipulation

                          -The operations related to coroutines comprise a sub-library of -the basic library and come inside the table coroutine. +This library comprise the operations to manipulate coroutines, +which come inside the table coroutine. See §2.6 for a general description of coroutines. @@ -7590,7 +7591,7 @@

                          6.2 – Coroutine Manipulation

                          Creates a new coroutine, with body f. -f must be a Lua function. +f must be a function. Returns this new coroutine, an object with type "thread". @@ -7674,7 +7675,7 @@

                          6.2 – Coroutine Manipulation

                          Creates a new coroutine, with body f. -f must be a Lua function. +f must be a function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. @@ -8186,18 +8187,23 @@

                          6.4 – String Manipulation

                          Options -A and a (when available), -E, e, f, +A, a, E, e, f, G, and g all expect a number as argument. Options c, d, i, o, u, X, and x expect an integer. -Option q expects a string; -option s expects a string without embedded zeros. -If the argument to option s is not a string, +Option q expects a string. +Option s expects a string without embedded zeros; +if its argument is not a string, it is converted to one following the same rules of tostring. +

                          +When Lua is compiled with a non-C99 compiler, +options A and a (hexadecimal floats) +do not support any modifier (flags, width, length). + +

                          @@ -8859,7 +8865,7 @@

                          6.6 – Table Manipulation

                          Remember that, whenever an operation needs the length of a table, the table must be a proper sequence or have a __len metamethod (see §3.4.7). -All functions ignore non-numeric keys +All functions ignore non-numerical keys in the tables given as arguments. @@ -8904,7 +8910,7 @@

                          6.6 – Table Manipulation

                          a2[t],··· = a1[f],···,a1[e]. The default for a2 is a1. The destination range can overlap with the source range. -Index f must be positive. +The number of elements to be moved must fit in a Lua integer. @@ -9946,16 +9952,25 @@

                          6.9 – Operating System Facilities

                          Returns the current time when called without arguments, -or a time representing the date and time specified by the given table. +or a time representing the local date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour (default is 12), min (default is 0), sec (default is 0), and isdst (default is nil). +Other fields are ignored. For a description of these fields, see the os.date function. +

                          +The values in these fields do not need to be inside their valid ranges. +For instance, if sec is -10, +it means -10 seconds from the time specified by the other fields; +if hour is 1000, +it means +1000 hours from the time specified by the other fields. + +

                          The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, @@ -10093,7 +10108,7 @@

                          6.10 – The Debug Library

                          For instance, the expression debug.getinfo(1,"n").name returns -a table with a name for the current function, +a name for the current function, if a reasonable name can be found, and the expression debug.getinfo(print) returns a table with all available information @@ -10520,7 +10535,7 @@

                          8 – Incompatibilities with the Previous Version

                          Lua versions can always change the C API in ways that do not imply source-code changes in a program, -such as the numeric values for constants +such as the numerical values for constants or the implementation of functions as macros. Therefore, you should not assume that binaries are compatible between @@ -10599,7 +10614,8 @@

                          8.2 – Changes in the Libraries

                          It is easy to require a compatible external library or, better yet, to replace its functions with appropriate bitwise operations. (Keep in mind that bit32 operates on 32-bit integers, -while the bitwise operators in standard Lua operate on 64-bit integers.) +while the bitwise operators in Lua 5.3 operate on Lua integers, +which by default have 64 bits.)
                        3. @@ -10614,7 +10630,7 @@

                          8.2 – Changes in the Libraries

                        4. Option names in io.read do not have a starting '*' anymore. -For compatibility, Lua will continue to ignore this character. +For compatibility, Lua will continue to accept (and ignore) this character.
                        5. @@ -10641,6 +10657,12 @@

                          8.2 – Changes in the Libraries

                          but it did not document the change.)
                        6. +
                        7. +The call collectgarbage("count") now returns only one result. +(You can compute that second result from the fractional part +of the first result.) +
                        8. +
                      @@ -10776,13 +10798,12 @@

                      9 – The Complete Syntax of Lua

                      -
                      - + diff --git a/doc/readme.html b/doc/readme.html index 0165755701..152246f917 100644 --- a/doc/readme.html +++ b/doc/readme.html @@ -7,9 +7,9 @@